Not sure how to group the last couple of posts, but they seem to all relate... I would say that this is a bug...
Here's why...
For one, admin/sqlpatch.php is not exactly a full sql parser... By that I mean, there are some characteristics and things that it does or tries to do to make it easier to implement than to go to phpMyAdmin and try to execute the sql statement(s). So it has some "rules" or formats to consider... That said, in the "long" sql above, the parser recognizes the initial instruction of 'INSERT IGNORE INTO ...' and can identify where the table is to be identified and then take the action necessary to include it; however, a subsequent sql "statement" that uses a table within that line is not recognized... Hence the need for "multiple lines".
So, then the logic in the multiple line processing doesn't appear quite right as:
if (substr($line, -1) == ';') {
//found a semicolon, so treat it as a full command, incrementing counter of rows to process at once
if (substr($newline, -1) == ' ') {
$newline = substr($newline, 0, (strlen($newline) - 1));
}
$lines_to_keep_together_counter++;
if ($lines_to_keep_together_counter == $keep_together) { // if all grouped rows have been loaded, go to execute.
$complete_line = true;
$lines_to_keep_together_counter = 0;
} else {
$complete_line = false;
}
} //endif found ';'
else {
$messageStack->add(ERROR_LINE_INCOMPLETE, 'error');
}
The first group (where the completion of the line is evaluated) is not entered unless the line ends with a semi-colon, but as pointed out if it ends with a semi-colon then ultimately when all lines are attempted to be processed as one mysql will complain that there is an ending statement where one should not be (my words not mysql's). But if the semi-colon is omitted then in a way, the command doesn't appear that it will complete as '$complete_line' won't reach a true status until effectively the appropriate number of semi-colons have been reached to account for the initial grouping...
What I have had to do in situations like you have described (as a work around rather than a fix) is to personally add the DB_PREFIX at the later locations in the query that is on the single line, or "ignore" the missing semi-colon statement if execution is determined to be satisfactory...
In some cases the #NEXT_X_ROWS_AS_ONE_COMMAND:2 concept is to ensure that two (the number of identified commands to keep together) different actions are performed as a single transaction (assume you retrieve the total number of sales or some other "dynamic" data that are then used to perform a subsequent action. By them processing together, the expectation is that no external action will modify the state of that information between the first and second operation). This is different than a single transaction that carries over multiple lines (the two line query presented above)...
I can say that the zc_install process uses in some cases the #NEXT_X_ROWS_AS_ONE_COMMAND:X concept for a multiline query and other cases it doesn't. At my last touch of some of those operations I suggested use based on the information that the system provided back and its importance to say trouble shooting or collecting information. Possibly a backwards way to have approached the identified issues, but anything/everything can be made better. :) Eventually...
What might "make it better" would be in the else section, to possibly also evaluate the condition of the line and evaluate if there are lines remaining in the keep_together count... If there are no more lines to process, then present the message. If there are still lines to process then carry on and increment the counter... But... That also assumes that the '#NEXT_X_ROWS_AS_ONE_COMMAND:X' flag was/is also intended to represent processing of a single query that is presented over many lines... (I think so, but I'm just another forum member.)
This could possibly become something like:
if (substr($line, -1) == ';') {
//found a semicolon, so treat it as a full command, incrementing counter of rows to process at once
if (substr($newline, -1) == ' ') {
$newline = substr($newline, 0, (strlen($newline) - 1));
}
$lines_to_keep_together_counter++;
if ($lines_to_keep_together_counter == $keep_together) { // if all grouped rows have been loaded, go to execute.
$complete_line = true;
$lines_to_keep_together_counter = 0;
} else {
$complete_line = false;
}
} //endif found ';'
else {
if (substr($newline, -1) == ' ') {
$newline = substr($newline, 0, (strlen($newline) - 1));
}
$lines_to_keep_together_counter++;
if ($lines_to_keep_together_counter == $keep_together) { // if all grouped rows have been loaded, don't execute because don't have an ending semi-colon.
$messageStack->add(ERROR_LINE_INCOMPLETE, 'error');
$complete_line = false; // This may be unnecessary in the grand scheme of things, but it prevents the line from being processed.
$new_line = '';
}
}
Other thing to note though, is I believe the '#NEXT_X_ROWS_AS_ONE_COMMAND:X' feature is not properly implemented... Looking at the loop code as pseudocode:
go through a line of the sql.
Set $keep_together = 1;
Evaluate the current line to see if it suggests additional lines to keep together.
Evaluate the line for a semi-colon, if present and the number of semi-colons ($lines_to_keep_together_counter == $keep_together) have been reached then add up the content together and process. If the semi-colon is present and there are more lines to be processed then move on to the next line (this effectively returns to the top, but lets carry on) but increment $lines_to_keep_together_counter.
get the new line of the sql
set $keep_together = 1;
Evaluate this line to see if it suggests additional lines to keep together. (on the second line this will be effectively false which means that keep_together remains a value of 1).
if the current line contains a semi-colon, then increment the counter ($lines_to_keep_together_counter) but now, $lines_to_keep_together_counter will exceed $keep_together because of the reassignment to 1 instead of keeping it to the value that was previously found/identified... Which means that the query will still not execute and there seems to run the possibility that this group of query won't actually execute at all...
A possible solution to this last part might be:
at the completion of the query, to have:
#NEXT_X_ROWS_AS_ONE_COMMAND:X;
Noting how a semi-colon is used at the end, but... Problem still with that is that the value X will not be a number, but will "eventually" be cast to be of the same data type as the counter unless php and associated system settings (strict control for example) offer an myDebug message about attempting to evaluate (2==2;)
Btw, the message associated with the multi-line query (no '#NEXT_X_ROWS_AS_ONE_COMMAND:X' being used) is a result of:
https://github.com/zencart/zencart/pull/3288
In short, right now, would say that the missing semi-colon message is acceptable and will support processing, to use an existing "command of #NEXT_X_ROWS_AS_ONE_COMMAND:X" there appears to be a little work to be done on overall syntax/data tracking and/or a modification to the message being displayed such that it is not always displayed just because there exists a line in the sql that doesn't end with a semi-colon...
Thoroughly confused yet? I am highly certain that the one that prepared the above commit will be...