{"record":{"id":"433e109724add85f","repo":"phacility/phabricator","slug":"there-are-some-results-left-in-the-result-set-433e10","errorCode":null,"errorMessage":"There are some results left in the result set.","messagePattern":"There are some results left in the result set\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/infrastructure/storage/connection/mysql/AphrontMySQLiDatabaseConnection.php","lineNumber":222,"sourceCode":"      if (!$have_result) {\n        // End line in front of semicolon to allow single line comments at the\n        // end of queries.\n        $have_result = $conn->multi_query(implode(\"\\n;\\n\\n\", $raw_queries));\n      } else {\n        $have_result = $conn->next_result();\n      }\n\n      array_shift($raw_queries);\n\n      $result = $conn->store_result();\n      if (!$result && !$this->getErrorCode($conn)) {\n        $result = true;\n      }\n      $results[$key] = $this->processResult($result);\n    }\n\n    if ($conn->more_results()) {\n      throw new Exception(\n        pht('There are some results left in the result set.'));\n    }\n\n    return $results;\n  }\n\n  protected function freeResult($result) {\n    $result->free_result();\n  }\n\n  protected function fetchAssoc($result) {\n    return $result->fetch_assoc();\n  }\n\n  protected function getErrorCode($connection) {\n    return $connection->errno;\n  }\n","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/storage/connection/mysql/AphrontMySQLiDatabaseConnection.php#L204-L240","documentation":"The mysqli driver's counterpart of the unconsumed-results check: after every expected statement was fetched via next_result()/store_result(), $conn->more_results() still reports pending result sets. The server produced more result sets than the client consumed, so the driver aborts instead of silently discarding them. Typically caused by multiple statements in one call or a stored procedure returning extra sets.","triggerScenarios":"Passing several ';'-separated statements through one queryfx()/queryf() call on the mysqli path; invoking a stored procedure that emits multiple result sets; stray trailing semicolons or concatenation adding statements to the query string.","commonSituations":"Executing migration scripts written as single multi-statement blobs; wrapping logic in stored procedures; copy-pasting SQL from a dump into a single query call.","solutions":["Split multi-statement strings into one queryfx() call per statement","Consume all result sets when a procedure legitimately returns several, or avoid procedures through this API","Log and inspect the exact SQL sent to catch accidental embedded statements","Keep the expected query count and the actual statement count in sync in custom query loops"],"exampleFix":"// before: two statements, one call\nqueryfx($conn_m, 'DELETE FROM a; DELETE FROM b;');\n\n// after: one statement per call\nqueryfx($conn_m, 'DELETE FROM a');\nqueryfx($conn_m, 'DELETE FROM b');","handlingStrategy":"validation","validationCode":"// Guard the input: exactly one statement per call on the mysqli path too.\nif (preg_match('/;\\s*\\S/', trim($raw_query))) {\n  throw new Exception('Split multi-statement SQL into separate calls.');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["One statement per queryfx()/queryf() call; split script files into statements before execution","Avoid stored procedures with multiple result sets through this API, or consume every set explicitly","Log the exact SQL string when custom query loops are involved so count mismatches are debuggable"],"tags":["mysqli","multi-statement","result-set","protocol","mysql"],"backgroundTag":"unconsumed-query-results","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}