TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Database\Query;
|
||||
|
||||
use Doctrine\DBAL\Connection as DoctrineConnection;
|
||||
use TYPO3\CMS\Core\Database\Connection as Typo3Connection;
|
||||
|
||||
/**
|
||||
* Provides functionality to generate and execute row based bulk INSERT statements.
|
||||
*
|
||||
* Based on work by Steve Müller <st.mueller@dzh-online.de> for the Doctrine project,
|
||||
* licensed under the MIT license.
|
||||
*
|
||||
* This class will be removed from core and the functionality will be provided by
|
||||
* the upstream implementation once the pull request has been merged into Doctrine DBAL.
|
||||
*
|
||||
* @see https://github.com/doctrine/dbal/pull/682
|
||||
* @internal
|
||||
*/
|
||||
class BulkInsertQuery
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $columns;
|
||||
|
||||
/**
|
||||
* @var DoctrineConnection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $parameters = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $types = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $values = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param DoctrineConnection $connection The connection to use for query execution.
|
||||
* @param string $table The name of the table to insert rows into.
|
||||
* @param string[] $columns The names of the columns to insert values into.
|
||||
* Can be left empty to allow arbitrary row inserts based on the table's column order.
|
||||
*/
|
||||
public function __construct(DoctrineConnection $connection, string $table, array $columns = [])
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->table = $connection->quoteIdentifier($table);
|
||||
$this->columns = $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the bulk insert statement as string.
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->getSQL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a set of values to the bulk insert query to be inserted as a row into the specified table.
|
||||
*
|
||||
* @param array $values The set of values to be inserted as a row into the table.
|
||||
* If no columns have been specified for insertion, this can be
|
||||
* an arbitrary list of values to be inserted into the table.
|
||||
* Otherwise the values' keys have to match either one of the
|
||||
* specified column names or indexes.
|
||||
* @param array $types The types for the given values to bind to the query.
|
||||
* If no columns have been specified for insertion, the types'
|
||||
* keys will be matched against the given values' keys.
|
||||
* Otherwise the types' keys will be matched against the
|
||||
* specified column names and indexes.
|
||||
* Non-matching keys will be discarded, missing keys will not
|
||||
* be bound to a specific type.
|
||||
*
|
||||
* @throws \InvalidArgumentException if columns were specified for this query
|
||||
* and either no value for one of the specified
|
||||
* columns is given or multiple values are given
|
||||
* for a single column (named and indexed) or
|
||||
* multiple types are given for a single column
|
||||
* (named and indexed).
|
||||
*/
|
||||
public function addValues(array $values, array $types = [])
|
||||
{
|
||||
$valueSet = [];
|
||||
|
||||
if (empty($this->columns)) {
|
||||
foreach ($values as $index => $value) {
|
||||
$this->parameters[] = $value;
|
||||
$this->types[] = $types[$index] ?? null;
|
||||
$valueSet[] = '?';
|
||||
}
|
||||
|
||||
$this->values[] = $valueSet;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->columns as $index => $column) {
|
||||
$namedValue = isset($values[$column]) || array_key_exists($column, $values);
|
||||
$positionalValue = isset($values[$index]) || array_key_exists($index, $values);
|
||||
|
||||
if (!$namedValue && !$positionalValue) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('No value specified for column %s (index %d).', $column, $index),
|
||||
1476049651
|
||||
);
|
||||
}
|
||||
|
||||
if ($namedValue && $positionalValue && $values[$column] !== $values[$index]) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('Multiple values specified for column %s (index %d).', $column, $index),
|
||||
1476049652
|
||||
);
|
||||
}
|
||||
|
||||
$this->parameters[] = $namedValue ? $values[$column] : $values[$index];
|
||||
$valueSet[] = '?';
|
||||
|
||||
$namedType = isset($types[$column]);
|
||||
$positionalType = isset($types[$index]);
|
||||
|
||||
if ($namedType && $positionalType && $types[$column] !== $types[$index]) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('Multiple types specified for column %s (index %d).', $column, $index),
|
||||
1476049653
|
||||
);
|
||||
}
|
||||
|
||||
if ($namedType) {
|
||||
$this->types[] = $types[$column];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($positionalType) {
|
||||
$this->types[] = $types[$index];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->types[] = Typo3Connection::PARAM_STR;
|
||||
}
|
||||
|
||||
$this->values[] = $valueSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes this INSERT query using the bound parameters and their types.
|
||||
*
|
||||
* @return int The number of affected rows.
|
||||
*
|
||||
* @throws \LogicException if this query contains more rows than acceptable
|
||||
* for a single INSERT statement by the underlying platform.
|
||||
*/
|
||||
public function execute(): int
|
||||
{
|
||||
return $this->connection->executeStatement($this->getSQL(), $this->parameters, $this->types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameters for this INSERT query being constructed indexed by parameter index.
|
||||
*/
|
||||
public function getParameters(): array
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameter types for this INSERT query being constructed indexed by parameter index.
|
||||
*/
|
||||
public function getParameterTypes(): array
|
||||
{
|
||||
return $this->types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SQL formed by the current specifications of this INSERT query.
|
||||
*
|
||||
*
|
||||
* @throws \LogicException if no values have been specified yet.
|
||||
*/
|
||||
public function getSQL(): string
|
||||
{
|
||||
if (empty($this->values)) {
|
||||
throw new \LogicException(
|
||||
'You need to add at least one set of values before generating the SQL.',
|
||||
1476049702
|
||||
);
|
||||
}
|
||||
|
||||
$connection = $this->connection;
|
||||
$columnList = '';
|
||||
|
||||
if (!empty($this->columns)) {
|
||||
$columnList = sprintf(
|
||||
' (%s)',
|
||||
implode(
|
||||
', ',
|
||||
array_map(
|
||||
static function (string $column) use ($connection): string {
|
||||
return $connection->quoteIdentifier($column);
|
||||
},
|
||||
$this->columns
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'INSERT INTO %s%s VALUES (%s)',
|
||||
$this->table,
|
||||
$columnList,
|
||||
implode(
|
||||
'), (',
|
||||
array_map(
|
||||
static function (array $valueSet): string {
|
||||
return implode(', ', $valueSet);
|
||||
},
|
||||
$this->values
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user