r66680 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r66679‎ | r66680 | r66681 >
Date:04:33, 20 May 2010
Author:jeroendedauw
Status:deferred
Tags:
Comment:
Changes for 1.5.1 - improved table and index creation code in the SQL store. Will follow up soon with fix for the light store.
Modified paths:
  • /trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLHelpers.php (modified) (history)
  • /trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore2.php (modified) (history)
  • /trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStoreLight.php (modified) (history)

Diff [purge]

Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStoreLight.php
@@ -995,8 +995,8 @@
996996 $fieldarray[$fieldname] = $dbtypes[$typeid];
997997 }
998998 $indexes = array_merge( $indexes, $proptable->indexes );
999 - SMWSQLHelpers::setupTable( $db->tableName( $proptable->name ), $fieldarray, $db, $reportTo );
1000 - SMWSQLHelpers::setupIndex( $db->tableName( $proptable->name ), $indexes, $db );
 999+ SMWSQLHelpers::setupTable( $proptable->name, $fieldarray, $db, $reportTo );
 1000+ SMWSQLHelpers::setupIndex( $proptable->name, $indexes, $db );
10011001 }
10021002
10031003 $this->reportProgress( "Database initialised successfully.\n\n", $verbose );
Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore2.php
@@ -1182,9 +1182,11 @@
11831183
11841184 public function getStatistics() {
11851185 wfProfileIn( 'SMWSQLStore2::getStatistics (SMW)' );
 1186+
11861187 $db = wfGetDB( DB_SLAVE );
11871188 $result = array();
11881189 $proptables = self::getPropertyTables();
 1190+
11891191 // count number of declared properties by counting "has type" annotations
11901192 $typeprop = SMWPropertyValue::makeProperty( '_TYPE' );
11911193 $typetable = $proptables[self::findPropertyTableID( $typeprop )];
@@ -1192,10 +1194,12 @@
11931195 $row = $db->fetchObject( $res );
11941196 $result['DECLPROPS'] = $row->count;
11951197 $db->freeResult( $res );
 1198+
11961199 // count property uses by counting rows in property tables,
11971200 // count used properties by counting distinct properties in each table
11981201 $result['PROPUSES'] = 0;
11991202 $result['USEDPROPS'] = 0;
 1203+
12001204 foreach ( self::getPropertyTables() as $proptable ) {
12011205 /// Note: subproperties that are part of container values are counted individually;
12021206 /// It does not seem to be important to filter them by adding more conditions.
@@ -1203,6 +1207,7 @@
12041208 $row = $db->fetchObject( $res );
12051209 $result['PROPUSES'] += $row->count;
12061210 $db->freeResult( $res );
 1211+
12071212 if ( $proptable->fixedproperty == false ) {
12081213 $res = $db->select( $proptable->name, 'COUNT(DISTINCT(p_id)) AS count', '', 'SMW::getStatistics' );
12091214 $row = $db->fetchObject( $res );
@@ -1211,6 +1216,7 @@
12121217 $res = $db->select( $proptable->name, '*', '', 'SMW::getStatistics', array( 'LIMIT' => 1 ) );
12131218 if ( $db->numRows( $res ) > 0 ) $result['USEDPROPS']++;
12141219 }
 1220+
12151221 $db->freeResult( $res );
12161222 }
12171223
@@ -1260,7 +1266,6 @@
12611267 protected function setupTables( $verbose, $db ) {
12621268 global $wgDBtype;
12631269
1264 - extract( $db->tableNames( 'smw_ids', 'smw_spec2', 'smw_conccache', 'smw_conc2' ) );
12651270 $reportTo = $verbose ? $this : null; // Use $this to report back from static SMWSQLHelpers.
12661271
12671272 // Repeatedly used DB field types defined here for convenience.
@@ -1276,6 +1281,8 @@
12771282 'w' => SMWSQLHelpers::getStandardDBType( 'iw' )
12781283 );
12791284
 1285+ $smw_spec2 = $db->tableName( 'smw_spec2' );
 1286+
12801287 // DB update: field renaming between SMW 1.3 and SMW 1.4.
12811288 if ( ( $db->tableExists( $smw_spec2 ) ) && ( $db->fieldExists( $smw_spec2, 'sp_id', 'SMWSQLStore2::setup' ) ) ) {
12821289 if ( $wgDBtype == 'postgres' ) {
@@ -1287,7 +1294,7 @@
12881295
12891296 // Set up table for internal IDs used in this store:
12901297 SMWSQLHelpers::setupTable(
1291 - $smw_ids,
 1298+ 'smw_ids',
12921299 array(
12931300 'smw_id' => $dbtypes['p'] . ' NOT NULL' . ( $wgDBtype == 'postgres' ? ' PRIMARY KEY' : ' KEY AUTO_INCREMENT' ),
12941301 'smw_namespace' => $dbtypes['n'] . ' NOT NULL',
@@ -1299,11 +1306,11 @@
13001307 $reportTo
13011308 );
13021309
1303 - SMWSQLHelpers::setupIndex( $smw_ids, array( 'smw_id', 'smw_title,smw_namespace,smw_iw', 'smw_sortkey' ), $db );
 1310+ SMWSQLHelpers::setupIndex( 'smw_ids', array( 'smw_id', 'smw_title,smw_namespace,smw_iw', 'smw_sortkey' ), $db );
13041311
13051312 // Set up concept cache: member elements (s)->concepts (o)
13061313 SMWSQLHelpers::setupTable(
1307 - $smw_conccache,
 1314+ 'smw_conccache',
13081315 array(
13091316 's_id' => $dbtypes['p'] . ' NOT NULL',
13101317 'o_id' => $dbtypes['p'] . ' NOT NULL'
@@ -1312,11 +1319,11 @@
13131320 $reportTo
13141321 );
13151322
1316 - SMWSQLHelpers::setupIndex( $smw_conccache, array( 'o_id' ), $db );
 1323+ SMWSQLHelpers::setupIndex( 'smw_conccache', array( 'o_id' ), $db );
13171324
13181325 // Set up concept descriptions.
13191326 SMWSQLHelpers::setupTable(
1320 - $smw_conc2,
 1327+ 'smw_conc2',
13211328 array(
13221329 's_id' => $dbtypes['p'] . ' NOT NULL' . ( $wgDBtype == 'postgres' ? ' PRIMARY KEY' : ' KEY' ),
13231330 'concept_txt' => $dbtypes['l'],
@@ -1331,7 +1338,7 @@
13321339 $reportTo
13331340 );
13341341
1335 - SMWSQLHelpers::setupIndex( $smw_conc2, array( 's_id' ), $db );
 1342+ SMWSQLHelpers::setupIndex( 'smw_conc2', array( 's_id' ), $db );
13361343
13371344 // Set up all property tables as defined:
13381345 $this->setupPropertyTables( $dbtypes, $db, $reportTo );
@@ -1378,8 +1385,8 @@
13791386
13801387 $indexes = array_merge( $indexes, $proptable->indexes );
13811388
1382 - SMWSQLHelpers::setupTable( $db->tableName( $proptable->name ), $fieldarray, $db, $reportTo );
1383 - SMWSQLHelpers::setupIndex( $db->tableName( $proptable->name ), $indexes, $db );
 1389+ SMWSQLHelpers::setupTable( $proptable->name, $fieldarray, $db, $reportTo );
 1390+ SMWSQLHelpers::setupIndex( $proptable->name, $indexes, $db );
13841391 }
13851392 }
13861393
@@ -2432,6 +2439,7 @@
24332440 */
24342441 public static function getPropertyTables() {
24352442 if ( count( self::$prop_tables ) > 0 ) return self::$prop_tables; // don't initialise twice
 2443+
24362444 self::$prop_tables['smw_rels2'] = new SMWSQLStore2Table( 'smw_rels2',
24372445 array( 'o_id' => 'p' ),
24382446 array( 'o_id' ) );
Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLHelpers.php
@@ -5,6 +5,8 @@
66 *
77 * @author Markus Krötzsch
88 * @author Marcel Gsteiger
 9+ * @author Jeroen De Dauw
 10+ *
911 * @file
1012 * @ingroup SMWStore
1113 */
@@ -12,6 +14,7 @@
1315 /**
1416 * Static class to collect some helper functions that SMW uses
1517 * for settnig up SQL databases.
 18+ *
1619 * @ingroup SMWStore
1720 */
1821 class SMWSQLHelpers {
@@ -26,13 +29,15 @@
2730 */
2831 static public function getStandardDBType( $input ) {
2932 global $wgDBtype;
 33+
3034 switch ( $input ) {
31 - case 'id': return $wgDBtype == 'postgres' ? 'SERIAL':'INT(8) UNSIGNED'; // like page_id in MW page table
32 - case 'namespace': return $wgDBtype == 'postgres' ? 'BIGINT':'INT(11)'; // like page_namespace in MW page table
33 - case 'title': return $wgDBtype == 'postgres' ? 'TEXT':'VARBINARY(255)'; // like page_title in MW page table
34 - case 'iw': return $wgDBtype == 'postgres' ? 'TEXT':'VARCHAR(32) binary'; // like iw_prefix in MW interwiki table
35 - case 'blob': return $wgDBtype == 'postgres' ? 'BYTEA':'MEDIUMBLOB'; // larger blobs of character data, usually not subject to SELECT conditions
 35+ case 'id': return $wgDBtype == 'postgres' ? 'SERIAL' : 'INT(8) UNSIGNED'; // like page_id in MW page table
 36+ case 'namespace': return $wgDBtype == 'postgres' ? 'BIGINT' : 'INT(11)'; // like page_namespace in MW page table
 37+ case 'title': return $wgDBtype == 'postgres' ? 'TEXT' : 'VARBINARY(255)'; // like page_title in MW page table
 38+ case 'iw': return $wgDBtype == 'postgres' ? 'TEXT' : 'VARCHAR(32) binary'; // like iw_prefix in MW interwiki table
 39+ case 'blob': return $wgDBtype == 'postgres' ? 'BYTEA' : 'MEDIUMBLOB'; // larger blobs of character data, usually not subject to SELECT conditions
3640 }
 41+
3742 return false;
3843 }
3944
@@ -58,29 +63,45 @@
5964 *
6065 * @note The function partly ignores the order in which fields are set up.
6166 * Only if the type of some field changes will its order be adjusted explicitly.
 67+ *
 68+ * @param string $tableName The table name. Does not need to have been passed to DatabaseBase->tableName yet.
 69+ * @param array $columns The field names to put indexes on
 70+ * @param DatabaseBase $db
 71+ * @param $reportTo
 72+ *
 73+ * TODO: split up megamoth srysly o_O
6274 */
63 - public static function setupTable( $table, $fields, $db, $reportTo = null ) {
 75+ public static function setupTable( $tableName, array $fields, DatabaseBase $db, $reportTo = null ) {
6476 global $wgDBname, $wgDBtype, $wgDBTableOptions;
 77+
 78+ $tableName = $db->tableName( $tableName );
6579 $fname = 'SMWSQLHelpers::setupTable';
6680
67 - SMWSQLHelpers::reportProgress( "Setting up table $table ...\n", $reportTo );
68 - if ( $db->tableExists( $table ) === false ) { // create new table
69 - $sql = 'CREATE TABLE ' . ( $wgDBtype == 'postgres' ? '': "`$wgDBname`." ) . $table . ' (';
 81+ SMWSQLHelpers::reportProgress( "Setting up table $tableName ...\n", $reportTo );
 82+
 83+ if ( $db->tableExists( $tableName ) === false ) { // create new table
 84+ $sql = 'CREATE TABLE ' . ( $wgDBtype == 'postgres' ? '' : "`$wgDBname`." ) . $tableName . ' (';
7085 $first = true;
 86+
7187 foreach ( $fields as $name => $type ) {
7288 if ( $first ) {
7389 $first = false;
7490 } else {
7591 $sql .= ',';
7692 }
 93+
7794 $sql .= $name . ' ' . $type;
7895 }
79 - $sql .= ') ' . ( $wgDBtype == 'postgres' ? '':$wgDBTableOptions );
 96+
 97+ $sql .= ') ' . ( $wgDBtype == 'postgres' ? '' : $wgDBTableOptions );
8098 $db->query( $sql, $fname );
 99+
81100 SMWSQLHelpers::reportProgress( " ... new table created\n", $reportTo );
 101+
82102 return array();
83103 } else { // check table signature
84104 SMWSQLHelpers::reportProgress( " ... table exists already, checking structure ...\n", $reportTo );
 105+
85106 if ( $wgDBtype == 'postgres' ) { // postgresql
86107 // use the data dictionary in postgresql to get an output comparable to DESCRIBE
87108 // To find out what kind of magic takes place here (and to remove the bugs included), simply use:
@@ -98,19 +119,22 @@
99120 . ' SELECT c.oid '
100121 . ' FROM pg_catalog.pg_class c '
101122 . ' LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace '
102 - . ' WHERE c.relname ~ \'^(' . $table . ')$\' '
 123+ . ' WHERE c.relname ~ \'^(' . $tableName . ')$\' '
103124 . ' AND pg_catalog.pg_table_is_visible(c.oid) '
104125 . ' LIMIT 1 '
105126 . ' ) AND a.attnum > 0 AND NOT a.attisdropped '
106127 . ' ORDER BY a.attnum';
107 - } else { // mysql
108 - $sql = 'DESCRIBE ' . $table;
 128+ } else { // MySQL
 129+ $sql = 'DESCRIBE ' . $tableName;
109130 }
 131+
110132 $res = $db->query( $sql, $fname );
111133 $curfields = array();
112134 $result = array();
 135+
113136 while ( $row = $db->fetchObject( $res ) ) {
114137 $type = strtoupper( $row->Type );
 138+
115139 if ( $wgDBtype == 'postgres' ) { // postgresql
116140 if ( eregi( '^nextval\\(.+\\)$', $row->Extra ) ) {
117141 $type = 'SERIAL NOT NULL';
@@ -121,44 +145,57 @@
122146 if ( substr( $type, 0, 8 ) == 'VARCHAR(' ) {
123147 $type .= ' binary'; // just assume this to be the case for VARCHAR, though DESCRIBE will not tell us
124148 }
 149+
125150 if ( $row->Null != 'YES' ) {
126151 $type .= ' NOT NULL';
127152 }
 153+
128154 if ( $row->Key == 'PRI' ) { /// FIXME: updating "KEY" is not possible, the below query will fail in this case.
129155 $type .= ' KEY';
130156 }
 157+
131158 if ( $row->Extra == 'auto_increment' ) {
132159 $type .= ' AUTO_INCREMENT';
133160 }
134161 }
 162+
135163 $curfields[$row->Field] = $type;
136164 }
137165
138166 if ( $wgDBtype == 'postgres' ) { // postgresql
139167 foreach ( $fields as $name => $type ) {
140168 $keypos = strpos( $type, ' PRIMARY KEY' );
 169+
141170 if ( $keypos > 0 ) {
142171 $type = substr( $type, 0, $keypos );
143172 }
 173+
144174 if ( !array_key_exists( $name, $curfields ) ) {
145175 SMWSQLHelpers::reportProgress( " ... creating column $name ... ", $reportTo );
146 - $db->query( "ALTER TABLE $table ADD \"" . $name . "\" $type", $fname );
 176+
 177+ $db->query( "ALTER TABLE $tableName ADD \"" . $name . "\" $type", $fname );
147178 $result[$name] = 'new';
 179+
148180 SMWSQLHelpers::reportProgress( "done \n", $reportTo );
149181 } elseif ( $curfields[$name] != $type ) {
150182 SMWSQLHelpers::reportProgress( " ... changing type of column $name from '$curfields[$name]' to '$type' ... ", $reportTo );
151183 $notnullposnew = strpos( $type, ' NOT NULL' );
 184+
152185 if ( $notnullposnew > 0 ) {
153186 $type = substr( $type, 0, $notnullposnew );
154187 }
 188+
155189 $notnullposold = strpos( $curfields[$name], ' NOT NULL' );
156190 $typeold = ( $notnullposold > 0 ) ? substr( $curfields[$name], 0, $notnullposold ):$curfields[$name];
 191+
157192 if ( $typeold != $type ) {
158 - $db->query( "ALTER TABLE \"" . $table . "\" ALTER COLUMN \"" . $name . "\" TYPE " . $type, $fname );
 193+ $db->query( "ALTER TABLE \"" . $tableName . "\" ALTER COLUMN \"" . $name . "\" TYPE " . $type, $fname );
159194 }
 195+
160196 if ( $notnullposold != $notnullposnew ) {
161 - $db->query( "ALTER TABLE \"" . $table . "\" ALTER COLUMN \"" . $name . "\" " . ( $notnullposnew > 0 ? 'SET':'DROP' ) . " NOT NULL", $fname );
 197+ $db->query( "ALTER TABLE \"" . $tableName . "\" ALTER COLUMN \"" . $name . "\" " . ( $notnullposnew > 0 ? 'SET':'DROP' ) . " NOT NULL", $fname );
162198 }
 199+
163200 $result[$name] = 'up';
164201 $curfields[$name] = false;
165202 SMWSQLHelpers::reportProgress( "done.\n", $reportTo );
@@ -167,45 +204,56 @@
168205 $curfields[$name] = false;
169206 }
170207 }
 208+
171209 foreach ( $curfields as $name => $value ) {
172210 if ( $value !== false ) {
173211 SMWSQLHelpers::reportProgress( " ... deleting obsolete column $name ... ", $reportTo );
174 - $db->query( "ALTER TABLE \"" . $table . "\" DROP COLUMN \"" . $name . "\"", $fname );
 212+
 213+ $db->query( "ALTER TABLE \"" . $tableName . "\" DROP COLUMN \"" . $name . "\"", $fname );
175214 $result[$name] = 'del';
 215+
176216 SMWSQLHelpers::reportProgress( "done.\n", $reportTo );
177217 }
178218 }
179219 } else { // mysql
180220 $position = 'FIRST';
 221+
181222 foreach ( $fields as $name => $type ) {
182223 if ( !array_key_exists( $name, $curfields ) ) {
183224 SMWSQLHelpers::reportProgress( " ... creating column $name ... ", $reportTo );
184 - $db->query( "ALTER TABLE $table ADD `$name` $type $position", $fname );
 225+
 226+ $db->query( "ALTER TABLE $tableName ADD `$name` $type $position", $fname );
185227 $result[$name] = 'new';
 228+
186229 SMWSQLHelpers::reportProgress( "done \n", $reportTo );
187230 } elseif ( $curfields[$name] != $type ) {
188231 SMWSQLHelpers::reportProgress( " ... changing type of column $name from '$curfields[$name]' to '$type' ... ", $reportTo );
189 - $db->query( "ALTER TABLE $table CHANGE `$name` `$name` $type $position", $fname );
 232+
 233+ $db->query( "ALTER TABLE $tableName CHANGE `$name` `$name` $type $position", $fname );
190234 $result[$name] = 'up';
191235 $curfields[$name] = false;
 236+
192237 SMWSQLHelpers::reportProgress( "done.\n", $reportTo );
193238 } else {
194239 SMWSQLHelpers::reportProgress( " ... column $name is fine\n", $reportTo );
 240+
195241 $curfields[$name] = false;
196242 }
197243 $position = "AFTER $name";
198244 }
 245+
199246 foreach ( $curfields as $name => $value ) {
200247 if ( $value !== false ) { // not encountered yet --> delete
201248 SMWSQLHelpers::reportProgress( " ... deleting obsolete column $name ... ", $reportTo );
202 - $db->query( "ALTER TABLE $table DROP COLUMN `$name`", $fname );
 249+ $db->query( "ALTER TABLE $tableName DROP COLUMN `$name`", $fname );
203250 $result[$name] = 'del';
204251 SMWSQLHelpers::reportProgress( "done.\n", $reportTo );
205252 }
206253 }
207254 }
208255
209 - SMWSQLHelpers::reportProgress( " ... table $table set up successfully.\n", $reportTo );
 256+ SMWSQLHelpers::reportProgress( " ... table $tableName set up successfully.\n", $reportTo );
 257+
210258 return $result;
211259 }
212260 }
@@ -213,10 +261,15 @@
214262 /**
215263 * Make sure that each of the column descriptions in the given array is indexed by *one* index
216264 * in the given DB table.
 265+ *
 266+ * @param string $tableName The table name. Does not need to have been passed to DatabaseBase->tableName yet.
 267+ * @param array $columns The field names to put indexes on
 268+ * @param DatabaseBase $db
217269 */
218 - public static function setupIndex( $table, $columns, $db, $reportTo = null ) {
 270+ public static function setupIndex( $tableName, array $columns, DatabaseBase $db ) {
219271 global $wgDBtype, $verbose;
220 - $table = $db->tableName( $table );
 272+
 273+ $tableName = $db->tableName( $tableName );
221274 $fname = 'SMWSQLHelpers::setupIndex';
222275
223276 if ( $wgDBtype == 'postgres' ) { // postgresql
@@ -229,53 +282,62 @@
230283 . " LEFT JOIN pg_namespace n ON n.oid = c.relnamespace"
231284 . " LEFT JOIN pg_tablespace t ON t.oid = i.reltablespace"
232285 . " WHERE c.relkind = 'r'::\"char\" AND i.relkind = 'i'::\"char\""
233 - . " AND c.relname = '" . $table . "'"
 286+ . " AND c.relname = '" . $tableName . "'"
234287 . " AND NOT pg_get_indexdef(i.oid) ~ '^CREATE UNIQUE INDEX'";
235288 $res = $db->query( $sql, $fname );
 289+
236290 if ( !$res ) {
237291 return false;
238292 }
 293+
239294 $indexes = array();
 295+
240296 while ( $row = $db->fetchObject( $res ) ) {
241 - // remove unneeded indexes, let indexes alone that already exist in the correct fashion
 297+ // Remove the unneeded indexes, let indexes alone that already exist in the correct fashion.
242298 if ( array_key_exists( $row->indexcolumns, $columns ) ) {
243299 $columns[$row->indexcolumns] = false;
244300 } else {
245301 $db->query( 'DROP INDEX IF EXISTS ' . $row->indexname, $fname );
246302 }
247303 }
248 - foreach ( $columns as $key => $column ) { // add remaining indexes
 304+
 305+ foreach ( $columns as $key => $column ) { // Ddd the remaining indexes.
249306 if ( $column != false ) {
250 - $db->query( "CREATE INDEX " . $table . "_index" . $key . " ON " . $table . " USING btree(" . $column . ")", $fname );
 307+ $db->query( "CREATE INDEX " . $tableName . "_index" . $key . " ON " . $tableName . " USING btree(" . $column . ")", $fname );
251308 }
252309 }
253 - } else { // mysql
254 - $res = $db->query( 'SHOW INDEX FROM ' . $table , $fname );
 310+ } else { // MySQL
 311+ $res = $db->query( 'SHOW INDEX FROM ' . $tableName , $fname );
 312+
255313 if ( !$res ) {
256314 return false;
257315 }
 316+
258317 $indexes = array();
 318+
259319 while ( $row = $db->fetchObject( $res ) ) {
260320 if ( !array_key_exists( $row->Key_name, $indexes ) ) {
261321 $indexes[$row->Key_name] = array();
262322 }
263323 $indexes[$row->Key_name][$row->Seq_in_index] = $row->Column_name;
264324 }
265 - foreach ( $indexes as $key => $index ) { // clean up existing indexes
 325+
 326+ foreach ( $indexes as $key => $index ) { // Clean up the existing indexes.
266327 $id = array_search( implode( ',', $index ), $columns );
267328 if ( $id !== false ) {
268329 $columns[$id] = false;
269 - } else { // duplicate or unrequired index
270 - $db->query( 'DROP INDEX ' . $key . ' ON ' . $table, $fname );
 330+ } else { // Duplicate or unrequired index.
 331+ $db->query( 'DROP INDEX ' . $key . ' ON ' . $tableName, $fname );
271332 }
272333 }
273334
274 - foreach ( $columns as $key => $column ) { // add remaining indexes
 335+ foreach ( $columns as $key => $column ) { // Ddd the remaining indexes.
275336 if ( $column != false ) {
276 - $db->query( "ALTER TABLE $table ADD INDEX ( $column )", $fname );
 337+ $db->query( "ALTER TABLE $tableName ADD INDEX ( $column )", $fname );
277338 }
278339 }
279340 }
 341+
280342 return true;
281343 }
282344

Follow-up revisions

RevisionCommit summaryAuthorDate
r66681Follow up to r66680 - copied improvements to the light SQL storejeroendedauw04:47, 20 May 2010

Status & tagging log