bcmcfc
bcmcfc

Reputation: 26785

How do I get MySQLi to return more detail about an error returned whilst processing a file of SQL queries?

We have a method which initialises a test database as follows:

    $db=file_get_contents('test-data.sql');

    /* @var $result mysqli_result */
    $result=self::$_mysqlConn->multi_query($db);
    if (!$result) {
        fwrite(STDERR, self::$_mysqlConn->error."\nBUILD FAILED!\n");
        exit(1);
    }

    while ($nextResRes = self::$_mysqlConn->next_result()) {
        $tempRes = self::$_mysqlConn->store_result();
        if (!self::$_mysqlConn->more_results()) break;
    }

    if (self::$_mysqlConn->errno) {
        fwrite(STDERR, "DB QUERIES FAILED. FILE: ".$file."\n");
        fwrite(STDERR, self::$_mysqlConn->error."\nBUILD FAILED!\n");
        exit(1);
    }

The build is currently failing because of one of the queries in the data.sql file. The error being returned isn't very helpful:

DB QUERIES FAILED. FILE: data
Column count doesn't match value count at row 1
BUILD FAILED!

I'd like to somehow output the specific query which failed to STDERR at this point. How do I achieve this with MySQLi?

Upvotes: 0

Views: 95

Answers (1)

DaveRandom
DaveRandom

Reputation: 88687

You will have to split your multi-query string and run the queries individually. AFAIK there is no way to extract the query from MySQLi. You could obviously just split on ; but that is potentially going cause errors (e.g. if one of your queries uses a string containing a ;) and really you need to ensure that your test-data.sql file contains strings delimited by something that will never appear in a query.

One approach to this which should be safe is to split on ;\n and ensure that all your queries are separated with new lines, and the a literal new line never appears in a query - essentially ensure you always use \n (which you should do anyway).

For example (Note: I am not sure how or even if store_result() will work here - I have taken a best guess but this is untested and may need to be adapted):

test-data.sql:

INSERT INTO someTable
  (col1, col2, col3)
VALUES
  ('val1', 'val2', 'val3');

UPDATE someTable SET col1 = 'val' WHERE id = 4;

DELETE FROM someTable WHERE id > 7;

PHP:

// Get data from file and create an array of queries
$db = file_get_contents('test-data.sql');
$queries = explode(";\n", $db);

// Loop queries
foreach ($queries as $query) {

    // Trim whitespace and skip empty queries (mostly useful for last one)
    if (($query = trim($query)) === '') continue;

    // Do this query
    $result = self::$_mysqlConn->query($query);
    if (!$result) {
        fwrite(STDERR, self::$_mysqlConn->error."\nQuery: $query\nBUILD FAILED!\n");
        exit(1);
    }

    // Store result (?)
    self::$_mysqlConn->store_result();

    // This may not be the best place for this and it may not even be required
    // any more - that's a decision for you really
    if (self::$_mysqlConn->errno) {
        fwrite(STDERR, "DB QUERIES FAILED. FILE: ".$file."\n");
        exit(1);
    }

}

Upvotes: 1

Related Questions