Skip to content

Commit

Permalink
Accept stream resources as the value of Horde_Db_Value objects.
Browse files Browse the repository at this point in the history
For drivers that can support it, will bind the stream resource as
the data. Currently only implemented in PDO adapter.
  • Loading branch information
mrubinsk committed Feb 2, 2017
1 parent 37c419a commit e55ed28
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 2 deletions.
145 changes: 145 additions & 0 deletions framework/Db/lib/Horde/Db/Adapter/Pdo/Base.php
Expand Up @@ -241,6 +241,151 @@ public function execute($sql, $arg1 = null, $arg2 = null)
return $stmt;
}

/**
* Use a PDO prepared statement to execute a query. Used when passing
* values to insert/update as a stream resource.
*
* @param string $sql The SQL statement. Includes '?' placeholder
* for binding non-stream values. Stream values are bound using a
* placeholders named like ':binary0', ':binary1' etc...
*
* @param array $values An array of non-stream values.
* @param array $binary_values An array of stream resources.
*
* @throws Horde_Db_Exception
*/
protected function _executePrepared($sql, $values, $binary_values)
{
$query = $this->_replaceParameters($sql, $values);
try {
$stmt = $this->_connection->prepare($query);
foreach ($binary_values as $key => $bvalue) {
$stmt->bindParam(':binary' . $key, $bvalue, PDO::PARAM_LOB);
}
} catch (PDOException $e) {
$this->_logInfo($sql, null);
$this->_logError($sql, 'QUERY FAILED: ' . $e->getMessage());
throw new Horde_Db_Exception($e);
}

$t = new Horde_Support_Timer;
$t->push();

try {
$this->_lastQuery = $sql;
$stmt->execute();
} catch (PDOException $e) {
$this->_logInfo($sql, null);
$this->_logError($sql, 'QUERY FAILED: ' . $e->getMessage());
throw new Horde_Db_Exception($e);
}

$t = new Horde_Support_Timer;
$t->push();

$this->_logInfo($sql, null, $t->pop());
$this->_rowCount = $stmt->rowCount();
}

/**
* Inserts a row including BLOBs into a table.
*
* @since Horde_Db 2.4.0
*
* @param string $table The table name.
* @param array $fields A hash of column names and values. BLOB columns
* must be provided as Horde_Db_Value_Binary
* objects.
* @param string $pk The primary key column.
* @param integer $idValue The primary key value. This parameter is
* required if the primary key is inserted
* manually.
*
* @return integer Last inserted ID.
* @throws Horde_Db_Exception
*/
public function insertBlob($table, $fields, $pk = null, $idValue = null)
{
$placeholders = $values = $binary = array();
$binary_cnt = 0;
foreach ($fields as $name => $value) {
if ($value instanceof Horde_Db_Value && is_resource($value->value)) {
$placeholders[] = ':binary' . $binary_cnt++;
$binary[] = $value->value;
} else {
$placeholders[] = '?';
$values[] = $value;
}
}

$query = sprintf(
'INSERT INTO %s (%s) VALUES (%s)',
$this->quoteTableName($table),
implode(', ', array_map(array($this, 'quoteColumnName'), array_keys($fields))),
implode(', ', $placeholders)
);

if ($binary_cnt > 0) {
$this->_executePrepared($query, $values, $binary);

return $idValue
? $idValue
: $this->_connection->lastInsertId(null);
}

return $this->insert($query, $fields, null, $pk, $idValue);
}

/**
* Updates rows including BLOBs into a table.
*
* @since Horde_Db 2.2.0
*
* @param string $table The table name.
* @param array $fields A hash of column names and values. BLOB
* columns must be provided as
* Horde_Db_Value_Binary objects.
* @param string|array $where A WHERE clause. Either a complete clause or
* an array containing a clause with
* placeholders and a list of values.
*
* @throws Horde_Db_Exception
*/
public function updateBlob($table, $fields, $where = null)
{
if (is_array($where)) {
$where = $this->_replaceParameters($where[0], $where[1]);
}

$values = $binary_values = $fnames = array();
$binary_cnt = 0;

foreach ($fields as $field => $value) {
if ($value instanceof Horde_Db_Value && is_resource($value->value)) {
$fnames[] = $this->quoteColumnName($field) . ' = :binary' . $binary_cnt++;
$binary_values[] = $value->value;
} else {
$fnames[] = $this->quoteColumnName($field) . ' = ?';
$values[] = $value;
}
}

$query = sprintf(
'UPDATE %s SET %s%s',
$this->quoteTableName($table),
implode(', ', $fnames),
strlen($where) ? ' WHERE ' . $where : ''
);

if ($binary_cnt > 0) {
$this->_executePrepared($query, $values, $binary_values);
return $this->_rowCount;
}

return $this->update($query, $fields);
}


/**
* Inserts a row into a table.
*
Expand Down
8 changes: 7 additions & 1 deletion framework/Db/lib/Horde/Db/Value/Binary.php
Expand Up @@ -30,7 +30,8 @@ class Horde_Db_Value_Binary implements Horde_Db_Value
/**
* Constructor
*
* @param string $binaryValue
* @param string|stream resource $binaryValue The binary value in either
* a string or a stream resource.
*/
public function __construct($binaryValue)
{
Expand All @@ -42,6 +43,11 @@ public function __construct($binaryValue)
*/
public function quote(Horde_Db_Adapter $db)
{
if (is_resource($this->value)) {
rewind($this->value);
return $db->quoteBinary(stream_get_contents($this->value));
}

return $db->quoteBinary($this->value);
}
}
7 changes: 6 additions & 1 deletion framework/Db/lib/Horde/Db/Value/Text.php
Expand Up @@ -30,7 +30,8 @@ class Horde_Db_Value_Text implements Horde_Db_Value
/**
* Constructor
*
* @param string $textValue
* @param string|stream $textValue The text value in a string or stream
* resource.
*/
public function __construct($textValue)
{
Expand All @@ -42,6 +43,10 @@ public function __construct($textValue)
*/
public function quote(Horde_Db_Adapter $db)
{
if (is_resource($this->value)) {
rewind($this->value);
return $db->quoteString(stream_get_contents($this->value));
}
return $db->quoteString($this->value);
}
}
55 changes: 55 additions & 0 deletions framework/Db/test/Horde/Db/Adapter/TestBase.php
Expand Up @@ -228,8 +228,39 @@ public function testInsertBlob()
8
);
$this->assertEquals(8, $result);

$stream = fopen('php://temp', 'r+');
fwrite($stream, str_repeat('X', 5000));
rewind($stream);
$result = $this->_conn->insertBlob(
'unit_tests',
array(
'id' => 9,
'integer_value' => 1001,
'text_value' => new Horde_Db_Value_Text($stream)
),
null,
9
);
$this->assertEquals(9, $result);

$stream = fopen('php://temp', 'r+');
fwrite($stream, str_repeat("\0", 5000));
rewind($stream);
$result = $this->_conn->insertBlob(
'unit_tests',
array(
'id' => 10,
'integer_value' => 1002,
'blob_value' => new Horde_Db_Value_Binary($stream)
),
null,
10
);
$this->assertEquals(10, $result);
}


public function testUpdate()
{
$this->_createTable();
Expand Down Expand Up @@ -261,6 +292,30 @@ public function testUpdateBlob()
'id = 1'
);
$this->assertEquals(1, $result);

$stream = fopen('php://temp', 'r+');
fwrite($stream, str_repeat('X', 5001));
rewind($stream);
$result = $this->_conn->updateBlob(
'unit_tests',
array(
'text_value' => new Horde_Db_Value_Text($stream)
),
'id = 1'
);
$this->assertEquals(1, $result);

$stream = fopen('php://temp', 'r+');
fwrite($stream, str_repeat("\0", 5001));
rewind($stream);
$result = $this->_conn->updateBlob(
'unit_tests',
array(
'blob_value' => new Horde_Db_Value_Binary($stream)
),
'id = 1'
);
$this->assertEquals(1, $result);
}

public function testDelete()
Expand Down

0 comments on commit e55ed28

Please sign in to comment.