The current API documentation of DeleteQuery::execute says:

"Return value
The return value is dependent on the database connection."

This doesn't tell much about the nature of return value.
A suggestion (as a result of discussion with chx and sajt on #drupal.hu IRC channel):

"The return value is the number of deleted rows but this is dependent on the database connection."

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Bug because documentation is incorrect or misleading
Issue priority Normal because it is not critical or major
Unfrozen changes Unfrozen because it only changes documentation

Comments

pkiraly’s picture

I attached the patch with the modified documentation sentence.

pkiraly’s picture

Status: Active » Needs review
chx’s picture

Title: DeleteQuery::execute needs explicit return value documentation » DeleteQuery::execute return value documentation is unusable
Category: feature » bug
Status: Needs review » Needs work

94 characters; need a linebreak before 80; otherwise great.

pkiraly’s picture

Status: Needs work » Needs review
StatusFileSize
new550 bytes
chx’s picture

Status: Needs review » Reviewed & tested by the community

Good to go.

jhodgdon’s picture

Title: DeleteQuery::execute return value documentation is unusable » DeleteQuery::execute (Delete::execute() in D8) return value documentation is unusable
Version: 7.x-dev » 8.x-dev
Status: Reviewed & tested by the community » Needs work

Um... Maybe it should say that the return value is *typically* the number of deleted rows? What else could it be and in what way does it depend on the database connection? I don't really think this makes the situation much clearer.

Also, I think we need to do this in D8 first:
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Database!Query!De...
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Database!Query!De...
and other classes/interfaces

chx’s picture

Apparently I remembered wrong. Here's the code:

        case Database::RETURN_AFFECTED:
          return $stmt->rowCount();

Here's the official docs: http://www.php.net/manual/en/pdostatement.rowcount.php and a relevant #805858: Affected rows inconsistent across database engines well researched issue.

Reading the latter,

In line with the ANSI SQL standard, both PostgreSQL and SQLite define "affected rows" as all rows matched by the query.

So apparently the standard does define affected rows... and the problem really is only with UPDATEs not DELETEs. Well then, thanks for catching me being too cautious -- let's make the patch say definitely it is the number of deleted rows.

jhodgdon’s picture

Issue tags: +Novice, +Needs backport to D7

Excellent! Thanks for the detailed research notes. I think this is now a good Novice issue. The task:

Search out all Delete query classes/interfaces in Drupal 8, and make sure their execute() return value docs say that the return value is the number of deleted rows.

oriol_e9g’s picture

Status: Needs work » Needs review
StatusFileSize
new556 bytes

I just found another occurrence but the documentation seems right:

/**
 * SQLite specific implementation of DeleteQuery.
 *
 * When the WHERE is omitted from a DELETE statement and the table being deleted
 * has no triggers, SQLite uses an optimization to erase the entire table content
 * without having to visit each row of the table individually.
 *
 * Prior to SQLite 3.6.5, SQLite does not return the actual number of rows deleted
 * by that optimized "truncate" optimization.
 */
class Delete extends QueryDelete {
jhodgdon’s picture

It sounds like the SQLite class's execute() documentation should say that it returns the number of rows deleted, except in the case where there is no WHERE, then? Or does it? The documentation you pasted here is just the class documentation, not the execute() method.

And aren't there more cases than just core/lib/Drupal/Core/Database/Query/Delete.php where the execute() documentation needs an update?

oriol_e9g’s picture

Status: Needs work » Needs review

@jhodgdon I just found this extra case. The documentation is in the class and nothing in the execute method.

Maybe we can move some documentation from the class to the execute method:

/**
 * SQLite specific implementation of DeleteQuery.
 *
 * When the WHERE is omitted from a DELETE statement and the table being deleted
 * has no triggers, SQLite uses an optimization to erase the entire table content
 * without having to visit each row of the table individually.
 *
 * Prior to SQLite 3.6.5, SQLite does not return the actual number of rows deleted
 * by that optimized "truncate" optimization.
 */
class Delete extends QueryDelete {
  public function execute() {
  ...

So, you can found similar documentation in other places like TRUCATE executes:

* Executes the TRUNCATE query.
*
* @return
* Return value is dependent on the database type.

...but all those cases are out of the issue scope.

jhodgdon’s picture

Status: Needs review » Needs work

Right, let's stick with the execute() method on Delete classes for this issue, and yes, let's move the documentation on the return value of execute() to the execute() method on the SQLite class.

And maybe on the delete interface, we should mention that some engines do make exceptions to the rule that execute() always returns the number of rows.

Anyway, the supplied patch does not appear to fix all the cases of execute() on all Delete classes and interfaces, right?

Status: Needs review » Needs work
ivanchaer’s picture

Assigned: Unassigned » ivanchaer
Issue summary: View changes
Issue tags: +SprintWeekend2014
ivanchaer’s picture

Assigned: ivanchaer » Unassigned
Status: Needs work » Needs review
StatusFileSize
new1.16 KB

In order to find all the files that implemented the execute() function of Delete, I made a search for all files that contained the string "function execute()", and then made another search for the string "delete", just on the files that were returned by the first search.

The only result besides the file previously patched (a/core/lib/Drupal/Core/Database/Query/Delete.php) was a/core/lib/Drupal/Core/Database/Driver/sqlite/Delete.php.

I added the {@inheritdoc} to its execute() function.

jhodgdon’s picture

Status: Needs review » Needs work

Thanks! I agree with your analysis and the SQLite class is the only one that overrides the base Delete::execute() method.

However, as noted above, in SQLite, the execute() method does not always return the number of rows deleted, so it should not be inheriting the documentation from the base class. It needs its own documentation header.

Also, when attaching a patch, please name it *.patch so it gets flagged as a patch for testing/review. Thanks!

lucaslg’s picture

StatusFileSize
new2.11 KB

I added its own documentation to the SQLite implementation and mentioned on the parent class that some implementations work differently.

Anonymous’s picture

Status: Needs work » Needs review
Issue tags: +drupaldevdays

Status: Needs review » Needs work

The last submitted patch, 17: deletequery_execute-2042239-17.patch, failed testing.

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 17: deletequery_execute-2042239-17.patch, failed testing.

lucaslg’s picture

Status: Needs work » Needs review
StatusFileSize
new2.07 KB

Same as #17 but with unix line ending

Status: Needs review » Needs work

The last submitted patch, 22: deletequery_execute-2042239-22.patch, failed testing.

lucaslg’s picture

Status: Needs work » Needs review
Related issues: +#2465221: Raise the minimun version requirement for SQLite to 3.6.8

#22 failed because of changes in #2465221: Raise the minimun version requirement for SQLite to 3.6.8. Beginner error, i forgot to git pull.

I think that now, because SQLite support starts at 3.6.8 which always return the number of rows deleted , #9 is relevant and should be used.

jhodgdon’s picture

Issue tags: +sqlite

tagging in hopes the SQLite folks see this... I do not know the answer.

cilefen’s picture

Status: Needs review » Needs work
Issue tags: +Needs beta evaluation, +Needs reroll
cilefen’s picture

In response to #24 and #25, it seems the "number of rows deleted" bug was fixed in 3.6.5.

travis-bradbury’s picture

Issue summary: View changes

Added beta evaluation.

travis-bradbury’s picture

Issue tags: -Needs beta evaluation
travis-bradbury’s picture

Status: Needs work » Fixed
Issue tags: -Needs reroll

This was actually fixed with issue 2465221. There is no longer a special behaviour to Delete for sqlite and the documentation in question has already been removed.

jhodgdon’s picture

Version: 8.0.x-dev » 7.x-dev
Status: Fixed » Patch (to be ported)

In that case, it's a D7 issue.

travis-bradbury’s picture

How does this look? There didn't appear to be anything unclear about the documentation in 7.x but I modified it a little to limit lines to 80 characters and added @return, like the D8 patch.

Anonymous’s picture

Status: Patch (to be ported) » Needs review

Triggering testbot, but it will need to be put in needs work for the feedback below.

It generally looks ok to me.

+++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Delete.php
index 8848391..1bff37e 100644
--- a/core/lib/Drupal/Core/Database/Query/Delete.php

The patch in #22 also had a doc change here. Is that not relevant in D7?

+++ b/includes/database/sqlite/query.inc
@@ -100,12 +100,15 @@ class UpdateQuery_sqlite extends UpdateQuery {
+ * deleted has no triggers, SQLite uses an optimization to erase the entire ¶

There is a trailing space at the end here. It should be removed.
Also optimisation is with an "s".

Edit:

+++ b/includes/database/sqlite/query.inc
@@ -100,12 +100,15 @@ class UpdateQuery_sqlite extends UpdateQuery {
+ * When the WHERE is omitted from a DELETE statement and the table being
+ * deleted has no triggers, SQLite uses an optimization to erase the entire ¶
+ * table content without having to visit each row of the table individually.

Actually this wrapping is incorrect. "deleted" should move up a line. It just fits.

travis-bradbury’s picture

StatusFileSize
new927 bytes
new1.09 KB

I removed the extra whitespace after "entire" and moved "deleted" up a line.
I left the spelling as "optimization" because, as far as I can tell, Drupal prefers the Oxford spelling.[1]

There wasn't anything wrong with the changes #22; it's just not applicable to D8 any more and it doesn't apply to D7.

[1] https://www.drupal.org/style-guide/content#english

jhodgdon’s picture

yes, please use American English spelling with a Z not S in optimization.

Anonymous’s picture

Status: Needs review » Reviewed & tested by the community

Oh I see. Looks good to me!

jhodgdon’s picture

+1, thanks!

David_Rothstein’s picture

Status: Reviewed & tested by the community » Needs work
+ * @return
+ *  The return value is the number of deleted rows.
....
  */
+ * Prior to SQLite 3.6.5, SQLite does not return the actual number of rows
+ * deleted by that optimized "truncate" optimization.
  */
 class DeleteQuery_sqlite extends DeleteQuery {
   public function execute() {

This doesn't look right to me; classes don't have return values. Perhaps the @return is supposed to be on the execute() method instead?

And it's written pretty definitively but that conflicts with the documentation below which says that it depends on SQLite version...

Also, this patch no longer seems to deal with the original issue, which is DeleteQuery::execute() itself, which still says the vague/unhelpful "The return value is dependent on the database connection"....

jhodgdon’s picture

Version: 7.x-dev » 8.0.x-dev

Doh. Actually, we should go back to Drupal 8 first. The Delete::execute() method does not say what its return value is. All it says is:
The return value is dependent on the database connection.

That will teach me to accept it when someone else says the issue is fixed, when it isn't.

Anonymous’s picture

Status: Needs work » Needs review
StatusFileSize
new607 bytes

After reading this thread again, I think we need to fix the return docs. The sqllite docs state that the number of affected rows is returned (see https://www.sqlite.org/lang_delete.html). According to http://php.net/manual/en/pdostatement.rowcount.php the type would be int.

The comment about version 3.6.5 is only relevant for D7, since the min version for D8 is 3.6.8. That was done in #2465221: Raise the minimun version requirement for SQLite to 3.6.8.

jhodgdon’s picture

Status: Needs review » Reviewed & tested by the community

Looks good, thanks!

Also I noticed #2594845: Many database driver classes have no class doc blocks while checking this... Sigh. Who lets all these documentless-classes into Core???!?

xjm’s picture

Status: Reviewed & tested by the community » Fixed
Issue tags: +rc eligible

That's much better. :) As a documentation-only fix, this change is considered "rc eligible" and can be committed any time during RC. Reference: https://www.drupal.org/core/d8-allowed-changes#rc

Committed and pushed to 8.0.x. Thanks!

  • xjm committed 9af4f7a on 8.0.x
    Issue #2042239 by tbradbury, pkiraly, lucaslg, pjonckiere, oriol_e9g,...
jhodgdon’s picture

Version: 8.0.x-dev » 7.x-dev
Status: Fixed » Patch (to be ported)
snehi’s picture

Status: Patch (to be ported) » Needs review
StatusFileSize
new522 bytes

Done for 7.x

jhodgdon’s picture

Status: Needs review » Needs work
+++ b/includes/database/query.inc
@@ -845,8 +845,8 @@ class DeleteQuery extends Query implements QueryConditionInterface {
+   *   The number of rows affected by the delete query. ¶

This line has an extra space at the end.

By the way, there was a long discussion above about SQLite and whether it was correct that all of the databases return the number of rows affected. So I looked at the execute() method on the D7 SQLite DeleteQuery_sqlite class, and the execute method definitely returns the number of rows (the implementation has some code that makes sure this happens).

So, in this patch, we should remove this text in the class header docs... or actually, we should move it into a code comment:

 * When the WHERE is omitted from a DELETE statement and the table being deleted
 * has no triggers, SQLite uses an optimization to erase the entire table content
 * without having to visit each row of the table individually.
 *
 * Prior to SQLite 3.6.5, SQLite does not return the actual number of rows deleted
 * by that optimized "truncate" optimization.

This information should be turned into // comments and put just before this if() in the execute() method:

 * When the WHERE is omitted from a DELETE statement and the table being deleted
 * has no triggers, SQLite uses an optimization to erase the entire table content
 * without having to visit each row of the table individually.
 *
 * Prior to SQLite 3.6.5, SQLite does not return the actual number of rows deleted
 * by that optimized "truncate" optimization.

Also maybe say something like "But we want to return the number of rows affected, so we calculate it directly.

snehi’s picture

Status: Needs work » Needs review
StatusFileSize
new1.11 KB
new1.08 KB

Please review attached one.

jhodgdon’s picture

Status: Needs review » Needs work
+++ b/includes/database/query.inc
@@ -845,11 +845,18 @@ class DeleteQuery extends Query implements QueryConditionInterface {
+    // When the WHERE is omitted from a DELETE statement and the table being
+    // deleted has no triggers, SQLite uses an optimization to erase the entire
+    // table content without having to visit each row of the table individually.
+    // Prior to SQLite 3.6.5, SQLite does not return the actual number of rows
+    // deleted by that optimized "truncate" optimization. But we want to return
+    // the number of rows affected, so we calculate it directly.

This information needs to go into the SQLite Delete class, not the generic class. Sorry, my comment above wasn't specific and I pasted in the comment again instead of the if() statement I was referring to. But you need to find the place in the SQLite class where it calculates the number of rows affected, and put this comment there.

  • xjm committed 9af4f7a on 8.1.x
    Issue #2042239 by tbradbury, pkiraly, lucaslg, pjonckiere, oriol_e9g,...
lucaslg’s picture

Status: Needs work » Needs review
StatusFileSize
new1.95 KB

Hi,

I moved the comment to the SQLite Delete class as mentionned in #48 and removed the class header comment.

  • xjm committed 9af4f7a on 8.3.x
    Issue #2042239 by tbradbury, pkiraly, lucaslg, pjonckiere, oriol_e9g,...

  • xjm committed 9af4f7a on 8.3.x
    Issue #2042239 by tbradbury, pkiraly, lucaslg, pjonckiere, oriol_e9g,...
stefan.r’s picture

Issue tags: -rc eligible +Dublin2016

Tagging the Drupal 7 backport as Novice -- this still needs review to see if this is RTBC and all the feedback has been addressed, and to further iterate if necessary.

  • xjm committed 9af4f7a on 8.4.x
    Issue #2042239 by tbradbury, pkiraly, lucaslg, pjonckiere, oriol_e9g,...

  • xjm committed 9af4f7a on 8.4.x
    Issue #2042239 by tbradbury, pkiraly, lucaslg, pjonckiere, oriol_e9g,...
yago elias’s picture

Status: Needs review » Reviewed & tested by the community

Changing the status of this ticket.

David_Rothstein’s picture

Title: DeleteQuery::execute (Delete::execute() in D8) return value documentation is unusable » Fix DeleteQuery::execute() return value documentation and DeleteQuery_sqlite documentation (fix Delete::execute() documentation in Drupal 8)
Status: Reviewed & tested by the community » Fixed

Committed to 7.x - thanks!

I removed this on commit since we don't have @inheritdoc anywhere else in Drupal 7 right now and I didn't want to add it to just this one place:

diff --git a/includes/database/sqlite/query.inc b/includes/database/sqlite/query.inc
index 1ac4464..c9c028b 100644
--- a/includes/database/sqlite/query.inc
+++ b/includes/database/sqlite/query.inc
@@ -101,9 +101,6 @@ class UpdateQuery_sqlite extends UpdateQuery {
  * SQLite specific implementation of DeleteQuery.
  */
 class DeleteQuery_sqlite extends DeleteQuery {
-  /**
-  * {@inheritdoc}
-  */
   public function execute() {
     // When the WHERE is omitted from a DELETE statement and the table being
     // deleted has no triggers, SQLite uses an optimization to erase the entire

  • David_Rothstein committed 8a09ddd on 7.x
    Issue #2042239 by lucaslg, tbradbury, snehi, pkiraly, pjonckiere,...
yago elias’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.