Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| SHA1 Hash: | 70bf1f87e4f7b0d6083c39e7bb0a49203f8ea3e7 |
|---|---|
| Date: | 2008-11-13 17:28:33 |
| User: | stephan |
| Comment: | fixed missing-children bug in sql reader (required an extra alloc, though :() |
Changes
Changes to src/c11n_io_handler_sql.c
| Old (47c8a0b6690ef747) | New (8d436283c0bcbe1c) | |||
|---|---|---|---|---|
| 1 | #include <stdlib.h> /* malloc()/free() */ | 1 | #include <stdlib.h> /* malloc()/free() */ | |
| 2 | #include <sqlite3.h> | 2 | #include <sqlite3.h> | |
| 3 | #include <assert.h> | 3 | #include <assert.h> | |
| 4 | #include "s11n.net/c11n/io/c11n_io_handler_sql.h" | 4 | #include "s11n.net/c11n/io/c11n_io_handler_sql.h" | |
| 5 | #include "s11n.net/c11n/io/c11n_stream_whclob.h" | 5 | #include "s11n.net/c11n/io/c11n_stream_whclob.h" | |
| 86 hidden lines | ||||
| 92 | while( SQLITE_ROW == rc ) | 92 | while( SQLITE_ROW == rc ) | |
| 93 | { | 93 | { | |
| 94 | c11n_node * n = c11n_node_create( 0 ); | 94 | c11n_node * n = c11n_node_create( 0 ); | |
| 95 | if( ! impl->root ) impl->root = n; | 95 | if( ! impl->root ) impl->root = n; | |
| 96 | const char * k = (char const *)sqlite3_column_text(stmt,0); | 96 | const char * k = (char const *)sqlite3_column_text(stmt,0); | |
| > | 97 | #if 1 | ||
| 97 | c11n_node_prop_set( n, ".id", k ); | 98 | c11n_node_prop_set( n, ".id", k ); | |
| 98 | #if 0 | | | 99 | /* We have to copy this string to avoid lifetime issues - stmt owns k. |
| 99 | whhash_insert( impl->ht, c11n_copy_str( k ), n ); /* We have to copy this string to avoid lifetime issues - stmt owns k. */ | | | 100 | In theory we could use the value from c11n_node_prop_get(n,".id",&k), |
| | | 101 | but when i do so the address of k is stored in the hashtable, which | ||
| | | 102 | isn't useful because it's the same on each loop iteration. | ||
| | | 103 | */ | ||
| | | 104 | whhash_insert( impl->ht, c11n_copy_str( k ), n ); | ||
| 100 | #else | 105 | #else | |
| 101 | c11n_node_prop_get( n, ".id", &k ); | 106 | c11n_node_prop_get( n, ".id", &k ); | |
| 102 | whhash_insert( impl->ht, (char /*i fucking hate this cast*/ *)k, n ); /* c11n_node_prop_get() copies k, so we can use that copy as a key. */ | 107 | whhash_insert( impl->ht, (char /*i fucking hate this cast*/ *)k, n ); /* c11n_node_prop_get() copies k, so we can use that copy as a key. */ | |
| 103 | #endif | 108 | #endif | |
| > | 109 | //MARKER("Added .id [%s] = node@%p\n", k, whhash_search(impl->ht,k) ); | ||
| 104 | k = (char const *) sqlite3_column_text(stmt,1); | 110 | k = (char const *) sqlite3_column_text(stmt,1); | |
| 105 | c11n_node_prop_set( n, ".pid", k ); | 111 | c11n_node_prop_set( n, ".pid", k ); | |
| 106 | k = (char const *) sqlite3_column_text(stmt,2); | 112 | k = (char const *) sqlite3_column_text(stmt,2); | |
| 107 | c11n_node_set_name( n, k ); | 113 | c11n_node_set_name( n, k ); | |
| 108 | k = (char const *) sqlite3_column_text(stmt,3); | 114 | k = (char const *) sqlite3_column_text(stmt,3); | |
| 109 | c11n_node_set_class( n, k ); | 115 | c11n_node_set_class( n, k ); | |
| 110 | rc = sqlite3_step(stmt); | 116 | rc = sqlite3_step(stmt); | |
| 111 | } | 117 | } | |
| 112 | sqlite3_finalize(stmt); | 118 | sqlite3_finalize(stmt); | |
| 113 | if( (SQLITE_DONE != rc) && (SQLITE_OK != rc) ) return false; | | | 119 | if( (SQLITE_DONE != rc) && (SQLITE_OK != rc) ) |
| 114 | //MARKER("root = @%p. Hashed %u entries.\n",impl->root,whhash_count(impl->ht)); | | | 120 | { |
| | | 121 | C11N_LOG(C11N_LOG_IO_ERR)("FIXME: loading of nodes from SQL failed at a bad point. We're probably leaking nodes here!"); | ||
| | | 122 | return false; | ||
| | | 123 | } | ||
| | | 124 | //MARKER("root = @%p. Hashed %u entries.\n",(void const *)impl->root,whhash_count(impl->ht)); | ||
| 115 | whhash_iter * hit = whhash_get_iter(impl->ht); | 125 | whhash_iter * hit = whhash_get_iter(impl->ht); | |
| 116 | if( ! hit ) return false; | 126 | if( ! hit ) return false; | |
| 117 | bool isokay = true; | 127 | bool isokay = true; | |
| 118 | do | 128 | do | |
| 119 | { | 129 | { | |
| 2 hidden lines | ||||
| 122 | char const * key = 0; | 132 | char const * key = 0; | |
| 123 | c11n_node_prop_get( aN, ".pid", &key ); | 133 | c11n_node_prop_get( aN, ".pid", &key ); | |
| 124 | assert( key && "got an empty .pid!"); | 134 | assert( key && "got an empty .pid!"); | |
| 125 | //MARKER("aN.pid=[%s]\n", key ); | 135 | //MARKER("aN.pid=[%s]\n", key ); | |
| 126 | c11n_node * aP = (c11n_node *)whhash_search( impl->ht, key ); | 136 | c11n_node * aP = (c11n_node *)whhash_search( impl->ht, key ); | |
| 127 | //MARKER("node#%s p=%p aN.pid=#%s\n", (char const *)whhash_iter_key(hit), aP, key ); | | | 137 | //MARKER("node#%s parent=%p aN.pid=#%s\n", (char const *)whhash_iter_key(hit), (void const *)aP, key ); |
| 128 | size_t NID = 0; | 138 | size_t NID = 0; | |
| 129 | c11n_node_prop_get_fe( aN, ".id", "%lu", &NID ); | 139 | c11n_node_prop_get_fe( aN, ".id", "%lu", &NID ); | |
| 130 | c11n_node_prop_unset( aN, ".id" ); | 140 | c11n_node_prop_unset( aN, ".id" ); | |
| 131 | c11n_node_prop_unset( aN, ".pid" ); | 141 | c11n_node_prop_unset( aN, ".pid" ); | |
| 132 | if( aP ) | 142 | if( aP ) | |
| 95 hidden lines | ||||
| 228 | "DROP INDEX IF EXISTS ndx_nodes;\n" | 238 | "DROP INDEX IF EXISTS ndx_nodes;\n" | |
| 229 | "DROP INDEX IF EXISTS ndx_props;\n" | 239 | "DROP INDEX IF EXISTS ndx_props;\n" | |
| 230 | "DROP TABLE IF EXISTS n;\n" | 240 | "DROP TABLE IF EXISTS n;\n" | |
| 231 | "DROP TABLE IF EXISTS p;\n" | 241 | "DROP TABLE IF EXISTS p;\n" | |
| 232 | "\n" | 242 | "\n" | |
| 233 | "CREATE TABLE n -- c11n_node trees\n" | | | 243 | "CREATE TABLE n -- c11n_node tree\n" |
| 234 | "(\n" | 244 | "(\n" | |
| 235 | " id INTEGER PRIMARY KEY AUTOINCREMENT,\n" | 245 | " id INTEGER PRIMARY KEY AUTOINCREMENT,\n" | |
| 236 | " pid INTEGER REFERENCES n(id),\n" | 246 | " pid INTEGER REFERENCES n(id),\n" | |
| 237 | " name TEXT,\n" | 247 | " name TEXT,\n" | |
| 238 | " class TEXT\n" | 248 | " class TEXT\n" | |
| 30 hidden lines | ||||
| 269 | } | 279 | } | |
| 270 | static bool c11n_io_handler_sql_save_one_node( c11n_io_handler * self, | 280 | static bool c11n_io_handler_sql_save_one_node( c11n_io_handler * self, | |
| 271 | c11n_node const * src, | 281 | c11n_node const * src, | |
| 272 | c11n_stream * dest ) | 282 | c11n_stream * dest ) | |
| 273 | { | 283 | { | |
| 274 | #define PUL(X) ((unsigned int)(X)) | | | 284 | #define PUL(X) ((unsigned long)(X)) |
| 275 | c11n_node const * par = c11n_node_parent_c( src ); | 285 | c11n_node const * par = c11n_node_parent_c( src ); | |
| > | 286 | /** | ||
| > | 287 | Maybe todo: replace the %Q writef specifiers with | ||
| > | 288 | c11n_io_escape_string(). %Q is an extension of vappendf(), | ||
| > | 289 | inherited from the sqlite3 origins of vappendf()'s | ||
| > | 290 | implementation. | ||
| > | 291 | */ | ||
| 276 | c11n_stream_writef( dest, | 292 | c11n_stream_writef( dest, | |
| 277 | "INSERT INTO n (id,pid,name,class) " | 293 | "INSERT INTO n (id,pid,name,class) " | |
| 278 | "VALUES (%u,%u,%Q,%Q);\n", | 294 | "VALUES (%u,%u,%Q,%Q);\n", | |
| 279 | PUL(src), | 295 | PUL(src), | |
| 280 | PUL((par?par:0)), | 296 | PUL((par?par:0)), | |
| 10 hidden lines | ||||
| 291 | c11n_prop_iter_key( &piter ), | 307 | c11n_prop_iter_key( &piter ), | |
| 292 | c11n_prop_iter_val( &piter ) ); | 308 | c11n_prop_iter_val( &piter ) ); | |
| 293 | if( ! rc ) return false; | 309 | if( ! rc ) return false; | |
| 294 | c11n_prop_iter_next(&piter); | 310 | c11n_prop_iter_next(&piter); | |
| 295 | } | 311 | } | |
| 296 | #undef PUL | | | 312 | #undef PUL /* i sometimes find it interesting that even though macros do not respect scope, we programmers tend to respect it when defining/undefining macros. */ |
| 297 | c11n_node_iter_c chi = c11n_node_children_iter_c( src ); | 313 | c11n_node_iter_c chi = c11n_node_children_iter_c( src ); | |
| 298 | while( c11n_node_iter_isvalid_c( &chi ) ) | 314 | while( c11n_node_iter_isvalid_c( &chi ) ) | |
| 299 | { | 315 | { | |
| 300 | if( ! c11n_io_handler_sql_save_one_node( self, chi.node, dest ) ) return false; | 316 | if( ! c11n_io_handler_sql_save_one_node( self, chi.node, dest ) ) return false; | |
| 301 | c11n_node_iter_next_c(&chi); | 317 | c11n_node_iter_next_c(&chi); | |
| 302 | } | 318 | } | |
| 303 | 319 | |||
| 304 | return true; | 320 | return true; | |
| 305 | } | 321 | } | |
| > | 322 | |||
| 306 | /** | 323 | /** | |
| 307 | Implementation of c11n_io_handler::save_node() for c11n_io_handler_sql. | 324 | Implementation of c11n_io_handler::save_node() for c11n_io_handler_sql. | |
| 308 | */ | 325 | */ | |
| 309 | static bool c11n_io_handler_sql_save_root_node( c11n_io_handler * self, | 326 | static bool c11n_io_handler_sql_save_root_node( c11n_io_handler * self, | |
| 310 | c11n_node const * src, | 327 | c11n_node const * src, | |
| 79 hidden lines | ||||
| 390 | meta->ht = whhash_create(17, | 407 | meta->ht = whhash_create(17, | |
| 391 | whhash_hash_cstring_djb2m, | 408 | whhash_hash_cstring_djb2m, | |
| 392 | whhash_cmp_cstring ); | 409 | whhash_cmp_cstring ); | |
| 393 | if( meta->ht ) | 410 | if( meta->ht ) | |
| 394 | { | 411 | { | |
| 395 | //whhash_set_dtors( meta->ht, free, 0 ); | | | 412 | whhash_set_dtors( meta->ht, free, 0 ); |
| 396 | st->implData = meta; | 413 | st->implData = meta; | |
| 397 | } | 414 | } | |
| 398 | else | 415 | else | |
| 399 | { | 416 | { | |
| 400 | st->api->destroy(st); | 417 | st->api->destroy(st); | |
| 17 hidden lines | ||||
| 418 | 435 | |||
| 419 | c11n_io_handler * c11n_io_handler_factory_sql( c11n_const_string_t ignored ) | 436 | c11n_io_handler * c11n_io_handler_factory_sql( c11n_const_string_t ignored ) | |
| 420 | { | 437 | { | |
| 421 | return c11n_io_handler_sql_new(); | 438 | return c11n_io_handler_sql_new(); | |
| 422 | } | 439 | } | |