Real implementation is in DB\Adapter* classestags/v6.0.0alpha2
@@ -389,58 +389,7 @@ class OC_DB { | |||
*/ | |||
public static function insertIfNotExist($table, $input) { | |||
self::connect(); | |||
$table = self::$connection->replaceTablePrefix( $table ); | |||
if(is_null(self::$type)) { | |||
self::$type=OC_Config::getValue( "dbtype", "sqlite" ); | |||
} | |||
$type = self::$type; | |||
$query = ''; | |||
$inserts = array_values($input); | |||
// differences in escaping of table names ('`' for mysql) and getting the current timestamp | |||
if( $type == 'sqlite' || $type == 'sqlite3' ) { | |||
// NOTE: For SQLite we have to use this clumsy approach | |||
// otherwise all fieldnames used must have a unique key. | |||
$query = 'SELECT * FROM `' . $table . '` WHERE '; | |||
foreach($input as $key => $value) { | |||
$query .= '`' . $key . '` = ? AND '; | |||
} | |||
$query = substr($query, 0, strlen($query) - 5); | |||
try { | |||
$result = self::executeAudited($query, $inserts); | |||
} catch(DatabaseException $e) { | |||
OC_Template::printExceptionErrorPage( $e ); | |||
} | |||
if((int)$result->numRows() === 0) { | |||
$query = 'INSERT INTO `' . $table . '` (`' | |||
. implode('`,`', array_keys($input)) . '`) VALUES(' | |||
. str_repeat('?,', count($input)-1).'? ' . ')'; | |||
} else { | |||
return 0; //no rows updated | |||
} | |||
} elseif( $type == 'pgsql' || $type == 'oci' || $type == 'mysql' || $type == 'mssql') { | |||
$query = 'INSERT INTO `' .$table . '` (`' | |||
. implode('`,`', array_keys($input)) . '`) SELECT ' | |||
. str_repeat('?,', count($input)-1).'? ' // Is there a prettier alternative? | |||
. 'FROM `' . $table . '` WHERE '; | |||
foreach($input as $key => $value) { | |||
$query .= '`' . $key . '` = ? AND '; | |||
} | |||
$query = substr($query, 0, strlen($query) - 5); | |||
$query .= ' HAVING COUNT(*) = 0'; | |||
$inserts = array_merge($inserts, $inserts); | |||
} | |||
try { | |||
$result = self::executeAudited($query, $inserts); | |||
} catch(\Doctrine\DBAL\DBALException $e) { | |||
OC_Template::printExceptionErrorPage( $e ); | |||
} | |||
return $result; | |||
return self::$connection->insertIfNotExist($table, $input); | |||
} | |||
/** |
@@ -22,4 +22,32 @@ class Adapter { | |||
public function fixupStatement($statement) { | |||
return $statement; | |||
} | |||
public function insertIfNotExist($table, $input) { | |||
$query = 'INSERT INTO `' .$table . '` (`' | |||
. implode('`,`', array_keys($input)) . '`) SELECT ' | |||
. str_repeat('?,', count($input)-1).'? ' // Is there a prettier alternative? | |||
. 'FROM `' . $table . '` WHERE '; | |||
foreach($input as $key => $value) { | |||
$query .= '`' . $key . '` = ? AND '; | |||
} | |||
$query = substr($query, 0, strlen($query) - 5); | |||
$query .= ' HAVING COUNT(*) = 0'; | |||
$inserts = array_values($input); | |||
$inserts = array_merge($inserts, $inserts); | |||
try { | |||
$statement = $this->conn->prepare($query); | |||
$result = $statement->execute($inserts); | |||
} catch(\Doctrine\DBAL\DBALException $e) { | |||
$entry = 'DB Error: "'.$e->getMessage() . '"<br />'; | |||
$entry .= 'Offending command was: ' . $query.'<br />'; | |||
OC_Log::write('core', $entry, OC_Log::FATAL); | |||
error_log('DB error: ' . $entry); | |||
OC_Template::printErrorPage( $entry ); | |||
} | |||
return $result; | |||
} | |||
} |
@@ -16,4 +16,45 @@ class AdapterSqlite extends Adapter { | |||
$statement = str_ireplace( 'UNIX_TIMESTAMP()', 'strftime(\'%s\',\'now\')', $statement ); | |||
return $statement; | |||
} | |||
public function insertIfNotExist($table, $input) { | |||
// NOTE: For SQLite we have to use this clumsy approach | |||
// otherwise all fieldnames used must have a unique key. | |||
$query = 'SELECT COUNT(*) FROM `' . $table . '` WHERE '; | |||
foreach($input as $key => $value) { | |||
$query .= '`' . $key . '` = ? AND '; | |||
} | |||
$query = substr($query, 0, strlen($query) - 5); | |||
try { | |||
$stmt = $this->conn->prepare($query); | |||
$result = $stmt->execute(array($input)); | |||
} catch(\Doctrine\DBAL\DBALException $e) { | |||
$entry = 'DB Error: "'.$e->getMessage() . '"<br />'; | |||
$entry .= 'Offending command was: ' . $query . '<br />'; | |||
OC_Log::write('core', $entry, OC_Log::FATAL); | |||
error_log('DB error: '.$entry); | |||
OC_Template::printErrorPage( $entry ); | |||
} | |||
if ($stmt->fetchColumn() === 0) { | |||
$query = 'INSERT INTO `' . $table . '` (`' | |||
. implode('`,`', array_keys($input)) . '`) VALUES(' | |||
. str_repeat('?,', count($input)-1).'? ' . ')'; | |||
} else { | |||
return 0; //no rows updated | |||
} | |||
try { | |||
$statement = $this->conn->prepare($query); | |||
$result = $statement->execute(array_values($input)); | |||
} catch(\Doctrine\DBAL\DBALException $e) { | |||
$entry = 'DB Error: "'.$e->getMessage() . '"<br />'; | |||
$entry .= 'Offending command was: ' . $query.'<br />'; | |||
OC_Log::write('core', $entry, OC_Log::FATAL); | |||
error_log('DB error: ' . $entry); | |||
OC_Template::printErrorPage( $entry ); | |||
} | |||
return $result; | |||
} | |||
} |
@@ -138,8 +138,18 @@ class Connection extends \Doctrine\DBAL\Connection { | |||
return parent::lastInsertId($seqName); | |||
} | |||
/** | |||
* @brief Insert a row if a matching row doesn't exists. | |||
* @param string $table. The table to insert into in the form '*PREFIX*tableName' | |||
* @param array $input. An array of fieldname/value pairs | |||
* @returns bool The return value from execute() | |||
*/ | |||
public function insertIfNotExist($table, $input) { | |||
return $this->adapter->insertIfNotExist($table, $input); | |||
} | |||
// internal use | |||
public function replaceTablePrefix($statement) { | |||
protected function replaceTablePrefix($statement) { | |||
return str_replace( '*PREFIX*', $this->table_prefix, $statement ); | |||
} | |||