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
Bug with $db->setQueryOption('IGNORE')->insertMulti #770
Comments
because this looks like a regular mysql error, i would suggest, you show us your |
$array_of_arrays is arbitrary - the issue is because the getLastQuery doesn't have "Ignore" in it - if it did then the script wouldn't bomb. For illustration I've just tried with the following and had the same error: $array_of_arrays = array(
array('name' =>'recordname', 'date' => '2018-07-05'),
array('name' =>'recordname', 'date' => '2018-07-05')
); |
I dunno... the code logic seems sound.. It goes insertMulti -> insert -> _buildInsert which then puts the option into the query
And Do you get the same issue if you
|
maybe a trace shows more infos what´s going on here 🤔 |
Array
(
[0] => Array
(
[0] => INSERT IGNORE INTO db.table (`name`, `date`) VALUES ('test', '2018-07-18')
[1] => 0.61394000053406
[2] => MysqliDb->insertMulti() >> file "/dir/bulkInsertTest.php" line #102
)
[1] => Array
(
[0] => INSERT INTO db.table (`name`, `date`) VALUES ('test', '2018-07-18')
[1] => 0.54291319847107
[2] => MysqliDb->insertMulti() >> file "/dir/bulkInsertTest.php" line #102
)
)
|
@LunarDevelopment i am new to this project, so sorry if i can´t offer much help. i study some issues here to evaluate if this class works for me. after seeing your case i got interested in this so i ask myself, what would i do ? 😏 i saw this class offers a trace, which seems to be nice feature. |
@michabbb Ah sorry, because you were being so helpful I assumed you were a collaborator or something. Yeah it looks like the library is forgetting that IGNORE is set as a query option after first query.. I'll play around and see if I can fix, but any external help is much appreciated - it seems like a fairly large oversight in the library considering there's a closed thread about this issue in 2017. |
This is due to What needs to happen, is in
|
good catch guys. should be pretty trivial to fix |
actually my above wont fully work, as @avbdr has some custom class variables in setQueryOption on certain ifs that arent populated over to
|
yep. we would need to store those variables before insert cycle, and then redefine them before each insert() |
@avbdr i've updated my above fix... that should be enough? |
you would need to store all of those |
@avbdr I have, refer the above fix :) in my post earlier |
seems i have checked cached page. Yes, your fix looks like a good one. |
The below from @VeNoMouS kinda works.. but produces the following : Stack trace shows that it's adding If there are no duplicates then the script completes and commits rows to DB. If there are duplicates then the script doesn't commit any of the rows to the DB and returns Minor issue is:
foreach ($options as $k => $v) {
$this->${k} = $v;
} Function I've used from @VeNoMouS is ... public function insertMulti($tableName, array $multiInsertData, array $dataKeys = null)
{
// only auto-commit our inserts, if no transaction is currently running
$autoCommit = (isset($this->_transaction_in_progress) ? !$this->_transaction_in_progress : true);
$ids = array();
$options = [
'_queryOptions' => $this->_queryOptions,
'_nestJoin' => $this->_nestJoin,
'_forUpdate' => $this->_forUpdate,
'_lockInShareMode' => $this->_lockInShareMode
];
if($autoCommit) {
$this->startTransaction();
}
foreach ($multiInsertData as $insertData) {
if($dataKeys !== null) {
// apply column-names if given, else assume they're already given in the data
$insertData = array_combine($dataKeys, $insertData);
}
foreach ($options as $k => $v) {
$this->${k} = $v;
}
$id = $this->insert($tableName, $insertData);
if(!$id) {
if($autoCommit) {
$this->rollback();
}
return false;
}
$ids[] = $id;
}
if($autoCommit) {
$this->commit();
}
return $ids;
} |
thanks. This is an expected behavior since multiInsert() does all data entry within a single transaction as you can see from the function. @VeNoMouS can you please fix a warning and submit a pull request with this change? |
function returns false in case of failure and you can use getLastError() to get an error. |
I've submitted a pull request with a fix for the k warning. When using multi insert with ignore though, is it desired to roll back? If so, then the "ignore" option is redundant with insertMulti. If roll back is desired then I'll just create an extension of the class. |
|
this should properly handle IGNORE case |
@avbdr just tested and that doesn't work, can't see why not though. I tried moving a bit of logic around too: $id = $this->insert($tableName, $insertData);
if(!$id ) {
if($autoCommit && !in_array('IGNORE', $this->_queryOptions)) {
$this->rollback();
}
return false;
}
$ids[] = $id; |
Seems solid, returns array of ids/ true and false if IGNORE is set : public function insertMulti($tableName, array $multiInsertData, array $dataKeys = null)
{
// only auto-commit our inserts, if no transaction is currently running
$autoCommit = (isset($this->_transaction_in_progress) ? !$this->_transaction_in_progress : true);
$ids = array();
$options = [
'_queryOptions' => $this->_queryOptions,
'_nestJoin' => $this->_nestJoin,
'_forUpdate' => $this->_forUpdate,
'_lockInShareMode' => $this->_lockInShareMode
];
if($autoCommit) {
$this->startTransaction();
}
foreach ($multiInsertData as $insertData) {
if($dataKeys !== null) {
// apply column-names if given, else assume they're already given in the data
$insertData = array_combine($dataKeys, $insertData);
}
foreach ($options as $k => $v) {
$this->${'k'} = $v;
}
$id = $this->insert($tableName, $insertData);
if(!$id ) {
if($autoCommit && !in_array('IGNORE', $options['_queryOptions'])) {
$this->rollback();
}
}
$ids[] = $id;
}
if($autoCommit) {
$this->commit();
}
return $ids;
} |
I know we're solving a bug in the above, but in thinking a bit more about it - there's no speed benefit to using insertMulti over using insert in a foreach in the calling script. Surely insertMulti should build a statement like: insert into db.table (`name`, `date`)
VALUES
('lewis', '01-02,2018'),
('dave', '01-02,2018'),
('charles', '01-02,2018') ; Or maybe there should be an insertBatch function which does the above.. ? |
you last changes are breaking return type on rollback. Please if you want to submit a patch -- make it less intrusive |
Sorry was thinking of http://php.net/manual/en/migration70.incompatible.php
Should be
I wrote that on the fly without thinking :P my bad |
I'm having the same issue as described above. Is this bug fixed? |
Doesn't look like the PR was merged.. #775 |
Hello, I'm trying to use IGNORE with insertMulti but getting duplicate key errors, code and error below, with the only notable oddity being the table being inserted into has a compound primary key - that shouldn't affect IGNORE though :
Results of $db->getLastQuery()
composer.json :
Also tried on v2.9.2 with same error messages.
The text was updated successfully, but these errors were encountered: