From: Konrad Rosenbaum Date: Thu, 24 Dec 2015 10:31:59 +0000 (+0100) Subject: configurable config table X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=fc6c5fa3de1c581cfb1480e2aea793d5f31b6c7a;p=web%2Fkonrad%2Fpack.git configurable config table --- diff --git a/phpbase/db.php b/phpbase/db.php index e54c0aa..c36a5f1 100644 --- a/phpbase/db.php +++ b/phpbase/db.php @@ -17,6 +17,9 @@ abstract class DbEngine /**connect to the database, must be overwritten by DB driver*/ public abstract function tryConnect(); + + ///check whether the DB object is connected to an actual database + public abstract function isConnected(); /**set the admin passcode; used by the config.php file if admin access is allowed*/ public function setAdminPassCode($u,$p) @@ -45,8 +48,7 @@ abstract class DbEngine /**returns the version of the DB layout that is required by this version of Magic Smoke*/ public function needVersion() { - global $dbScheme; - return $dbScheme->version(); + return WobSchema::version(); } /**returns whether the table exists; must be implemented by driver*/ @@ -198,28 +200,27 @@ abstract class DbEngine /**creates a SQL92 statement for inserts; overwrite this to implement DB specific syntax*/ protected function sqlInsert($table,array $values) { - global $dbScheme; $ret="INSERT INTO ".$this->tableName($table)." ("; reset($values); $cm=""; $val=") VALUES ("; while(list($k,$v)=each($values)){ //make sure the column exists, ignore the riff-raff - if(!$dbScheme->tableHasColumn($table,$k))continue; + if(!WobSchema::tableHasColumn($table,$k))continue; $ret.=$cm;$val.=$cm;$cm=","; //append column name $ret.=$k; //append value - if($dbScheme->isIntColumn($table,$k)) + if(WobSchema::isIntColumn($table,$k)) $val.=$this->escapeInt($v); else - if($dbScheme->isStringColumn($table,$k)) + if(WobSchema::isStringColumn($table,$k)) $val.=$this->escapeString($v); else - if($dbScheme->isBlobColumn($table,$k)) + if(WobSchema::isBlobColumn($table,$k)) $val.=$this->escapeBlob($v); else - if($dbScheme->isBoolColumn($table,$k)) + if(WobSchema::isBoolColumn($table,$k)) $val.=$this->escapeBool($v); else //don't know how to escape it... @@ -241,27 +242,26 @@ abstract class DbEngine /**creates a SQL92 statement for updates; overwrite this to implement DB specific syntax*/ protected function sqlUpdate($table,array $values,$where) { - global $dbScheme; $ret="UPDATE ".$this->tableName($table)." SET "; reset($values); $cm=""; while(list($k,$v)=each($values)){ //make sure the column exists, ignore the riff-raff - if(!$dbScheme->tableHasColumn($table,$k))continue; + if(!WobSchema::tableHasColumn($table,$k))continue; $ret.=$cm;$cm=","; //append column name $ret.=$k."="; //append value - if($dbScheme->isIntColumn($table,$k)) + if(WobSchema::isIntColumn($table,$k)) $ret.=$this->escapeInt($v); else - if($dbScheme->isStringColumn($table,$k)) + if(WobSchema::isStringColumn($table,$k)) $ret.=$this->escapeString($v); else - if($dbScheme->isBlobColumn($table,$k)) + if(WobSchema::isBlobColumn($table,$k)) $ret.=$this->escapeBlob($v); else - if($dbScheme->isBoolColumn($table,$k)) + if(WobSchema::isBoolColumn($table,$k)) $ret.=$this->escapeBool($v); else //don't know how to escape it... @@ -379,11 +379,10 @@ abstract class DbEngine /**generic escape routine: queries the schema for the correct escape mechanism and then returns the appropriately escaped value*/ public function escapeColumn($table,$col,$val) { - global $dbScheme; - if($dbScheme->isIntColumn($table,$col))return $this->escapeInt($val); - if($dbScheme->isStringColumn($table,$col))return $this->escapeString($val); - if($dbScheme->isBlobColumn($table,$col))return $this->escapeBlob($val); - if($dbScheme->isBoolColumn($table,$col))return $this->escapeBool($val); + if(WobSchema::isIntColumn($table,$col))return $this->escapeInt($val); + if(WobSchema::isStringColumn($table,$col))return $this->escapeString($val); + if(WobSchema::isBlobColumn($table,$col))return $this->escapeBlob($val); + if(WobSchema::isBoolColumn($table,$col))return $this->escapeBool($val); //fallback: NULL return "NULL"; } @@ -391,7 +390,7 @@ abstract class DbEngine /**returns a configuration setting*/ public function getConfig($key) { - $mar=$this->select("config","cval","ckey=".$this->escapeString($key)); + $mar=$this->select(WobSchema::configTable(),WobSchema::configValueColumn(),WobSchema::configKeyColumn()."=".$this->escapeString($key)); if(count($mar)>0)return $mar[0][0]; return false; } @@ -400,37 +399,41 @@ abstract class DbEngine public function setConfig($key,$val) { $this->beginTransaction(); - $mar=$this->select("config","cval","ckey=".$this->escapeString($key)); - if(count($mar)>0)$this->update("config",array("cval"=>$val),"ckey=".$this->escapeString($key)); - else $this->insert("config",array("ckey"=>$key,"cval"=>$val)); + $ctable=WobSchema::configTable(); + $ckey=WobSchema::configKeyColumn(); + $cval=WobSchema::configValueColumn(); + $mar=$this->select($ctable,$cval,$ckey."=".$this->escapeString($key)); + if(count($mar)>0)$this->update($ctable,array($cval=>$val),$key."=".$this->escapeString($key)); + else $this->insert($ctable,array($ckey=>$key,$cval=>$val)); $this->commitTransaction(); } /**tries to find out whether the connected DB version is usable*/ - public function canUseDb() + public function canUseDb($checkVersion=true) { - if(!$this->hasTable("config")) + if(!$this->isConnected()) + return false; + if(!$this->hasTable(WobSchema::configTable())) return false; - return $this->getConfig("MagicSmokeVersion")==$this->needVersion(); + return !$checkVersion || $this->getConfig(WobSchema::configVersionRow())==$this->needVersion(); } /**creates the database, used by admin.php only!!*/ public function createDb() { - global $dbScheme; $this->beginTransaction(); //iterate DB schema and create tables - $tabs=$dbScheme->tableNames(); + $tabs=WobSchema::tableNames(); for($i=0;$icreateTable($tabs[$i],$dbScheme->tableDefinition($tabs[$i]))){ + if(!$this->createTable($tabs[$i],WobSchema::tableDefinition($tabs[$i]))){ print("DB Error while creating ".$tabs[$i].": ".$this->lastError()."

\n"); - print("Last statement was: ".$this->sqlCreateTable($tabs[$i],$dbScheme->tableDefinition($tabs[$i]))."

\n"); + print("Last statement was: ".$this->sqlCreateTable($tabs[$i],WobSchema::tableDefinition($tabs[$i]))."

\n"); $this->rollbackTransaction(); die("Unable to create database."); } //insert defaults - foreach($dbScheme->tableDefaults($tabs[$i]) as $def){ + foreach(WobSchema::tableDefaults($tabs[$i]) as $def){ $this->insert($tabs[$i],$def); } } @@ -441,16 +444,15 @@ abstract class DbEngine /**shows how the database would be created, used by admin.php only!!*/ public function showCreateDb() { - global $dbScheme; print("

Database Creation SQL Script

\n
\n");
 		print(htmlentities($this->sqlBeginTransaction()).";\n");
 		//iterate DB schema and create tables
-		$tabs=$dbScheme->tableNames();
+		$tabs=WobSchema::tableNames();
 		for($i=0;$isqlCreateTable($tabs[$i],$dbScheme->tableDefinition($tabs[$i]))).";\n");
+			print(htmlentities($this->sqlCreateTable($tabs[$i],WobSchema::tableDefinition($tabs[$i]))).";\n");
 			//insert defaults
-			foreach($dbScheme->tableDefaults($tabs[$i]) as $def){
+			foreach(WobSchema::tableDefaults($tabs[$i]) as $def){
 				print(htmlentities($this->sqlInsert($tabs[$i],$def)).";\n");
 			}
 		}
@@ -486,9 +488,8 @@ abstract class DbEngine
 		//check for NULL
 		if($this->isNull($val))return "NULL NULL";
 		//get type
-		global $dbScheme;
-		if($dbScheme->isIntColumn($tab,$col))return "int ".($val+0);
-		if($dbScheme->isBoolColumn($tab,$col)){
+		if(WobSchema::isIntColumn($tab,$col))return "int ".($val+0);
+		if(WobSchema::isBoolColumn($tab,$col)){
 			if($val)return "bool 1";
 			else return "bool 0";
 		}
@@ -499,18 +500,17 @@ abstract class DbEngine
 	/**dump a backup (returned as string)*/
 	public function dumpBackup()
 	{
-		global $dbScheme;
 		//make sure nobody else can disturb us (read lock)
 		$this->lockDB(false);
 		//dump basic stuff
 		$ret="startbackup\n";
 		$ret.="backupversion 0\n";
-		$ret.="dbversion ".$dbScheme->version()."\n";
+		$ret.="dbversion ".WobSchema::version()."\n";
 		//go through backup tables
-		foreach($dbScheme->backupTables() as $tab){
+		foreach(WobSchema::backupTables() as $tab){
 			$ret.="table ".$tab."\n";
 			//get columns
-			$cols=$dbScheme->tableColumns($tab);
+			$cols=WobSchema::tableColumns($tab);
 			//go through rows
 			$res=$this->select($tab,"*","1=1");
 			foreach($res as $row){
@@ -528,6 +528,50 @@ abstract class DbEngine
 		
 		return $ret;
 	}
+
+	/**explore the backup settings and database and return an index to the current data as structured text;
+	 each line has the following format:
+	 S
+	 T tablename [min max [groupSize]]
+	 V base64value
+	 E
+
+	 -> S/E mark the start/end of the data
+	 -> T is a table description line
+	 -> min/max are minimal/maximal integer values of the backup key, if both are "-" then it is a string column
+	 -> groupSize is the recommended size of backup groups (in different key values) for this table
+	 -> V is a single value of the backup key if the preceding table has a string backup key
+	 */
+	public function exploreBackup()
+	{
+		$ret="S\n";
+		foreach(WobSchema::backupTables() as $tab){
+			$ret+="T $tab";
+			// get key and min/max/size
+			$col=WobSchema::backupKeyForTable($tab);
+			if($col!=""){
+				if(WobSchema::isIntColumn($tab,$col)){
+					$res=$this->select($tab,"min($col) as min, max($col) as max");
+					if($res!==false){
+						$ret+=" ".$res[0]["min"]." ".$res[0]["max"];
+					}else
+						$ret+=" ? ?";
+				}else
+					$ret+=" - -";
+				$size=WobSchema::backupGroupSizeForTable($tab);
+				if($size>0)
+					$ret+=" $size";
+			}
+			$ret+="\n";
+			if($col!="" && WobSchema::isStringColumn($tab,$col)){
+				$res=$this->select($tab,$col);
+				foreach($res as $r)
+					$ret+="V ".base64_encode($r[$col])."\n";
+			}
+		}
+		$ret+="E\n";
+		return $ret;
+	}
 	
 	/**helper: decode backup data from transport format*/
 	private function unescapeBackup($fmt,$val)
@@ -546,9 +590,8 @@ abstract class DbEngine
 	/**synchronize all sequences with current data*/
 	public function syncSequences()
 	{
-		global $dbScheme;
-		foreach($dbScheme->tableNames() as $table)
-			if($dbScheme->hasSequence($table)!==false)
+		foreach(WobSchema::tableNames() as $table)
+			if(WobSchema::hasSequence($table)!==false)
 				$this->syncSequence($table);
 	}
 	
@@ -558,9 +601,8 @@ abstract class DbEngine
 	/**helper: inserts data from backup*/
 	private function backupInsert($table,$data,$overwrite)
 	{
-		global $dbScheme;
 		//get primary keys
-		$pk=$dbScheme->primaryKeyColumns($table);
+		$pk=WobSchema::primaryKeyColumns($table);
 		//scan whether data is existent
 		$pks="";$q="";
 		foreach($pk as $p){
diff --git a/phpbase/db_mysql.php b/phpbase/db_mysql.php
index f9b4518..48d9580 100644
--- a/phpbase/db_mysql.php
+++ b/phpbase/db_mysql.php
@@ -82,11 +82,16 @@ class MysqlEngine extends DbEngine
 		if(mysqli_query($this->dbhdl,"SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE")===false)
 			die("Cannot make this database transaction safe, aborting");
 	}
+
+	///check whether the DB object is connected to an actual database
+	public function isConnected()
+	{
+		return $this->dbhdl!==false;
+	}
 	
 	public function hasTable($tnm)
 	{
-		global $dbScheme;
-		if(!$dbScheme->hasTable($tnm))return false;
+		if(!WobSchema::hasTable($tnm))return false;
 		$res=mysqli_query($this->dbhdl,"select * from ".$this->tableName($tnm)." where 1=2");
 		if($res===false)return false;
 		mysqli_free_result($res);
@@ -118,10 +123,9 @@ class MysqlEngine extends DbEngine
 	
 	protected function lockDB($wl)
 	{
-		global $dbScheme;
 		$req="SET autocommit = 0 ; LOCK TABLES ";
 		$i=0;
-		foreach($dbScheme->backupTables() as $tab){
+		foreach(WobSchema::backupTables() as $tab){
 			if($i)$req.=",";
 			$i++;
 			$req.=$this->tableName($tab);
@@ -234,8 +238,7 @@ class MysqlEngine extends DbEngine
 		$res=mysqli_query($this->dbhdl,$sql);
 		WobTransaction::debug("DB Insert: ".$sql."\n".($res===false?"failed":"successful"),WobTransaction::DebugDbQuery);
 		if($res===false)return false;
-		global $dbScheme;
-		$seq=$dbScheme->hasSequence($table);
+		$seq=WobSchema::hasSequence($table);
 		if($seq!==false){
 			if(isset($values[$seq]))return $values[$seq];
 			$res=mysqli_query($this->dbhdl,"select LAST_INSERT_ID()");
diff --git a/phpbase/db_pgsql.php b/phpbase/db_pgsql.php
index 9d9b44e..d32d87a 100644
--- a/phpbase/db_pgsql.php
+++ b/phpbase/db_pgsql.php
@@ -55,11 +55,16 @@ class PGsqlEngine extends DbEngine
 		if(@pg_query($this->dbhdl,"SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE")===false)
 			die("Cannot make this database transaction safe, aborting");
 	}
-	
+
+	///check whether the DB object is connected to an actual database
+	public function isConnected()
+	{
+		return $this->dbhdl!==false;
+	}
+
 	public function hasTable($tnm)
 	{
-		global $dbScheme;
-		if(!$dbScheme->hasTable($tnm))return false;
+		if(!WobSchema::hasTable($tnm))return false;
 		$res=@pg_query($this->dbhdl,"select * from ".$this->tableName($tnm)." where 1=2");
 		if($res===false){
 			$this->db_debug_error("has table",$tnm);
@@ -109,11 +114,10 @@ class PGsqlEngine extends DbEngine
 	
 	protected function lockDB($wl)
 	{
-		global $dbScheme;
 		if(!$this->intrans)$this->beginTransaction();
 		$req="LOCK TABLE ";
 		$i=0;
-		foreach($dbScheme->backupTables() as $tab){
+		foreach(WobSchema::backupTables() as $tab){
 			if($i)$req.=",";
 			$i++;
 			$req.=$this->tableName($tab);
@@ -151,7 +155,6 @@ class PGsqlEngine extends DbEngine
 		//get column names and types
 		$nf=pg_num_fields($res);
 		$fnames=array();
-		global $dbScheme;
 		for($i=0;$i<$nf;$i++)
 			$fnames[$i]=pg_field_name($res,$i);
 		//convert data
@@ -165,13 +168,13 @@ class PGsqlEngine extends DbEngine
 				if(pg_field_is_null($res,$i,$j))
 					$crw[$j]=null;
 				else
-				if($dbScheme->isIntColumn($table,$fn))
+				if(WobSchema::isIntColumn($table,$fn))
 					$crw[$j]=$row[$j]+0;
 				else
-				if($dbScheme->isBlobColumn($table,$fn))
+				if(WobSchema::isBlobColumn($table,$fn))
 					$crw[$j]=pg_unescape_bytea($row[$j]);
 				else
-				if($dbScheme->isBoolColumn($table,$fn))
+				if(WobSchema::isBoolColumn($table,$fn))
 					$crw[$j]=$this->unescapeBool($row[$j]);
 				else //any other type: hope string is ok
 					$crw[$j]=$row[$j];
@@ -256,8 +259,7 @@ class PGsqlEngine extends DbEngine
 			return false;
 		}
 		pg_free_result($res);
-		global $dbScheme;
-		$seq=$dbScheme->hasSequence($table);
+		$seq=WobSchema::hasSequence($table);
 		if($seq!==false){
 			if(isset($values[$seq]))return $values[$seq];
 			$res=@pg_query($this->dbhdl,"select lastval()");
@@ -338,8 +340,7 @@ class PGsqlEngine extends DbEngine
 	public function syncSequence($table)
 	{
 		$tab=$this->tableName($table);
-		global $dbScheme;
-		$col=$dbScheme->hasSequence($table);
+		$col=WobSchema::hasSequence($table);
 		if($col===false)return;
 		$seq=$tab."_".$col."_seq";
 		$q="select setval('".$seq."',(select max(".$col.") from ".$tab."))";
diff --git a/phpbase/schema.php b/phpbase/schema.php
index 01065cb..fec5750 100644
--- a/phpbase/schema.php
+++ b/phpbase/schema.php
@@ -1,42 +1,88 @@
 
+// Copyright (C) 2009-2015 by Konrad Rosenbaum 
 // protected under the GNU LGPL version 3 or at your option any newer.
 // See COPYING.LGPL file that comes with this distribution.
 //
-/**This class parses the high-level description of the database structure generated by woc; access it via $dbScheme*/
+/**This class parses the high-level description of the database structure generated by woc; access it via WobScheme::* */
 class WobSchemaBase {
 	protected static $scheme;
 	protected static $preset;
 	protected static $sversion;
 	protected static $backup;
+	protected static $backupCfg;
+	protected static $config;
 	
 	function __construct()
 	{
+		self::$scheme=array();
+		self::$preset=array();
+		self::$sversion="";
+		self::$backup=array();
+		self::$backupCfg=array();
+		self::$config=array();
 	}
 	
 	/**return the version of this scheme*/
-	public function version(){return self::$sversion;}
+	public static function version(){return self::$sversion;}
 	
 	/**return the tables to be created in order*/
-	public function tableNames()
+	public static function tableNames()
 	{
 		return array_keys(self::$scheme);
 	}
-	
+
+	public static function configTable()
+	{
+		return self::$config["table"];
+	}
+
+	public static function configKeyColumn()
+	{
+		return self::$config["key"];
+	}
+
+	public static function configValueColumn()
+	{
+		return self::$config["value"];
+	}
+
+	public static function configVersionRow()
+	{
+		return self::$config["vrow"];
+	}
+
 	/**returns whether a table exists in the schema*/
-	public function hasTable($t)
+	public static function hasTable($t)
 	{
 		return in_array($t,array_keys(self::$scheme));
 	}
 	
 	/**return the tables that are included in the backup*/
-	public function backupTables()
+	public static function backupTables()
 	{
 		return self::$backup;
 	}
-	
+
+	/**return the key by which backups should be grouped for a table, empty string if it should not be backed up or be backed up in full*/
+	public static function backupKeyForTable($table)
+	{
+		if(isset(self::$backupCfg[$table]))
+			return self::$backupCfg[$table]["key"];
+		else
+			return "";
+	}
+
+	/**return the recommended group size for backups or <=0 for default*/
+	public static function backupGroupSizeForTable($table)
+	{
+		if(isset(self::$backupCfg[$table]))
+			return self::$backupCfg[$table]["size"];
+		else
+			return -1;
+	}
+
 	/**return the full definition of a table, or false if it does not exist*/
-	public function tableDefinition($tab)
+	public static function tableDefinition($tab)
 	{
 		if(!isset(self::$scheme[$tab]))
 			return false;
@@ -44,7 +90,7 @@ class WobSchemaBase {
 	}
 	
 	/**return the names of all columns of a table, or false if the table does not exist*/
-	public function tableColumns($tab)
+	public static function tableColumns($tab)
 	{
 		if(!isset(self::$scheme[$tab]))
 			return false;
@@ -56,20 +102,20 @@ class WobSchemaBase {
 	}
 	
 	/**return whether the table has this column*/
-	public function tableHasColumn($tab,$col)
+	public static function tableHasColumn($tab,$col)
 	{
 		return isset(self::$scheme[$tab][$col]);
 	}
 	
 	/**return default lines of the table for the initialization; returns empty array if there are none*/
-	public function tableDefaults($tab)
+	public static function tableDefaults($tab)
 	{
 		if(isset(self::$preset[$tab]))return self::$preset[$tab];
 		else return array();
 	}
 	
 	/**return the type of a column, or false if it does not exist*/
-	public function columnType($tab,$col)
+	public static function columnType($tab,$col)
 	{
 		if(!isset(self::$scheme[$tab][$col]))
 			return false;
@@ -77,7 +123,7 @@ class WobSchemaBase {
 	}
 	
 	/**return the flags of a column, empty array if no flags are set, or false if the column does not exist*/
-	public function columnFlags($tab,$col)
+	public static function columnFlags($tab,$col)
 	{
 		if(!isset(self::$scheme[$tab][$col]))
 			return false;
@@ -87,7 +133,7 @@ class WobSchemaBase {
 	}
 	
 	/**returns true if the given column is of an integer type*/
-	public function isIntColumn($tab,$col)
+	public static function isIntColumn($tab,$col)
 	{
 		if(!isset(self::$scheme[$tab][$col]))
 			return false;
@@ -101,7 +147,7 @@ class WobSchemaBase {
 	}
 	
 	/**returns the sequence column name if the table has a sequence, false otherwise*/
-	public function hasSequence($tab)
+	public static function hasSequence($tab)
 	{
 		if(!isset(self::$scheme[$tab]))
 			return false;
@@ -113,7 +159,7 @@ class WobSchemaBase {
 	}
 	
 	/**returns true if the given column is of a string type*/
-	public function isStringColumn($tab,$col)
+	public static function isStringColumn($tab,$col)
 	{
 		if(!isset(self::$scheme[$tab][$col]))
 			return false;
@@ -127,7 +173,7 @@ class WobSchemaBase {
 	}
 
 	/**returns true if the given column is of a blob type*/
-	public function isBlobColumn($tab,$col)
+	public static function isBlobColumn($tab,$col)
 	{
 		if(!isset(self::$scheme[$tab][$col]))
 			return false;
@@ -141,7 +187,7 @@ class WobSchemaBase {
 	}
 	
 	/**returns true if the given column is of a bool type*/
-	public function isBoolColumn($tab,$col)
+	public static function isBoolColumn($tab,$col)
 	{
 		if(!isset(self::$scheme[$tab][$col]))
 			return false;
@@ -156,7 +202,7 @@ class WobSchemaBase {
 	}
 	
 	/**returns the names of all primary key columns of the table*/
-	public function primaryKeyColumns($tab)
+	public static function primaryKeyColumns($tab)
 	{
 		$r=array();
 		//search for direct mark
diff --git a/phpbase/table.php b/phpbase/table.php
index 4671a63..2e2f32a 100644
--- a/phpbase/table.php
+++ b/phpbase/table.php
@@ -92,8 +92,7 @@ abstract class WobTable
 	/**returns whether the table contains a specific column*/
 	public function hasColumn($c)
 	{
-		global $dbScheme;
-		return $dbScheme->tableHasColumn($this->table,$name);
+		return WobSchema::tableHasColumn($this->table,$name);
 	}
 	
 	/**overridden by woc, returns true if the property exists*/
@@ -108,9 +107,9 @@ abstract class WobTable
 	/**returns the where clause to find this instance (via primary key columns)*/
 	public function where()
 	{
-		global $dbScheme,$db;
+		global $db;
 		$r="";
-		$pk=$dbScheme->primaryKeyColumns($this->table);
+		$pk=WobSchema::primaryKeyColumns($this->table);
 		foreach($pk as $c){
 			if($r!="")$r.=" AND ";
 			$r.=$c."=".$db->escapeColumn($this->table,$c,$this->data[$c]);
@@ -145,7 +144,6 @@ abstract class WobTable
 	/**unsets column-properties to NULL*/
 	public function __unset($name)
 	{
-		global $dbScheme;
 		//reset to null
 		if($this->hasProperty($name))$this->cdata[$name]=null;
 	}
@@ -165,7 +163,7 @@ abstract class WobTable
 	/**insert the object under a new primary key value into the DB (implicitly calls newKey); returns true on success*/
 	public function insert()
 	{
-		global $dbScheme,$db;
+		global $db;
 		$this->isfromdb=false;
 		//create new key
 		$this->newKey();
@@ -179,7 +177,7 @@ abstract class WobTable
 		$this->data=$data;
 		$this->cdata=array();
 		//assign primary key if sequence (otherwise newKey has done it)
-		$seq=$dbScheme->hasSequence($this->table);
+		$seq=WobSchema::hasSequence($this->table);
 		if($seq!==false)
 			$this->data[$seq]=$r;
 		//create audit data
@@ -191,10 +189,9 @@ abstract class WobTable
 	/**generate a new primary key value for insert and marks the object as not yet in the DB; the default sets the primary key to NULL if it is a sequence; call the original first if you overwrite it*/
 	public function newKey()
 	{
-		global $dbScheme;
 		$this->isfromdb=false;
 		$this->resetAudit();
-		$pk=$dbScheme->hasSequence($this->table);
+		$pk=WobSchema::hasSequence($this->table);
 		if($pk!==false){
 			if(array_key_exists($pk,$this->data))unset($this->data[$pk]);
 			if(array_key_exists($pk,$this->cdata))unset($this->cdata[$pk]);
diff --git a/woc/php/phpdb.cpp b/woc/php/phpdb.cpp
index 22f6a9e..472d928 100644
--- a/woc/php/phpdb.cpp
+++ b/woc/php/phpdb.cpp
@@ -28,13 +28,18 @@ WocPHPTable::WocPHPTable(WocPHPOut* p)
 	m_schema.write(PHPSTART);
 	m_schema.write(SCHEMASTART);
 	m_schema.write(("\tself::$sversion=\""+WocProcessor::instance()->dbVersion()+"\";\n").toLatin1());
-	addLoad("WobSchema","schema");
+	m_schema.write(("\tself::$config[\"table\"]=\""+WocProcessor::instance()->dbConfigTable()+"\";\n").toLatin1());
+	m_schema.write(("\tself::$config[\"key\"]=\""+WocProcessor::instance()->dbConfigKeyColumn()+"\";\n").toLatin1());
+	m_schema.write(("\tself::$config[\"value\"]=\""+WocProcessor::instance()->dbConfigValueColumn()+"\";\n").toLatin1());
+	m_schema.write(("\tself::$config[\"vrow\"]=\""+WocProcessor::instance()->dbVersionRow()+"\";\n").toLatin1());
+	m_parent->addStaticLoad("WobSchema","schema");
 }
 
 void WocPHPTable::finalize()
 {
 	if(m_schema.isOpen()){
 		m_schema.write(SCHEMAEND);
+		m_schema.write(("$"+WocProcessor::instance()->dbSchema()+"=new WobSchema();\n").toLatin1());
 		m_schema.write(PHPEND);
 		m_schema.close();
 	}
@@ -194,7 +199,10 @@ void WocPHPTable::newTable(const WocTable&tbl)
 		code+=")";
 	}
 	code+="\n\t);\n";
-	if(tbl.inBackup())code+="\tself::$backup[]=\""+tbl.name()+"\";\n";
+	if(tbl.inBackup()){
+		code+="\tself::$backup[]=\""+tbl.name()+"\";\n";
+		code+="\tself::$backupCfg[\""+tbl.name()+"\"]=array(\"key\"=>\""+tbl.backupKey()+"\",\"size\"=>"+QString::number(tbl.backupGroupSize())+");\n";
+	}
 	//write presets
 	QList >presets=tbl.presets();
 	if(presets.size()>0){
diff --git a/woc/php/phpout.cpp b/woc/php/phpout.cpp
index cc63670..ab0ff0b 100644
--- a/woc/php/phpout.cpp
+++ b/woc/php/phpout.cpp
@@ -79,6 +79,13 @@ void WocPHPOut::finalize()
 }
 
 
+void WocPHPOut::addStaticLoad(QString cn,QString fn)
+{
+	Q_UNUSED(cn);
+	QString ld="include($d.\"/"+fn+m_fileext+"\");\n";
+	m_loader.write(ld.toLatin1());
+}
+
 void WocPHPOut::addLoad(QString cn,QString fn)
 {
 	QString ld="wob_autoclass(\""+cn+"\",$d.\"/"+fn+m_fileext+"\");\n";
diff --git a/woc/php/phpout.h b/woc/php/phpout.h
index 86afb42..798d2c0 100644
--- a/woc/php/phpout.h
+++ b/woc/php/phpout.h
@@ -49,7 +49,9 @@ class WocPHPOut:public WocOutput
 		
 		/**helper: adds a loader line for a class to autoload.php*/
 		void addLoad(QString classname,QString filename);
-		
+		/**helper: adds an immediate loader line for a class to autoload.php*/
+		void addStaticLoad(QString classname,QString filename);
+
 		WocPHPClass*pclass;
 		WocPHPTable*ptable;
 		WocPHPTransaction*ptrans;
diff --git a/woc/proc/processor.cpp b/woc/proc/processor.cpp
index fefee7b..f7c6b23 100644
--- a/woc/proc/processor.cpp
+++ b/woc/proc/processor.cpp
@@ -162,6 +162,14 @@ bool WocProcessor::processFile(QString fn)
 				m_dbVer=el.attribute("version");
 			if(el.hasAttribute("defaultUpdating"))
 				m_dbUpd=str2bool(el.attribute("defaultUpdating"));
+			if(el.hasAttribute("configTable"))
+				m_dbConfigTable=el.attribute(("configTable"));
+			if(el.hasAttribute("configKeyColumn"))
+				m_dbConfigKey=el.attribute(("configKeyColumn"));
+			if(el.hasAttribute("configValueColumn"))
+				m_dbConfigVal=el.attribute(("configValueColumn"));
+			if(el.hasAttribute("versionRow"))
+				m_dbVersionRow=el.attribute(("versionRow"));
 			QList nl=elementsByTagName(el,"AuditTables");
 			for(int i=0;im_verInfo;
 		QStringList m_verSys;
-		QString m_dbInst,m_dbSchema,m_dbVer;
+		QString m_dbInst,m_dbSchema,m_dbVer,m_dbConfigTable,m_dbConfigKey,m_dbConfigVal,m_dbVersionRow;
 		QString m_xmlNS,m_xmlPackNS,m_xmlSoap12NS,m_xmlSchemaNS,m_xmlXmlNS;
 		QStringList m_docstrings;
 		bool m_error,m_dbUpd;
diff --git a/woc/proc/proctable.cpp b/woc/proc/proctable.cpp
index 4986c50..1555d5f 100644
--- a/woc/proc/proctable.cpp
+++ b/woc/proc/proctable.cpp
@@ -45,6 +45,8 @@ WocTable::WocTable(const QDomElement&tbl)
 		return;
 	}
 	m_backup=str2bool(tbl.attribute("backup","0"));
+	m_backupkey=tbl.attribute("backupKey",QString());
+	m_backupsize=tbl.attribute("backupSize","-1").toInt();
 	m_base=tbl.attribute("base","WobTable");
 	m_audit=str2bool(tbl.attribute("audit","0"));
 	qDebug("Info: parsing table %s",m_name.toLatin1().data());
diff --git a/woc/proc/proctable.h b/woc/proc/proctable.h
index 0595b20..b17cc95 100644
--- a/woc/proc/proctable.h
+++ b/woc/proc/proctable.h
@@ -29,11 +29,16 @@ class WocTable
 		
 		/**returns the table name*/
 		QString name()const{return m_name;}
-		/**returns whether the table is marked for backup*/
-		bool inBackup()const{return m_backup;}
 		/**returns the parent class of the table class - default: WobTable*/
 		QString baseClass()const{return m_base;}
 		
+		/**returns whether the table is marked for backup*/
+		bool inBackup()const{return m_backup;}
+		///returns which column the table uses for backup grouping
+		QString backupKey()const{return m_backupkey;}
+		///returns the default group size for backup or <=0 if default is to be used
+		int backupGroupSize()const{return m_backupsize;}
+
 		/**returns whether the table has a column with this name*/
 		bool hasColumn(QString)const;
 		/**returns a list of all defined column names*/
@@ -96,7 +101,7 @@ class WocTable
 		
 	private:
 		bool m_valid,m_backup,m_audit;
-		QString m_name,m_base;
+		QString m_name,m_base,m_backupkey;
 		///holds data for a DB table column
 		struct s_col {
 			QString name,type,foreign,defaultval,doc;
@@ -108,6 +113,7 @@ class WocTable
 		static QListm_staticauditcolumns;
 		QList >m_foreign;
 		QList >m_presets;
+		int m_backupsize=-1;
 		
 		QStringList m_docstrings;
 		QMapm_fordocs;