Shift data around between different data stores.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.1 KiB

<?php
namespace DbCopy\Driver;
class Postgres implements IDriver
{
private $_options;
private $_pdo;
private $_insert_statement, $_insert_statement_size, $_insert_statement_fields;
public function open(array $params): void
{
$params = array_merge([
'dsn' => null,
'username' => null,
'password' => null,
'query' => null,
'table' => null
], $params);
$this->_options = $params;
$this->_pdo = new \PDO($params['dsn'], $params['username'], $params['password']);
$this->_pdo->query('SET AUTOCOMMIT');
}
public function close(): void
{
$this->_pdo = null;
}
public function get(array $params = []): \DbCopy\ICursor
{
$options = array_merge($this->_options, $params);
$statement = $this->_pdo->prepare($params['query']);
$statement->execute();
return new \DbCopy\Cursor(function() use ($options, $statement) {
$record = $statement->fetch(\PDO::FETCH_ASSOC);
if (!$record) return [];
return [$record];
});
}
public function put(array $record, array $params = []): void
{
$params = array_merge($this->_options, $params);
$sql = 'insert into "'.$params['table'].'"(';
$fields = array_keys($record);
$sql .= '"'.implode('", "', $fields).'"';
$sql .= ') VALUES ('.implode(', ', str_split(str_repeat('?', sizeof($fields)))).')';
$statement = $this->_pdo->prepare($sql);
$result = $statement->execute(array_values($record));
if ($result === false)
{
var_dump($record);
throw new \Exception("Error inserting record into Postgres: ".print_r($statement->errorInfo(), true));
}
}
public function putBatch(array $records, array $params = []): void
{
$params = array_merge($this->_options, $params);
// Find all possible fields in all records while sorting their keys
// so they're all consistent
$fields = [];
foreach ($records as &$record)
{
$fields = array_merge($fields, array_keys($record));
}
unset($record);
// Make unique
$fields = array_unique($fields);
// Sort so this is kinda stable
sort($fields);
// Generate prepared statement if one doesn't exist or it doesn't match
// the current batch
if (!isset($this->_insert_statement) ||
sizeof($records) != $this->_insert_statement_size ||
$fields !== $this->_insert_statement_fields)
{
echo 'new statement'.PHP_EOL;
$sql = 'insert into "'.$params['table'].'"(';
$sql .= '"'.implode('", "', $fields).'"';
$sql .= ') VALUES ';
$sql .= substr(str_repeat('('.implode(', ', str_split(str_repeat('?', sizeof($fields)))).'), ', sizeof($records)), 0, -2);
$this->_insert_statement = $this->_pdo->prepare($sql);
$this->_insert_statement_size = sizeof($records);
$this->_insert_statement_fields = $fields;
}
// Generate values from records
$values = [];
foreach ($records as $record)
{
foreach ($fields as $field)
{
if (isset($record[$field]))
$values[] = $record[$field];
else
$values[] = null;
}
}
// Execute statement
$result = $this->_insert_statement->execute($values);
if ($result === false)
{
throw new \Exception("Error inserting record into Postgres: ".print_r($this->_insert_statement->errorInfo(), true));
}
}
}