PDO support for multiple queries (PDO_MYSQL, PDO_MYSQLND)

后端 未结 7 2276
长发绾君心
长发绾君心 2020-11-21 06:03

I do know that PDO does not support multiple queries getting executed in one statement. I\'ve been Googleing and found few posts talking about PDO_MYSQL and PDO_MYSQLND.

相关标签:
7条回答
  • 2020-11-21 06:28

    Try this function : mltiple queries and multiple values insertion.

    function employmentStatus($Status) {
    $pdo = PDO2::getInstance();
    
    $sql_parts = array(); 
    for($i=0; $i<count($Status); $i++){
        $sql_parts[] = "(:userID, :val$i)";
    }
    
    $requete = $pdo->dbh->prepare("DELETE FROM employment_status WHERE userid = :userID; INSERT INTO employment_status (userid, status) VALUES ".implode(",", $sql_parts));
    $requete->bindParam(":userID", $_SESSION['userID'],PDO::PARAM_INT);
    for($i=0; $i<count($Status); $i++){
        $requete->bindParam(":val$i", $Status[$i],PDO::PARAM_STR);
    }
    if ($requete->execute()) {
        return true;
    }
    return $requete->errorInfo();
    }
    
    0 讨论(0)
  • 2020-11-21 06:31

    A quick-and-dirty approach:

    function exec_sql_from_file($path, PDO $pdo) {
        if (! preg_match_all("/('(\\\\.|.)*?'|[^;])+/s", file_get_contents($path), $m))
            return;
    
        foreach ($m[0] as $sql) {
            if (strlen(trim($sql)))
                $pdo->exec($sql);
        }
    }
    

    Splits at reasonable SQL statement end points. There is no error checking, no injection protection. Understand your use before using it. Personally, I use it for seeding raw migration files for integration testing.

    0 讨论(0)
  • 2020-11-21 06:33

    As I know, PDO_MYSQLND replaced PDO_MYSQL in PHP 5.3. Confusing part is that name is still PDO_MYSQL. So now ND is default driver for MySQL+PDO.

    Overall, to execute multiple queries at once you need:

    • PHP 5.3+
    • mysqlnd
    • Emulated prepared statements. Make sure PDO::ATTR_EMULATE_PREPARES is set to 1 (default). Alternatively you can avoid using prepared statements and use $pdo->exec directly.

    Using exec

    $db = new PDO("mysql:host=localhost;dbname=test", 'root', '');
    
    // works regardless of statements emulation
    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
    
    $sql = "
    DELETE FROM car; 
    INSERT INTO car(name, type) VALUES ('car1', 'coupe'); 
    INSERT INTO car(name, type) VALUES ('car2', 'coupe');
    ";
    
    $db->exec($sql);
    

    Using statements

    $db = new PDO("mysql:host=localhost;dbname=test", 'root', '');
    
    // works not with the following set to 0. You can comment this line as 1 is default
    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
    
    $sql = "
    DELETE FROM car; 
    INSERT INTO car(name, type) VALUES ('car1', 'coupe'); 
    INSERT INTO car(name, type) VALUES ('car2', 'coupe');
    ";
    
    $stmt = $db->prepare($sql);
    $stmt->execute();
    

    A note:

    When using emulated prepared statements, make sure you have set proper encoding (that reflects actual data encoding) in DSN (available since 5.3.6). Otherwise there can be a slight possibility for SQL injection if some odd encoding is used.

    0 讨论(0)
  • 2020-11-21 06:33

    Like thousands of people, I'm looking for this question:
    Can run multiple queries simultaneously, and if there was one error, none would run I went to this page everywhere
    But although the friends here gave good answers, these answers were not good for my problem
    So I wrote a function that works well and has almost no problem with sql Injection.
    It might be helpful for those who are looking for similar questions so I put them here to use

    function arrayOfQuerys($arrayQuery)
    {
        $mx = true;
        $conn->beginTransaction();
        try {
            foreach ($arrayQuery AS $item) {
                $stmt = $conn->prepare($item["query"]);
                $stmt->execute($item["params"]);
                $result = $stmt->rowCount();
                if($result == 0)
                    $mx = false;
             }
             if($mx == true)
                 $conn->commit();
             else
                 $conn->rollBack();
        } catch (Exception $e) {
            $conn->rollBack();
            echo "Failed: " . $e->getMessage();
        }
        return $mx;
    }
    

    for use(example):

     $arrayQuery = Array(
        Array(
            "query" => "UPDATE test SET title = ? WHERE test.id = ?",
            "params" => Array("aa1", 1)
        ),
        Array(
            "query" => "UPDATE test SET title = ? WHERE test.id = ?",
            "params" => Array("bb1", 2)
        )
    );
    arrayOfQuerys($arrayQuery);
    

    and my connection:

        try {
            $options = array(
                //For updates where newvalue = oldvalue PDOStatement::rowCount()   returns zero. You can use this:
                PDO::MYSQL_ATTR_FOUND_ROWS => true
            );
            $conn = new PDO("mysql:host=$servername;dbname=$database", $username, $password, $options);
            $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            echo "Error connecting to SQL Server: " . $e->getMessage();
        }
    

    Note:
    This solution helps you to run multiple statement together,
    If an incorrect a statement occurs, it does not execute any other statement

    0 讨论(0)
  • 2020-11-21 06:38

    PDO does support this (as of 2020). Just do a query() call on a PDO object as usual, separating queries by ; and then nextRowset() to step to the next SELECT result, if you have multiple. Resultsets will be in the same order as the queries. Obviously think about the security implications - so don't accept user supplied queries, use parameters, etc. I use it with queries generated by code for example.

    $statement = $connection->query($query);
    do {
      $data[] = $statement->fetchAll(PDO::FETCH_ASSOC);
    } while ($statement->nextRowset());
    0 讨论(0)
  • 2020-11-21 06:43

    After half a day of fiddling with this, found out that PDO had a bug where...

    --

    //This would run as expected:
    $pdo->exec("valid-stmt1; valid-stmt2;");
    

    --

    //This would error out, as expected:
    $pdo->exec("non-sense; valid-stmt1;");
    

    --

    //Here is the bug:
    $pdo->exec("valid-stmt1; non-sense; valid-stmt3;");
    

    It would execute the "valid-stmt1;", stop on "non-sense;" and never throw an error. Will not run the "valid-stmt3;", return true and lie that everything ran good.

    I would expect it to error out on the "non-sense;" but it doesn't.

    Here is where I found this info: Invalid PDO query does not return an error

    Here is the bug: https://bugs.php.net/bug.php?id=61613


    So, I tried doing this with mysqli and haven't really found any solid answer on how it works so I thought I's just leave it here for those who want to use it..

    try{
        // db connection
        $mysqli = new mysqli("host", "user" , "password", "database");
        if($mysqli->connect_errno){
            throw new Exception("Connection Failed: [".$mysqli->connect_errno. "] : ".$mysqli->connect_error );
            exit();
        }
    
        // read file.
        // This file has multiple sql statements.
        $file_sql = file_get_contents("filename.sql");
    
        if($file_sql == "null" || empty($file_sql) || strlen($file_sql) <= 0){
            throw new Exception("File is empty. I wont run it..");
        }
    
        //run the sql file contents through the mysqli's multi_query function.
        // here is where it gets complicated...
        // if the first query has errors, here is where you get it.
        $sqlFileResult = $mysqli->multi_query($file_sql);
        // this returns false only if there are errros on first sql statement, it doesn't care about the rest of the sql statements.
    
        $sqlCount = 1;
        if( $sqlFileResult == false ){
            throw new Exception("File: '".$fullpath."' , Query#[".$sqlCount."], [".$mysqli->errno."]: '".$mysqli->error."' }");
        }
    
        // so handle the errors on the subsequent statements like this.
        // while I have more results. This will start from the second sql statement. The first statement errors are thrown above on the $mysqli->multi_query("SQL"); line
        while($mysqli->more_results()){
            $sqlCount++;
            // load the next result set into mysqli's active buffer. if this fails the $mysqli->error, $mysqli->errno will have appropriate error info.
            if($mysqli->next_result() == false){
                throw new Exception("File: '".$fullpath."' , Query#[".$sqlCount."], Error No: [".$mysqli->errno."]: '".$mysqli->error."' }");
            }
        }
    }
    catch(Exception $e){
        echo $e->getMessage(). " <pre>".$e->getTraceAsString()."</pre>";
    }
    
    0 讨论(0)
提交回复
热议问题