Completed
Push — master ( 3f331e...c65848 )
by Joas
123:00 queued 110:59
created
lib/private/DB/Connection.php 1 patch
Indentation   +377 added lines, -377 removed lines patch added patch discarded remove patch
@@ -41,381 +41,381 @@
 block discarded – undo
41 41
 use OCP\PreConditionNotMetException;
42 42
 
43 43
 class Connection extends \Doctrine\DBAL\Connection implements IDBConnection {
44
-	/**
45
-	 * @var string $tablePrefix
46
-	 */
47
-	protected $tablePrefix;
48
-
49
-	/**
50
-	 * @var \OC\DB\Adapter $adapter
51
-	 */
52
-	protected $adapter;
53
-
54
-	protected $lockedTable = null;
55
-
56
-	public function connect() {
57
-		try {
58
-			return parent::connect();
59
-		} catch (DBALException $e) {
60
-			// throw a new exception to prevent leaking info from the stacktrace
61
-			throw new DBALException('Failed to connect to the database: ' . $e->getMessage(), $e->getCode());
62
-		}
63
-	}
64
-
65
-	/**
66
-	 * Returns a QueryBuilder for the connection.
67
-	 *
68
-	 * @return \OCP\DB\QueryBuilder\IQueryBuilder
69
-	 */
70
-	public function getQueryBuilder() {
71
-		return new QueryBuilder(
72
-			$this,
73
-			\OC::$server->getSystemConfig(),
74
-			\OC::$server->getLogger()
75
-		);
76
-	}
77
-
78
-	/**
79
-	 * Gets the QueryBuilder for the connection.
80
-	 *
81
-	 * @return \Doctrine\DBAL\Query\QueryBuilder
82
-	 * @deprecated please use $this->getQueryBuilder() instead
83
-	 */
84
-	public function createQueryBuilder() {
85
-		$backtrace = $this->getCallerBacktrace();
86
-		\OC::$server->getLogger()->debug('Doctrine QueryBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
87
-		return parent::createQueryBuilder();
88
-	}
89
-
90
-	/**
91
-	 * Gets the ExpressionBuilder for the connection.
92
-	 *
93
-	 * @return \Doctrine\DBAL\Query\Expression\ExpressionBuilder
94
-	 * @deprecated please use $this->getQueryBuilder()->expr() instead
95
-	 */
96
-	public function getExpressionBuilder() {
97
-		$backtrace = $this->getCallerBacktrace();
98
-		\OC::$server->getLogger()->debug('Doctrine ExpressionBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
99
-		return parent::getExpressionBuilder();
100
-	}
101
-
102
-	/**
103
-	 * Get the file and line that called the method where `getCallerBacktrace()` was used
104
-	 *
105
-	 * @return string
106
-	 */
107
-	protected function getCallerBacktrace() {
108
-		$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
109
-
110
-		// 0 is the method where we use `getCallerBacktrace`
111
-		// 1 is the target method which uses the method we want to log
112
-		if (isset($traces[1])) {
113
-			return $traces[1]['file'] . ':' . $traces[1]['line'];
114
-		}
115
-
116
-		return '';
117
-	}
118
-
119
-	/**
120
-	 * @return string
121
-	 */
122
-	public function getPrefix() {
123
-		return $this->tablePrefix;
124
-	}
125
-
126
-	/**
127
-	 * Initializes a new instance of the Connection class.
128
-	 *
129
-	 * @param array $params  The connection parameters.
130
-	 * @param \Doctrine\DBAL\Driver $driver
131
-	 * @param \Doctrine\DBAL\Configuration $config
132
-	 * @param \Doctrine\Common\EventManager $eventManager
133
-	 * @throws \Exception
134
-	 */
135
-	public function __construct(array $params, Driver $driver, Configuration $config = null,
136
-		EventManager $eventManager = null)
137
-	{
138
-		if (!isset($params['adapter'])) {
139
-			throw new \Exception('adapter not set');
140
-		}
141
-		if (!isset($params['tablePrefix'])) {
142
-			throw new \Exception('tablePrefix not set');
143
-		}
144
-		parent::__construct($params, $driver, $config, $eventManager);
145
-		$this->adapter = new $params['adapter']($this);
146
-		$this->tablePrefix = $params['tablePrefix'];
147
-
148
-		parent::setTransactionIsolation(parent::TRANSACTION_READ_COMMITTED);
149
-	}
150
-
151
-	/**
152
-	 * Prepares an SQL statement.
153
-	 *
154
-	 * @param string $statement The SQL statement to prepare.
155
-	 * @param int $limit
156
-	 * @param int $offset
157
-	 * @return \Doctrine\DBAL\Driver\Statement The prepared statement.
158
-	 */
159
-	public function prepare( $statement, $limit=null, $offset=null ) {
160
-		if ($limit === -1) {
161
-			$limit = null;
162
-		}
163
-		if (!is_null($limit)) {
164
-			$platform = $this->getDatabasePlatform();
165
-			$statement = $platform->modifyLimitQuery($statement, $limit, $offset);
166
-		}
167
-		$statement = $this->replaceTablePrefix($statement);
168
-		$statement = $this->adapter->fixupStatement($statement);
169
-
170
-		if(\OC::$server->getSystemConfig()->getValue( 'log_query', false)) {
171
-			\OCP\Util::writeLog('core', 'DB prepare : '.$statement, \OCP\Util::DEBUG);
172
-		}
173
-		return parent::prepare($statement);
174
-	}
175
-
176
-	/**
177
-	 * Executes an, optionally parametrized, SQL query.
178
-	 *
179
-	 * If the query is parametrized, a prepared statement is used.
180
-	 * If an SQLLogger is configured, the execution is logged.
181
-	 *
182
-	 * @param string                                      $query  The SQL query to execute.
183
-	 * @param array                                       $params The parameters to bind to the query, if any.
184
-	 * @param array                                       $types  The types the previous parameters are in.
185
-	 * @param \Doctrine\DBAL\Cache\QueryCacheProfile|null $qcp    The query cache profile, optional.
186
-	 *
187
-	 * @return \Doctrine\DBAL\Driver\Statement The executed statement.
188
-	 *
189
-	 * @throws \Doctrine\DBAL\DBALException
190
-	 */
191
-	public function executeQuery($query, array $params = array(), $types = array(), QueryCacheProfile $qcp = null)
192
-	{
193
-		$query = $this->replaceTablePrefix($query);
194
-		$query = $this->adapter->fixupStatement($query);
195
-		return parent::executeQuery($query, $params, $types, $qcp);
196
-	}
197
-
198
-	/**
199
-	 * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
200
-	 * and returns the number of affected rows.
201
-	 *
202
-	 * This method supports PDO binding types as well as DBAL mapping types.
203
-	 *
204
-	 * @param string $query  The SQL query.
205
-	 * @param array  $params The query parameters.
206
-	 * @param array  $types  The parameter types.
207
-	 *
208
-	 * @return integer The number of affected rows.
209
-	 *
210
-	 * @throws \Doctrine\DBAL\DBALException
211
-	 */
212
-	public function executeUpdate($query, array $params = array(), array $types = array())
213
-	{
214
-		$query = $this->replaceTablePrefix($query);
215
-		$query = $this->adapter->fixupStatement($query);
216
-		return parent::executeUpdate($query, $params, $types);
217
-	}
218
-
219
-	/**
220
-	 * Returns the ID of the last inserted row, or the last value from a sequence object,
221
-	 * depending on the underlying driver.
222
-	 *
223
-	 * Note: This method may not return a meaningful or consistent result across different drivers,
224
-	 * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY
225
-	 * columns or sequences.
226
-	 *
227
-	 * @param string $seqName Name of the sequence object from which the ID should be returned.
228
-	 * @return string A string representation of the last inserted ID.
229
-	 */
230
-	public function lastInsertId($seqName = null) {
231
-		if ($seqName) {
232
-			$seqName = $this->replaceTablePrefix($seqName);
233
-		}
234
-		return $this->adapter->lastInsertId($seqName);
235
-	}
236
-
237
-	// internal use
238
-	public function realLastInsertId($seqName = null) {
239
-		return parent::lastInsertId($seqName);
240
-	}
241
-
242
-	/**
243
-	 * Insert a row if the matching row does not exists.
244
-	 *
245
-	 * @param string $table The table name (will replace *PREFIX* with the actual prefix)
246
-	 * @param array $input data that should be inserted into the table  (column name => value)
247
-	 * @param array|null $compare List of values that should be checked for "if not exists"
248
-	 *				If this is null or an empty array, all keys of $input will be compared
249
-	 *				Please note: text fields (clob) must not be used in the compare array
250
-	 * @return int number of inserted rows
251
-	 * @throws \Doctrine\DBAL\DBALException
252
-	 */
253
-	public function insertIfNotExist($table, $input, array $compare = null) {
254
-		return $this->adapter->insertIfNotExist($table, $input, $compare);
255
-	}
256
-
257
-	private function getType($value) {
258
-		if (is_bool($value)) {
259
-			return IQueryBuilder::PARAM_BOOL;
260
-		} else if (is_int($value)) {
261
-			return IQueryBuilder::PARAM_INT;
262
-		} else {
263
-			return IQueryBuilder::PARAM_STR;
264
-		}
265
-	}
266
-
267
-	/**
268
-	 * Insert or update a row value
269
-	 *
270
-	 * @param string $table
271
-	 * @param array $keys (column name => value)
272
-	 * @param array $values (column name => value)
273
-	 * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
274
-	 * @return int number of new rows
275
-	 * @throws \Doctrine\DBAL\DBALException
276
-	 * @throws PreConditionNotMetException
277
-	 */
278
-	public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
279
-		try {
280
-			$insertQb = $this->getQueryBuilder();
281
-			$insertQb->insert($table)
282
-				->values(
283
-					array_map(function($value) use ($insertQb) {
284
-						return $insertQb->createNamedParameter($value, $this->getType($value));
285
-					}, array_merge($keys, $values))
286
-				);
287
-			return $insertQb->execute();
288
-		} catch (ConstraintViolationException $e) {
289
-			// value already exists, try update
290
-			$updateQb = $this->getQueryBuilder();
291
-			$updateQb->update($table);
292
-			foreach ($values as $name => $value) {
293
-				$updateQb->set($name, $updateQb->createNamedParameter($value, $this->getType($value)));
294
-			}
295
-			$where = $updateQb->expr()->andX();
296
-			$whereValues = array_merge($keys, $updatePreconditionValues);
297
-			foreach ($whereValues as $name => $value) {
298
-				$where->add($updateQb->expr()->eq(
299
-					$name,
300
-					$updateQb->createNamedParameter($value, $this->getType($value)),
301
-					$this->getType($value)
302
-				));
303
-			}
304
-			$updateQb->where($where);
305
-			$affected = $updateQb->execute();
306
-
307
-			if ($affected === 0 && !empty($updatePreconditionValues)) {
308
-				throw new PreConditionNotMetException();
309
-			}
310
-
311
-			return 0;
312
-		}
313
-	}
314
-
315
-	/**
316
-	 * Create an exclusive read+write lock on a table
317
-	 *
318
-	 * @param string $tableName
319
-	 * @throws \BadMethodCallException When trying to acquire a second lock
320
-	 * @since 9.1.0
321
-	 */
322
-	public function lockTable($tableName) {
323
-		if ($this->lockedTable !== null) {
324
-			throw new \BadMethodCallException('Can not lock a new table until the previous lock is released.');
325
-		}
326
-
327
-		$tableName = $this->tablePrefix . $tableName;
328
-		$this->lockedTable = $tableName;
329
-		$this->adapter->lockTable($tableName);
330
-	}
331
-
332
-	/**
333
-	 * Release a previous acquired lock again
334
-	 *
335
-	 * @since 9.1.0
336
-	 */
337
-	public function unlockTable() {
338
-		$this->adapter->unlockTable();
339
-		$this->lockedTable = null;
340
-	}
341
-
342
-	/**
343
-	 * returns the error code and message as a string for logging
344
-	 * works with DoctrineException
345
-	 * @return string
346
-	 */
347
-	public function getError() {
348
-		$msg = $this->errorCode() . ': ';
349
-		$errorInfo = $this->errorInfo();
350
-		if (is_array($errorInfo)) {
351
-			$msg .= 'SQLSTATE = '.$errorInfo[0] . ', ';
352
-			$msg .= 'Driver Code = '.$errorInfo[1] . ', ';
353
-			$msg .= 'Driver Message = '.$errorInfo[2];
354
-		}
355
-		return $msg;
356
-	}
357
-
358
-	/**
359
-	 * Drop a table from the database if it exists
360
-	 *
361
-	 * @param string $table table name without the prefix
362
-	 */
363
-	public function dropTable($table) {
364
-		$table = $this->tablePrefix . trim($table);
365
-		$schema = $this->getSchemaManager();
366
-		if($schema->tablesExist(array($table))) {
367
-			$schema->dropTable($table);
368
-		}
369
-	}
370
-
371
-	/**
372
-	 * Check if a table exists
373
-	 *
374
-	 * @param string $table table name without the prefix
375
-	 * @return bool
376
-	 */
377
-	public function tableExists($table){
378
-		$table = $this->tablePrefix . trim($table);
379
-		$schema = $this->getSchemaManager();
380
-		return $schema->tablesExist(array($table));
381
-	}
382
-
383
-	// internal use
384
-	/**
385
-	 * @param string $statement
386
-	 * @return string
387
-	 */
388
-	protected function replaceTablePrefix($statement) {
389
-		return str_replace( '*PREFIX*', $this->tablePrefix, $statement );
390
-	}
391
-
392
-	/**
393
-	 * Check if a transaction is active
394
-	 *
395
-	 * @return bool
396
-	 * @since 8.2.0
397
-	 */
398
-	public function inTransaction() {
399
-		return $this->getTransactionNestingLevel() > 0;
400
-	}
401
-
402
-	/**
403
-	 * Espace a parameter to be used in a LIKE query
404
-	 *
405
-	 * @param string $param
406
-	 * @return string
407
-	 */
408
-	public function escapeLikeParameter($param) {
409
-		return addcslashes($param, '\\_%');
410
-	}
411
-
412
-	/**
413
-	 * Check whether or not the current database support 4byte wide unicode
414
-	 *
415
-	 * @return bool
416
-	 * @since 11.0.0
417
-	 */
418
-	public function supports4ByteText() {
419
-		return ! ($this->getDatabasePlatform() instanceof MySqlPlatform && $this->getParams()['charset'] !== 'utf8mb4');
420
-	}
44
+    /**
45
+     * @var string $tablePrefix
46
+     */
47
+    protected $tablePrefix;
48
+
49
+    /**
50
+     * @var \OC\DB\Adapter $adapter
51
+     */
52
+    protected $adapter;
53
+
54
+    protected $lockedTable = null;
55
+
56
+    public function connect() {
57
+        try {
58
+            return parent::connect();
59
+        } catch (DBALException $e) {
60
+            // throw a new exception to prevent leaking info from the stacktrace
61
+            throw new DBALException('Failed to connect to the database: ' . $e->getMessage(), $e->getCode());
62
+        }
63
+    }
64
+
65
+    /**
66
+     * Returns a QueryBuilder for the connection.
67
+     *
68
+     * @return \OCP\DB\QueryBuilder\IQueryBuilder
69
+     */
70
+    public function getQueryBuilder() {
71
+        return new QueryBuilder(
72
+            $this,
73
+            \OC::$server->getSystemConfig(),
74
+            \OC::$server->getLogger()
75
+        );
76
+    }
77
+
78
+    /**
79
+     * Gets the QueryBuilder for the connection.
80
+     *
81
+     * @return \Doctrine\DBAL\Query\QueryBuilder
82
+     * @deprecated please use $this->getQueryBuilder() instead
83
+     */
84
+    public function createQueryBuilder() {
85
+        $backtrace = $this->getCallerBacktrace();
86
+        \OC::$server->getLogger()->debug('Doctrine QueryBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
87
+        return parent::createQueryBuilder();
88
+    }
89
+
90
+    /**
91
+     * Gets the ExpressionBuilder for the connection.
92
+     *
93
+     * @return \Doctrine\DBAL\Query\Expression\ExpressionBuilder
94
+     * @deprecated please use $this->getQueryBuilder()->expr() instead
95
+     */
96
+    public function getExpressionBuilder() {
97
+        $backtrace = $this->getCallerBacktrace();
98
+        \OC::$server->getLogger()->debug('Doctrine ExpressionBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
99
+        return parent::getExpressionBuilder();
100
+    }
101
+
102
+    /**
103
+     * Get the file and line that called the method where `getCallerBacktrace()` was used
104
+     *
105
+     * @return string
106
+     */
107
+    protected function getCallerBacktrace() {
108
+        $traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
109
+
110
+        // 0 is the method where we use `getCallerBacktrace`
111
+        // 1 is the target method which uses the method we want to log
112
+        if (isset($traces[1])) {
113
+            return $traces[1]['file'] . ':' . $traces[1]['line'];
114
+        }
115
+
116
+        return '';
117
+    }
118
+
119
+    /**
120
+     * @return string
121
+     */
122
+    public function getPrefix() {
123
+        return $this->tablePrefix;
124
+    }
125
+
126
+    /**
127
+     * Initializes a new instance of the Connection class.
128
+     *
129
+     * @param array $params  The connection parameters.
130
+     * @param \Doctrine\DBAL\Driver $driver
131
+     * @param \Doctrine\DBAL\Configuration $config
132
+     * @param \Doctrine\Common\EventManager $eventManager
133
+     * @throws \Exception
134
+     */
135
+    public function __construct(array $params, Driver $driver, Configuration $config = null,
136
+        EventManager $eventManager = null)
137
+    {
138
+        if (!isset($params['adapter'])) {
139
+            throw new \Exception('adapter not set');
140
+        }
141
+        if (!isset($params['tablePrefix'])) {
142
+            throw new \Exception('tablePrefix not set');
143
+        }
144
+        parent::__construct($params, $driver, $config, $eventManager);
145
+        $this->adapter = new $params['adapter']($this);
146
+        $this->tablePrefix = $params['tablePrefix'];
147
+
148
+        parent::setTransactionIsolation(parent::TRANSACTION_READ_COMMITTED);
149
+    }
150
+
151
+    /**
152
+     * Prepares an SQL statement.
153
+     *
154
+     * @param string $statement The SQL statement to prepare.
155
+     * @param int $limit
156
+     * @param int $offset
157
+     * @return \Doctrine\DBAL\Driver\Statement The prepared statement.
158
+     */
159
+    public function prepare( $statement, $limit=null, $offset=null ) {
160
+        if ($limit === -1) {
161
+            $limit = null;
162
+        }
163
+        if (!is_null($limit)) {
164
+            $platform = $this->getDatabasePlatform();
165
+            $statement = $platform->modifyLimitQuery($statement, $limit, $offset);
166
+        }
167
+        $statement = $this->replaceTablePrefix($statement);
168
+        $statement = $this->adapter->fixupStatement($statement);
169
+
170
+        if(\OC::$server->getSystemConfig()->getValue( 'log_query', false)) {
171
+            \OCP\Util::writeLog('core', 'DB prepare : '.$statement, \OCP\Util::DEBUG);
172
+        }
173
+        return parent::prepare($statement);
174
+    }
175
+
176
+    /**
177
+     * Executes an, optionally parametrized, SQL query.
178
+     *
179
+     * If the query is parametrized, a prepared statement is used.
180
+     * If an SQLLogger is configured, the execution is logged.
181
+     *
182
+     * @param string                                      $query  The SQL query to execute.
183
+     * @param array                                       $params The parameters to bind to the query, if any.
184
+     * @param array                                       $types  The types the previous parameters are in.
185
+     * @param \Doctrine\DBAL\Cache\QueryCacheProfile|null $qcp    The query cache profile, optional.
186
+     *
187
+     * @return \Doctrine\DBAL\Driver\Statement The executed statement.
188
+     *
189
+     * @throws \Doctrine\DBAL\DBALException
190
+     */
191
+    public function executeQuery($query, array $params = array(), $types = array(), QueryCacheProfile $qcp = null)
192
+    {
193
+        $query = $this->replaceTablePrefix($query);
194
+        $query = $this->adapter->fixupStatement($query);
195
+        return parent::executeQuery($query, $params, $types, $qcp);
196
+    }
197
+
198
+    /**
199
+     * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
200
+     * and returns the number of affected rows.
201
+     *
202
+     * This method supports PDO binding types as well as DBAL mapping types.
203
+     *
204
+     * @param string $query  The SQL query.
205
+     * @param array  $params The query parameters.
206
+     * @param array  $types  The parameter types.
207
+     *
208
+     * @return integer The number of affected rows.
209
+     *
210
+     * @throws \Doctrine\DBAL\DBALException
211
+     */
212
+    public function executeUpdate($query, array $params = array(), array $types = array())
213
+    {
214
+        $query = $this->replaceTablePrefix($query);
215
+        $query = $this->adapter->fixupStatement($query);
216
+        return parent::executeUpdate($query, $params, $types);
217
+    }
218
+
219
+    /**
220
+     * Returns the ID of the last inserted row, or the last value from a sequence object,
221
+     * depending on the underlying driver.
222
+     *
223
+     * Note: This method may not return a meaningful or consistent result across different drivers,
224
+     * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY
225
+     * columns or sequences.
226
+     *
227
+     * @param string $seqName Name of the sequence object from which the ID should be returned.
228
+     * @return string A string representation of the last inserted ID.
229
+     */
230
+    public function lastInsertId($seqName = null) {
231
+        if ($seqName) {
232
+            $seqName = $this->replaceTablePrefix($seqName);
233
+        }
234
+        return $this->adapter->lastInsertId($seqName);
235
+    }
236
+
237
+    // internal use
238
+    public function realLastInsertId($seqName = null) {
239
+        return parent::lastInsertId($seqName);
240
+    }
241
+
242
+    /**
243
+     * Insert a row if the matching row does not exists.
244
+     *
245
+     * @param string $table The table name (will replace *PREFIX* with the actual prefix)
246
+     * @param array $input data that should be inserted into the table  (column name => value)
247
+     * @param array|null $compare List of values that should be checked for "if not exists"
248
+     *				If this is null or an empty array, all keys of $input will be compared
249
+     *				Please note: text fields (clob) must not be used in the compare array
250
+     * @return int number of inserted rows
251
+     * @throws \Doctrine\DBAL\DBALException
252
+     */
253
+    public function insertIfNotExist($table, $input, array $compare = null) {
254
+        return $this->adapter->insertIfNotExist($table, $input, $compare);
255
+    }
256
+
257
+    private function getType($value) {
258
+        if (is_bool($value)) {
259
+            return IQueryBuilder::PARAM_BOOL;
260
+        } else if (is_int($value)) {
261
+            return IQueryBuilder::PARAM_INT;
262
+        } else {
263
+            return IQueryBuilder::PARAM_STR;
264
+        }
265
+    }
266
+
267
+    /**
268
+     * Insert or update a row value
269
+     *
270
+     * @param string $table
271
+     * @param array $keys (column name => value)
272
+     * @param array $values (column name => value)
273
+     * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
274
+     * @return int number of new rows
275
+     * @throws \Doctrine\DBAL\DBALException
276
+     * @throws PreConditionNotMetException
277
+     */
278
+    public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
279
+        try {
280
+            $insertQb = $this->getQueryBuilder();
281
+            $insertQb->insert($table)
282
+                ->values(
283
+                    array_map(function($value) use ($insertQb) {
284
+                        return $insertQb->createNamedParameter($value, $this->getType($value));
285
+                    }, array_merge($keys, $values))
286
+                );
287
+            return $insertQb->execute();
288
+        } catch (ConstraintViolationException $e) {
289
+            // value already exists, try update
290
+            $updateQb = $this->getQueryBuilder();
291
+            $updateQb->update($table);
292
+            foreach ($values as $name => $value) {
293
+                $updateQb->set($name, $updateQb->createNamedParameter($value, $this->getType($value)));
294
+            }
295
+            $where = $updateQb->expr()->andX();
296
+            $whereValues = array_merge($keys, $updatePreconditionValues);
297
+            foreach ($whereValues as $name => $value) {
298
+                $where->add($updateQb->expr()->eq(
299
+                    $name,
300
+                    $updateQb->createNamedParameter($value, $this->getType($value)),
301
+                    $this->getType($value)
302
+                ));
303
+            }
304
+            $updateQb->where($where);
305
+            $affected = $updateQb->execute();
306
+
307
+            if ($affected === 0 && !empty($updatePreconditionValues)) {
308
+                throw new PreConditionNotMetException();
309
+            }
310
+
311
+            return 0;
312
+        }
313
+    }
314
+
315
+    /**
316
+     * Create an exclusive read+write lock on a table
317
+     *
318
+     * @param string $tableName
319
+     * @throws \BadMethodCallException When trying to acquire a second lock
320
+     * @since 9.1.0
321
+     */
322
+    public function lockTable($tableName) {
323
+        if ($this->lockedTable !== null) {
324
+            throw new \BadMethodCallException('Can not lock a new table until the previous lock is released.');
325
+        }
326
+
327
+        $tableName = $this->tablePrefix . $tableName;
328
+        $this->lockedTable = $tableName;
329
+        $this->adapter->lockTable($tableName);
330
+    }
331
+
332
+    /**
333
+     * Release a previous acquired lock again
334
+     *
335
+     * @since 9.1.0
336
+     */
337
+    public function unlockTable() {
338
+        $this->adapter->unlockTable();
339
+        $this->lockedTable = null;
340
+    }
341
+
342
+    /**
343
+     * returns the error code and message as a string for logging
344
+     * works with DoctrineException
345
+     * @return string
346
+     */
347
+    public function getError() {
348
+        $msg = $this->errorCode() . ': ';
349
+        $errorInfo = $this->errorInfo();
350
+        if (is_array($errorInfo)) {
351
+            $msg .= 'SQLSTATE = '.$errorInfo[0] . ', ';
352
+            $msg .= 'Driver Code = '.$errorInfo[1] . ', ';
353
+            $msg .= 'Driver Message = '.$errorInfo[2];
354
+        }
355
+        return $msg;
356
+    }
357
+
358
+    /**
359
+     * Drop a table from the database if it exists
360
+     *
361
+     * @param string $table table name without the prefix
362
+     */
363
+    public function dropTable($table) {
364
+        $table = $this->tablePrefix . trim($table);
365
+        $schema = $this->getSchemaManager();
366
+        if($schema->tablesExist(array($table))) {
367
+            $schema->dropTable($table);
368
+        }
369
+    }
370
+
371
+    /**
372
+     * Check if a table exists
373
+     *
374
+     * @param string $table table name without the prefix
375
+     * @return bool
376
+     */
377
+    public function tableExists($table){
378
+        $table = $this->tablePrefix . trim($table);
379
+        $schema = $this->getSchemaManager();
380
+        return $schema->tablesExist(array($table));
381
+    }
382
+
383
+    // internal use
384
+    /**
385
+     * @param string $statement
386
+     * @return string
387
+     */
388
+    protected function replaceTablePrefix($statement) {
389
+        return str_replace( '*PREFIX*', $this->tablePrefix, $statement );
390
+    }
391
+
392
+    /**
393
+     * Check if a transaction is active
394
+     *
395
+     * @return bool
396
+     * @since 8.2.0
397
+     */
398
+    public function inTransaction() {
399
+        return $this->getTransactionNestingLevel() > 0;
400
+    }
401
+
402
+    /**
403
+     * Espace a parameter to be used in a LIKE query
404
+     *
405
+     * @param string $param
406
+     * @return string
407
+     */
408
+    public function escapeLikeParameter($param) {
409
+        return addcslashes($param, '\\_%');
410
+    }
411
+
412
+    /**
413
+     * Check whether or not the current database support 4byte wide unicode
414
+     *
415
+     * @return bool
416
+     * @since 11.0.0
417
+     */
418
+    public function supports4ByteText() {
419
+        return ! ($this->getDatabasePlatform() instanceof MySqlPlatform && $this->getParams()['charset'] !== 'utf8mb4');
420
+    }
421 421
 }
Please login to merge, or discard this patch.