staabm / phpstan-dba

PHPStan based SQL static analysis and type inference for the database access layer
https://staabm.github.io/archive.html#phpstan-dba
MIT License
255 stars 17 forks source link

Support for (PDO->prepare())->execute() #603

Open thbley opened 1 year ago

thbley commented 1 year ago

Currently I'm not getting any errors/hints for (PDO->prepare())->execute(). It would be nice to have support for (PDO->prepare())->execute().

e.g.

        $dsn = sprintf('mysql:host=%s;dbname=%s;port=3306;charset=utf8mb4;', 'host', 'database');
        $pdo = new PDO($dsn, 'username', 'password', []);
        $query = '... query ...';
        $statement = $pdo->prepare($query);
        $statement->execute([...bind values...]);
        $result = $statement->fetchAll();

configuration used:

$config = new RuntimeConfiguration();
$config->analyzeQueryPlans(true);
$config->utilizeSqlAst(true);

$dsn = sprintf('mysql:host=%s;dbname=%s;port=3306;charset=utf8mb4;', 'host', 'database');
$pdo = new PDO($dsn, 'username', 'password', []);

QueryReflection::setupReflector(
    new ReplayAndRecordingQueryReflector(
        ReflectionCache::create($cacheFile),
        new PdoMysqlQueryReflector($pdo),
        new SchemaHasherMysql($pdo)
    ),
    $config
);

Version tested: 0.2.72

Thanks!

thbley commented 1 year ago

no error (but table tasks_invalid does not exist):

        $pdo = new \PDO('mysql:host=mysql;dbname=tasks;port=3306;charset=utf8mb4;', 'root', 'root');
        $query = 'SELECT id, title, duedate, completed, last_updated_by FROM tasks_invalid WHERE customer_id = ? AND completed = 1';
        $statement = $pdo->prepare($query);
        $statement->execute([123]);
        $result = $statement->fetch();

Query error: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'tasks.tasks_invalid' doesn't exist (42S02).

        $pdo = new \PDO('mysql:host=mysql;dbname=tasks;port=3306;charset=utf8mb4;', 'root', 'root');
        $query = 'SELECT id, title, duedate, completed, last_updated_by FROM tasks_invalid WHERE customer_id = 123 AND completed = 1';
        $statement = $pdo->prepare($query);
        $statement->execute([]);
        $result = $statement->fetch();
thbley commented 1 year ago

Another example:

no error (but table task_invalid does not exist):

        $pdo = new \PDO('mysql:host=mysql;dbname=tasks;port=3306;charset=utf8mb4;', 'root', 'root');
        $ids = implode(',', array_map(intval(...), [1,2,3]));
        $query = sprintf('SELECT id, title, duedate, completed, last_updated_by FROM task_invalid WHERE id IN (%s)', $ids);
        $statement = $pdo->query($query);

Query error: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'tasks.task_invalid' doesn't exist (42S02).

        $pdo = new \PDO('mysql:host=mysql;dbname=tasks;port=3306;charset=utf8mb4;', 'root', 'root');
        $ids = '1,2,3';
        $query = sprintf('SELECT id, title, duedate, completed, last_updated_by FROM task_invalid WHERE id IN (%s)', $ids);
        $statement = $pdo->query($query);
staabm commented 1 year ago

thanks for the report.

please try enabling debugMode and see whether you get a usefull error.

can you reproduce the error in a small repository?

thbley commented 1 year ago
<?php

$pdo = new \PDO('mysql:host=mysql;dbname=tasks;port=3306;charset=utf8mb4;', 'root', 'root');
$ids = implode(',', array_map(intval(...), [1,2,3]));
$query = sprintf('SELECT id, title, duedate, completed, last_updated_by FROM task_invalid WHERE id IN (%s)', $ids);
$statement = $pdo->query($query);
print_r($statement->fetchAll());

$pdo = new \PDO('mysql:host=mysql;dbname=tasks;port=3306;charset=utf8mb4;', 'root', 'root');
$query = sprintf('SELECT id, title, duedate, completed, last_updated_by FROM task_invalid WHERE id IN (%s)', '1,2,3');
$statement = $pdo->query($query);
print_r($statement->fetchAll());

$pdo = new \PDO('mysql:host=mysql;dbname=tasks;port=3306;charset=utf8mb4;', 'root', 'root');
$query = 'SELECT id, title, duedate, completed, last_updated_by FROM tasks_invalid WHERE customer_id = ? AND completed = 1';
$statement = $pdo->prepare($query);
$statement->execute([123]);
$result = $statement->fetch();

$pdo = new \PDO('mysql:host=mysql;dbname=tasks;port=3306;charset=utf8mb4;', 'root', 'root');
$query = 'SELECT id, title, duedate, completed, last_updated_by FROM tasks_invalid WHERE customer_id = 123 AND completed = 1';
$statement = $pdo->prepare($query);
$statement->execute([]);
$result = $statement->fetch();

gives:

 ------ --------------------------------------------------------------------------------------------------------------------- 
  Line   test.php                                                                                                             
 ------ --------------------------------------------------------------------------------------------------------------------- 
  6      Unresolvable Query: Cannot resolve query with variable type: non-falsy-string.                                       
         💡 Consider replacing concatenated string-variables with prepared statements or @phpstandba-inference-placeholder.   
  6      Unresolvable Query: Cannot resolve query with variable type: non-falsy-string.                                       
         💡 Consider replacing concatenated string-variables with prepared statements or @phpstandba-inference-placeholder.   
  11     Query error: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'tasks.task_invalid' doesn't exist (42S02).   
  22     Query error: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'tasks.tasks_invalid' doesn't exist (42S02).  
 ------ --------------------------------------------------------------------------------------------------------------------- 
thbley commented 1 year ago

here is the repository and the pipeline: https://github.com/thbley/phpstan_dba https://github.com/thbley/phpstan_dba/actions/runs/5081767755/jobs/9130588776

thbley commented 1 year ago

Closing due to inactivity of project maintainer.