Passed
Push — master ( 8f4c95...39bee7 )
by Joas
15:38 queued 10s
created
lib/private/DB/QueryBuilder/QueryBuilder.php 2 patches
Indentation   +1205 added lines, -1205 removed lines patch added patch discarded remove patch
@@ -52,1209 +52,1209 @@
 block discarded – undo
52 52
 
53 53
 class QueryBuilder implements IQueryBuilder {
54 54
 
55
-	/** @var \OCP\IDBConnection */
56
-	private $connection;
57
-
58
-	/** @var SystemConfig */
59
-	private $systemConfig;
60
-
61
-	/** @var ILogger */
62
-	private $logger;
63
-
64
-	/** @var \Doctrine\DBAL\Query\QueryBuilder */
65
-	private $queryBuilder;
66
-
67
-	/** @var QuoteHelper */
68
-	private $helper;
69
-
70
-	/** @var bool */
71
-	private $automaticTablePrefix = true;
72
-
73
-	/** @var string */
74
-	protected $lastInsertedTable;
75
-
76
-	/**
77
-	 * Initializes a new QueryBuilder.
78
-	 *
79
-	 * @param IDBConnection $connection
80
-	 * @param SystemConfig $systemConfig
81
-	 * @param ILogger $logger
82
-	 */
83
-	public function __construct(IDBConnection $connection, SystemConfig $systemConfig, ILogger $logger) {
84
-		$this->connection = $connection;
85
-		$this->systemConfig = $systemConfig;
86
-		$this->logger = $logger;
87
-		$this->queryBuilder = new \Doctrine\DBAL\Query\QueryBuilder($this->connection);
88
-		$this->helper = new QuoteHelper();
89
-	}
90
-
91
-	/**
92
-	 * Enable/disable automatic prefixing of table names with the oc_ prefix
93
-	 *
94
-	 * @param bool $enabled If set to true table names will be prefixed with the
95
-	 * owncloud database prefix automatically.
96
-	 * @since 8.2.0
97
-	 */
98
-	public function automaticTablePrefix($enabled) {
99
-		$this->automaticTablePrefix = (bool) $enabled;
100
-	}
101
-
102
-	/**
103
-	 * Gets an ExpressionBuilder used for object-oriented construction of query expressions.
104
-	 * This producer method is intended for convenient inline usage. Example:
105
-	 *
106
-	 * <code>
107
-	 *     $qb = $conn->getQueryBuilder()
108
-	 *         ->select('u')
109
-	 *         ->from('users', 'u')
110
-	 *         ->where($qb->expr()->eq('u.id', 1));
111
-	 * </code>
112
-	 *
113
-	 * For more complex expression construction, consider storing the expression
114
-	 * builder object in a local variable.
115
-	 *
116
-	 * @return \OCP\DB\QueryBuilder\IExpressionBuilder
117
-	 */
118
-	public function expr() {
119
-		if ($this->connection instanceof OracleConnection) {
120
-			return new OCIExpressionBuilder($this->connection, $this);
121
-		} elseif ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
122
-			return new PgSqlExpressionBuilder($this->connection, $this);
123
-		} elseif ($this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
124
-			return new MySqlExpressionBuilder($this->connection, $this);
125
-		} elseif ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
126
-			return new SqliteExpressionBuilder($this->connection, $this);
127
-		} else {
128
-			return new ExpressionBuilder($this->connection, $this);
129
-		}
130
-	}
131
-
132
-	/**
133
-	 * Gets an FunctionBuilder used for object-oriented construction of query functions.
134
-	 * This producer method is intended for convenient inline usage. Example:
135
-	 *
136
-	 * <code>
137
-	 *     $qb = $conn->getQueryBuilder()
138
-	 *         ->select('u')
139
-	 *         ->from('users', 'u')
140
-	 *         ->where($qb->fun()->md5('u.id'));
141
-	 * </code>
142
-	 *
143
-	 * For more complex function construction, consider storing the function
144
-	 * builder object in a local variable.
145
-	 *
146
-	 * @return \OCP\DB\QueryBuilder\IFunctionBuilder
147
-	 */
148
-	public function func() {
149
-		if ($this->connection instanceof OracleConnection) {
150
-			return new OCIFunctionBuilder($this->helper);
151
-		} elseif ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
152
-			return new SqliteFunctionBuilder($this->helper);
153
-		} elseif ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
154
-			return new PgSqlFunctionBuilder($this->helper);
155
-		} else {
156
-			return new FunctionBuilder($this->helper);
157
-		}
158
-	}
159
-
160
-	/**
161
-	 * Gets the type of the currently built query.
162
-	 *
163
-	 * @return integer
164
-	 */
165
-	public function getType() {
166
-		return $this->queryBuilder->getType();
167
-	}
168
-
169
-	/**
170
-	 * Gets the associated DBAL Connection for this query builder.
171
-	 *
172
-	 * @return \OCP\IDBConnection
173
-	 */
174
-	public function getConnection() {
175
-		return $this->connection;
176
-	}
177
-
178
-	/**
179
-	 * Gets the state of this query builder instance.
180
-	 *
181
-	 * @return integer Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN.
182
-	 */
183
-	public function getState() {
184
-		return $this->queryBuilder->getState();
185
-	}
186
-
187
-	/**
188
-	 * Executes this query using the bound parameters and their types.
189
-	 *
190
-	 * Uses {@see Connection::executeQuery} for select statements and {@see Connection::executeUpdate}
191
-	 * for insert, update and delete statements.
192
-	 *
193
-	 * @return \Doctrine\DBAL\Driver\Statement|int
194
-	 */
195
-	public function execute() {
196
-		if ($this->systemConfig->getValue('log_query', false)) {
197
-			try {
198
-				$params = [];
199
-				foreach ($this->getParameters() as $placeholder => $value) {
200
-					if ($value instanceof \DateTime) {
201
-						$params[] = $placeholder . ' => DateTime:\'' . $value->format('c') . '\'';
202
-					} elseif (is_array($value)) {
203
-						$params[] = $placeholder . ' => (\'' . implode('\', \'', $value) . '\')';
204
-					} else {
205
-						$params[] = $placeholder . ' => \'' . $value . '\'';
206
-					}
207
-				}
208
-				if (empty($params)) {
209
-					$this->logger->debug('DB QueryBuilder: \'{query}\'', [
210
-						'query' => $this->getSQL(),
211
-						'app' => 'core',
212
-					]);
213
-				} else {
214
-					$this->logger->debug('DB QueryBuilder: \'{query}\' with parameters: {params}', [
215
-						'query' => $this->getSQL(),
216
-						'params' => implode(', ', $params),
217
-						'app' => 'core',
218
-					]);
219
-				}
220
-			} catch (\Error $e) {
221
-				// likely an error during conversion of $value to string
222
-				$this->logger->debug('DB QueryBuilder: error trying to log SQL query');
223
-				$this->logger->logException($e);
224
-			}
225
-		}
226
-
227
-		if (!empty($this->getQueryPart('select'))) {
228
-			$select = $this->getQueryPart('select');
229
-			$hasSelectAll = array_filter($select, static function ($s) {
230
-				return $s === '*';
231
-			});
232
-			$hasSelectSpecific = array_filter($select, static function ($s) {
233
-				return $s !== '*';
234
-			});
235
-
236
-			if (empty($hasSelectAll) === empty($hasSelectSpecific)) {
237
-				$exception = new QueryException('Query is selecting * and specific values in the same query. This is not supported in Oracle.');
238
-				$this->logger->logException($exception, [
239
-					'message' => 'Query is selecting * and specific values in the same query. This is not supported in Oracle.',
240
-					'query' => $this->getSQL(),
241
-					'level' => ILogger::ERROR,
242
-					'app' => 'core',
243
-				]);
244
-			}
245
-		}
246
-
247
-		return $this->queryBuilder->execute();
248
-	}
249
-
250
-	/**
251
-	 * Gets the complete SQL string formed by the current specifications of this QueryBuilder.
252
-	 *
253
-	 * <code>
254
-	 *     $qb = $conn->getQueryBuilder()
255
-	 *         ->select('u')
256
-	 *         ->from('User', 'u')
257
-	 *     echo $qb->getSQL(); // SELECT u FROM User u
258
-	 * </code>
259
-	 *
260
-	 * @return string The SQL query string.
261
-	 */
262
-	public function getSQL() {
263
-		return $this->queryBuilder->getSQL();
264
-	}
265
-
266
-	/**
267
-	 * Sets a query parameter for the query being constructed.
268
-	 *
269
-	 * <code>
270
-	 *     $qb = $conn->getQueryBuilder()
271
-	 *         ->select('u')
272
-	 *         ->from('users', 'u')
273
-	 *         ->where('u.id = :user_id')
274
-	 *         ->setParameter(':user_id', 1);
275
-	 * </code>
276
-	 *
277
-	 * @param string|integer $key The parameter position or name.
278
-	 * @param mixed $value The parameter value.
279
-	 * @param string|null|int $type One of the IQueryBuilder::PARAM_* constants.
280
-	 *
281
-	 * @return $this This QueryBuilder instance.
282
-	 */
283
-	public function setParameter($key, $value, $type = null) {
284
-		$this->queryBuilder->setParameter($key, $value, $type);
285
-
286
-		return $this;
287
-	}
288
-
289
-	/**
290
-	 * Sets a collection of query parameters for the query being constructed.
291
-	 *
292
-	 * <code>
293
-	 *     $qb = $conn->getQueryBuilder()
294
-	 *         ->select('u')
295
-	 *         ->from('users', 'u')
296
-	 *         ->where('u.id = :user_id1 OR u.id = :user_id2')
297
-	 *         ->setParameters(array(
298
-	 *             ':user_id1' => 1,
299
-	 *             ':user_id2' => 2
300
-	 *         ));
301
-	 * </code>
302
-	 *
303
-	 * @param array $params The query parameters to set.
304
-	 * @param array $types The query parameters types to set.
305
-	 *
306
-	 * @return $this This QueryBuilder instance.
307
-	 */
308
-	public function setParameters(array $params, array $types = []) {
309
-		$this->queryBuilder->setParameters($params, $types);
310
-
311
-		return $this;
312
-	}
313
-
314
-	/**
315
-	 * Gets all defined query parameters for the query being constructed indexed by parameter index or name.
316
-	 *
317
-	 * @return array The currently defined query parameters indexed by parameter index or name.
318
-	 */
319
-	public function getParameters() {
320
-		return $this->queryBuilder->getParameters();
321
-	}
322
-
323
-	/**
324
-	 * Gets a (previously set) query parameter of the query being constructed.
325
-	 *
326
-	 * @param mixed $key The key (index or name) of the bound parameter.
327
-	 *
328
-	 * @return mixed The value of the bound parameter.
329
-	 */
330
-	public function getParameter($key) {
331
-		return $this->queryBuilder->getParameter($key);
332
-	}
333
-
334
-	/**
335
-	 * Gets all defined query parameter types for the query being constructed indexed by parameter index or name.
336
-	 *
337
-	 * @return array The currently defined query parameter types indexed by parameter index or name.
338
-	 */
339
-	public function getParameterTypes() {
340
-		return $this->queryBuilder->getParameterTypes();
341
-	}
342
-
343
-	/**
344
-	 * Gets a (previously set) query parameter type of the query being constructed.
345
-	 *
346
-	 * @param mixed $key The key (index or name) of the bound parameter type.
347
-	 *
348
-	 * @return mixed The value of the bound parameter type.
349
-	 */
350
-	public function getParameterType($key) {
351
-		return $this->queryBuilder->getParameterType($key);
352
-	}
353
-
354
-	/**
355
-	 * Sets the position of the first result to retrieve (the "offset").
356
-	 *
357
-	 * @param integer $firstResult The first result to return.
358
-	 *
359
-	 * @return $this This QueryBuilder instance.
360
-	 */
361
-	public function setFirstResult($firstResult) {
362
-		$this->queryBuilder->setFirstResult($firstResult);
363
-
364
-		return $this;
365
-	}
366
-
367
-	/**
368
-	 * Gets the position of the first result the query object was set to retrieve (the "offset").
369
-	 * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder.
370
-	 *
371
-	 * @return integer The position of the first result.
372
-	 */
373
-	public function getFirstResult() {
374
-		return $this->queryBuilder->getFirstResult();
375
-	}
376
-
377
-	/**
378
-	 * Sets the maximum number of results to retrieve (the "limit").
379
-	 *
380
-	 * NOTE: Setting max results to "0" will cause mixed behaviour. While most
381
-	 * of the databases will just return an empty result set, Oracle will return
382
-	 * all entries.
383
-	 *
384
-	 * @param integer $maxResults The maximum number of results to retrieve.
385
-	 *
386
-	 * @return $this This QueryBuilder instance.
387
-	 */
388
-	public function setMaxResults($maxResults) {
389
-		$this->queryBuilder->setMaxResults($maxResults);
390
-
391
-		return $this;
392
-	}
393
-
394
-	/**
395
-	 * Gets the maximum number of results the query object was set to retrieve (the "limit").
396
-	 * Returns NULL if {@link setMaxResults} was not applied to this query builder.
397
-	 *
398
-	 * @return int|null The maximum number of results.
399
-	 */
400
-	public function getMaxResults() {
401
-		return $this->queryBuilder->getMaxResults();
402
-	}
403
-
404
-	/**
405
-	 * Specifies an item that is to be returned in the query result.
406
-	 * Replaces any previously specified selections, if any.
407
-	 *
408
-	 * <code>
409
-	 *     $qb = $conn->getQueryBuilder()
410
-	 *         ->select('u.id', 'p.id')
411
-	 *         ->from('users', 'u')
412
-	 *         ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id');
413
-	 * </code>
414
-	 *
415
-	 * @param mixed ...$selects The selection expressions.
416
-	 *
417
-	 * '@return $this This QueryBuilder instance.
418
-	 */
419
-	public function select(...$selects) {
420
-		if (count($selects) === 1 && is_array($selects[0])) {
421
-			$selects = $selects[0];
422
-		}
423
-
424
-		$this->queryBuilder->select(
425
-			$this->helper->quoteColumnNames($selects)
426
-		);
427
-
428
-		return $this;
429
-	}
430
-
431
-	/**
432
-	 * Specifies an item that is to be returned with a different name in the query result.
433
-	 *
434
-	 * <code>
435
-	 *     $qb = $conn->getQueryBuilder()
436
-	 *         ->selectAlias('u.id', 'user_id')
437
-	 *         ->from('users', 'u')
438
-	 *         ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id');
439
-	 * </code>
440
-	 *
441
-	 * @param mixed $select The selection expressions.
442
-	 * @param string $alias The column alias used in the constructed query.
443
-	 *
444
-	 * @return $this This QueryBuilder instance.
445
-	 */
446
-	public function selectAlias($select, $alias) {
447
-		$this->queryBuilder->addSelect(
448
-			$this->helper->quoteColumnName($select) . ' AS ' . $this->helper->quoteColumnName($alias)
449
-		);
450
-
451
-		return $this;
452
-	}
453
-
454
-	/**
455
-	 * Specifies an item that is to be returned uniquely in the query result.
456
-	 *
457
-	 * <code>
458
-	 *     $qb = $conn->getQueryBuilder()
459
-	 *         ->selectDistinct('type')
460
-	 *         ->from('users');
461
-	 * </code>
462
-	 *
463
-	 * @param mixed $select The selection expressions.
464
-	 *
465
-	 * @return $this This QueryBuilder instance.
466
-	 */
467
-	public function selectDistinct($select) {
468
-		if (!is_array($select)) {
469
-			$select = [$select];
470
-		}
471
-
472
-		$quotedSelect = $this->helper->quoteColumnNames($select);
473
-
474
-		$this->queryBuilder->addSelect(
475
-			'DISTINCT ' . implode(', ', $quotedSelect)
476
-		);
477
-
478
-		return $this;
479
-	}
480
-
481
-	/**
482
-	 * Adds an item that is to be returned in the query result.
483
-	 *
484
-	 * <code>
485
-	 *     $qb = $conn->getQueryBuilder()
486
-	 *         ->select('u.id')
487
-	 *         ->addSelect('p.id')
488
-	 *         ->from('users', 'u')
489
-	 *         ->leftJoin('u', 'phonenumbers', 'u.id = p.user_id');
490
-	 * </code>
491
-	 *
492
-	 * @param mixed ...$selects The selection expression.
493
-	 *
494
-	 * @return $this This QueryBuilder instance.
495
-	 */
496
-	public function addSelect(...$selects) {
497
-		if (count($selects) === 1 && is_array($selects[0])) {
498
-			$selects = $selects[0];
499
-		}
500
-
501
-		$this->queryBuilder->addSelect(
502
-			$this->helper->quoteColumnNames($selects)
503
-		);
504
-
505
-		return $this;
506
-	}
507
-
508
-	/**
509
-	 * Turns the query being built into a bulk delete query that ranges over
510
-	 * a certain table.
511
-	 *
512
-	 * <code>
513
-	 *     $qb = $conn->getQueryBuilder()
514
-	 *         ->delete('users', 'u')
515
-	 *         ->where('u.id = :user_id');
516
-	 *         ->setParameter(':user_id', 1);
517
-	 * </code>
518
-	 *
519
-	 * @param string $delete The table whose rows are subject to the deletion.
520
-	 * @param string $alias The table alias used in the constructed query.
521
-	 *
522
-	 * @return $this This QueryBuilder instance.
523
-	 */
524
-	public function delete($delete = null, $alias = null) {
525
-		$this->queryBuilder->delete(
526
-			$this->getTableName($delete),
527
-			$alias
528
-		);
529
-
530
-		return $this;
531
-	}
532
-
533
-	/**
534
-	 * Turns the query being built into a bulk update query that ranges over
535
-	 * a certain table
536
-	 *
537
-	 * <code>
538
-	 *     $qb = $conn->getQueryBuilder()
539
-	 *         ->update('users', 'u')
540
-	 *         ->set('u.password', md5('password'))
541
-	 *         ->where('u.id = ?');
542
-	 * </code>
543
-	 *
544
-	 * @param string $update The table whose rows are subject to the update.
545
-	 * @param string $alias The table alias used in the constructed query.
546
-	 *
547
-	 * @return $this This QueryBuilder instance.
548
-	 */
549
-	public function update($update = null, $alias = null) {
550
-		$this->queryBuilder->update(
551
-			$this->getTableName($update),
552
-			$alias
553
-		);
554
-
555
-		return $this;
556
-	}
557
-
558
-	/**
559
-	 * Turns the query being built into an insert query that inserts into
560
-	 * a certain table
561
-	 *
562
-	 * <code>
563
-	 *     $qb = $conn->getQueryBuilder()
564
-	 *         ->insert('users')
565
-	 *         ->values(
566
-	 *             array(
567
-	 *                 'name' => '?',
568
-	 *                 'password' => '?'
569
-	 *             )
570
-	 *         );
571
-	 * </code>
572
-	 *
573
-	 * @param string $insert The table into which the rows should be inserted.
574
-	 *
575
-	 * @return $this This QueryBuilder instance.
576
-	 */
577
-	public function insert($insert = null) {
578
-		$this->queryBuilder->insert(
579
-			$this->getTableName($insert)
580
-		);
581
-
582
-		$this->lastInsertedTable = $insert;
583
-
584
-		return $this;
585
-	}
586
-
587
-	/**
588
-	 * Creates and adds a query root corresponding to the table identified by the
589
-	 * given alias, forming a cartesian product with any existing query roots.
590
-	 *
591
-	 * <code>
592
-	 *     $qb = $conn->getQueryBuilder()
593
-	 *         ->select('u.id')
594
-	 *         ->from('users', 'u')
595
-	 * </code>
596
-	 *
597
-	 * @param string $from The table.
598
-	 * @param string|null $alias The alias of the table.
599
-	 *
600
-	 * @return $this This QueryBuilder instance.
601
-	 */
602
-	public function from($from, $alias = null) {
603
-		$this->queryBuilder->from(
604
-			$this->getTableName($from),
605
-			$this->quoteAlias($alias)
606
-		);
607
-
608
-		return $this;
609
-	}
610
-
611
-	/**
612
-	 * Creates and adds a join to the query.
613
-	 *
614
-	 * <code>
615
-	 *     $qb = $conn->getQueryBuilder()
616
-	 *         ->select('u.name')
617
-	 *         ->from('users', 'u')
618
-	 *         ->join('u', 'phonenumbers', 'p', 'p.is_primary = 1');
619
-	 * </code>
620
-	 *
621
-	 * @param string $fromAlias The alias that points to a from clause.
622
-	 * @param string $join The table name to join.
623
-	 * @param string $alias The alias of the join table.
624
-	 * @param string $condition The condition for the join.
625
-	 *
626
-	 * @return $this This QueryBuilder instance.
627
-	 */
628
-	public function join($fromAlias, $join, $alias, $condition = null) {
629
-		$this->queryBuilder->join(
630
-			$this->quoteAlias($fromAlias),
631
-			$this->getTableName($join),
632
-			$this->quoteAlias($alias),
633
-			$condition
634
-		);
635
-
636
-		return $this;
637
-	}
638
-
639
-	/**
640
-	 * Creates and adds a join to the query.
641
-	 *
642
-	 * <code>
643
-	 *     $qb = $conn->getQueryBuilder()
644
-	 *         ->select('u.name')
645
-	 *         ->from('users', 'u')
646
-	 *         ->innerJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1');
647
-	 * </code>
648
-	 *
649
-	 * @param string $fromAlias The alias that points to a from clause.
650
-	 * @param string $join The table name to join.
651
-	 * @param string $alias The alias of the join table.
652
-	 * @param string $condition The condition for the join.
653
-	 *
654
-	 * @return $this This QueryBuilder instance.
655
-	 */
656
-	public function innerJoin($fromAlias, $join, $alias, $condition = null) {
657
-		$this->queryBuilder->innerJoin(
658
-			$this->quoteAlias($fromAlias),
659
-			$this->getTableName($join),
660
-			$this->quoteAlias($alias),
661
-			$condition
662
-		);
663
-
664
-		return $this;
665
-	}
666
-
667
-	/**
668
-	 * Creates and adds a left join to the query.
669
-	 *
670
-	 * <code>
671
-	 *     $qb = $conn->getQueryBuilder()
672
-	 *         ->select('u.name')
673
-	 *         ->from('users', 'u')
674
-	 *         ->leftJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1');
675
-	 * </code>
676
-	 *
677
-	 * @param string $fromAlias The alias that points to a from clause.
678
-	 * @param string $join The table name to join.
679
-	 * @param string $alias The alias of the join table.
680
-	 * @param string $condition The condition for the join.
681
-	 *
682
-	 * @return $this This QueryBuilder instance.
683
-	 */
684
-	public function leftJoin($fromAlias, $join, $alias, $condition = null) {
685
-		$this->queryBuilder->leftJoin(
686
-			$this->quoteAlias($fromAlias),
687
-			$this->getTableName($join),
688
-			$this->quoteAlias($alias),
689
-			$condition
690
-		);
691
-
692
-		return $this;
693
-	}
694
-
695
-	/**
696
-	 * Creates and adds a right join to the query.
697
-	 *
698
-	 * <code>
699
-	 *     $qb = $conn->getQueryBuilder()
700
-	 *         ->select('u.name')
701
-	 *         ->from('users', 'u')
702
-	 *         ->rightJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1');
703
-	 * </code>
704
-	 *
705
-	 * @param string $fromAlias The alias that points to a from clause.
706
-	 * @param string $join The table name to join.
707
-	 * @param string $alias The alias of the join table.
708
-	 * @param string $condition The condition for the join.
709
-	 *
710
-	 * @return $this This QueryBuilder instance.
711
-	 */
712
-	public function rightJoin($fromAlias, $join, $alias, $condition = null) {
713
-		$this->queryBuilder->rightJoin(
714
-			$this->quoteAlias($fromAlias),
715
-			$this->getTableName($join),
716
-			$this->quoteAlias($alias),
717
-			$condition
718
-		);
719
-
720
-		return $this;
721
-	}
722
-
723
-	/**
724
-	 * Sets a new value for a column in a bulk update query.
725
-	 *
726
-	 * <code>
727
-	 *     $qb = $conn->getQueryBuilder()
728
-	 *         ->update('users', 'u')
729
-	 *         ->set('u.password', md5('password'))
730
-	 *         ->where('u.id = ?');
731
-	 * </code>
732
-	 *
733
-	 * @param string $key The column to set.
734
-	 * @param ILiteral|IParameter|IQueryFunction|string $value The value, expression, placeholder, etc.
735
-	 *
736
-	 * @return $this This QueryBuilder instance.
737
-	 */
738
-	public function set($key, $value) {
739
-		$this->queryBuilder->set(
740
-			$this->helper->quoteColumnName($key),
741
-			$this->helper->quoteColumnName($value)
742
-		);
743
-
744
-		return $this;
745
-	}
746
-
747
-	/**
748
-	 * Specifies one or more restrictions to the query result.
749
-	 * Replaces any previously specified restrictions, if any.
750
-	 *
751
-	 * <code>
752
-	 *     $qb = $conn->getQueryBuilder()
753
-	 *         ->select('u.name')
754
-	 *         ->from('users', 'u')
755
-	 *         ->where('u.id = ?');
756
-	 *
757
-	 *     // You can optionally programatically build and/or expressions
758
-	 *     $qb = $conn->getQueryBuilder();
759
-	 *
760
-	 *     $or = $qb->expr()->orx();
761
-	 *     $or->add($qb->expr()->eq('u.id', 1));
762
-	 *     $or->add($qb->expr()->eq('u.id', 2));
763
-	 *
764
-	 *     $qb->update('users', 'u')
765
-	 *         ->set('u.password', md5('password'))
766
-	 *         ->where($or);
767
-	 * </code>
768
-	 *
769
-	 * @param mixed ...$predicates The restriction predicates.
770
-	 *
771
-	 * @return $this This QueryBuilder instance.
772
-	 */
773
-	public function where(...$predicates) {
774
-		call_user_func_array(
775
-			[$this->queryBuilder, 'where'],
776
-			$predicates
777
-		);
778
-
779
-		return $this;
780
-	}
781
-
782
-	/**
783
-	 * Adds one or more restrictions to the query results, forming a logical
784
-	 * conjunction with any previously specified restrictions.
785
-	 *
786
-	 * <code>
787
-	 *     $qb = $conn->getQueryBuilder()
788
-	 *         ->select('u')
789
-	 *         ->from('users', 'u')
790
-	 *         ->where('u.username LIKE ?')
791
-	 *         ->andWhere('u.is_active = 1');
792
-	 * </code>
793
-	 *
794
-	 * @param mixed ...$where The query restrictions.
795
-	 *
796
-	 * @return $this This QueryBuilder instance.
797
-	 *
798
-	 * @see where()
799
-	 */
800
-	public function andWhere(...$where) {
801
-		call_user_func_array(
802
-			[$this->queryBuilder, 'andWhere'],
803
-			$where
804
-		);
805
-
806
-		return $this;
807
-	}
808
-
809
-	/**
810
-	 * Adds one or more restrictions to the query results, forming a logical
811
-	 * disjunction with any previously specified restrictions.
812
-	 *
813
-	 * <code>
814
-	 *     $qb = $conn->getQueryBuilder()
815
-	 *         ->select('u.name')
816
-	 *         ->from('users', 'u')
817
-	 *         ->where('u.id = 1')
818
-	 *         ->orWhere('u.id = 2');
819
-	 * </code>
820
-	 *
821
-	 * @param mixed ...$where The WHERE statement.
822
-	 *
823
-	 * @return $this This QueryBuilder instance.
824
-	 *
825
-	 * @see where()
826
-	 */
827
-	public function orWhere(...$where) {
828
-		call_user_func_array(
829
-			[$this->queryBuilder, 'orWhere'],
830
-			$where
831
-		);
832
-
833
-		return $this;
834
-	}
835
-
836
-	/**
837
-	 * Specifies a grouping over the results of the query.
838
-	 * Replaces any previously specified groupings, if any.
839
-	 *
840
-	 * <code>
841
-	 *     $qb = $conn->getQueryBuilder()
842
-	 *         ->select('u.name')
843
-	 *         ->from('users', 'u')
844
-	 *         ->groupBy('u.id');
845
-	 * </code>
846
-	 *
847
-	 * @param mixed ...$groupBys The grouping expression.
848
-	 *
849
-	 * @return $this This QueryBuilder instance.
850
-	 */
851
-	public function groupBy(...$groupBys) {
852
-		if (count($groupBys) === 1 && is_array($groupBys[0])) {
853
-			$groupBys = $groupBys[0];
854
-		}
855
-
856
-		call_user_func_array(
857
-			[$this->queryBuilder, 'groupBy'],
858
-			$this->helper->quoteColumnNames($groupBys)
859
-		);
860
-
861
-		return $this;
862
-	}
863
-
864
-	/**
865
-	 * Adds a grouping expression to the query.
866
-	 *
867
-	 * <code>
868
-	 *     $qb = $conn->getQueryBuilder()
869
-	 *         ->select('u.name')
870
-	 *         ->from('users', 'u')
871
-	 *         ->groupBy('u.lastLogin');
872
-	 *         ->addGroupBy('u.createdAt')
873
-	 * </code>
874
-	 *
875
-	 * @param mixed ...$groupBy The grouping expression.
876
-	 *
877
-	 * @return $this This QueryBuilder instance.
878
-	 */
879
-	public function addGroupBy(...$groupBys) {
880
-		if (count($groupBys) === 1 && is_array($groupBys[0])) {
881
-			$$groupBys = $groupBys[0];
882
-		}
883
-
884
-		call_user_func_array(
885
-			[$this->queryBuilder, 'addGroupBy'],
886
-			$this->helper->quoteColumnNames($groupBys)
887
-		);
888
-
889
-		return $this;
890
-	}
891
-
892
-	/**
893
-	 * Sets a value for a column in an insert query.
894
-	 *
895
-	 * <code>
896
-	 *     $qb = $conn->getQueryBuilder()
897
-	 *         ->insert('users')
898
-	 *         ->values(
899
-	 *             array(
900
-	 *                 'name' => '?'
901
-	 *             )
902
-	 *         )
903
-	 *         ->setValue('password', '?');
904
-	 * </code>
905
-	 *
906
-	 * @param string $column The column into which the value should be inserted.
907
-	 * @param IParameter|string $value The value that should be inserted into the column.
908
-	 *
909
-	 * @return $this This QueryBuilder instance.
910
-	 */
911
-	public function setValue($column, $value) {
912
-		$this->queryBuilder->setValue(
913
-			$this->helper->quoteColumnName($column),
914
-			(string) $value
915
-		);
916
-
917
-		return $this;
918
-	}
919
-
920
-	/**
921
-	 * Specifies values for an insert query indexed by column names.
922
-	 * Replaces any previous values, if any.
923
-	 *
924
-	 * <code>
925
-	 *     $qb = $conn->getQueryBuilder()
926
-	 *         ->insert('users')
927
-	 *         ->values(
928
-	 *             array(
929
-	 *                 'name' => '?',
930
-	 *                 'password' => '?'
931
-	 *             )
932
-	 *         );
933
-	 * </code>
934
-	 *
935
-	 * @param array $values The values to specify for the insert query indexed by column names.
936
-	 *
937
-	 * @return $this This QueryBuilder instance.
938
-	 */
939
-	public function values(array $values) {
940
-		$quotedValues = [];
941
-		foreach ($values as $key => $value) {
942
-			$quotedValues[$this->helper->quoteColumnName($key)] = $value;
943
-		}
944
-
945
-		$this->queryBuilder->values($quotedValues);
946
-
947
-		return $this;
948
-	}
949
-
950
-	/**
951
-	 * Specifies a restriction over the groups of the query.
952
-	 * Replaces any previous having restrictions, if any.
953
-	 *
954
-	 * @param mixed ...$having The restriction over the groups.
955
-	 *
956
-	 * @return $this This QueryBuilder instance.
957
-	 */
958
-	public function having(...$having) {
959
-		call_user_func_array(
960
-			[$this->queryBuilder, 'having'],
961
-			$having
962
-		);
963
-
964
-		return $this;
965
-	}
966
-
967
-	/**
968
-	 * Adds a restriction over the groups of the query, forming a logical
969
-	 * conjunction with any existing having restrictions.
970
-	 *
971
-	 * @param mixed ...$having The restriction to append.
972
-	 *
973
-	 * @return $this This QueryBuilder instance.
974
-	 */
975
-	public function andHaving(...$having) {
976
-		call_user_func_array(
977
-			[$this->queryBuilder, 'andHaving'],
978
-			$having
979
-		);
980
-
981
-		return $this;
982
-	}
983
-
984
-	/**
985
-	 * Adds a restriction over the groups of the query, forming a logical
986
-	 * disjunction with any existing having restrictions.
987
-	 *
988
-	 * @param mixed ...$having The restriction to add.
989
-	 *
990
-	 * @return $this This QueryBuilder instance.
991
-	 */
992
-	public function orHaving(...$having) {
993
-		call_user_func_array(
994
-			[$this->queryBuilder, 'orHaving'],
995
-			$having
996
-		);
997
-
998
-		return $this;
999
-	}
1000
-
1001
-	/**
1002
-	 * Specifies an ordering for the query results.
1003
-	 * Replaces any previously specified orderings, if any.
1004
-	 *
1005
-	 * @param string $sort The ordering expression.
1006
-	 * @param string $order The ordering direction.
1007
-	 *
1008
-	 * @return $this This QueryBuilder instance.
1009
-	 */
1010
-	public function orderBy($sort, $order = null) {
1011
-		$this->queryBuilder->orderBy(
1012
-			$this->helper->quoteColumnName($sort),
1013
-			$order
1014
-		);
1015
-
1016
-		return $this;
1017
-	}
1018
-
1019
-	/**
1020
-	 * Adds an ordering to the query results.
1021
-	 *
1022
-	 * @param string $sort The ordering expression.
1023
-	 * @param string $order The ordering direction.
1024
-	 *
1025
-	 * @return $this This QueryBuilder instance.
1026
-	 */
1027
-	public function addOrderBy($sort, $order = null) {
1028
-		$this->queryBuilder->addOrderBy(
1029
-			$this->helper->quoteColumnName($sort),
1030
-			$order
1031
-		);
1032
-
1033
-		return $this;
1034
-	}
1035
-
1036
-	/**
1037
-	 * Gets a query part by its name.
1038
-	 *
1039
-	 * @param string $queryPartName
1040
-	 *
1041
-	 * @return mixed
1042
-	 */
1043
-	public function getQueryPart($queryPartName) {
1044
-		return $this->queryBuilder->getQueryPart($queryPartName);
1045
-	}
1046
-
1047
-	/**
1048
-	 * Gets all query parts.
1049
-	 *
1050
-	 * @return array
1051
-	 */
1052
-	public function getQueryParts() {
1053
-		return $this->queryBuilder->getQueryParts();
1054
-	}
1055
-
1056
-	/**
1057
-	 * Resets SQL parts.
1058
-	 *
1059
-	 * @param array|null $queryPartNames
1060
-	 *
1061
-	 * @return $this This QueryBuilder instance.
1062
-	 */
1063
-	public function resetQueryParts($queryPartNames = null) {
1064
-		$this->queryBuilder->resetQueryParts($queryPartNames);
1065
-
1066
-		return $this;
1067
-	}
1068
-
1069
-	/**
1070
-	 * Resets a single SQL part.
1071
-	 *
1072
-	 * @param string $queryPartName
1073
-	 *
1074
-	 * @return $this This QueryBuilder instance.
1075
-	 */
1076
-	public function resetQueryPart($queryPartName) {
1077
-		$this->queryBuilder->resetQueryPart($queryPartName);
1078
-
1079
-		return $this;
1080
-	}
1081
-
1082
-	/**
1083
-	 * Creates a new named parameter and bind the value $value to it.
1084
-	 *
1085
-	 * This method provides a shortcut for PDOStatement::bindValue
1086
-	 * when using prepared statements.
1087
-	 *
1088
-	 * The parameter $value specifies the value that you want to bind. If
1089
-	 * $placeholder is not provided bindValue() will automatically create a
1090
-	 * placeholder for you. An automatic placeholder will be of the name
1091
-	 * ':dcValue1', ':dcValue2' etc.
1092
-	 *
1093
-	 * For more information see {@link http://php.net/pdostatement-bindparam}
1094
-	 *
1095
-	 * Example:
1096
-	 * <code>
1097
-	 * $value = 2;
1098
-	 * $q->eq( 'id', $q->bindValue( $value ) );
1099
-	 * $stmt = $q->executeQuery(); // executed with 'id = 2'
1100
-	 * </code>
1101
-	 *
1102
-	 * @license New BSD License
1103
-	 * @link http://www.zetacomponents.org
1104
-	 *
1105
-	 * @param mixed $value
1106
-	 * @param mixed $type
1107
-	 * @param string $placeHolder The name to bind with. The string must start with a colon ':'.
1108
-	 *
1109
-	 * @return IParameter the placeholder name used.
1110
-	 */
1111
-	public function createNamedParameter($value, $type = IQueryBuilder::PARAM_STR, $placeHolder = null) {
1112
-		return new Parameter($this->queryBuilder->createNamedParameter($value, $type, $placeHolder));
1113
-	}
1114
-
1115
-	/**
1116
-	 * Creates a new positional parameter and bind the given value to it.
1117
-	 *
1118
-	 * Attention: If you are using positional parameters with the query builder you have
1119
-	 * to be very careful to bind all parameters in the order they appear in the SQL
1120
-	 * statement , otherwise they get bound in the wrong order which can lead to serious
1121
-	 * bugs in your code.
1122
-	 *
1123
-	 * Example:
1124
-	 * <code>
1125
-	 *  $qb = $conn->getQueryBuilder();
1126
-	 *  $qb->select('u.*')
1127
-	 *     ->from('users', 'u')
1128
-	 *     ->where('u.username = ' . $qb->createPositionalParameter('Foo', IQueryBuilder::PARAM_STR))
1129
-	 *     ->orWhere('u.username = ' . $qb->createPositionalParameter('Bar', IQueryBuilder::PARAM_STR))
1130
-	 * </code>
1131
-	 *
1132
-	 * @param mixed $value
1133
-	 * @param integer $type
1134
-	 *
1135
-	 * @return IParameter
1136
-	 */
1137
-	public function createPositionalParameter($value, $type = IQueryBuilder::PARAM_STR) {
1138
-		return new Parameter($this->queryBuilder->createPositionalParameter($value, $type));
1139
-	}
1140
-
1141
-	/**
1142
-	 * Creates a new parameter
1143
-	 *
1144
-	 * Example:
1145
-	 * <code>
1146
-	 *  $qb = $conn->getQueryBuilder();
1147
-	 *  $qb->select('u.*')
1148
-	 *     ->from('users', 'u')
1149
-	 *     ->where('u.username = ' . $qb->createParameter('name'))
1150
-	 *     ->setParameter('name', 'Bar', IQueryBuilder::PARAM_STR))
1151
-	 * </code>
1152
-	 *
1153
-	 * @param string $name
1154
-	 *
1155
-	 * @return IParameter
1156
-	 */
1157
-	public function createParameter($name) {
1158
-		return new Parameter(':' . $name);
1159
-	}
1160
-
1161
-	/**
1162
-	 * Creates a new function
1163
-	 *
1164
-	 * Attention: Column names inside the call have to be quoted before hand
1165
-	 *
1166
-	 * Example:
1167
-	 * <code>
1168
-	 *  $qb = $conn->getQueryBuilder();
1169
-	 *  $qb->select($qb->createFunction('COUNT(*)'))
1170
-	 *     ->from('users', 'u')
1171
-	 *  echo $qb->getSQL(); // SELECT COUNT(*) FROM `users` u
1172
-	 * </code>
1173
-	 * <code>
1174
-	 *  $qb = $conn->getQueryBuilder();
1175
-	 *  $qb->select($qb->createFunction('COUNT(`column`)'))
1176
-	 *     ->from('users', 'u')
1177
-	 *  echo $qb->getSQL(); // SELECT COUNT(`column`) FROM `users` u
1178
-	 * </code>
1179
-	 *
1180
-	 * @param string $call
1181
-	 *
1182
-	 * @return IQueryFunction
1183
-	 */
1184
-	public function createFunction($call) {
1185
-		return new QueryFunction($call);
1186
-	}
1187
-
1188
-	/**
1189
-	 * Used to get the id of the last inserted element
1190
-	 * @return int
1191
-	 * @throws \BadMethodCallException When being called before an insert query has been run.
1192
-	 */
1193
-	public function getLastInsertId() {
1194
-		if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::INSERT && $this->lastInsertedTable) {
1195
-			// lastInsertId() needs the prefix but no quotes
1196
-			$table = $this->prefixTableName($this->lastInsertedTable);
1197
-			return (int) $this->connection->lastInsertId($table);
1198
-		}
1199
-
1200
-		throw new \BadMethodCallException('Invalid call to getLastInsertId without using insert() before.');
1201
-	}
1202
-
1203
-	/**
1204
-	 * Returns the table name quoted and with database prefix as needed by the implementation
1205
-	 *
1206
-	 * @param string $table
1207
-	 * @return string
1208
-	 */
1209
-	public function getTableName($table) {
1210
-		if ($table instanceof IQueryFunction) {
1211
-			return (string) $table;
1212
-		}
1213
-
1214
-		$table = $this->prefixTableName($table);
1215
-		return $this->helper->quoteColumnName($table);
1216
-	}
1217
-
1218
-	/**
1219
-	 * Returns the table name with database prefix as needed by the implementation
1220
-	 *
1221
-	 * @param string $table
1222
-	 * @return string
1223
-	 */
1224
-	protected function prefixTableName($table) {
1225
-		if ($this->automaticTablePrefix === false || strpos($table, '*PREFIX*') === 0) {
1226
-			return $table;
1227
-		}
1228
-
1229
-		return '*PREFIX*' . $table;
1230
-	}
1231
-
1232
-	/**
1233
-	 * Returns the column name quoted and with table alias prefix as needed by the implementation
1234
-	 *
1235
-	 * @param string $column
1236
-	 * @param string $tableAlias
1237
-	 * @return string
1238
-	 */
1239
-	public function getColumnName($column, $tableAlias = '') {
1240
-		if ($tableAlias !== '') {
1241
-			$tableAlias .= '.';
1242
-		}
1243
-
1244
-		return $this->helper->quoteColumnName($tableAlias . $column);
1245
-	}
1246
-
1247
-	/**
1248
-	 * Returns the column name quoted and with table alias prefix as needed by the implementation
1249
-	 *
1250
-	 * @param string $alias
1251
-	 * @return string
1252
-	 */
1253
-	public function quoteAlias($alias) {
1254
-		if ($alias === '' || $alias === null) {
1255
-			return $alias;
1256
-		}
1257
-
1258
-		return $this->helper->quoteColumnName($alias);
1259
-	}
55
+    /** @var \OCP\IDBConnection */
56
+    private $connection;
57
+
58
+    /** @var SystemConfig */
59
+    private $systemConfig;
60
+
61
+    /** @var ILogger */
62
+    private $logger;
63
+
64
+    /** @var \Doctrine\DBAL\Query\QueryBuilder */
65
+    private $queryBuilder;
66
+
67
+    /** @var QuoteHelper */
68
+    private $helper;
69
+
70
+    /** @var bool */
71
+    private $automaticTablePrefix = true;
72
+
73
+    /** @var string */
74
+    protected $lastInsertedTable;
75
+
76
+    /**
77
+     * Initializes a new QueryBuilder.
78
+     *
79
+     * @param IDBConnection $connection
80
+     * @param SystemConfig $systemConfig
81
+     * @param ILogger $logger
82
+     */
83
+    public function __construct(IDBConnection $connection, SystemConfig $systemConfig, ILogger $logger) {
84
+        $this->connection = $connection;
85
+        $this->systemConfig = $systemConfig;
86
+        $this->logger = $logger;
87
+        $this->queryBuilder = new \Doctrine\DBAL\Query\QueryBuilder($this->connection);
88
+        $this->helper = new QuoteHelper();
89
+    }
90
+
91
+    /**
92
+     * Enable/disable automatic prefixing of table names with the oc_ prefix
93
+     *
94
+     * @param bool $enabled If set to true table names will be prefixed with the
95
+     * owncloud database prefix automatically.
96
+     * @since 8.2.0
97
+     */
98
+    public function automaticTablePrefix($enabled) {
99
+        $this->automaticTablePrefix = (bool) $enabled;
100
+    }
101
+
102
+    /**
103
+     * Gets an ExpressionBuilder used for object-oriented construction of query expressions.
104
+     * This producer method is intended for convenient inline usage. Example:
105
+     *
106
+     * <code>
107
+     *     $qb = $conn->getQueryBuilder()
108
+     *         ->select('u')
109
+     *         ->from('users', 'u')
110
+     *         ->where($qb->expr()->eq('u.id', 1));
111
+     * </code>
112
+     *
113
+     * For more complex expression construction, consider storing the expression
114
+     * builder object in a local variable.
115
+     *
116
+     * @return \OCP\DB\QueryBuilder\IExpressionBuilder
117
+     */
118
+    public function expr() {
119
+        if ($this->connection instanceof OracleConnection) {
120
+            return new OCIExpressionBuilder($this->connection, $this);
121
+        } elseif ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
122
+            return new PgSqlExpressionBuilder($this->connection, $this);
123
+        } elseif ($this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
124
+            return new MySqlExpressionBuilder($this->connection, $this);
125
+        } elseif ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
126
+            return new SqliteExpressionBuilder($this->connection, $this);
127
+        } else {
128
+            return new ExpressionBuilder($this->connection, $this);
129
+        }
130
+    }
131
+
132
+    /**
133
+     * Gets an FunctionBuilder used for object-oriented construction of query functions.
134
+     * This producer method is intended for convenient inline usage. Example:
135
+     *
136
+     * <code>
137
+     *     $qb = $conn->getQueryBuilder()
138
+     *         ->select('u')
139
+     *         ->from('users', 'u')
140
+     *         ->where($qb->fun()->md5('u.id'));
141
+     * </code>
142
+     *
143
+     * For more complex function construction, consider storing the function
144
+     * builder object in a local variable.
145
+     *
146
+     * @return \OCP\DB\QueryBuilder\IFunctionBuilder
147
+     */
148
+    public function func() {
149
+        if ($this->connection instanceof OracleConnection) {
150
+            return new OCIFunctionBuilder($this->helper);
151
+        } elseif ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
152
+            return new SqliteFunctionBuilder($this->helper);
153
+        } elseif ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
154
+            return new PgSqlFunctionBuilder($this->helper);
155
+        } else {
156
+            return new FunctionBuilder($this->helper);
157
+        }
158
+    }
159
+
160
+    /**
161
+     * Gets the type of the currently built query.
162
+     *
163
+     * @return integer
164
+     */
165
+    public function getType() {
166
+        return $this->queryBuilder->getType();
167
+    }
168
+
169
+    /**
170
+     * Gets the associated DBAL Connection for this query builder.
171
+     *
172
+     * @return \OCP\IDBConnection
173
+     */
174
+    public function getConnection() {
175
+        return $this->connection;
176
+    }
177
+
178
+    /**
179
+     * Gets the state of this query builder instance.
180
+     *
181
+     * @return integer Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN.
182
+     */
183
+    public function getState() {
184
+        return $this->queryBuilder->getState();
185
+    }
186
+
187
+    /**
188
+     * Executes this query using the bound parameters and their types.
189
+     *
190
+     * Uses {@see Connection::executeQuery} for select statements and {@see Connection::executeUpdate}
191
+     * for insert, update and delete statements.
192
+     *
193
+     * @return \Doctrine\DBAL\Driver\Statement|int
194
+     */
195
+    public function execute() {
196
+        if ($this->systemConfig->getValue('log_query', false)) {
197
+            try {
198
+                $params = [];
199
+                foreach ($this->getParameters() as $placeholder => $value) {
200
+                    if ($value instanceof \DateTime) {
201
+                        $params[] = $placeholder . ' => DateTime:\'' . $value->format('c') . '\'';
202
+                    } elseif (is_array($value)) {
203
+                        $params[] = $placeholder . ' => (\'' . implode('\', \'', $value) . '\')';
204
+                    } else {
205
+                        $params[] = $placeholder . ' => \'' . $value . '\'';
206
+                    }
207
+                }
208
+                if (empty($params)) {
209
+                    $this->logger->debug('DB QueryBuilder: \'{query}\'', [
210
+                        'query' => $this->getSQL(),
211
+                        'app' => 'core',
212
+                    ]);
213
+                } else {
214
+                    $this->logger->debug('DB QueryBuilder: \'{query}\' with parameters: {params}', [
215
+                        'query' => $this->getSQL(),
216
+                        'params' => implode(', ', $params),
217
+                        'app' => 'core',
218
+                    ]);
219
+                }
220
+            } catch (\Error $e) {
221
+                // likely an error during conversion of $value to string
222
+                $this->logger->debug('DB QueryBuilder: error trying to log SQL query');
223
+                $this->logger->logException($e);
224
+            }
225
+        }
226
+
227
+        if (!empty($this->getQueryPart('select'))) {
228
+            $select = $this->getQueryPart('select');
229
+            $hasSelectAll = array_filter($select, static function ($s) {
230
+                return $s === '*';
231
+            });
232
+            $hasSelectSpecific = array_filter($select, static function ($s) {
233
+                return $s !== '*';
234
+            });
235
+
236
+            if (empty($hasSelectAll) === empty($hasSelectSpecific)) {
237
+                $exception = new QueryException('Query is selecting * and specific values in the same query. This is not supported in Oracle.');
238
+                $this->logger->logException($exception, [
239
+                    'message' => 'Query is selecting * and specific values in the same query. This is not supported in Oracle.',
240
+                    'query' => $this->getSQL(),
241
+                    'level' => ILogger::ERROR,
242
+                    'app' => 'core',
243
+                ]);
244
+            }
245
+        }
246
+
247
+        return $this->queryBuilder->execute();
248
+    }
249
+
250
+    /**
251
+     * Gets the complete SQL string formed by the current specifications of this QueryBuilder.
252
+     *
253
+     * <code>
254
+     *     $qb = $conn->getQueryBuilder()
255
+     *         ->select('u')
256
+     *         ->from('User', 'u')
257
+     *     echo $qb->getSQL(); // SELECT u FROM User u
258
+     * </code>
259
+     *
260
+     * @return string The SQL query string.
261
+     */
262
+    public function getSQL() {
263
+        return $this->queryBuilder->getSQL();
264
+    }
265
+
266
+    /**
267
+     * Sets a query parameter for the query being constructed.
268
+     *
269
+     * <code>
270
+     *     $qb = $conn->getQueryBuilder()
271
+     *         ->select('u')
272
+     *         ->from('users', 'u')
273
+     *         ->where('u.id = :user_id')
274
+     *         ->setParameter(':user_id', 1);
275
+     * </code>
276
+     *
277
+     * @param string|integer $key The parameter position or name.
278
+     * @param mixed $value The parameter value.
279
+     * @param string|null|int $type One of the IQueryBuilder::PARAM_* constants.
280
+     *
281
+     * @return $this This QueryBuilder instance.
282
+     */
283
+    public function setParameter($key, $value, $type = null) {
284
+        $this->queryBuilder->setParameter($key, $value, $type);
285
+
286
+        return $this;
287
+    }
288
+
289
+    /**
290
+     * Sets a collection of query parameters for the query being constructed.
291
+     *
292
+     * <code>
293
+     *     $qb = $conn->getQueryBuilder()
294
+     *         ->select('u')
295
+     *         ->from('users', 'u')
296
+     *         ->where('u.id = :user_id1 OR u.id = :user_id2')
297
+     *         ->setParameters(array(
298
+     *             ':user_id1' => 1,
299
+     *             ':user_id2' => 2
300
+     *         ));
301
+     * </code>
302
+     *
303
+     * @param array $params The query parameters to set.
304
+     * @param array $types The query parameters types to set.
305
+     *
306
+     * @return $this This QueryBuilder instance.
307
+     */
308
+    public function setParameters(array $params, array $types = []) {
309
+        $this->queryBuilder->setParameters($params, $types);
310
+
311
+        return $this;
312
+    }
313
+
314
+    /**
315
+     * Gets all defined query parameters for the query being constructed indexed by parameter index or name.
316
+     *
317
+     * @return array The currently defined query parameters indexed by parameter index or name.
318
+     */
319
+    public function getParameters() {
320
+        return $this->queryBuilder->getParameters();
321
+    }
322
+
323
+    /**
324
+     * Gets a (previously set) query parameter of the query being constructed.
325
+     *
326
+     * @param mixed $key The key (index or name) of the bound parameter.
327
+     *
328
+     * @return mixed The value of the bound parameter.
329
+     */
330
+    public function getParameter($key) {
331
+        return $this->queryBuilder->getParameter($key);
332
+    }
333
+
334
+    /**
335
+     * Gets all defined query parameter types for the query being constructed indexed by parameter index or name.
336
+     *
337
+     * @return array The currently defined query parameter types indexed by parameter index or name.
338
+     */
339
+    public function getParameterTypes() {
340
+        return $this->queryBuilder->getParameterTypes();
341
+    }
342
+
343
+    /**
344
+     * Gets a (previously set) query parameter type of the query being constructed.
345
+     *
346
+     * @param mixed $key The key (index or name) of the bound parameter type.
347
+     *
348
+     * @return mixed The value of the bound parameter type.
349
+     */
350
+    public function getParameterType($key) {
351
+        return $this->queryBuilder->getParameterType($key);
352
+    }
353
+
354
+    /**
355
+     * Sets the position of the first result to retrieve (the "offset").
356
+     *
357
+     * @param integer $firstResult The first result to return.
358
+     *
359
+     * @return $this This QueryBuilder instance.
360
+     */
361
+    public function setFirstResult($firstResult) {
362
+        $this->queryBuilder->setFirstResult($firstResult);
363
+
364
+        return $this;
365
+    }
366
+
367
+    /**
368
+     * Gets the position of the first result the query object was set to retrieve (the "offset").
369
+     * Returns NULL if {@link setFirstResult} was not applied to this QueryBuilder.
370
+     *
371
+     * @return integer The position of the first result.
372
+     */
373
+    public function getFirstResult() {
374
+        return $this->queryBuilder->getFirstResult();
375
+    }
376
+
377
+    /**
378
+     * Sets the maximum number of results to retrieve (the "limit").
379
+     *
380
+     * NOTE: Setting max results to "0" will cause mixed behaviour. While most
381
+     * of the databases will just return an empty result set, Oracle will return
382
+     * all entries.
383
+     *
384
+     * @param integer $maxResults The maximum number of results to retrieve.
385
+     *
386
+     * @return $this This QueryBuilder instance.
387
+     */
388
+    public function setMaxResults($maxResults) {
389
+        $this->queryBuilder->setMaxResults($maxResults);
390
+
391
+        return $this;
392
+    }
393
+
394
+    /**
395
+     * Gets the maximum number of results the query object was set to retrieve (the "limit").
396
+     * Returns NULL if {@link setMaxResults} was not applied to this query builder.
397
+     *
398
+     * @return int|null The maximum number of results.
399
+     */
400
+    public function getMaxResults() {
401
+        return $this->queryBuilder->getMaxResults();
402
+    }
403
+
404
+    /**
405
+     * Specifies an item that is to be returned in the query result.
406
+     * Replaces any previously specified selections, if any.
407
+     *
408
+     * <code>
409
+     *     $qb = $conn->getQueryBuilder()
410
+     *         ->select('u.id', 'p.id')
411
+     *         ->from('users', 'u')
412
+     *         ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id');
413
+     * </code>
414
+     *
415
+     * @param mixed ...$selects The selection expressions.
416
+     *
417
+     * '@return $this This QueryBuilder instance.
418
+     */
419
+    public function select(...$selects) {
420
+        if (count($selects) === 1 && is_array($selects[0])) {
421
+            $selects = $selects[0];
422
+        }
423
+
424
+        $this->queryBuilder->select(
425
+            $this->helper->quoteColumnNames($selects)
426
+        );
427
+
428
+        return $this;
429
+    }
430
+
431
+    /**
432
+     * Specifies an item that is to be returned with a different name in the query result.
433
+     *
434
+     * <code>
435
+     *     $qb = $conn->getQueryBuilder()
436
+     *         ->selectAlias('u.id', 'user_id')
437
+     *         ->from('users', 'u')
438
+     *         ->leftJoin('u', 'phonenumbers', 'p', 'u.id = p.user_id');
439
+     * </code>
440
+     *
441
+     * @param mixed $select The selection expressions.
442
+     * @param string $alias The column alias used in the constructed query.
443
+     *
444
+     * @return $this This QueryBuilder instance.
445
+     */
446
+    public function selectAlias($select, $alias) {
447
+        $this->queryBuilder->addSelect(
448
+            $this->helper->quoteColumnName($select) . ' AS ' . $this->helper->quoteColumnName($alias)
449
+        );
450
+
451
+        return $this;
452
+    }
453
+
454
+    /**
455
+     * Specifies an item that is to be returned uniquely in the query result.
456
+     *
457
+     * <code>
458
+     *     $qb = $conn->getQueryBuilder()
459
+     *         ->selectDistinct('type')
460
+     *         ->from('users');
461
+     * </code>
462
+     *
463
+     * @param mixed $select The selection expressions.
464
+     *
465
+     * @return $this This QueryBuilder instance.
466
+     */
467
+    public function selectDistinct($select) {
468
+        if (!is_array($select)) {
469
+            $select = [$select];
470
+        }
471
+
472
+        $quotedSelect = $this->helper->quoteColumnNames($select);
473
+
474
+        $this->queryBuilder->addSelect(
475
+            'DISTINCT ' . implode(', ', $quotedSelect)
476
+        );
477
+
478
+        return $this;
479
+    }
480
+
481
+    /**
482
+     * Adds an item that is to be returned in the query result.
483
+     *
484
+     * <code>
485
+     *     $qb = $conn->getQueryBuilder()
486
+     *         ->select('u.id')
487
+     *         ->addSelect('p.id')
488
+     *         ->from('users', 'u')
489
+     *         ->leftJoin('u', 'phonenumbers', 'u.id = p.user_id');
490
+     * </code>
491
+     *
492
+     * @param mixed ...$selects The selection expression.
493
+     *
494
+     * @return $this This QueryBuilder instance.
495
+     */
496
+    public function addSelect(...$selects) {
497
+        if (count($selects) === 1 && is_array($selects[0])) {
498
+            $selects = $selects[0];
499
+        }
500
+
501
+        $this->queryBuilder->addSelect(
502
+            $this->helper->quoteColumnNames($selects)
503
+        );
504
+
505
+        return $this;
506
+    }
507
+
508
+    /**
509
+     * Turns the query being built into a bulk delete query that ranges over
510
+     * a certain table.
511
+     *
512
+     * <code>
513
+     *     $qb = $conn->getQueryBuilder()
514
+     *         ->delete('users', 'u')
515
+     *         ->where('u.id = :user_id');
516
+     *         ->setParameter(':user_id', 1);
517
+     * </code>
518
+     *
519
+     * @param string $delete The table whose rows are subject to the deletion.
520
+     * @param string $alias The table alias used in the constructed query.
521
+     *
522
+     * @return $this This QueryBuilder instance.
523
+     */
524
+    public function delete($delete = null, $alias = null) {
525
+        $this->queryBuilder->delete(
526
+            $this->getTableName($delete),
527
+            $alias
528
+        );
529
+
530
+        return $this;
531
+    }
532
+
533
+    /**
534
+     * Turns the query being built into a bulk update query that ranges over
535
+     * a certain table
536
+     *
537
+     * <code>
538
+     *     $qb = $conn->getQueryBuilder()
539
+     *         ->update('users', 'u')
540
+     *         ->set('u.password', md5('password'))
541
+     *         ->where('u.id = ?');
542
+     * </code>
543
+     *
544
+     * @param string $update The table whose rows are subject to the update.
545
+     * @param string $alias The table alias used in the constructed query.
546
+     *
547
+     * @return $this This QueryBuilder instance.
548
+     */
549
+    public function update($update = null, $alias = null) {
550
+        $this->queryBuilder->update(
551
+            $this->getTableName($update),
552
+            $alias
553
+        );
554
+
555
+        return $this;
556
+    }
557
+
558
+    /**
559
+     * Turns the query being built into an insert query that inserts into
560
+     * a certain table
561
+     *
562
+     * <code>
563
+     *     $qb = $conn->getQueryBuilder()
564
+     *         ->insert('users')
565
+     *         ->values(
566
+     *             array(
567
+     *                 'name' => '?',
568
+     *                 'password' => '?'
569
+     *             )
570
+     *         );
571
+     * </code>
572
+     *
573
+     * @param string $insert The table into which the rows should be inserted.
574
+     *
575
+     * @return $this This QueryBuilder instance.
576
+     */
577
+    public function insert($insert = null) {
578
+        $this->queryBuilder->insert(
579
+            $this->getTableName($insert)
580
+        );
581
+
582
+        $this->lastInsertedTable = $insert;
583
+
584
+        return $this;
585
+    }
586
+
587
+    /**
588
+     * Creates and adds a query root corresponding to the table identified by the
589
+     * given alias, forming a cartesian product with any existing query roots.
590
+     *
591
+     * <code>
592
+     *     $qb = $conn->getQueryBuilder()
593
+     *         ->select('u.id')
594
+     *         ->from('users', 'u')
595
+     * </code>
596
+     *
597
+     * @param string $from The table.
598
+     * @param string|null $alias The alias of the table.
599
+     *
600
+     * @return $this This QueryBuilder instance.
601
+     */
602
+    public function from($from, $alias = null) {
603
+        $this->queryBuilder->from(
604
+            $this->getTableName($from),
605
+            $this->quoteAlias($alias)
606
+        );
607
+
608
+        return $this;
609
+    }
610
+
611
+    /**
612
+     * Creates and adds a join to the query.
613
+     *
614
+     * <code>
615
+     *     $qb = $conn->getQueryBuilder()
616
+     *         ->select('u.name')
617
+     *         ->from('users', 'u')
618
+     *         ->join('u', 'phonenumbers', 'p', 'p.is_primary = 1');
619
+     * </code>
620
+     *
621
+     * @param string $fromAlias The alias that points to a from clause.
622
+     * @param string $join The table name to join.
623
+     * @param string $alias The alias of the join table.
624
+     * @param string $condition The condition for the join.
625
+     *
626
+     * @return $this This QueryBuilder instance.
627
+     */
628
+    public function join($fromAlias, $join, $alias, $condition = null) {
629
+        $this->queryBuilder->join(
630
+            $this->quoteAlias($fromAlias),
631
+            $this->getTableName($join),
632
+            $this->quoteAlias($alias),
633
+            $condition
634
+        );
635
+
636
+        return $this;
637
+    }
638
+
639
+    /**
640
+     * Creates and adds a join to the query.
641
+     *
642
+     * <code>
643
+     *     $qb = $conn->getQueryBuilder()
644
+     *         ->select('u.name')
645
+     *         ->from('users', 'u')
646
+     *         ->innerJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1');
647
+     * </code>
648
+     *
649
+     * @param string $fromAlias The alias that points to a from clause.
650
+     * @param string $join The table name to join.
651
+     * @param string $alias The alias of the join table.
652
+     * @param string $condition The condition for the join.
653
+     *
654
+     * @return $this This QueryBuilder instance.
655
+     */
656
+    public function innerJoin($fromAlias, $join, $alias, $condition = null) {
657
+        $this->queryBuilder->innerJoin(
658
+            $this->quoteAlias($fromAlias),
659
+            $this->getTableName($join),
660
+            $this->quoteAlias($alias),
661
+            $condition
662
+        );
663
+
664
+        return $this;
665
+    }
666
+
667
+    /**
668
+     * Creates and adds a left join to the query.
669
+     *
670
+     * <code>
671
+     *     $qb = $conn->getQueryBuilder()
672
+     *         ->select('u.name')
673
+     *         ->from('users', 'u')
674
+     *         ->leftJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1');
675
+     * </code>
676
+     *
677
+     * @param string $fromAlias The alias that points to a from clause.
678
+     * @param string $join The table name to join.
679
+     * @param string $alias The alias of the join table.
680
+     * @param string $condition The condition for the join.
681
+     *
682
+     * @return $this This QueryBuilder instance.
683
+     */
684
+    public function leftJoin($fromAlias, $join, $alias, $condition = null) {
685
+        $this->queryBuilder->leftJoin(
686
+            $this->quoteAlias($fromAlias),
687
+            $this->getTableName($join),
688
+            $this->quoteAlias($alias),
689
+            $condition
690
+        );
691
+
692
+        return $this;
693
+    }
694
+
695
+    /**
696
+     * Creates and adds a right join to the query.
697
+     *
698
+     * <code>
699
+     *     $qb = $conn->getQueryBuilder()
700
+     *         ->select('u.name')
701
+     *         ->from('users', 'u')
702
+     *         ->rightJoin('u', 'phonenumbers', 'p', 'p.is_primary = 1');
703
+     * </code>
704
+     *
705
+     * @param string $fromAlias The alias that points to a from clause.
706
+     * @param string $join The table name to join.
707
+     * @param string $alias The alias of the join table.
708
+     * @param string $condition The condition for the join.
709
+     *
710
+     * @return $this This QueryBuilder instance.
711
+     */
712
+    public function rightJoin($fromAlias, $join, $alias, $condition = null) {
713
+        $this->queryBuilder->rightJoin(
714
+            $this->quoteAlias($fromAlias),
715
+            $this->getTableName($join),
716
+            $this->quoteAlias($alias),
717
+            $condition
718
+        );
719
+
720
+        return $this;
721
+    }
722
+
723
+    /**
724
+     * Sets a new value for a column in a bulk update query.
725
+     *
726
+     * <code>
727
+     *     $qb = $conn->getQueryBuilder()
728
+     *         ->update('users', 'u')
729
+     *         ->set('u.password', md5('password'))
730
+     *         ->where('u.id = ?');
731
+     * </code>
732
+     *
733
+     * @param string $key The column to set.
734
+     * @param ILiteral|IParameter|IQueryFunction|string $value The value, expression, placeholder, etc.
735
+     *
736
+     * @return $this This QueryBuilder instance.
737
+     */
738
+    public function set($key, $value) {
739
+        $this->queryBuilder->set(
740
+            $this->helper->quoteColumnName($key),
741
+            $this->helper->quoteColumnName($value)
742
+        );
743
+
744
+        return $this;
745
+    }
746
+
747
+    /**
748
+     * Specifies one or more restrictions to the query result.
749
+     * Replaces any previously specified restrictions, if any.
750
+     *
751
+     * <code>
752
+     *     $qb = $conn->getQueryBuilder()
753
+     *         ->select('u.name')
754
+     *         ->from('users', 'u')
755
+     *         ->where('u.id = ?');
756
+     *
757
+     *     // You can optionally programatically build and/or expressions
758
+     *     $qb = $conn->getQueryBuilder();
759
+     *
760
+     *     $or = $qb->expr()->orx();
761
+     *     $or->add($qb->expr()->eq('u.id', 1));
762
+     *     $or->add($qb->expr()->eq('u.id', 2));
763
+     *
764
+     *     $qb->update('users', 'u')
765
+     *         ->set('u.password', md5('password'))
766
+     *         ->where($or);
767
+     * </code>
768
+     *
769
+     * @param mixed ...$predicates The restriction predicates.
770
+     *
771
+     * @return $this This QueryBuilder instance.
772
+     */
773
+    public function where(...$predicates) {
774
+        call_user_func_array(
775
+            [$this->queryBuilder, 'where'],
776
+            $predicates
777
+        );
778
+
779
+        return $this;
780
+    }
781
+
782
+    /**
783
+     * Adds one or more restrictions to the query results, forming a logical
784
+     * conjunction with any previously specified restrictions.
785
+     *
786
+     * <code>
787
+     *     $qb = $conn->getQueryBuilder()
788
+     *         ->select('u')
789
+     *         ->from('users', 'u')
790
+     *         ->where('u.username LIKE ?')
791
+     *         ->andWhere('u.is_active = 1');
792
+     * </code>
793
+     *
794
+     * @param mixed ...$where The query restrictions.
795
+     *
796
+     * @return $this This QueryBuilder instance.
797
+     *
798
+     * @see where()
799
+     */
800
+    public function andWhere(...$where) {
801
+        call_user_func_array(
802
+            [$this->queryBuilder, 'andWhere'],
803
+            $where
804
+        );
805
+
806
+        return $this;
807
+    }
808
+
809
+    /**
810
+     * Adds one or more restrictions to the query results, forming a logical
811
+     * disjunction with any previously specified restrictions.
812
+     *
813
+     * <code>
814
+     *     $qb = $conn->getQueryBuilder()
815
+     *         ->select('u.name')
816
+     *         ->from('users', 'u')
817
+     *         ->where('u.id = 1')
818
+     *         ->orWhere('u.id = 2');
819
+     * </code>
820
+     *
821
+     * @param mixed ...$where The WHERE statement.
822
+     *
823
+     * @return $this This QueryBuilder instance.
824
+     *
825
+     * @see where()
826
+     */
827
+    public function orWhere(...$where) {
828
+        call_user_func_array(
829
+            [$this->queryBuilder, 'orWhere'],
830
+            $where
831
+        );
832
+
833
+        return $this;
834
+    }
835
+
836
+    /**
837
+     * Specifies a grouping over the results of the query.
838
+     * Replaces any previously specified groupings, if any.
839
+     *
840
+     * <code>
841
+     *     $qb = $conn->getQueryBuilder()
842
+     *         ->select('u.name')
843
+     *         ->from('users', 'u')
844
+     *         ->groupBy('u.id');
845
+     * </code>
846
+     *
847
+     * @param mixed ...$groupBys The grouping expression.
848
+     *
849
+     * @return $this This QueryBuilder instance.
850
+     */
851
+    public function groupBy(...$groupBys) {
852
+        if (count($groupBys) === 1 && is_array($groupBys[0])) {
853
+            $groupBys = $groupBys[0];
854
+        }
855
+
856
+        call_user_func_array(
857
+            [$this->queryBuilder, 'groupBy'],
858
+            $this->helper->quoteColumnNames($groupBys)
859
+        );
860
+
861
+        return $this;
862
+    }
863
+
864
+    /**
865
+     * Adds a grouping expression to the query.
866
+     *
867
+     * <code>
868
+     *     $qb = $conn->getQueryBuilder()
869
+     *         ->select('u.name')
870
+     *         ->from('users', 'u')
871
+     *         ->groupBy('u.lastLogin');
872
+     *         ->addGroupBy('u.createdAt')
873
+     * </code>
874
+     *
875
+     * @param mixed ...$groupBy The grouping expression.
876
+     *
877
+     * @return $this This QueryBuilder instance.
878
+     */
879
+    public function addGroupBy(...$groupBys) {
880
+        if (count($groupBys) === 1 && is_array($groupBys[0])) {
881
+            $$groupBys = $groupBys[0];
882
+        }
883
+
884
+        call_user_func_array(
885
+            [$this->queryBuilder, 'addGroupBy'],
886
+            $this->helper->quoteColumnNames($groupBys)
887
+        );
888
+
889
+        return $this;
890
+    }
891
+
892
+    /**
893
+     * Sets a value for a column in an insert query.
894
+     *
895
+     * <code>
896
+     *     $qb = $conn->getQueryBuilder()
897
+     *         ->insert('users')
898
+     *         ->values(
899
+     *             array(
900
+     *                 'name' => '?'
901
+     *             )
902
+     *         )
903
+     *         ->setValue('password', '?');
904
+     * </code>
905
+     *
906
+     * @param string $column The column into which the value should be inserted.
907
+     * @param IParameter|string $value The value that should be inserted into the column.
908
+     *
909
+     * @return $this This QueryBuilder instance.
910
+     */
911
+    public function setValue($column, $value) {
912
+        $this->queryBuilder->setValue(
913
+            $this->helper->quoteColumnName($column),
914
+            (string) $value
915
+        );
916
+
917
+        return $this;
918
+    }
919
+
920
+    /**
921
+     * Specifies values for an insert query indexed by column names.
922
+     * Replaces any previous values, if any.
923
+     *
924
+     * <code>
925
+     *     $qb = $conn->getQueryBuilder()
926
+     *         ->insert('users')
927
+     *         ->values(
928
+     *             array(
929
+     *                 'name' => '?',
930
+     *                 'password' => '?'
931
+     *             )
932
+     *         );
933
+     * </code>
934
+     *
935
+     * @param array $values The values to specify for the insert query indexed by column names.
936
+     *
937
+     * @return $this This QueryBuilder instance.
938
+     */
939
+    public function values(array $values) {
940
+        $quotedValues = [];
941
+        foreach ($values as $key => $value) {
942
+            $quotedValues[$this->helper->quoteColumnName($key)] = $value;
943
+        }
944
+
945
+        $this->queryBuilder->values($quotedValues);
946
+
947
+        return $this;
948
+    }
949
+
950
+    /**
951
+     * Specifies a restriction over the groups of the query.
952
+     * Replaces any previous having restrictions, if any.
953
+     *
954
+     * @param mixed ...$having The restriction over the groups.
955
+     *
956
+     * @return $this This QueryBuilder instance.
957
+     */
958
+    public function having(...$having) {
959
+        call_user_func_array(
960
+            [$this->queryBuilder, 'having'],
961
+            $having
962
+        );
963
+
964
+        return $this;
965
+    }
966
+
967
+    /**
968
+     * Adds a restriction over the groups of the query, forming a logical
969
+     * conjunction with any existing having restrictions.
970
+     *
971
+     * @param mixed ...$having The restriction to append.
972
+     *
973
+     * @return $this This QueryBuilder instance.
974
+     */
975
+    public function andHaving(...$having) {
976
+        call_user_func_array(
977
+            [$this->queryBuilder, 'andHaving'],
978
+            $having
979
+        );
980
+
981
+        return $this;
982
+    }
983
+
984
+    /**
985
+     * Adds a restriction over the groups of the query, forming a logical
986
+     * disjunction with any existing having restrictions.
987
+     *
988
+     * @param mixed ...$having The restriction to add.
989
+     *
990
+     * @return $this This QueryBuilder instance.
991
+     */
992
+    public function orHaving(...$having) {
993
+        call_user_func_array(
994
+            [$this->queryBuilder, 'orHaving'],
995
+            $having
996
+        );
997
+
998
+        return $this;
999
+    }
1000
+
1001
+    /**
1002
+     * Specifies an ordering for the query results.
1003
+     * Replaces any previously specified orderings, if any.
1004
+     *
1005
+     * @param string $sort The ordering expression.
1006
+     * @param string $order The ordering direction.
1007
+     *
1008
+     * @return $this This QueryBuilder instance.
1009
+     */
1010
+    public function orderBy($sort, $order = null) {
1011
+        $this->queryBuilder->orderBy(
1012
+            $this->helper->quoteColumnName($sort),
1013
+            $order
1014
+        );
1015
+
1016
+        return $this;
1017
+    }
1018
+
1019
+    /**
1020
+     * Adds an ordering to the query results.
1021
+     *
1022
+     * @param string $sort The ordering expression.
1023
+     * @param string $order The ordering direction.
1024
+     *
1025
+     * @return $this This QueryBuilder instance.
1026
+     */
1027
+    public function addOrderBy($sort, $order = null) {
1028
+        $this->queryBuilder->addOrderBy(
1029
+            $this->helper->quoteColumnName($sort),
1030
+            $order
1031
+        );
1032
+
1033
+        return $this;
1034
+    }
1035
+
1036
+    /**
1037
+     * Gets a query part by its name.
1038
+     *
1039
+     * @param string $queryPartName
1040
+     *
1041
+     * @return mixed
1042
+     */
1043
+    public function getQueryPart($queryPartName) {
1044
+        return $this->queryBuilder->getQueryPart($queryPartName);
1045
+    }
1046
+
1047
+    /**
1048
+     * Gets all query parts.
1049
+     *
1050
+     * @return array
1051
+     */
1052
+    public function getQueryParts() {
1053
+        return $this->queryBuilder->getQueryParts();
1054
+    }
1055
+
1056
+    /**
1057
+     * Resets SQL parts.
1058
+     *
1059
+     * @param array|null $queryPartNames
1060
+     *
1061
+     * @return $this This QueryBuilder instance.
1062
+     */
1063
+    public function resetQueryParts($queryPartNames = null) {
1064
+        $this->queryBuilder->resetQueryParts($queryPartNames);
1065
+
1066
+        return $this;
1067
+    }
1068
+
1069
+    /**
1070
+     * Resets a single SQL part.
1071
+     *
1072
+     * @param string $queryPartName
1073
+     *
1074
+     * @return $this This QueryBuilder instance.
1075
+     */
1076
+    public function resetQueryPart($queryPartName) {
1077
+        $this->queryBuilder->resetQueryPart($queryPartName);
1078
+
1079
+        return $this;
1080
+    }
1081
+
1082
+    /**
1083
+     * Creates a new named parameter and bind the value $value to it.
1084
+     *
1085
+     * This method provides a shortcut for PDOStatement::bindValue
1086
+     * when using prepared statements.
1087
+     *
1088
+     * The parameter $value specifies the value that you want to bind. If
1089
+     * $placeholder is not provided bindValue() will automatically create a
1090
+     * placeholder for you. An automatic placeholder will be of the name
1091
+     * ':dcValue1', ':dcValue2' etc.
1092
+     *
1093
+     * For more information see {@link http://php.net/pdostatement-bindparam}
1094
+     *
1095
+     * Example:
1096
+     * <code>
1097
+     * $value = 2;
1098
+     * $q->eq( 'id', $q->bindValue( $value ) );
1099
+     * $stmt = $q->executeQuery(); // executed with 'id = 2'
1100
+     * </code>
1101
+     *
1102
+     * @license New BSD License
1103
+     * @link http://www.zetacomponents.org
1104
+     *
1105
+     * @param mixed $value
1106
+     * @param mixed $type
1107
+     * @param string $placeHolder The name to bind with. The string must start with a colon ':'.
1108
+     *
1109
+     * @return IParameter the placeholder name used.
1110
+     */
1111
+    public function createNamedParameter($value, $type = IQueryBuilder::PARAM_STR, $placeHolder = null) {
1112
+        return new Parameter($this->queryBuilder->createNamedParameter($value, $type, $placeHolder));
1113
+    }
1114
+
1115
+    /**
1116
+     * Creates a new positional parameter and bind the given value to it.
1117
+     *
1118
+     * Attention: If you are using positional parameters with the query builder you have
1119
+     * to be very careful to bind all parameters in the order they appear in the SQL
1120
+     * statement , otherwise they get bound in the wrong order which can lead to serious
1121
+     * bugs in your code.
1122
+     *
1123
+     * Example:
1124
+     * <code>
1125
+     *  $qb = $conn->getQueryBuilder();
1126
+     *  $qb->select('u.*')
1127
+     *     ->from('users', 'u')
1128
+     *     ->where('u.username = ' . $qb->createPositionalParameter('Foo', IQueryBuilder::PARAM_STR))
1129
+     *     ->orWhere('u.username = ' . $qb->createPositionalParameter('Bar', IQueryBuilder::PARAM_STR))
1130
+     * </code>
1131
+     *
1132
+     * @param mixed $value
1133
+     * @param integer $type
1134
+     *
1135
+     * @return IParameter
1136
+     */
1137
+    public function createPositionalParameter($value, $type = IQueryBuilder::PARAM_STR) {
1138
+        return new Parameter($this->queryBuilder->createPositionalParameter($value, $type));
1139
+    }
1140
+
1141
+    /**
1142
+     * Creates a new parameter
1143
+     *
1144
+     * Example:
1145
+     * <code>
1146
+     *  $qb = $conn->getQueryBuilder();
1147
+     *  $qb->select('u.*')
1148
+     *     ->from('users', 'u')
1149
+     *     ->where('u.username = ' . $qb->createParameter('name'))
1150
+     *     ->setParameter('name', 'Bar', IQueryBuilder::PARAM_STR))
1151
+     * </code>
1152
+     *
1153
+     * @param string $name
1154
+     *
1155
+     * @return IParameter
1156
+     */
1157
+    public function createParameter($name) {
1158
+        return new Parameter(':' . $name);
1159
+    }
1160
+
1161
+    /**
1162
+     * Creates a new function
1163
+     *
1164
+     * Attention: Column names inside the call have to be quoted before hand
1165
+     *
1166
+     * Example:
1167
+     * <code>
1168
+     *  $qb = $conn->getQueryBuilder();
1169
+     *  $qb->select($qb->createFunction('COUNT(*)'))
1170
+     *     ->from('users', 'u')
1171
+     *  echo $qb->getSQL(); // SELECT COUNT(*) FROM `users` u
1172
+     * </code>
1173
+     * <code>
1174
+     *  $qb = $conn->getQueryBuilder();
1175
+     *  $qb->select($qb->createFunction('COUNT(`column`)'))
1176
+     *     ->from('users', 'u')
1177
+     *  echo $qb->getSQL(); // SELECT COUNT(`column`) FROM `users` u
1178
+     * </code>
1179
+     *
1180
+     * @param string $call
1181
+     *
1182
+     * @return IQueryFunction
1183
+     */
1184
+    public function createFunction($call) {
1185
+        return new QueryFunction($call);
1186
+    }
1187
+
1188
+    /**
1189
+     * Used to get the id of the last inserted element
1190
+     * @return int
1191
+     * @throws \BadMethodCallException When being called before an insert query has been run.
1192
+     */
1193
+    public function getLastInsertId() {
1194
+        if ($this->getType() === \Doctrine\DBAL\Query\QueryBuilder::INSERT && $this->lastInsertedTable) {
1195
+            // lastInsertId() needs the prefix but no quotes
1196
+            $table = $this->prefixTableName($this->lastInsertedTable);
1197
+            return (int) $this->connection->lastInsertId($table);
1198
+        }
1199
+
1200
+        throw new \BadMethodCallException('Invalid call to getLastInsertId without using insert() before.');
1201
+    }
1202
+
1203
+    /**
1204
+     * Returns the table name quoted and with database prefix as needed by the implementation
1205
+     *
1206
+     * @param string $table
1207
+     * @return string
1208
+     */
1209
+    public function getTableName($table) {
1210
+        if ($table instanceof IQueryFunction) {
1211
+            return (string) $table;
1212
+        }
1213
+
1214
+        $table = $this->prefixTableName($table);
1215
+        return $this->helper->quoteColumnName($table);
1216
+    }
1217
+
1218
+    /**
1219
+     * Returns the table name with database prefix as needed by the implementation
1220
+     *
1221
+     * @param string $table
1222
+     * @return string
1223
+     */
1224
+    protected function prefixTableName($table) {
1225
+        if ($this->automaticTablePrefix === false || strpos($table, '*PREFIX*') === 0) {
1226
+            return $table;
1227
+        }
1228
+
1229
+        return '*PREFIX*' . $table;
1230
+    }
1231
+
1232
+    /**
1233
+     * Returns the column name quoted and with table alias prefix as needed by the implementation
1234
+     *
1235
+     * @param string $column
1236
+     * @param string $tableAlias
1237
+     * @return string
1238
+     */
1239
+    public function getColumnName($column, $tableAlias = '') {
1240
+        if ($tableAlias !== '') {
1241
+            $tableAlias .= '.';
1242
+        }
1243
+
1244
+        return $this->helper->quoteColumnName($tableAlias . $column);
1245
+    }
1246
+
1247
+    /**
1248
+     * Returns the column name quoted and with table alias prefix as needed by the implementation
1249
+     *
1250
+     * @param string $alias
1251
+     * @return string
1252
+     */
1253
+    public function quoteAlias($alias) {
1254
+        if ($alias === '' || $alias === null) {
1255
+            return $alias;
1256
+        }
1257
+
1258
+        return $this->helper->quoteColumnName($alias);
1259
+    }
1260 1260
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -198,11 +198,11 @@  discard block
 block discarded – undo
198 198
 				$params = [];
199 199
 				foreach ($this->getParameters() as $placeholder => $value) {
200 200
 					if ($value instanceof \DateTime) {
201
-						$params[] = $placeholder . ' => DateTime:\'' . $value->format('c') . '\'';
201
+						$params[] = $placeholder.' => DateTime:\''.$value->format('c').'\'';
202 202
 					} elseif (is_array($value)) {
203
-						$params[] = $placeholder . ' => (\'' . implode('\', \'', $value) . '\')';
203
+						$params[] = $placeholder.' => (\''.implode('\', \'', $value).'\')';
204 204
 					} else {
205
-						$params[] = $placeholder . ' => \'' . $value . '\'';
205
+						$params[] = $placeholder.' => \''.$value.'\'';
206 206
 					}
207 207
 				}
208 208
 				if (empty($params)) {
@@ -226,10 +226,10 @@  discard block
 block discarded – undo
226 226
 
227 227
 		if (!empty($this->getQueryPart('select'))) {
228 228
 			$select = $this->getQueryPart('select');
229
-			$hasSelectAll = array_filter($select, static function ($s) {
229
+			$hasSelectAll = array_filter($select, static function($s) {
230 230
 				return $s === '*';
231 231
 			});
232
-			$hasSelectSpecific = array_filter($select, static function ($s) {
232
+			$hasSelectSpecific = array_filter($select, static function($s) {
233 233
 				return $s !== '*';
234 234
 			});
235 235
 
@@ -445,7 +445,7 @@  discard block
 block discarded – undo
445 445
 	 */
446 446
 	public function selectAlias($select, $alias) {
447 447
 		$this->queryBuilder->addSelect(
448
-			$this->helper->quoteColumnName($select) . ' AS ' . $this->helper->quoteColumnName($alias)
448
+			$this->helper->quoteColumnName($select).' AS '.$this->helper->quoteColumnName($alias)
449 449
 		);
450 450
 
451 451
 		return $this;
@@ -472,7 +472,7 @@  discard block
 block discarded – undo
472 472
 		$quotedSelect = $this->helper->quoteColumnNames($select);
473 473
 
474 474
 		$this->queryBuilder->addSelect(
475
-			'DISTINCT ' . implode(', ', $quotedSelect)
475
+			'DISTINCT '.implode(', ', $quotedSelect)
476 476
 		);
477 477
 
478 478
 		return $this;
@@ -1155,7 +1155,7 @@  discard block
 block discarded – undo
1155 1155
 	 * @return IParameter
1156 1156
 	 */
1157 1157
 	public function createParameter($name) {
1158
-		return new Parameter(':' . $name);
1158
+		return new Parameter(':'.$name);
1159 1159
 	}
1160 1160
 
1161 1161
 	/**
@@ -1226,7 +1226,7 @@  discard block
 block discarded – undo
1226 1226
 			return $table;
1227 1227
 		}
1228 1228
 
1229
-		return '*PREFIX*' . $table;
1229
+		return '*PREFIX*'.$table;
1230 1230
 	}
1231 1231
 
1232 1232
 	/**
@@ -1241,7 +1241,7 @@  discard block
 block discarded – undo
1241 1241
 			$tableAlias .= '.';
1242 1242
 		}
1243 1243
 
1244
-		return $this->helper->quoteColumnName($tableAlias . $column);
1244
+		return $this->helper->quoteColumnName($tableAlias.$column);
1245 1245
 	}
1246 1246
 
1247 1247
 	/**
Please login to merge, or discard this patch.