* @copyright Copyright (c) 2014, Matthias Mullie. All rights reserved * @license LICENSE MIT */ class PostgreSQL extends SQL { /** * @var bool */ protected $conflictSupport = true; /** * {@inheritdoc} */ public function flush() { return false !== $this->client->exec("TRUNCATE TABLE $this->table"); } /** * {@inheritdoc} */ public function set($key, $value, $expire = 0) { if (!$this->conflictSupport) { return parent::set($key, $value, $expire); } $this->clearExpired(); $serialized = $this->serialize($value); $expiration = $this->expire($expire); $statement = $this->client->prepare( "INSERT INTO $this->table (k, v, e) VALUES (:key, :value, :expire) ON CONFLICT (k) DO UPDATE SET v=EXCLUDED.v, e=EXCLUDED.e" ); $statement->bindParam(':key', $key); $statement->bindParam(':value', $serialized, \PDO::PARAM_LOB, strlen($serialized)); $statement->bindParam(':expire', $expiration); $statement->execute(); // ON CONFLICT is not supported in versions < 9.5, in which case we'll // have to fall back on add/replace if ('42601' === $statement->errorCode()) { $this->conflictSupport = false; return $this->set($key, $value, $expire); } return 1 === $statement->rowCount(); } /** * {@inheritdoc} */ public function get($key, &$token = null) { $return = parent::get($key, $token); if (null !== $token) { // BYTEA data return streams - we actually need the data in // serialized format, not some silly stream $token = $this->serialize($return); } return $return; } /** * {@inheritdoc} */ public function getMulti(array $keys, array &$tokens = null) { $return = parent::getMulti($keys, $tokens); foreach ($return as $key => $value) { // BYTEA data return streams - we actually need the data in // serialized format, not some silly stream $tokens[$key] = $this->serialize($value); } return $return; } /** * {@inheritdoc} */ protected function init() { $this->client->exec( "CREATE TABLE IF NOT EXISTS $this->table ( k VARCHAR NOT NULL PRIMARY KEY, v BYTEA, e TIMESTAMP NULL DEFAULT NULL )" ); $this->client->exec("CREATE INDEX IF NOT EXISTS e_index ON $this->table (e)"); } /** * {@inheritdoc} */ protected function unserialize($value) { // BYTEA data return streams. Even though it's not how init() will // configure the DB by default, it could be used instead! if (is_resource($value)) { $value = stream_get_contents($value); } return parent::unserialize($value); } }