class sqlite_common extends cache_common
{
var $cfg = array(
'db_file_path' => 'sqlite.db',
'table_name' => 'table_name',
'table_schema' => 'CREATE TABLE table_name (...)',
'pconnect' => true,
'con_required' => true,
'log_name' => 'SQLite',
'shard_type' => 'none', # none, string, int (тип перевичного ключа для шардинга)
'shard_val' => 0, # для string - кол. начальных символов, для int - делитель (будет использован остаток от деления)
);
var $engine = 'SQLite';
var $dbh = null;
var $connected = false;
var $shard_val = false;
var $table_create_attempts = 0;
function sqlite_common ($cfg)
{
$this->cfg = array_merge($this->cfg, $cfg);
$this->dbg_enabled = sql_dbg_enabled();
}
function connect ()
{
$this->cur_query = ($this->dbg_enabled) ? ($this->cfg['pconnect'] ? 'p' : '') .'connect to: '. $this->cfg['db_file_path'] : 'connect';
$this->debug('start');
$connect_type = ($this->cfg['pconnect']) ? 'sqlite_popen' : 'sqlite_open';
if ($this->cfg['shard_type'] != 'none' && $this->shard_val === false)
{
trigger_error("cannot shard: shard_val not defined for {$this->cfg['db_file_path']}", E_USER_ERROR);
}
if (@$this->dbh = $connect_type($this->cfg['db_file_path'], 0666, $sqlite_error))
{
$this->connected = true;
}
if (!$this->connected && $this->cfg['con_required'])
{
trigger_error($sqlite_error, E_USER_ERROR);
}
$this->debug('stop');
$this->cur_query = null;
}
function create_table ()
{
$this->table_create_attempts++;
return sqlite_query($this->dbh, $this->cfg['table_schema']);
}
function shard ($name)
{
$type = $this->cfg['shard_type'];
if ($type == 'none') return;
if (is_array($name)) trigger_error('cannot shard: $name is array', E_USER_ERROR);
// define shard_val
if ($type == 'string')
{
$shard_val = substr($name, 0, $this->cfg['shard_val']);
}
else
{
$shard_val = $name % $this->cfg['shard_val'];
}
// все запросы должны быть к одному и тому же шарду
if ($this->shard_val !== false)
{
if ($shard_val != $this->shard_val)
{
trigger_error("shard cannot be reassigned. [{$this->shard_val}, $shard_val, $name]", E_USER_ERROR);
}
else
{
return;
}
}
$this->shard_val = $shard_val;
$this->cfg['db_file_path'] = str_replace('*', $shard_val, $this->cfg['db_file_path']);
}
function query ($query)
{
if (!$this->connected) $this->connect();
$this->cur_query = $query;
$this->debug('start');
if (!$result = @sqlite_unbuffered_query($this->dbh, $query, SQLITE_ASSOC))
{
if (!$this->table_create_attempts && !sqlite_num_rows(sqlite_query($this->dbh, "PRAGMA table_info({$this->cfg['table_name']})")))
{
if ($this->create_table())
{
$result = sqlite_unbuffered_query($this->dbh, $query, SQLITE_ASSOC);
}
}
if (!$result)
{
$this->trigger_error($this->get_error_msg());
}
}
$this->debug('stop');
$this->cur_query = null;
$this->num_queries++;
return $result;
}
function fetch_row ($query)
{
$result = $this->query($query);
return is_resource($result) ? sqlite_fetch_array($result, SQLITE_ASSOC) : false;
}
function fetch_rowset ($query)
{
$result = $this->query($query);
return is_resource($result) ? sqlite_fetch_all($result, SQLITE_ASSOC) : array();
}
function changes ()
{
return is_resource($this->dbh) ? sqlite_changes($this->dbh) : 0;
}
function escape ($str)
{
return sqlite_escape_string($str);
}
function get_error_msg ()
{
return 'SQLite error #'. ($err_code = sqlite_last_error($this->dbh)) .': '. sqlite_error_string($err_code);
}
function rm ($name = '')
{
if ($name)
{
$this->db->shard($this->prefix . $name);
$result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_name = '". sqlite_escape_string($this->prefix . $name) ."'");
}
else
{
$result = $this->db->query("DELETE FROM ". $this->cfg['table_name']);
}
return (bool) $result;
}
function gc ($expire_time = TIMENOW)
{
$result = $this->db->query("DELETE FROM ". $this->cfg['table_name'] ." WHERE cache_expire_time < $expire_time");
return ($result) ? sqlite_changes($this->db->dbh) : 0;
}
function trigger_error ($msg = 'DB Error')
{
if (error_reporting()) trigger_error($msg, E_USER_ERROR);
}
}