Merge branch 'oracle'

pull/221/head
Aleksander Machniak 10 years ago
commit ff767a14ff

@ -0,0 +1,221 @@
-- Roundcube Webmail initial database structure
-- This was tested with Oracle 11g
CREATE TABLE "users" (
"user_id" integer PRIMARY KEY,
"username" varchar(128) NOT NULL,
"mail_host" varchar(128) NOT NULL,
"created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"last_login" timestamp with time zone DEFAULT NULL,
"language" varchar(5),
"preferences" long DEFAULT NULL,
CONSTRAINT "users_username_key" UNIQUE ("username", "mail_host")
);
CREATE SEQUENCE "users_seq"
START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE TRIGGER "users_seq_trig"
BEFORE INSERT ON "users" FOR EACH ROW
BEGIN
:NEW."user_id" := "users_seq".nextval;
END;
CREATE TABLE "session" (
"sess_id" varchar(128) NOT NULL PRIMARY KEY,
"created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"changed" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"ip" varchar(41) NOT NULL,
"vars" long NOT NULL
);
CREATE INDEX "session_changed_idx" ON "session" ("changed");
CREATE TABLE "identities" (
"identity_id" integer PRIMARY KEY,
"user_id" integer NOT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE,
"changed" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"del" smallint DEFAULT 0 NOT NULL,
"standard" smallint DEFAULT 0 NOT NULL,
"name" varchar(128) NOT NULL,
"organization" varchar(128),
"email" varchar(128) NOT NULL,
"reply-to" varchar(128),
"bcc" varchar(128),
"signature" long,
"html_signature" integer DEFAULT 0 NOT NULL
);
CREATE INDEX "identities_user_id_idx" ON "identities" ("user_id", "del");
CREATE INDEX "identities_email_idx" ON "identities" ("email", "del");
CREATE SEQUENCE "identities_seq"
START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE TRIGGER "identities_seq_trig"
BEFORE INSERT ON "identities" FOR EACH ROW
BEGIN
:NEW."identity_id" := "identities_seq".nextval;
END;
CREATE TABLE "contacts" (
"contact_id" integer PRIMARY KEY,
"user_id" integer NOT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE,
"changed" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"del" smallint DEFAULT 0 NOT NULL,
"name" varchar(128) DEFAULT NULL,
"email" varchar(4000) DEFAULT NULL,
"firstname" varchar(128) DEFAULT NULL,
"surname" varchar(128) DEFAULT NULL,
"vcard" long,
"words" varchar(4000)
);
CREATE INDEX "contacts_user_id_idx" ON "contacts" ("user_id", "del");
CREATE SEQUENCE "contacts_seq"
START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE TRIGGER "contacts_seq_trig"
BEFORE INSERT ON "contacts" FOR EACH ROW
BEGIN
:NEW."contact_id" := "contacts_seq".nextval;
END;
CREATE TABLE "contactgroups" (
"contactgroup_id" integer PRIMARY KEY,
"user_id" integer NOT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE,
"changed" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"del" smallint DEFAULT 0 NOT NULL,
"name" varchar(128) NOT NULL
);
CREATE INDEX "contactgroups_user_id_idx" ON "contactgroups" ("user_id", "del");
CREATE SEQUENCE "contactgroups_seq"
START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE TRIGGER "contactgroups_seq_trig"
BEFORE INSERT ON "contactgroups" FOR EACH ROW
BEGIN
:NEW."contactgroup_id" := "contactgroups_seq".nextval;
END;
CREATE TABLE "contactgroupmembers" (
"contactgroup_id" integer NOT NULL
REFERENCES "contactgroups" ("contactgroup_id") ON DELETE CASCADE,
"contact_id" integer NOT NULL
REFERENCES "contacts" ("contact_id") ON DELETE CASCADE,
"created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
PRIMARY KEY ("contactgroup_id", "contact_id")
);
CREATE INDEX "contactgroupmembers_idx" ON "contactgroupmembers" ("contact_id");
CREATE TABLE "cache" (
"user_id" integer NOT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE,
"cache_key" varchar(128) NOT NULL,
"created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"expires" timestamp with time zone DEFAULT NULL,
"data" long NOT NULL
);
CREATE INDEX "cache_user_id_idx" ON "cache" ("user_id", "cache_key");
CREATE INDEX "cache_expires_idx" ON "cache" ("expires");
CREATE TABLE "cache_shared" (
"cache_key" varchar(255) NOT NULL,
"created" timestamp with time zone DEFAULT current_timestamp NOT NULL,
"expires" timestamp with time zone DEFAULT NULL,
"data" long NOT NULL
);
CREATE INDEX "cache_shared_cache_key_idx" ON "cache_shared" ("cache_key");
CREATE INDEX "cache_shared_expires_idx" ON "cache_shared" ("expires");
CREATE TABLE "cache_index" (
"user_id" integer NOT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE,
"mailbox" varchar(255) NOT NULL,
"expires" timestamp with time zone DEFAULT NULL,
"valid" smallint DEFAULT 0 NOT NULL,
"data" long NOT NULL,
PRIMARY KEY ("user_id", "mailbox")
);
CREATE INDEX "cache_index_expires_idx" ON "cache_index" ("expires");
CREATE TABLE "cache_thread" (
"user_id" integer NOT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE,
"mailbox" varchar(255) NOT NULL,
"expires" timestamp with time zone DEFAULT NULL,
"data" long NOT NULL,
PRIMARY KEY ("user_id", "mailbox")
);
CREATE INDEX "cache_thread_expires_idx" ON "cache_thread" ("expires");
CREATE TABLE "cache_messages" (
"user_id" integer NOT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE,
"mailbox" varchar(255) NOT NULL,
"uid" integer NOT NULL,
"expires" timestamp with time zone DEFAULT NULL,
"data" long NOT NULL,
"flags" integer DEFAULT 0 NOT NULL,
PRIMARY KEY ("user_id", "mailbox", "uid")
);
CREATE INDEX "cache_messages_expires_idx" ON "cache_messages" ("expires");
CREATE TABLE "dictionary" (
"user_id" integer DEFAULT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE,
"language" varchar(5) NOT NULL,
"data" long DEFAULT NULL,
CONSTRAINT "dictionary_user_id_lang_key" UNIQUE ("user_id", "language")
);
CREATE TABLE "searches" (
"search_id" integer PRIMARY KEY,
"user_id" integer NOT NULL
REFERENCES "users" ("user_id") ON DELETE CASCADE,
"type" smallint DEFAULT 0 NOT NULL,
"name" varchar(128) NOT NULL,
"data" long NOT NULL,
CONSTRAINT "searches_user_id_key" UNIQUE ("user_id", "type", "name")
);
CREATE SEQUENCE "searches_seq"
START WITH 1 INCREMENT BY 1 NOMAXVALUE;
CREATE TRIGGER "searches_seq_trig"
BEFORE INSERT ON "searches" FOR EACH ROW
BEGIN
:NEW."search_id" := "searches_seq".nextval;
END;
CREATE TABLE "system" (
"name" varchar(64) NOT NULL PRIMARY KEY,
"value" long
);
INSERT INTO "system" ("name", "value") VALUES ('roundcube-version', '2014042900');

@ -48,7 +48,7 @@ $threshold = date('Y-m-d 00:00:00', time() - $days * 86400);
foreach (array('contacts','contactgroups','identities') as $table) { foreach (array('contacts','contactgroups','identities') as $table) {
$sqltable = $db->table_name($table); $sqltable = $db->table_name($table, true);
// also delete linked records // also delete linked records
// could be skipped for databases which respect foreign key constraints // could be skipped for databases which respect foreign key constraints
@ -59,10 +59,10 @@ foreach (array('contacts','contactgroups','identities') as $table) {
$memberstable = $db->table_name('contactgroupmembers'); $memberstable = $db->table_name('contactgroupmembers');
$db->query( $db->query(
"DELETE FROM $memberstable". "DELETE FROM " . $db->quote_identifier($memberstable).
" WHERE $pk IN (". " WHERE `$pk` IN (".
"SELECT $pk FROM $sqltable". "SELECT `$pk` FROM $sqltable".
" WHERE del=1 AND changed < ?". " WHERE `del` = 1 AND `changed` < ?".
")", ")",
$threshold); $threshold);
@ -70,7 +70,7 @@ foreach (array('contacts','contactgroups','identities') as $table) {
} }
// delete outdated records // delete outdated records
$db->query("DELETE FROM $sqltable WHERE del=1 AND changed < ?", $threshold); $db->query("DELETE FROM $sqltable WHERE `del` = 1 AND `changed` < ?", $threshold);
echo $db->affected_rows() . " records deleted from '$table'\n"; echo $db->affected_rows() . " records deleted from '$table'\n";
} }

@ -91,7 +91,7 @@ if ($plugin['abort']) {
// deleting the user record should be sufficient due to ON DELETE CASCADE foreign key references // deleting the user record should be sufficient due to ON DELETE CASCADE foreign key references
// but not all database backends actually support this so let's do it by hand // but not all database backends actually support this so let's do it by hand
foreach (array('identities','contacts','contactgroups','dictionaries','cache','cache_index','cache_messages','cache_thread','searches','users') as $table) { foreach (array('identities','contacts','contactgroups','dictionaries','cache','cache_index','cache_messages','cache_thread','searches','users') as $table) {
$db->query('DELETE FROM ' . $db->table_name($table) . ' WHERE user_id=?', $user->ID); $db->query('DELETE FROM ' . $db->table_name($table, true) . ' WHERE `user_id` = ?', $user->ID);
} }
if ($db->is_error()) { if ($db->is_error()) {

@ -35,7 +35,7 @@ if (!$db->is_connected() || $db->is_error()) {
} }
// iterate over all users // iterate over all users
$sql_result = $db->query("SELECT user_id FROM " . $db->table_name('users') . " ORDER BY user_id"); $sql_result = $db->query("SELECT `user_id` FROM " . $db->table_name('users', true) . " ORDER BY `user_id`");
while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) { while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) {
echo "Indexing contacts for user " . $sql_arr['user_id'] . "..."; echo "Indexing contacts for user " . $sql_arr['user_id'] . "...";

@ -58,10 +58,10 @@ if (!$db->is_connected() || $db->is_error())
$query = '1=1'; $query = '1=1';
if ($args['user']) if ($args['user'])
$query = 'user_id=' . intval($args['user']); $query = '`user_id` = ' . intval($args['user']);
// iterate over all users // iterate over all users
$sql_result = $db->query("SELECT * FROM " . $db->table_name('users') . " WHERE $query"); $sql_result = $db->query("SELECT * FROM " . $db->table_name('users', true) . " WHERE $query");
while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) { while ($sql_result && ($sql_arr = $db->fetch_assoc($sql_result))) {
echo "Updating prefs for user " . $sql_arr['user_id'] . "..."; echo "Updating prefs for user " . $sql_arr['user_id'] . "...";

@ -55,9 +55,9 @@ if (!$DB->is_connected()) {
// Read DB schema version from database (if 'system' table exists) // Read DB schema version from database (if 'system' table exists)
if (in_array($DB->table_name('system'), (array)$DB->list_tables())) { if (in_array($DB->table_name('system'), (array)$DB->list_tables())) {
$DB->query("SELECT " . $DB->quote_identifier('value') $DB->query("SELECT `value`"
." FROM " . $DB->quote_identifier($DB->table_name('system')) ." FROM " . $DB->table_name('system', true)
." WHERE " . $DB->quote_identifier('name') ." = ?", ." WHERE `name` = ?",
$opts['package'] . '-version'); $opts['package'] . '-version');
$row = $DB->fetch_array(); $row = $DB->fetch_array();
@ -159,17 +159,16 @@ function update_db_schema($package, $version, $file)
return; return;
} }
$system_table = $DB->quote_identifier($DB->table_name('system')); $system_table = $DB->table_name('system', true);
$DB->query("UPDATE " . $system_table $DB->query("UPDATE " . $system_table
." SET " . $DB->quote_identifier('value') . " = ?" ." SET `value` = ?"
." WHERE " . $DB->quote_identifier('name') . " = ?", ." WHERE `name` = ?",
$version, $package . '-version'); $version, $package . '-version');
if (!$DB->is_error() && !$DB->affected_rows()) { if (!$DB->is_error() && !$DB->affected_rows()) {
$DB->query("INSERT INTO " . $system_table $DB->query("INSERT INTO " . $system_table
." (" . $DB->quote_identifier('name') . ", " . $DB->quote_identifier('value') . ")" ." (`name`, `value`) VALUES (?, ?)",
." VALUES (?, ?)",
$package . '-version', $version); $package . '-version', $version);
} }

@ -154,7 +154,7 @@ else if ($db_working && $_POST['updatedb']) {
// test database // test database
if ($db_working) { if ($db_working) {
$db_read = $DB->query("SELECT count(*) FROM {$RCI->config['db_prefix']}users"); $db_read = $DB->query("SELECT count(*) FROM " . $DB->quote_identifier($RCI->config['db_prefix'] . 'users'));
if ($DB->is_error()) { if ($DB->is_error()) {
$RCI->fail('DB Schema', "Database not initialized"); $RCI->fail('DB Schema', "Database not initialized");
echo '<p><input type="submit" name="initdb" value="Initialize database" /></p>'; echo '<p><input type="submit" name="initdb" value="Initialize database" /></p>';
@ -178,11 +178,13 @@ if ($db_working) {
if ($db_working) { if ($db_working) {
// write test // write test
$insert_id = md5(uniqid()); $insert_id = md5(uniqid());
$db_write = $DB->query("INSERT INTO {$RCI->config['db_prefix']}session (sess_id, created, ip, vars) VALUES (?, ".$DB->now().", '127.0.0.1', 'foo')", $insert_id); $db_write = $DB->query("INSERT INTO " . $DB->quote_identifier($RCI->config['db_prefix'] . 'session')
. " (`sess_id`, `created`, `ip`, `vars`) VALUES (?, ".$DB->now().", '127.0.0.1', 'foo')", $insert_id);
if ($db_write) { if ($db_write) {
$RCI->pass('DB Write'); $RCI->pass('DB Write');
$DB->query("DELETE FROM {$RCI->config['db_prefix']}session WHERE sess_id=?", $insert_id); $DB->query("DELETE FROM " . $DB->quote_identifier($RCI->config['db_prefix'] . 'session')
. " WHERE `sess_id` = ?", $insert_id);
} }
else { else {
$RCI->fail('DB Write', $RCI->get_error()); $RCI->fail('DB Write', $RCI->get_error());

@ -164,14 +164,16 @@ class squirrelmail_usercopy extends rcube_plugin
if ($db_charset) if ($db_charset)
$db->query('SET NAMES '.$db_charset); $db->query('SET NAMES '.$db_charset);
$sql_result = $db->query('SELECT * FROM '.$userprefs_table.' WHERE user=?', $uname); // ? is replaced with emailaddress $sql_result = $db->query('SELECT * FROM ' . $db->quote_identifier($userprefs_table)
.' WHERE `user` = ?', $uname); // ? is replaced with emailaddress
while ($sql_array = $db->fetch_assoc($sql_result) ) { // fetch one row from result while ($sql_array = $db->fetch_assoc($sql_result) ) { // fetch one row from result
$this->prefs[$sql_array['prefkey']] = rcube_charset::convert(rtrim($sql_array['prefval']), $db_charset); $this->prefs[$sql_array['prefkey']] = rcube_charset::convert(rtrim($sql_array['prefval']), $db_charset);
} }
/* retrieve address table data */ /* retrieve address table data */
$sql_result = $db->query('SELECT * FROM '.$address_table.' WHERE owner=?', $uname); // ? is replaced with emailaddress $sql_result = $db->query('SELECT * FROM ' . $db->quote_identifier($address_table)
.' WHERE `owner` = ?', $uname); // ? is replaced with emailaddress
// parse addres book // parse addres book
while ($sql_array = $db->fetch_assoc($sql_result) ) { // fetch one row from result while ($sql_array = $db->fetch_assoc($sql_result) ) { // fetch one row from result
@ -186,5 +188,4 @@ class squirrelmail_usercopy extends rcube_plugin
} }
} // end if 'sql'-driver } // end if 'sql'-driver
} }
} }

@ -75,7 +75,7 @@ class rcube_cache
else { else {
$this->type = 'db'; $this->type = 'db';
$this->db = $rcube->get_dbh(); $this->db = $rcube->get_dbh();
$this->table = $this->db->table_name('cache'); $this->table = $this->db->table_name('cache', true);
} }
// convert ttl string to seconds // convert ttl string to seconds
@ -197,10 +197,10 @@ class rcube_cache
{ {
if ($this->type == 'db' && $this->db && $this->ttl) { if ($this->type == 'db' && $this->db && $this->ttl) {
$this->db->query( $this->db->query(
"DELETE FROM ".$this->table. "DELETE FROM {$this->table}".
" WHERE user_id = ?". " WHERE `user_id` = ?".
" AND cache_key LIKE ?". " AND `cache_key` LIKE ?".
" AND expires < " . $this->db->now(), " AND `expires` < " . $this->db->now(),
$this->userid, $this->userid,
$this->prefix.'.%'); $this->prefix.'.%');
} }
@ -215,7 +215,7 @@ class rcube_cache
$rcube = rcube::get_instance(); $rcube = rcube::get_instance();
$db = $rcube->get_dbh(); $db = $rcube->get_dbh();
$db->query("DELETE FROM " . $db->table_name('cache') . " WHERE expires < " . $db->now()); $db->query("DELETE FROM " . $db->table_name('cache', true) . " WHERE `expires` < " . $db->now());
} }
@ -284,13 +284,12 @@ class rcube_cache
} }
else { else {
$sql_result = $this->db->limitquery( $sql_result = $this->db->limitquery(
"SELECT data, cache_key". "SELECT `data`, `cache_key`".
" FROM " . $this->table. " FROM {$this->table}".
" WHERE user_id = ?". " WHERE `user_id` = ? AND `cache_key` = ?".
" AND cache_key = ?".
// for better performance we allow more records for one key // for better performance we allow more records for one key
// get the newer one // get the newer one
" ORDER BY created DESC", " ORDER BY `created` DESC",
0, 1, $this->userid, $this->prefix.'.'.$key); 0, 1, $this->userid, $this->prefix.'.'.$key);
if ($sql_arr = $this->db->fetch_assoc($sql_result)) { if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
@ -346,9 +345,8 @@ class rcube_cache
// Remove NULL rows (here we don't need to check if the record exist) // Remove NULL rows (here we don't need to check if the record exist)
if ($data == 'N;') { if ($data == 'N;') {
$this->db->query( $this->db->query(
"DELETE FROM " . $this->table. "DELETE FROM {$this->table}".
" WHERE user_id = ?". " WHERE `user_id` = ? AND `cache_key` = ?",
" AND cache_key = ?",
$this->userid, $key); $this->userid, $key);
return true; return true;
@ -357,12 +355,12 @@ class rcube_cache
// update existing cache record // update existing cache record
if ($key_exists) { if ($key_exists) {
$result = $this->db->query( $result = $this->db->query(
"UPDATE " . $this->table. "UPDATE {$this->table}".
" SET created = " . $this->db->now(). " SET `created` = " . $this->db->now().
", expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL'). ", `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL').
", data = ?". ", `data` = ?".
" WHERE user_id = ?". " WHERE `user_id` = ?".
" AND cache_key = ?", " AND `cache_key` = ?",
$data, $this->userid, $key); $data, $this->userid, $key);
} }
// add new cache record // add new cache record
@ -370,8 +368,8 @@ class rcube_cache
// for better performance we allow more records for one key // for better performance we allow more records for one key
// so, no need to check if record exist (see rcube_cache::read_record()) // so, no need to check if record exist (see rcube_cache::read_record())
$result = $this->db->query( $result = $this->db->query(
"INSERT INTO " . $this->table. "INSERT INTO {$this->table}".
" (created, expires, user_id, cache_key, data)". " (`created`, `expires`, `user_id`, `cache_key`, `data`)".
" VALUES (" . $this->db->now() . ", " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?, ?, ?)", " VALUES (" . $this->db->now() . ", " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?, ?, ?)",
$this->userid, $key, $data); $this->userid, $key, $data);
} }
@ -421,20 +419,19 @@ class rcube_cache
// Remove all keys (in specified cache) // Remove all keys (in specified cache)
if ($key === null) { if ($key === null) {
$where = " AND cache_key LIKE " . $this->db->quote($this->prefix.'.%'); $where = " AND `cache_key` LIKE " . $this->db->quote($this->prefix.'.%');
} }
// Remove keys by name prefix // Remove keys by name prefix
else if ($prefix_mode) { else if ($prefix_mode) {
$where = " AND cache_key LIKE " . $this->db->quote($this->prefix.'.'.$key.'%'); $where = " AND `cache_key` LIKE " . $this->db->quote($this->prefix.'.'.$key.'%');
} }
// Remove one key by name // Remove one key by name
else { else {
$where = " AND cache_key = " . $this->db->quote($this->prefix.'.'.$key); $where = " AND `cache_key` = " . $this->db->quote($this->prefix.'.'.$key);
} }
$this->db->query( $this->db->query(
"DELETE FROM " . $this->table. "DELETE FROM {$this->table} WHERE `user_id` = ?" . $where,
" WHERE user_id = ?" . $where,
$this->userid); $this->userid);
} }

@ -72,7 +72,7 @@ class rcube_cache_shared
else { else {
$this->type = 'db'; $this->type = 'db';
$this->db = $rcube->get_dbh(); $this->db = $rcube->get_dbh();
$this->table = $this->db->table_name('cache_shared'); $this->table = $this->db->table_name('cache_shared', true);
} }
// convert ttl string to seconds // convert ttl string to seconds
@ -193,9 +193,9 @@ class rcube_cache_shared
{ {
if ($this->type == 'db' && $this->db && $this->ttl) { if ($this->type == 'db' && $this->db && $this->ttl) {
$this->db->query( $this->db->query(
"DELETE FROM " . $this->table "DELETE FROM {$this->table}"
. " WHERE cache_key LIKE ?" . " WHERE `cache_key` LIKE ?"
. " AND expires < " . $this->db->now(), . " AND `expires` < " . $this->db->now(),
$this->prefix . '.%'); $this->prefix . '.%');
} }
} }
@ -209,7 +209,7 @@ class rcube_cache_shared
$rcube = rcube::get_instance(); $rcube = rcube::get_instance();
$db = $rcube->get_dbh(); $db = $rcube->get_dbh();
$db->query("DELETE FROM " . $db->table_name('cache_shared') . " WHERE expires < " . $db->now()); $db->query("DELETE FROM " . $db->table_name('cache_shared', true) . " WHERE `expires` < " . $db->now());
} }
@ -278,12 +278,12 @@ class rcube_cache_shared
} }
else { else {
$sql_result = $this->db->limitquery( $sql_result = $this->db->limitquery(
"SELECT data, cache_key". "SELECT `data`, `cache_key`".
" FROM " . $this->table . " FROM {$this->table}" .
" WHERE cache_key = ?". " WHERE `cache_key` = ?".
// for better performance we allow more records for one key // for better performance we allow more records for one key
// get the newer one // get the newer one
" ORDER BY created DESC", " ORDER BY `created` DESC",
0, 1, $this->prefix . '.' . $key); 0, 1, $this->prefix . '.' . $key);
if ($sql_arr = $this->db->fetch_assoc($sql_result)) { if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
@ -331,18 +331,18 @@ class rcube_cache_shared
// Remove NULL rows (here we don't need to check if the record exist) // Remove NULL rows (here we don't need to check if the record exist)
if ($data == 'N;') { if ($data == 'N;') {
$this->db->query("DELETE FROM " . $this->table . " WHERE cache_key = ?", $key); $this->db->query("DELETE FROM {$this->table} WHERE `cache_key` = ?", $key);
return true; return true;
} }
// update existing cache record // update existing cache record
if ($key_exists) { if ($key_exists) {
$result = $this->db->query( $result = $this->db->query(
"UPDATE " . $this->table . "UPDATE {$this->table}" .
" SET created = " . $this->db->now() . " SET `created` = " . $this->db->now() .
", expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') .
", data = ?". ", `data` = ?".
" WHERE cache_key = ?", " WHERE `cache_key` = ?",
$data, $key); $data, $key);
} }
// add new cache record // add new cache record
@ -350,8 +350,8 @@ class rcube_cache_shared
// for better performance we allow more records for one key // for better performance we allow more records for one key
// so, no need to check if record exist (see rcube_cache::read_record()) // so, no need to check if record exist (see rcube_cache::read_record())
$result = $this->db->query( $result = $this->db->query(
"INSERT INTO ".$this->table. "INSERT INTO {$this->table}".
" (created, expires, cache_key, data)". " (`created`, `expires`, `cache_key`, `data`)".
" VALUES (".$this->db->now().", " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?, ?)", " VALUES (".$this->db->now().", " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?, ?)",
$key, $data); $key, $data);
} }
@ -401,15 +401,15 @@ class rcube_cache_shared
// Remove all keys (in specified cache) // Remove all keys (in specified cache)
if ($key === null) { if ($key === null) {
$where = " WHERE cache_key LIKE " . $this->db->quote($this->prefix.'.%'); $where = " WHERE `cache_key` LIKE " . $this->db->quote($this->prefix.'.%');
} }
// Remove keys by name prefix // Remove keys by name prefix
else if ($prefix_mode) { else if ($prefix_mode) {
$where = " WHERE cache_key LIKE " . $this->db->quote($this->prefix.'.'.$key.'%'); $where = " WHERE `cache_key` LIKE " . $this->db->quote($this->prefix.'.'.$key.'%');
} }
// Remove one key by name // Remove one key by name
else { else {
$where = " WHERE cache_key = " . $this->db->quote($this->prefix.'.'.$key); $where = " WHERE `cache_key` = " . $this->db->quote($this->prefix.'.'.$key);
} }
$this->db->query("DELETE FROM " . $this->table . $where); $this->db->query("DELETE FROM " . $this->table . $where);

@ -167,11 +167,9 @@ class rcube_contacts extends rcube_addressbook
} }
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT * FROM ".$this->db->table_name($this->db_groups). "SELECT * FROM " . $this->db->table_name($this->db_groups, true)
" WHERE del<>1". . " WHERE `del` <> 1 AND `user_id` = ?" . $sql_filter
" AND user_id=?". . " ORDER BY `name`",
$sql_filter.
" ORDER BY name",
$this->user_id); $this->user_id);
while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) {
@ -192,10 +190,8 @@ class rcube_contacts extends rcube_addressbook
function get_group($group_id) function get_group($group_id)
{ {
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT * FROM ".$this->db->table_name($this->db_groups). "SELECT * FROM " . $this->db->table_name($this->db_groups, true)
" WHERE del<>1". . " WHERE `del` <> 1 AND `contactgroup_id` = ? AND `user_id` = ?",
" AND contactgroup_id=?".
" AND user_id=?",
$group_id, $this->user_id); $group_id, $this->user_id);
if ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { if ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) {
@ -228,25 +224,25 @@ class rcube_contacts extends rcube_addressbook
$length = $subset != 0 ? abs($subset) : $this->page_size; $length = $subset != 0 ? abs($subset) : $this->page_size;
if ($this->group_id) if ($this->group_id)
$join = " LEFT JOIN ".$this->db->table_name($this->db_groupmembers)." AS m". $join = " LEFT JOIN " . $this->db->table_name($this->db_groupmembers, true) . " AS m".
" ON (m.contact_id = c.".$this->primary_key.")"; " ON (m.`contact_id` = c.`".$this->primary_key."`)";
$order_col = (in_array($this->sort_col, $this->table_cols) ? $this->sort_col : 'name'); $order_col = (in_array($this->sort_col, $this->table_cols) ? $this->sort_col : 'name');
$order_cols = array('c.'.$order_col); $order_cols = array("c.`$order_col`");
if ($order_col == 'firstname') if ($order_col == 'firstname')
$order_cols[] = 'c.surname'; $order_cols[] = 'c.`surname`';
else if ($order_col == 'surname') else if ($order_col == 'surname')
$order_cols[] = 'c.firstname'; $order_cols[] = 'c.`firstname`';
if ($order_col != 'name') if ($order_col != 'name')
$order_cols[] = 'c.name'; $order_cols[] = 'c.`name`';
$order_cols[] = 'c.email'; $order_cols[] = 'c.`email`';
$sql_result = $this->db->limitquery( $sql_result = $this->db->limitquery(
"SELECT * FROM ".$this->db->table_name($this->db_name)." AS c" . "SELECT * FROM " . $this->db->table_name($this->db_name, true) . " AS c" .
$join . $join .
" WHERE c.del<>1" . " WHERE c.`del` <> 1" .
" AND c.user_id=?" . " AND c.`user_id` = ?" .
($this->group_id ? " AND m.contactgroup_id=?" : ""). ($this->group_id ? " AND m.`contactgroup_id` = ?" : "").
($this->filter ? " AND (".$this->filter.")" : "") . ($this->filter ? " AND (".$this->filter.")" : "") .
" ORDER BY ". $this->db->concat($order_cols) . " ORDER BY ". $this->db->concat($order_cols) .
" " . $this->sort_order, " " . $this->sort_order,
@ -442,7 +438,7 @@ class rcube_contacts extends rcube_addressbook
// build WHERE clause // build WHERE clause
$ids = $this->db->array2list($ids, 'integer'); $ids = $this->db->array2list($ids, 'integer');
$where = 'c.' . $this->primary_key.' IN ('.$ids.')'; $where = 'c.`' . $this->primary_key.'` IN ('.$ids.')';
// reset counter // reset counter
unset($this->cache['count']); unset($this->cache['count']);
@ -486,17 +482,17 @@ class rcube_contacts extends rcube_addressbook
private function _count() private function _count()
{ {
if ($this->group_id) if ($this->group_id)
$join = " LEFT JOIN ".$this->db->table_name($this->db_groupmembers)." AS m". $join = " LEFT JOIN " . $this->db->table_name($this->db_groupmembers, true) . " AS m".
" ON (m.contact_id=c.".$this->primary_key.")"; " ON (m.`contact_id` = c.`".$this->primary_key."`)";
// count contacts for this user // count contacts for this user
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT COUNT(c.contact_id) AS rows". "SELECT COUNT(c.`contact_id`) AS rows".
" FROM ".$this->db->table_name($this->db_name)." AS c". " FROM " . $this->db->table_name($this->db_name, true) . " AS c".
$join. $join.
" WHERE c.del<>1". " WHERE c.`del` <> 1".
" AND c.user_id=?". " AND c.`user_id` = ?".
($this->group_id ? " AND m.contactgroup_id=?" : ""). ($this->group_id ? " AND m.`contactgroup_id` = ?" : "").
($this->filter ? " AND (".$this->filter.")" : ""), ($this->filter ? " AND (".$this->filter.")" : ""),
$this->user_id, $this->user_id,
$this->group_id $this->group_id
@ -534,10 +530,10 @@ class rcube_contacts extends rcube_addressbook
return $assoc ? $first : $this->result; return $assoc ? $first : $this->result;
$this->db->query( $this->db->query(
"SELECT * FROM ".$this->db->table_name($this->db_name). "SELECT * FROM " . $this->db->table_name($this->db_name, true).
" WHERE contact_id=?". " WHERE `contact_id` = ?".
" AND user_id=?". " AND `user_id` = ?".
" AND del<>1", " AND `del` <> 1",
$id, $id,
$this->user_id $this->user_id
); );
@ -566,9 +562,11 @@ class rcube_contacts extends rcube_addressbook
return $results; return $results;
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT cgm.contactgroup_id, cg.name FROM " . $this->db->table_name($this->db_groupmembers) . " AS cgm" . "SELECT cgm.`contactgroup_id`, cg.`name` "
" LEFT JOIN " . $this->db->table_name($this->db_groups) . " AS cg ON (cgm.contactgroup_id = cg.contactgroup_id AND cg.del<>1)" . . " FROM " . $this->db->table_name($this->db_groupmembers, true) . " AS cgm"
" WHERE cgm.contact_id=?", . " LEFT JOIN " . $this->db->table_name($this->db_groups, true) . " AS cg"
. " ON (cgm.`contactgroup_id` = cg.`contactgroup_id` AND cg.`del` <> 1)"
. " WHERE cgm.`contact_id` = ?",
$id $id
); );
while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) {
@ -636,8 +634,8 @@ class rcube_contacts extends rcube_addressbook
if (!$existing->count && !empty($a_insert_cols)) { if (!$existing->count && !empty($a_insert_cols)) {
$this->db->query( $this->db->query(
"INSERT INTO ".$this->db->table_name($this->db_name). "INSERT INTO " . $this->db->table_name($this->db_name, true).
" (user_id, changed, del, ".join(', ', $a_insert_cols).")". " (`user_id`, `changed`, `del`, ".join(', ', $a_insert_cols).")".
" VALUES (".intval($this->user_id).", ".$this->db->now().", 0, ".join(', ', $a_insert_values).")" " VALUES (".intval($this->user_id).", ".$this->db->now().", 0, ".join(', ', $a_insert_values).")"
); );
@ -671,11 +669,11 @@ class rcube_contacts extends rcube_addressbook
if (!empty($write_sql)) { if (!empty($write_sql)) {
$this->db->query( $this->db->query(
"UPDATE ".$this->db->table_name($this->db_name). "UPDATE " . $this->db->table_name($this->db_name, true).
" SET changed=".$this->db->now().", ".join(', ', $write_sql). " SET `changed` = ".$this->db->now().", ".join(', ', $write_sql).
" WHERE contact_id=?". " WHERE `contact_id` = ?".
" AND user_id=?". " AND `user_id` = ?".
" AND del<>1", " AND `del` <> 1",
$id, $id,
$this->user_id $this->user_id
); );
@ -771,10 +769,10 @@ class rcube_contacts extends rcube_addressbook
// flag record as deleted (always) // flag record as deleted (always)
$this->db->query( $this->db->query(
"UPDATE ".$this->db->table_name($this->db_name). "UPDATE " . $this->db->table_name($this->db_name, true).
" SET del=1, changed=".$this->db->now(). " SET `del` = 1, `changed` = ".$this->db->now().
" WHERE user_id=?". " WHERE `user_id` = ?".
" AND contact_id IN ($ids)", " AND `contact_id` IN ($ids)",
$this->user_id $this->user_id
); );
@ -798,10 +796,10 @@ class rcube_contacts extends rcube_addressbook
// clear deleted flag // clear deleted flag
$this->db->query( $this->db->query(
"UPDATE ".$this->db->table_name($this->db_name). "UPDATE " . $this->db->table_name($this->db_name, true).
" SET del=0, changed=".$this->db->now(). " SET `del` = 0, `changed` = ".$this->db->now().
" WHERE user_id=?". " WHERE `user_id` = ?".
" AND contact_id IN ($ids)", " AND `contact_id` IN ($ids)",
$this->user_id $this->user_id
); );
@ -822,16 +820,18 @@ class rcube_contacts extends rcube_addressbook
{ {
$this->cache = null; $this->cache = null;
$this->db->query("UPDATE " . $this->db->table_name($this->db_name) $now = $this->db->now();
. " SET del = 1, changed = " . $this->db->now()
. " WHERE user_id = ?", $this->user_id); $this->db->query("UPDATE " . $this->db->table_name($this->db_name, true)
. " SET `del` = 1, `changed` = $now"
. " WHERE `user_id` = ?", $this->user_id);
$count = $this->db->affected_rows(); $count = $this->db->affected_rows();
if ($with_groups) { if ($with_groups) {
$this->db->query("UPDATE " . $this->db->table_name($this->db_groups) $this->db->query("UPDATE " . $this->db->table_name($this->db_groups, true)
. " SET del = 1, changed = " . $this->db->now() . " SET `del` = 1, `changed` = $now"
. " WHERE user_id = ?", $this->user_id); . " WHERE `user_id` = ?", $this->user_id);
$count += $this->db->affected_rows(); $count += $this->db->affected_rows();
} }
@ -854,13 +854,14 @@ class rcube_contacts extends rcube_addressbook
$name = $this->unique_groupname($name); $name = $this->unique_groupname($name);
$this->db->query( $this->db->query(
"INSERT INTO ".$this->db->table_name($this->db_groups). "INSERT INTO " . $this->db->table_name($this->db_groups, true).
" (user_id, changed, name)". " (`user_id`, `changed`, `name`)".
" VALUES (".intval($this->user_id).", ".$this->db->now().", ".$this->db->quote($name).")" " VALUES (".intval($this->user_id).", ".$this->db->now().", ".$this->db->quote($name).")"
); );
if ($insert_id = $this->db->insert_id($this->db_groups)) if ($insert_id = $this->db->insert_id($this->db_groups)) {
$result = array('id' => $insert_id, 'name' => $name); $result = array('id' => $insert_id, 'name' => $name);
}
return $result; return $result;
} }
@ -876,10 +877,10 @@ class rcube_contacts extends rcube_addressbook
{ {
// flag group record as deleted // flag group record as deleted
$this->db->query( $this->db->query(
"UPDATE " . $this->db->table_name($this->db_groups) "UPDATE " . $this->db->table_name($this->db_groups, true)
. " SET del = 1, changed = " . $this->db->now() . " SET `del` = 1, `changed` = " . $this->db->now()
. " WHERE contactgroup_id = ?" . " WHERE `contactgroup_id` = ?"
. " AND user_id = ?", . " AND `user_id` = ?",
$gid, $this->user_id $gid, $this->user_id
); );
@ -901,10 +902,10 @@ class rcube_contacts extends rcube_addressbook
$name = $this->unique_groupname($newname); $name = $this->unique_groupname($newname);
$sql_result = $this->db->query( $sql_result = $this->db->query(
"UPDATE ".$this->db->table_name($this->db_groups). "UPDATE " . $this->db->table_name($this->db_groups, true).
" SET name=?, changed=".$this->db->now(). " SET `name` = ?, `changed` = ".$this->db->now().
" WHERE contactgroup_id=?". " WHERE `contactgroup_id` = ?".
" AND user_id=?", " AND `user_id` = ?",
$name, $gid, $this->user_id $name, $gid, $this->user_id
); );
@ -930,9 +931,9 @@ class rcube_contacts extends rcube_addressbook
// get existing assignments ... // get existing assignments ...
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT contact_id FROM ".$this->db->table_name($this->db_groupmembers). "SELECT `contact_id` FROM " . $this->db->table_name($this->db_groupmembers, true).
" WHERE contactgroup_id=?". " WHERE `contactgroup_id` = ?".
" AND contact_id IN (".$this->db->array2list($ids, 'integer').")", " AND `contact_id` IN (".$this->db->array2list($ids, 'integer').")",
$group_id $group_id
); );
while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) {
@ -943,8 +944,8 @@ class rcube_contacts extends rcube_addressbook
foreach ($ids as $contact_id) { foreach ($ids as $contact_id) {
$this->db->query( $this->db->query(
"INSERT INTO ".$this->db->table_name($this->db_groupmembers). "INSERT INTO " . $this->db->table_name($this->db_groupmembers, true).
" (contactgroup_id, contact_id, created)". " (`contactgroup_id`, `contact_id`, `created`)".
" VALUES (?, ?, ".$this->db->now().")", " VALUES (?, ?, ".$this->db->now().")",
$group_id, $group_id,
$contact_id $contact_id
@ -976,9 +977,9 @@ class rcube_contacts extends rcube_addressbook
$ids = $this->db->array2list($ids, 'integer'); $ids = $this->db->array2list($ids, 'integer');
$sql_result = $this->db->query( $sql_result = $this->db->query(
"DELETE FROM ".$this->db->table_name($this->db_groupmembers). "DELETE FROM " . $this->db->table_name($this->db_groupmembers, true).
" WHERE contactgroup_id=?". " WHERE `contactgroup_id` = ?".
" AND contact_id IN ($ids)", " AND `contact_id` IN ($ids)",
$group_id $group_id
); );
@ -999,10 +1000,10 @@ class rcube_contacts extends rcube_addressbook
do { do {
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT 1 FROM ".$this->db->table_name($this->db_groups). "SELECT 1 FROM " . $this->db->table_name($this->db_groups, true).
" WHERE del<>1". " WHERE `del` <> 1".
" AND user_id=?". " AND `user_id` = ?".
" AND name=?", " AND `name` = ?",
$this->user_id, $this->user_id,
$checkname); $checkname);
@ -1014,5 +1015,4 @@ class rcube_contacts extends rcube_addressbook
return $checkname; return $checkname;
} }
} }

@ -50,6 +50,7 @@ class rcube_db
); );
const DEBUG_LINE_LENGTH = 4096; const DEBUG_LINE_LENGTH = 4096;
const DEFAULT_QUOTE = '`';
/** /**
* Factory, returns driver-specific instance of the class * Factory, returns driver-specific instance of the class
@ -238,8 +239,12 @@ class rcube_db
// Read or write ? // Read or write ?
$mode = preg_match('/^(select|show|set)/i', $query) ? 'r' : 'w'; $mode = preg_match('/^(select|show|set)/i', $query) ? 'r' : 'w';
$start = '[' . $this->options['identifier_start'] . self::DEFAULT_QUOTE . ']';
$end = '[' . $this->options['identifier_end'] . self::DEFAULT_QUOTE . ']';
$regex = '/(?:^|\s)(from|update|into|join)\s+'.$start.'?([a-z0-9._]+)'.$end.'?\s+/i';
// find tables involved in this query // find tables involved in this query
if (preg_match_all('/(?:^|\s)(from|update|into|join)\s+'.$this->options['identifier_start'].'?([a-z0-9._]+)'.$this->options['identifier_end'].'?\s+/i', $query, $matches, PREG_SET_ORDER)) { if (preg_match_all($regex, $query, $matches, PREG_SET_ORDER)) {
foreach ($matches as $m) { foreach ($matches as $m) {
$table = $m[2]; $table = $m[2];
@ -408,6 +413,9 @@ class rcube_db
$query = $this->set_limit($query, $numrows, $offset); $query = $this->set_limit($query, $numrows, $offset);
} }
// replace self::DEFAULT_QUOTE with driver-specific quoting
$query = $this->query_parse($query);
// Because in Roundcube we mostly use queries that are // Because in Roundcube we mostly use queries that are
// executed only once, we will not use prepared queries // executed only once, we will not use prepared queries
$pos = 0; $pos = 0;
@ -431,6 +439,7 @@ class rcube_db
$query = str_replace('??', '?', $query); $query = str_replace('??', '?', $query);
$query = rtrim($query, " \t\n\r\0\x0B;"); $query = rtrim($query, " \t\n\r\0\x0B;");
// log query
$this->debug($query); $this->debug($query);
// destroy reference to previous result, required for SQLite driver (#1488874) // destroy reference to previous result, required for SQLite driver (#1488874)
@ -449,6 +458,51 @@ class rcube_db
return $result; return $result;
} }
/**
* Parse SQL query and replace identifier quoting
*
* @param string $query SQL query
*
* @return string SQL query
*/
protected function query_parse($query)
{
$start = $this->options['identifier_start'];
$end = $this->options['identifier_end'];
$quote = self::DEFAULT_QUOTE;
if ($start == $quote) {
return $query;
}
$pos = 0;
$in = false;
while ($pos = strpos($query, $quote, $pos)) {
if ($query[$pos+1] == $quote) { // skip escaped quote
$pos += 2;
}
else {
if ($in) {
$q = $end;
$in = false;
}
else {
$q = $start;
$in = true;
}
$query = substr_replace($query, $q, $pos, 1);
$pos++;
}
}
// replace escaped quote back to normal, see self::quote()
$query = str_replace($quote.$quote, $quote, $query);
return $query;
}
/** /**
* Helper method to handle DB errors. * Helper method to handle DB errors.
* This by default logs the error but could be overriden by a driver implementation * This by default logs the error but could be overriden by a driver implementation
@ -677,8 +731,13 @@ class rcube_db
'bool' => PDO::PARAM_BOOL, 'bool' => PDO::PARAM_BOOL,
'integer' => PDO::PARAM_INT, 'integer' => PDO::PARAM_INT,
); );
$type = isset($map[$type]) ? $map[$type] : PDO::PARAM_STR; $type = isset($map[$type]) ? $map[$type] : PDO::PARAM_STR;
return strtr($this->dbh->quote($input, $type), array('?' => '??')); // escape ?
return strtr($this->dbh->quote($input, $type),
// escape ? and `
array('?' => '??', self::DEFAULT_QUOTE => self::DEFAULT_QUOTE.self::DEFAULT_QUOTE)
);
} }
return 'NULL'; return 'NULL';
@ -917,15 +976,20 @@ class rcube_db
/** /**
* Return correct name for a specific database table * Return correct name for a specific database table
* *
* @param string $table Table name * @param string $table Table name
* @param bool $quoted Quote table identifier
* *
* @return string Translated table name * @return string Translated table name
*/ */
public function table_name($table) public function table_name($table, $quoted = false)
{ {
// add prefix to the table name if configured // add prefix to the table name if configured
if (($prefix = $this->options['table_prefix']) && strpos($table, $prefix) !== 0) { if (($prefix = $this->options['table_prefix']) && strpos($table, $prefix) !== 0) {
return $prefix . $table; $table = $prefix . $table;
}
if ($quoted) {
$table = $this->quote_identifier($table);
} }
return $table; return $table;

@ -0,0 +1,263 @@
<?php
/**
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2011-2014, Kolab Systems AG |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
| Database wrapper class that implements PHP PDO functions |
| for Oracle database |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <machniak@kolabsys.com> |
+-----------------------------------------------------------------------+
*/
/**
* Database independent query interface
* This is a wrapper for the PHP PDO
*
* @package Framework
* @subpackage Database
*/
class rcube_db_oracle extends rcube_db
{
public $db_provider = 'oracle';
/**
* Driver-specific configuration of database connection
*
* @param array $dsn DSN for DB connections
* @param PDO $dbh Connection handler
*/
protected function conn_configure($dsn, $dbh)
{
$dbh->query("ALTER SESSION SET nls_date_format = 'YYYY-MM-DD'");
$dbh->query("ALTER SESSION SET nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'");
}
/**
* Get last inserted record ID
*
* @param string $table Table name (to find the incremented sequence)
*
* @return mixed ID or false on failure
*/
public function insert_id($table = null)
{
if (!$this->db_connected || $this->db_mode == 'r' || empty($table)) {
return false;
}
$sequence = $this->quote_identifier($this->sequence_name($table));
$result = $dbh->query("SELECT $sequence.currval FROM dual");
return $result ? $result->fetchColumn() : false;
}
/**
* Formats input so it can be safely used in a query
* PDO_OCI does not implement quote() method
*
* @param mixed $input Value to quote
* @param string $type Type of data (integer, bool, ident)
*
* @return string Quoted/converted string for use in query
*/
public function quote($input, $type = null)
{
// handle int directly for better performance
if ($type == 'integer' || $type == 'int') {
return intval($input);
}
if (is_null($input)) {
return 'NULL';
}
if ($type == 'ident') {
return $this->quote_identifier($input);
}
switch ($type) {
case 'bool':
case 'integer':
return intval($input);
default:
return "'" . strtr($input, array(
'?' => '??',
"'" => "''",
rcube_db::DEFAULT_QUOTE => rcube_db::DEFAULT_QUOTE . rcube_db::DEFAULT_QUOTE
)) . "'";
}
}
/**
* Return correct name for a specific database sequence
*
* @param string $table Table name
*
* @return string Translated sequence name
*/
protected function sequence_name($table)
{
// Note: we support only one sequence per table
// Note: The sequence name must be <table_name>_seq
$sequence = $table . '_seq';
// modify sequence name if prefix is configured
if ($prefix = $this->options['table_prefix']) {
return $prefix . $sequence;
}
return $sequence;
}
/**
* Return SQL statement for case insensitive LIKE
*
* @param string $column Field name
* @param string $value Search value
*
* @return string SQL statement to use in query
*/
public function ilike($column, $value)
{
return 'UPPER(' . $this->quote_identifier($column) . ') LIKE UPPER(' . $this->quote($value) . ')';
}
/**
* Return SQL function for current time and date
*
* @param int $interval Optional interval (in seconds) to add/subtract
*
* @return string SQL function to use in query
*/
public function now($interval = 0)
{
if ($interval) {
$interval = intval($interval);
return "current_timestamp + INTERVAL '$interval' SECOND";
}
return "current_timestamp";
}
/**
* Return SQL statement to convert a field value into a unix timestamp
*
* @param string $field Field name
*
* @return string SQL statement to use in query
* @deprecated
*/
public function unixtimestamp($field)
{
return "(($field - to_date('1970-01-01','YYYY-MM-DD')) * 60 * 60 * 24)";
}
/**
* Adds TOP (LIMIT,OFFSET) clause to the query
*
* @param string $query SQL query
* @param int $limit Number of rows
* @param int $offset Offset
*
* @return string SQL query
*/
protected function set_limit($query, $limit = 0, $offset = 0)
{
$limit = intval($limit);
$offset = intval($offset);
$end = $offset + $limit;
// @TODO: Oracle 12g has better OFFSET support
$orderby = stristr($query, 'ORDER BY');
$select = substr($query, 0, stripos($query, 'FROM'));
$offset += 1;
if ($orderby !== false) {
$query = trim(substr($query, 0, -1 * strlen($orderby)));
}
else {
// it shouldn't happen, paging without sorting has not much sense
// @FIXME: I don't know how to build paging query without ORDER BY
$orderby = "ORDER BY 1";
}
$query = preg_replace('/^SELECT\s/i', '', $query);
$query = "$select FROM (SELECT ROW_NUMBER() OVER ($orderby) AS row_number, $query)"
. " WHERE row_number BETWEEN $offset AND $end";
return $query;
}
/**
* Parse SQL file and fix table names according to table prefix
*/
protected function fix_table_names($sql)
{
if (!$this->options['table_prefix']) {
return $sql;
}
$sql = parent::fix_table_names($sql);
// replace sequence names, and other Oracle-specific commands
$sql = preg_replace_callback('/((SEQUENCE ["]?)([^" \r\n]+)/',
array($this, 'fix_table_names_callback'),
$sql
);
$sql = preg_replace_callback(
'/([ \r\n]+["]?)([^"\' \r\n\.]+)(["]?\.nextval)/',
array($this, 'fix_table_names_seq_callback'),
$sql
);
return $sql;
}
/**
* Preg_replace callback for fix_table_names()
*/
protected function fix_table_names_seq_callback($matches)
{
return $matches[1] . $this->options['table_prefix'] . $matches[2] . $matches[3];
}
/**
* Returns PDO DSN string from DSN array
*/
protected function dsn_string($dsn)
{
$params = array();
$result = 'oci:';
if ($dsn['hostspec']) {
$host = $dsn['hostspec'];
if ($dsn['port']) {
$host .= ':' . $dsn['port'];
}
$dsn['database'] = $host . '/' . $dsn['database'];
}
if ($dsn['database']) {
$params[] = 'dbname=' . $dsn['database'];
}
$params['charset'] = 'UTF8';
if (!empty($params)) {
$result .= implode(';', $params);
}
return $result;
}
}

@ -125,6 +125,11 @@ class rcube_imap_cache
// cache all possible information by default // cache all possible information by default
$this->mode = self::MODE_INDEX | self::MODE_MESSAGE; $this->mode = self::MODE_INDEX | self::MODE_MESSAGE;
// database tables
$this->index_table = $db->table_name('cache_index', true);
$this->thread_table = $db->table_name('cache_thread', true);
$this->messages_table = $db->table_name('cache_messages', true);
} }
@ -333,11 +338,11 @@ class rcube_imap_cache
if ($this->mode & self::MODE_MESSAGE) { if ($this->mode & self::MODE_MESSAGE) {
// Fetch messages from cache // Fetch messages from cache
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT uid, data, flags" "SELECT `uid`, `data`, `flags`"
." FROM ".$this->db->table_name('cache_messages') ." FROM {$this->messages_table}"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?" ." AND `mailbox` = ?"
." AND uid IN (".$this->db->array2list($msgs, 'integer').")", ." AND `uid` IN (".$this->db->array2list($msgs, 'integer').")",
$this->userid, $mailbox); $this->userid, $mailbox);
$msgs = array_flip($msgs); $msgs = array_flip($msgs);
@ -400,11 +405,11 @@ class rcube_imap_cache
if ($this->mode & self::MODE_MESSAGE) { if ($this->mode & self::MODE_MESSAGE) {
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT flags, data" "SELECT `flags`, `data`"
." FROM ".$this->db->table_name('cache_messages') ." FROM {$this->messages_table}"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?" ." AND `mailbox` = ?"
." AND uid = ?", ." AND `uid` = ?",
$this->userid, $mailbox, (int)$uid); $this->userid, $mailbox, (int)$uid);
if ($sql_arr = $this->db->fetch_assoc($sql_result)) { if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
@ -480,11 +485,11 @@ class rcube_imap_cache
// here will work as select, assume row exist if affected_rows=0) // here will work as select, assume row exist if affected_rows=0)
if (!$force) { if (!$force) {
$res = $this->db->query( $res = $this->db->query(
"UPDATE ".$this->db->table_name('cache_messages') "UPDATE {$this->messages_table}"
." SET flags = ?, data = ?, expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') ." SET `flags` = ?, `data` = ?, `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?" ." AND `mailbox` = ?"
." AND uid = ?", ." AND `uid` = ?",
$flags, $msg, $this->userid, $mailbox, (int) $message->uid); $flags, $msg, $this->userid, $mailbox, (int) $message->uid);
if ($this->db->affected_rows($res)) { if ($this->db->affected_rows($res)) {
@ -496,8 +501,8 @@ class rcube_imap_cache
// insert new record // insert new record
$res = $this->db->query( $res = $this->db->query(
"INSERT INTO ".$this->db->table_name('cache_messages') "INSERT INTO {$this->messages_table}"
." (user_id, mailbox, uid, flags, expires, data)" ." (`user_id`, `mailbox`, `uid`, `flags`, `expires`, `data`)"
." VALUES (?, ?, ?, ?, ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?)", ." VALUES (?, ?, ?, ?, ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL') . ", ?)",
$this->userid, $mailbox, (int) $message->uid, $flags, $msg); $this->userid, $mailbox, (int) $message->uid, $flags, $msg);
@ -505,12 +510,12 @@ class rcube_imap_cache
// thanks to ignore_key_errors "duplicate row" errors will be ignored // thanks to ignore_key_errors "duplicate row" errors will be ignored
if ($force && !$res && !$this->db->is_error($res)) { if ($force && !$res && !$this->db->is_error($res)) {
$this->db->query( $this->db->query(
"UPDATE ".$this->db->table_name('cache_messages') "UPDATE {$this->messages_table}"
." SET expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') ." SET `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
.", flags = ?, data = ?" .", `flags` = ?, `data` = ?"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?" ." AND `mailbox` = ?"
." AND uid = ?", ." AND `uid` = ?",
$flags, $msg, $this->userid, $mailbox, (int) $message->uid); $flags, $msg, $this->userid, $mailbox, (int) $message->uid);
} }
@ -558,13 +563,13 @@ class rcube_imap_cache
} }
$this->db->query( $this->db->query(
"UPDATE ".$this->db->table_name('cache_messages') "UPDATE {$this->messages_table}"
." SET expires = ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL') ." SET `expires` = ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
.", flags = flags ".($enabled ? "+ $idx" : "- $idx") .", `flags` = `flags` ".($enabled ? "+ $idx" : "- $idx")
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?" ." AND `mailbox` = ?"
.(!empty($uids) ? " AND uid IN (".$this->db->array2list($uids, 'integer').")" : "") .(!empty($uids) ? " AND `uid` IN (".$this->db->array2list($uids, 'integer').")" : "")
." AND (flags & $idx) ".($enabled ? "= 0" : "= $idx"), ." AND (`flags` & $idx) ".($enabled ? "= 0" : "= $idx"),
$this->userid, $mailbox); $this->userid, $mailbox);
} }
@ -583,8 +588,8 @@ class rcube_imap_cache
if (!strlen($mailbox)) { if (!strlen($mailbox)) {
$this->db->query( $this->db->query(
"DELETE FROM ".$this->db->table_name('cache_messages') "DELETE FROM {$this->messages_table}"
." WHERE user_id = ?", ." WHERE `user_id` = ?",
$this->userid); $this->userid);
} }
else { else {
@ -597,10 +602,10 @@ class rcube_imap_cache
} }
$this->db->query( $this->db->query(
"DELETE FROM ".$this->db->table_name('cache_messages') "DELETE FROM {$this->messages_table}"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?" ." AND `mailbox` = ?"
.($uids !== null ? " AND uid IN (".$this->db->array2list((array)$uids, 'integer').")" : ""), .($uids !== null ? " AND `uid` IN (".$this->db->array2list((array)$uids, 'integer').")" : ""),
$this->userid, $mailbox); $this->userid, $mailbox);
} }
} }
@ -619,18 +624,18 @@ class rcube_imap_cache
// otherwise use 'valid' flag to not loose HIGHESTMODSEQ value // otherwise use 'valid' flag to not loose HIGHESTMODSEQ value
if ($remove) { if ($remove) {
$this->db->query( $this->db->query(
"DELETE FROM ".$this->db->table_name('cache_index') "DELETE FROM {$this->index_table}"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
.(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : ""), .(strlen($mailbox) ? " AND `mailbox` = ".$this->db->quote($mailbox) : ""),
$this->userid $this->userid
); );
} }
else { else {
$this->db->query( $this->db->query(
"UPDATE ".$this->db->table_name('cache_index') "UPDATE {$this->index_table}"
." SET valid = 0" ." SET `valid` = 0"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
.(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : ""), .(strlen($mailbox) ? " AND `mailbox` = ".$this->db->quote($mailbox) : ""),
$this->userid $this->userid
); );
} }
@ -654,9 +659,9 @@ class rcube_imap_cache
function remove_thread($mailbox = null) function remove_thread($mailbox = null)
{ {
$this->db->query( $this->db->query(
"DELETE FROM ".$this->db->table_name('cache_thread') "DELETE FROM {$this->thread_table}"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
.(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : ""), .(strlen($mailbox) ? " AND `mailbox` = ".$this->db->quote($mailbox) : ""),
$this->userid $this->userid
); );
@ -692,15 +697,16 @@ class rcube_imap_cache
{ {
$rcube = rcube::get_instance(); $rcube = rcube::get_instance();
$db = $rcube->get_dbh(); $db = $rcube->get_dbh();
$now = $db->now();
$db->query("DELETE FROM ".$db->table_name('cache_messages') $db->query("DELETE FROM " . $db->table_name('cache_messages', true)
." WHERE expires < " . $db->now()); ." WHERE `expires` < $now");
$db->query("DELETE FROM ".$db->table_name('cache_index') $db->query("DELETE FROM " . $db->table_name('cache_index', true)
." WHERE expires < " . $db->now()); ." WHERE `expires` < $now");
$db->query("DELETE FROM ".$db->table_name('cache_thread') $db->query("DELETE FROM ".$db->table_name('cache_thread', true)
." WHERE expires < " . $db->now()); ." WHERE `expires` < $now");
} }
@ -711,10 +717,10 @@ class rcube_imap_cache
{ {
// Get index from DB // Get index from DB
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT data, valid" "SELECT `data`, `valid`"
." FROM ".$this->db->table_name('cache_index') ." FROM {$this->index_table}"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?", ." AND `mailbox` = ?",
$this->userid, $mailbox); $this->userid, $mailbox);
if ($sql_arr = $this->db->fetch_assoc($sql_result)) { if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
@ -748,10 +754,10 @@ class rcube_imap_cache
{ {
// Get thread from DB // Get thread from DB
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT data" "SELECT `data`"
." FROM ".$this->db->table_name('cache_thread') ." FROM {$this->thread_table}"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?", ." AND `mailbox` = ?",
$this->userid, $mailbox); $this->userid, $mailbox);
if ($sql_arr = $this->db->fetch_assoc($sql_result)) { if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
@ -789,14 +795,16 @@ class rcube_imap_cache
(int) $mbox_data['UIDNEXT'], (int) $mbox_data['UIDNEXT'],
$modseq ? $modseq : $mbox_data['HIGHESTMODSEQ'], $modseq ? $modseq : $mbox_data['HIGHESTMODSEQ'],
); );
$data = implode('@', $data);
$data = implode('@', $data);
$expires = $this->ttl ? $this->db->now($this->ttl) : 'NULL';
if ($exists) { if ($exists) {
$res = $this->db->query( $res = $this->db->query(
"UPDATE ".$this->db->table_name('cache_index') "UPDATE {$this->index_table}"
." SET data = ?, valid = 1, expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') ." SET `data` = ?, `valid` = 1, `expires` = $expires"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?", ." AND `mailbox` = ?",
$data, $this->userid, $mailbox); $data, $this->userid, $mailbox);
if ($this->db->affected_rows($res)) { if ($this->db->affected_rows($res)) {
@ -807,19 +815,19 @@ class rcube_imap_cache
$this->db->set_option('ignore_key_errors', true); $this->db->set_option('ignore_key_errors', true);
$res = $this->db->query( $res = $this->db->query(
"INSERT INTO ".$this->db->table_name('cache_index') "INSERT INTO {$this->index_table}"
." (user_id, mailbox, valid, expires, data)" ." (`user_id`, `mailbox`, `valid`, `expires`, `data`)"
." VALUES (?, ?, 1, ". ($this->ttl ? $this->db->now($this->ttl) : 'NULL') .", ?)", ." VALUES (?, ?, 1, $expires, ?)",
$this->userid, $mailbox, $data); $this->userid, $mailbox, $data);
// race-condition, insert failed so try update (#1489146) // race-condition, insert failed so try update (#1489146)
// thanks to ignore_key_errors "duplicate row" errors will be ignored // thanks to ignore_key_errors "duplicate row" errors will be ignored
if (!$exists && !$res && !$this->db->is_error($res)) { if (!$exists && !$res && !$this->db->is_error($res)) {
$res = $this->db->query( $res = $this->db->query(
"UPDATE ".$this->db->table_name('cache_index') "UPDATE {$this->index_table}"
." SET data = ?, valid = 1, expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') ." SET `data` = ?, `valid` = 1, `expires` = $expires"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?", ." AND `mailbox` = ?",
$data, $this->userid, $mailbox); $data, $this->userid, $mailbox);
} }
@ -838,16 +846,16 @@ class rcube_imap_cache
(int) $mbox_data['UIDVALIDITY'], (int) $mbox_data['UIDVALIDITY'],
(int) $mbox_data['UIDNEXT'], (int) $mbox_data['UIDNEXT'],
); );
$data = implode('@', $data);
$expires = ($this->ttl ? $this->db->now($this->ttl) : 'NULL'); $data = implode('@', $data);
$expires = $this->ttl ? $this->db->now($this->ttl) : 'NULL';
if ($exists) { if ($exists) {
$res = $this->db->query( $res = $this->db->query(
"UPDATE ".$this->db->table_name('cache_thread') "UPDATE {$this->thread_table}"
." SET data = ?, expires = $expires" ." SET `data` = ?, `expires` = $expires"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?", ." AND `mailbox` = ?",
$data, $this->userid, $mailbox); $data, $this->userid, $mailbox);
if ($this->db->affected_rows($res)) { if ($this->db->affected_rows($res)) {
@ -858,8 +866,8 @@ class rcube_imap_cache
$this->db->set_option('ignore_key_errors', true); $this->db->set_option('ignore_key_errors', true);
$res = $this->db->query( $res = $this->db->query(
"INSERT INTO ".$this->db->table_name('cache_thread') "INSERT INTO {$this->thread_table}"
." (user_id, mailbox, expires, data)" ." (`user_id`, `mailbox`, `expires`, `data`)"
." VALUES (?, ?, $expires, ?)", ." VALUES (?, ?, $expires, ?)",
$this->userid, $mailbox, $data); $this->userid, $mailbox, $data);
@ -867,10 +875,10 @@ class rcube_imap_cache
// thanks to ignore_key_errors "duplicate row" errors will be ignored // thanks to ignore_key_errors "duplicate row" errors will be ignored
if (!$exists && !$res && !$this->db->is_error($res)) { if (!$exists && !$res && !$this->db->is_error($res)) {
$this->db->query( $this->db->query(
"UPDATE ".$this->db->table_name('cache_thread') "UPDATE {$this->thread_table}"
." SET expires = $expires, data = ?" ." SET `expires` = $expires, `data` = ?"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?", ." AND `mailbox` = ?",
$data, $this->userid, $mailbox); $data, $this->userid, $mailbox);
} }
@ -1086,10 +1094,10 @@ class rcube_imap_cache
// Get known UIDs // Get known UIDs
if ($this->mode & self::MODE_MESSAGE) { if ($this->mode & self::MODE_MESSAGE) {
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT uid" "SELECT `uid`"
." FROM ".$this->db->table_name('cache_messages') ." FROM {$this->messages_table}"
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?", ." AND `mailbox` = ?",
$this->userid, $mailbox); $this->userid, $mailbox);
while ($sql_arr = $this->db->fetch_assoc($sql_result)) { while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
@ -1125,12 +1133,12 @@ class rcube_imap_cache
} }
$this->db->query( $this->db->query(
"UPDATE ".$this->db->table_name('cache_messages') "UPDATE {$this->messages_table}"
." SET flags = ?, expires = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL') ." SET `flags` = ?, `expires` = " . ($this->ttl ? $this->db->now($this->ttl) : 'NULL')
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND mailbox = ?" ." AND `mailbox` = ?"
." AND uid = ?" ." AND `uid` = ?"
." AND flags <> ?", ." AND `flags` <> ?",
$flags, $this->userid, $mailbox, $uid, $flags); $flags, $this->userid, $mailbox, $uid, $flags);
} }
} }

@ -103,6 +103,8 @@ class rcube_session
array($this, 'db_write'), array($this, 'db_write'),
array($this, 'db_destroy'), array($this, 'db_destroy'),
array($this, 'gc')); array($this, 'gc'));
$this->table_name = $this->db->table_name('session', true);
} }
} }
@ -175,9 +177,8 @@ class rcube_session
public function db_read($key) public function db_read($key)
{ {
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT vars, ip, changed, " . $this->db->now() . " AS ts" "SELECT `vars`, `ip`, `changed`, " . $this->db->now() . " AS ts"
. " FROM " . $this->db->table_name('session') . " FROM {$this->table_name} WHERE `sess_id` = ?", $key);
. " WHERE sess_id = ?", $key);
if ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { if ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) {
$this->time_diff = time() - strtotime($sql_arr['ts']); $this->time_diff = time() - strtotime($sql_arr['ts']);
@ -204,9 +205,8 @@ class rcube_session
*/ */
public function db_write($key, $vars) public function db_write($key, $vars)
{ {
$now = $this->db->now(); $now = $this->db->now();
$table = $this->db->table_name('session'); $ts = microtime(true);
$ts = microtime(true);
if ($this->nowrite) if ($this->nowrite)
return true; return true;
@ -227,17 +227,18 @@ class rcube_session
$newvars = $this->_fixvars($vars, $oldvars); $newvars = $this->_fixvars($vars, $oldvars);
if ($newvars !== $oldvars) { if ($newvars !== $oldvars) {
$this->db->query("UPDATE $table " $this->db->query("UPDATE {$this->table_name} "
. "SET changed = $now, vars = ? WHERE sess_id = ?", . "SET `changed` = $now, `vars` = ? WHERE `sess_id` = ?",
base64_encode($newvars), $key); base64_encode($newvars), $key);
} }
else if ($ts - $this->changed + $this->time_diff > $this->lifetime / 2) { else if ($ts - $this->changed + $this->time_diff > $this->lifetime / 2) {
$this->db->query("UPDATE $table SET changed = $now" $this->db->query("UPDATE {$this->table_name} SET `changed` = $now"
. " WHERE sess_id = ?", $key); . " WHERE `sess_id` = ?", $key);
} }
} }
else { else {
$this->db->query("INSERT INTO $table (sess_id, vars, ip, created, changed)" $this->db->query("INSERT INTO {$this->table_name}"
. " (`sess_id`, `vars`, `ip`, `created`, `changed`)"
. " VALUES (?, ?, ?, $now, $now)", . " VALUES (?, ?, ?, $now, $now)",
$key, base64_encode($vars), (string)$this->ip); $key, base64_encode($vars), (string)$this->ip);
} }
@ -290,8 +291,7 @@ class rcube_session
public function db_destroy($key) public function db_destroy($key)
{ {
if ($key) { if ($key) {
$this->db->query(sprintf("DELETE FROM %s WHERE sess_id = ?", $this->db->query("DELETE FROM {$this->table_name} WHERE `sess_id` = ?", $key);
$this->db->table_name('session')), $key);
} }
return true; return true;
@ -407,8 +407,8 @@ class rcube_session
if ($this->gc_enabled) { if ($this->gc_enabled) {
// just delete all expired sessions // just delete all expired sessions
if ($this->storage == 'db') { if ($this->storage == 'db') {
$this->db->query("DELETE FROM " . $this->db->table_name('session') $this->db->query("DELETE FROM {$this->table_name}"
. " WHERE changed < " . $this->db->now(-$this->gc_enabled)); . " WHERE `changed` < " . $this->db->now(-$this->gc_enabled));
} }
foreach ($this->gc_handlers as $fct) { foreach ($this->gc_handlers as $fct) {

@ -360,25 +360,25 @@ class rcube_spellchecker
if ($this->have_dict) { if ($this->have_dict) {
if (!empty($this->dict)) { if (!empty($this->dict)) {
$this->rc->db->query( $this->rc->db->query(
"UPDATE ".$this->rc->db->table_name('dictionary') "UPDATE " . $this->rc->db->table_name('dictionary', true)
." SET data = ?" ." SET `data` = ?"
." WHERE user_id " . ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL") ." WHERE `user_id` " . ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL")
." AND " . $this->rc->db->quote_identifier('language') . " = ?", ." AND `language` = ?",
implode(' ', $plugin['dictionary']), $plugin['language']); implode(' ', $plugin['dictionary']), $plugin['language']);
} }
// don't store empty dict // don't store empty dict
else { else {
$this->rc->db->query( $this->rc->db->query(
"DELETE FROM " . $this->rc->db->table_name('dictionary') "DELETE FROM " . $this->rc->db->table_name('dictionary', true)
." WHERE user_id " . ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL") ." WHERE `user_id` " . ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL")
." AND " . $this->rc->db->quote_identifier('language') . " = ?", ." AND `language` = ?",
$plugin['language']); $plugin['language']);
} }
} }
else if (!empty($this->dict)) { else if (!empty($this->dict)) {
$this->rc->db->query( $this->rc->db->query(
"INSERT INTO " .$this->rc->db->table_name('dictionary') "INSERT INTO " . $this->rc->db->table_name('dictionary', true)
." (user_id, " . $this->rc->db->quote_identifier('language') . ", data) VALUES (?, ?, ?)", ." (`user_id`, `language`, `data`) VALUES (?, ?, ?)",
$plugin['userid'], $plugin['language'], implode(' ', $plugin['dictionary'])); $plugin['userid'], $plugin['language'], implode(' ', $plugin['dictionary']));
} }
} }
@ -403,9 +403,9 @@ class rcube_spellchecker
if (empty($plugin['abort'])) { if (empty($plugin['abort'])) {
$dict = array(); $dict = array();
$sql_result = $this->rc->db->query( $sql_result = $this->rc->db->query(
"SELECT data FROM ".$this->rc->db->table_name('dictionary') "SELECT `data` FROM " . $this->rc->db->table_name('dictionary', true)
." WHERE user_id ". ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL") ." WHERE `user_id` ". ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL")
." AND " . $this->rc->db->quote_identifier('language') . " = ?", ." AND `language` = ?",
$plugin['language']); $plugin['language']);
if ($sql_arr = $this->rc->db->fetch_assoc($sql_result)) { if ($sql_arr = $this->rc->db->fetch_assoc($sql_result)) {
@ -427,5 +427,4 @@ class rcube_spellchecker
return $this->dict; return $this->dict;
} }
} }

@ -67,7 +67,8 @@ class rcube_user
if ($id && !$sql_arr) { if ($id && !$sql_arr) {
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT * FROM ".$this->db->table_name('users')." WHERE user_id = ?", $id); "SELECT * FROM " . $this->db->table_name('users', true)
. " WHERE `user_id` = ?", $id);
$sql_arr = $this->db->fetch_assoc($sql_result); $sql_arr = $this->db->fetch_assoc($sql_result);
} }
@ -189,10 +190,9 @@ class rcube_user
$save_prefs = serialize($save_prefs); $save_prefs = serialize($save_prefs);
$this->db->query( $this->db->query(
"UPDATE ".$this->db->table_name('users'). "UPDATE ".$this->db->table_name('users', true).
" SET preferences = ?". " SET `preferences` = ?, `language` = ?".
", language = ?". " WHERE `user_id` = ?",
" WHERE user_id = ?",
$save_prefs, $save_prefs,
$_SESSION['language'], $_SESSION['language'],
$this->ID); $this->ID);
@ -243,7 +243,7 @@ class rcube_user
$id = (int)$id; $id = (int)$id;
// cache identities for better performance // cache identities for better performance
if (!array_key_exists($id, $this->identities)) { if (!array_key_exists($id, $this->identities)) {
$result = $this->list_identities($id ? 'AND identity_id = ' . $id : ''); $result = $this->list_identities($id ? "AND `identity_id` = $id" : '');
$this->identities[$id] = $result[0]; $this->identities[$id] = $result[0];
} }
@ -264,13 +264,10 @@ class rcube_user
$result = array(); $result = array();
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT * FROM ".$this->db->table_name('identities'). "SELECT * FROM ".$this->db->table_name('identities', true).
" WHERE del <> 1 AND user_id = ?". " WHERE `del` <> 1 AND `user_id` = ?".
($sql_add ? " ".$sql_add : ""). ($sql_add ? " ".$sql_add : "").
" ORDER BY ". $this->db->quote_identifier('standard') . " DESC, " " ORDER BY `standard` DESC, `name` ASC, `email` ASC, `identity_id` ASC",
. $this->db->quote_identifier('name') . " ASC, "
. $this->db->quote_identifier('email') . " ASC, "
. $this->db->quote_identifier('identity_id') . " ASC",
$this->ID); $this->ID);
while ($sql_arr = $this->db->fetch_assoc($sql_result)) { while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
@ -311,11 +308,11 @@ class rcube_user
$query_params[] = $iid; $query_params[] = $iid;
$query_params[] = $this->ID; $query_params[] = $this->ID;
$sql = "UPDATE ".$this->db->table_name('identities'). $sql = "UPDATE ".$this->db->table_name('identities', true).
" SET changed = ".$this->db->now().", ".join(', ', $query_cols). " SET `changed` = ".$this->db->now().", ".join(', ', $query_cols).
" WHERE identity_id = ?". " WHERE `identity_id` = ?".
" AND user_id = ?". " AND `user_id` = ?".
" AND del <> 1"; " AND `del` <> 1";
call_user_func_array(array($this->db, 'query'), call_user_func_array(array($this->db, 'query'),
array_merge(array($sql), $query_params)); array_merge(array($sql), $query_params));
@ -344,11 +341,11 @@ class rcube_user
$insert_cols[] = $this->db->quote_identifier($col); $insert_cols[] = $this->db->quote_identifier($col);
$insert_values[] = $value; $insert_values[] = $value;
} }
$insert_cols[] = 'user_id'; $insert_cols[] = $this->db->quote_identifier('user_id');
$insert_values[] = $this->ID; $insert_values[] = $this->ID;
$sql = "INSERT INTO ".$this->db->table_name('identities'). $sql = "INSERT INTO ".$this->db->table_name('identities', true).
" (changed, ".join(', ', $insert_cols).")". " (`changed`, ".join(', ', $insert_cols).")".
" VALUES (".$this->db->now().", ".join(', ', array_pad(array(), sizeof($insert_values), '?')).")"; " VALUES (".$this->db->now().", ".join(', ', array_pad(array(), sizeof($insert_values), '?')).")";
call_user_func_array(array($this->db, 'query'), call_user_func_array(array($this->db, 'query'),
@ -372,8 +369,8 @@ class rcube_user
return false; return false;
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT count(*) AS ident_count FROM ".$this->db->table_name('identities'). "SELECT count(*) AS ident_count FROM ".$this->db->table_name('identities', true).
" WHERE user_id = ? AND del <> 1", " WHERE `user_id` = ? AND `del` <> 1",
$this->ID); $this->ID);
$sql_arr = $this->db->fetch_assoc($sql_result); $sql_arr = $this->db->fetch_assoc($sql_result);
@ -383,10 +380,10 @@ class rcube_user
return -1; return -1;
$this->db->query( $this->db->query(
"UPDATE ".$this->db->table_name('identities'). "UPDATE ".$this->db->table_name('identities', true).
" SET del = 1, changed = ".$this->db->now(). " SET `del` = 1, `changed` = ".$this->db->now().
" WHERE user_id = ?". " WHERE `user_id` = ?".
" AND identity_id = ?", " AND `identity_id` = ?",
$this->ID, $this->ID,
$iid); $iid);
@ -405,11 +402,9 @@ class rcube_user
{ {
if ($this->ID && $iid) { if ($this->ID && $iid) {
$this->db->query( $this->db->query(
"UPDATE ".$this->db->table_name('identities'). "UPDATE ".$this->db->table_name('identities', true).
" SET ".$this->db->quote_identifier('standard')." = '0'". " SET `standard` = '0'".
" WHERE user_id = ?". " WHERE `user_id` = ? AND `identity_id` <> ?",
" AND identity_id <> ?".
" AND del <> 1",
$this->ID, $this->ID,
$iid); $iid);
@ -425,9 +420,9 @@ class rcube_user
{ {
if ($this->ID) { if ($this->ID) {
$this->db->query( $this->db->query(
"UPDATE ".$this->db->table_name('users'). "UPDATE ".$this->db->table_name('users', true).
" SET last_login = ".$this->db->now(). " SET `last_login` = ".$this->db->now().
" WHERE user_id = ?", " WHERE `user_id` = ?",
$this->ID); $this->ID);
} }
} }
@ -456,17 +451,17 @@ class rcube_user
$config = rcube::get_instance()->config; $config = rcube::get_instance()->config;
// query for matching user name // query for matching user name
$sql_result = $dbh->query("SELECT * FROM " . $dbh->table_name('users') $sql_result = $dbh->query("SELECT * FROM " . $dbh->table_name('users', true)
." WHERE mail_host = ? AND username = ?", $host, $user); ." WHERE `mail_host` = ? AND `username` = ?", $host, $user);
$sql_arr = $dbh->fetch_assoc($sql_result); $sql_arr = $dbh->fetch_assoc($sql_result);
// username not found, try aliases from identities // username not found, try aliases from identities
if (empty($sql_arr) && $config->get('user_aliases') && strpos($user, '@')) { if (empty($sql_arr) && $config->get('user_aliases') && strpos($user, '@')) {
$sql_result = $dbh->limitquery("SELECT u.*" $sql_result = $dbh->limitquery("SELECT u.*"
." FROM " . $dbh->table_name('users') . " u" ." FROM " . $dbh->table_name('users', true) . " u"
." JOIN " . $dbh->table_name('identities') . " i ON (i.user_id = u.user_id)" ." JOIN " . $dbh->table_name('identities', true) . " i ON (i.`user_id` = u.`user_id`)"
." WHERE email = ? AND del <> 1", 0, 1, $user); ." WHERE `email` = ? AND `del` <> 1", 0, 1, $user);
$sql_arr = $dbh->fetch_assoc($sql_result); $sql_arr = $dbh->fetch_assoc($sql_result);
} }
@ -513,8 +508,8 @@ class rcube_user
} }
$dbh->query( $dbh->query(
"INSERT INTO ".$dbh->table_name('users'). "INSERT INTO ".$dbh->table_name('users', true).
" (created, last_login, username, mail_host, language)". " (`created`, `last_login`, `username`, `mail_host`, `language`)".
" VALUES (".$dbh->now().", ".$dbh->now().", ?, ?, ?)", " VALUES (".$dbh->now().", ".$dbh->now().", ?, ?, ?)",
$data['user'], $data['user'],
$data['host'], $data['host'],
@ -646,11 +641,10 @@ class rcube_user
$result = array(); $result = array();
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT search_id AS id, ".$this->db->quote_identifier('name') "SELECT `search_id` AS id, `name`"
." FROM ".$this->db->table_name('searches') ." FROM ".$this->db->table_name('searches', true)
." WHERE user_id = ?" ." WHERE `user_id` = ? AND `type` = ?"
." AND ".$this->db->quote_identifier('type')." = ?" ." ORDER BY `name`",
." ORDER BY ".$this->db->quote_identifier('name'),
(int) $this->ID, (int) $type); (int) $this->ID, (int) $type);
while ($sql_arr = $this->db->fetch_assoc($sql_result)) { while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
@ -678,12 +672,10 @@ class rcube_user
} }
$sql_result = $this->db->query( $sql_result = $this->db->query(
"SELECT ".$this->db->quote_identifier('name') "SELECT `name`, `data`, `type`"
.", ".$this->db->quote_identifier('data') . " FROM ".$this->db->table_name('searches', true)
.", ".$this->db->quote_identifier('type') . " WHERE `user_id` = ?"
." FROM ".$this->db->table_name('searches') ." AND `search_id` = ?",
." WHERE user_id = ?"
." AND search_id = ?",
(int) $this->ID, (int) $id); (int) $this->ID, (int) $id);
while ($sql_arr = $this->db->fetch_assoc($sql_result)) { while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
@ -712,9 +704,9 @@ class rcube_user
return false; return false;
$this->db->query( $this->db->query(
"DELETE FROM ".$this->db->table_name('searches') "DELETE FROM ".$this->db->table_name('searches', true)
." WHERE user_id = ?" ." WHERE `user_id` = ?"
." AND search_id = ?", ." AND `search_id` = ?",
(int) $this->ID, $sid); (int) $this->ID, $sid);
return $this->db->affected_rows(); return $this->db->affected_rows();
@ -742,7 +734,7 @@ class rcube_user
$insert_cols[] = $this->db->quote_identifier('data'); $insert_cols[] = $this->db->quote_identifier('data');
$insert_values[] = serialize($data['data']); $insert_values[] = serialize($data['data']);
$sql = "INSERT INTO ".$this->db->table_name('searches') $sql = "INSERT INTO ".$this->db->table_name('searches', true)
." (".join(', ', $insert_cols).")" ." (".join(', ', $insert_cols).")"
." VALUES (".join(', ', array_pad(array(), sizeof($insert_values), '?')).")"; ." VALUES (".join(', ', array_pad(array(), sizeof($insert_values), '?')).")";
@ -751,5 +743,4 @@ class rcube_user
return $this->db->insert_id('searches'); return $this->db->insert_id('searches');
} }
} }

@ -26,22 +26,27 @@ if (!$RCMAIL->config->get('devel_mode')) {
} }
// @TODO: transaction here (if supported by DB) would be a good thing // @TODO: transaction here (if supported by DB) would be a good thing
$res = $RCMAIL->db->query("DELETE FROM cache"); $res = $RCMAIL->db->query("DELETE FROM " . $RCMAIL->db->table_name('cache', true));
if ($err = $RCMAIL->db->is_error($res)) { if ($err = $RCMAIL->db->is_error($res)) {
exit($err); exit($err);
} }
$res = $RCMAIL->db->query("DELETE FROM cache_messages"); $res = $RCMAIL->db->query("DELETE FROM " . $RCMAIL->db->table_name('cache_shared', true));
if ($err = $RCMAIL->db->is_error($res)) { if ($err = $RCMAIL->db->is_error($res)) {
exit($err); exit($err);
} }
$res = $RCMAIL->db->query("DELETE FROM cache_index"); $res = $RCMAIL->db->query("DELETE FROM " . $RCMAIL->db->table_name('cache_messages', true));
if ($err = $RCMAIL->db->is_error($res)) { if ($err = $RCMAIL->db->is_error($res)) {
exit($err); exit($err);
} }
$res = $RCMAIL->db->query("DELETE FROM cache_thread"); $res = $RCMAIL->db->query("DELETE FROM " . $RCMAIL->db->table_name('cache_index', true));
if ($err = $RCMAIL->db->is_error($res)) {
exit($err);
}
$res = $RCMAIL->db->query("DELETE FROM " . $RCMAIL->db->table_name('cache_thread', true));
if ($err = $RCMAIL->db->is_error($res)) { if ($err = $RCMAIL->db->is_error($res)) {
exit($err); exit($err);
} }

@ -13,7 +13,7 @@ class Framework_ImapCache extends PHPUnit_Framework_TestCase
*/ */
function test_class() function test_class()
{ {
$object = new rcube_imap_cache(null, null, null, null); $object = new rcube_imap_cache(new rcube_db('test'), null, null, null);
$this->assertInstanceOf('rcube_imap_cache', $object, "Class constructor"); $this->assertInstanceOf('rcube_imap_cache', $object, "Class constructor");
} }

Loading…
Cancel
Save