Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bulk inserts #2762

Closed
wants to merge 2 commits into from
Closed

Bulk inserts #2762

wants to merge 2 commits into from

Conversation

edefimov
Copy link

This is an updated version of PR #682 solving issue #1392 refactored for php 7.1 and with small improvements like bulk insert execution even when the number of rows exceeds database limits.

@Ocramius Ocramius added this to the 2.7 milestone Jul 2, 2017
@Ocramius Ocramius requested a review from deeky666 July 2, 2017 10:12
@Ocramius
Copy link
Member

Ocramius commented Jul 2, 2017

@deeky666 this patch introduces some fixups on your existing bulk-insert patch.

Specifically, it will force transactions when an insert operation is acting on a range of values bigger than what the database supports.

We should consider further scenarios too:

  • when a query string is bigger than what is endorsed by the DB engine
  • when the number of bound parameters is bigger than what is allowed by the DB engine (for example, that's 1000 on OracleDB)

@morozov morozov removed this from the 2.7.0 milestone Mar 29, 2018
@Majkl578 Majkl578 added this to the 2.8.0 milestone Mar 29, 2018
Copy link
Member

@morozov morozov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@edefimov thank you for the patch. Please rebase it and make sure the most generic cases are tested in a functional way.

{
$valueSet = [];
foreach ($values as $index => $value) {
$this->parameters[] = $value; // todo: allow expressions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the semantics of $values from values to expressions would be a breaking change. It would make sense to implement it to avoid the breakage and maintain compatibility with QueryBuilder.

$valueSet = array();
foreach ($this->columns as $index => $column) {
$namedValue = isset($values[$column]) || array_key_exists($column, $values);
$positionalValue = isset($values[$index]) || array_key_exists($index, $values);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to allow mixing named and positional elements in the same call? Instead, we could see if $values is a numeric or associative array and act based on that.

$this->table->getQuotedName($platform),
$columnList,
implode(
'), (',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This syntax is not supported by Oracle. The following workaround could be used instead:

INSERT INTO MY_TABLE
SELECT 1, 2 FROM DUAL
UNION ALL
SELECT 3, 4 FROM DUAL

/**
* @param string $alias
* @param array $registeredAliases
*
* @return \Doctrine\DBAL\Query\QueryException
*/
static public function unknownAlias($alias, $registeredAliases)
static public function unknownAlias(string $alias, array $registeredAliases): QueryException
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change.

*/
public function getInsertMaxRows()
{
return 10;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could PHPUnit mocking API be used instead? Otherwise, there's a tight coupling between a globally used mock and the tests using it.


$query->addValues(array('bar', 'baz', 'named' => 'bloo'));

$this->assertSame("INSERT INTO foo VALUES (?, ?, ?)", $query->getSQL());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the "named" column is explicitly specified in the call above, how does this guarantee that the third value will be associated with that column? Looks like a dangerous feature.


$query = new BulkInsertQuery($this->connection, 'foo');

for ($i = 0; $i <= $insertMaxRows; $i++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this expected to work with the platforms which don't have the max rows limitation?

for ($i = 0; $i < $parameterCount; $i++) {
$valueSet[] = "\\(\\?\\)";
}
$sqlRegExp = "INSERT\\s+INTO\\s+foo\\s+\\(id\\)\s+VALUES\\s+" . implode("\\s*,\\s*", $valueSet);
Copy link
Member

@morozov morozov Jun 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This basically duplicates the implementation of building SQL and will have to be significantly reworked to implement compatibility with Oracle. It's enough to leave the functional part of the test. SQL is a platform-specific implementation detail.


$query = new BulkInsertQuery($this->connection, 'foo', ['id']);

$numberOfRows = 4*$insertMaxRows + (int) ceil($insertMaxRows / 2);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this formula come from?


$numberOfRows = 4*$insertMaxRows + (int) ceil($insertMaxRows / 2);
for ($i = 0; $i < $numberOfRows; $i++) {
$query->addValues(array('id' => $i), array('id' => 'type' . $i));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is a type equals to 'type' . $i expected to work?

@Majkl578 Majkl578 modified the milestones: 2.8.0, 2.9.0 Jun 14, 2018
@morozov morozov removed this from the 2.9.0 milestone Dec 2, 2018
@karousn
Copy link

karousn commented Sep 10, 2019

any news about this ? available in next major version(3) ?

@SenseException
Copy link
Member

The change requests weren't covered yet, so there is no way to tell when this can be merged and introduced to a new version.

@claudiobizzotto
Copy link

Until this gets incorporated into the next major release, here's a temporary option: https://github.com/pharako/mysql-dbal

@takahashiyuya
Copy link

i hope can use it.

Base automatically changed from master to 4.0.x January 22, 2021 07:43
@morozov
Copy link
Member

morozov commented Oct 26, 2021

Closing as stale.

@morozov morozov closed this Oct 26, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 27, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants