Utilisation de PHP PDO sur MySQL et Oracle
Par PlaceOweb le lundi, février 9 2009, 22:40 - PHP - Lien permanent
PDO (PHP Data Objects), interface pour accéder à n'importe quelle base de données depuis PHP.
Benchmark PDO
Bind est plus rapide que l'utilisation d'un array()
PDO::query reste plus rapide est plus simple qu'un Statement dans le cas d'une requête statique.
Difficultés rencontrés à l'utilisation de PDO
num_rows et num_fields
num_rows : le nombre de lignes (affectés) d'un résultat
- MySQL
- mysql_num_rows — Retourne le nombre de lignes d'un résultat MySQL
- mysql_affected_rows — Retourne le nombre de lignes affectées lors de la dernière opération MySQL
- Oracle
- oci_num_rows — Retourne le nombre de lignes affectées durant la dernière commande Oracle
Pour compter le nombre d'enregistrements contenus dans votre SELECT, il ne semble exister d'équivalence PDO à la fonction mysql_num_rows qui n'as d'ailleurs pas d'équivalent sous Oracle. A vous de vous organiser avec des count(fetchAll()) ou bien des requêtes COUNT(*) au préalable...
Pour connaître le nombre d'enregistrements affectés avec votre UPDATE, vous pouvez utiliser PDOStatement->rowCount — Retourne le nombre de lignes affectées par le dernier appel à la fonction PDOStatement::execute()
num_fields : le nombre de champs (colonnes) d'un résultat
- MySQL
- mysql_num_fields — Retourne le nombre de champs d'un résultat MySQL
- Oracle
- oci_num_fields — Retourne le nombre de colonnes dans un résultat Oracle
PDOStatement->columnCount — Retourne le nombre de colonnes dans le jeu de résultats
Par exemple pour mettre des en-têtes avant d'afficher vos données :
$sql = "SELECT * FROM MyTable"; $result = $DbToQuery->query($sql); // Get the number of columns $Cols = $result->columnCount(); // Loop through the results $countrows = 1; while($row = $result->fetch(PDO::FETCH_ASSOC)) { if($countrows == 1) { // Print column names print join(",", array_keys($row)); } $countrows++; // handle the row data // ... }
IN()
DATES
NULL
Problème pour un SELECT : IS NULL
, pas = NULL
On peut le typer avec les constantes PDO pré-définies
- PDO::PARAM_NULL
Oracle FAQ : NULL est un marqueur qui represente des données manquantes, inconnue ou inapplicables.
Les tris ASC et DESC sur les NULL avec Oracle : Dans l'ordre ASCendant, les valeurs NULL apparaissent toujours à la fin.
SELECT * FROM emp ORDER BY sal DESC NULLS FIRST; SELECT * FROM emp ORDER BY sal DESC NULLS LAST;
Avec MySQL, il n'y pas d'option de tri des NULL. Les NULL sont placés en premier pour un tri ASC.
Et les exemples valides et invalides :
Exemples invalides
Un NULL n'est pas égal à NULL:
SELECT * FROM emp WHERE NULL = NULL;
Un NULL ne peut pas être égal à un NULL:
SELECT * FROM emp WHERE NULL <> NULL;
Un NULL n'est pas égal à une chaine vide:
SELECT * FROM emp WHERE NULL = '';
Examples valides
Selection des valeurs nulles NULL d'une colonne:
SELECT * FROM emp WHERE comm IS NULL;
Selection des valeurs non nulles NOT NULL d'un colonne:
SELECT * FROM emp WHERE comm IS NOT NULL;
Changer la valeur d'une colonne en NULL:
UPDATE emp SET comm = NULL WHERE deptno = 20;
Les fetch modes de PDO
Vous aurez surement besoin d'avoir les un fetch mode numérique (PDO::FETCH_NUM) ou litteral (PDO::FETCH_NAMED), mais pas les 2 cumulés (PDO_FETCH_BOTH par défaut)
$stmt = $conPDO->query($query); $row = $stmt->fetch(PDO::FETCH_ASSOC); // Le code ci dessous est identique mais nécessite une ligne de plus $stmt = $conPDO->query($query); $stmt->setFetchMode(PDO::FETCH_ASSOC); $row = $stmt->fetch();
Consulter les constantes pré-définies de PDO pour connaitre les modes de fetch (PDO::FETCH_*) possibles.
Comment remplacer les différents fetch :
- MySQL
- mysql_fetch_array — Retourne une ligne de résultat MySQL sous la forme d'un tableau associatif, d'un tableau indexé, ou les deux
- mysql_fetch_assoc — Lit une ligne de résultat MySQL dans un tableau associatif
- mysql_fetch_field — Retourne les données enregistrées dans une colonne MySQL sous forme d'objet
- mysql_fetch_lengths — Retourne la taille de chaque colonne d'une ligne de résultat MySQL
- mysql_fetch_object — Retourne une ligne de résultat MySQL sous la forme d'un objet
- mysql_fetch_row — Retourne une ligne de résultat MySQL sous la forme d'un tableau
- Oracle
- oci_fetch_all — Lit toutes les lignes d'un résultat Oracle
- oci_fetch_array — Lit une ligne d'un résultat Oracle sous forme de tableau
- oci_fetch_assoc — Lit une ligne d'un résultat Oracle sous forme de tableau associatif
- oci_fetch_object — Lit une ligne d'un résultat Oracle sous forme d'objet
- oci_fetch_row — Lit une ligne d'un résultat Oracle sous forme de tableau numérique
- oci_fetch — Lit la prochaine ligne dans le résultat Oracle
De bonnes explications sont données sur le blog de BSO HQ :
- Les fetch modes de PDO
- Les fetch modes de PDO : les modes orientés objet
- Les fetch modes de PDO : les modes spéciaux
- Les fetch modes de PDO : les modes modificateurs
Également des notes utiles :
Ressources
Se connecter à une source de données (datasource) avec PDO
- PDO_MYSQL DSN — Connexion aux bases de données MySQL Le URI de la connexion MySQL :
mysql:host=localhost;dbname=database
- PDO_OCI DSN — Connexion aux bases de données Oracle Le URI de la connexion Oracle Instant Client :
oci:dbname=hostname/database
Erreurs
Oracle
Des erreurs Oracle avec PHP (et PDO)
Tous avec en complément de l'erreur : (/usr/src/php5-5.3.2/ext/pdo_oci/php-pdo-oci-1.0.1/PDO_OCI-1.0.1/oci_driver.c:579)
Mauvaise URI de connexion à la base et son serveur hôte
SQLSTATE[42S02]: pdo_oci_handle_factory: ORA-12154: TNS:could not resolve the connect identifier specified
Mauvais user/pass
SQLSTATE[HY000]: OCISessionBegin: ORA-01017: nom utilisateur/mot de passe non valide ; connexion refusee (/usr/src/php5-5.3.2/ext/pdo_oci/php-pdo-oci-1.0.1/PDO_OCI-1.0.1/oci_driver.c:630)
SELECT * WHERE 1 AND id = 3
SQLSTATE[HY000]: General error: 920 OCIStmtExecute: ORA-00920: operateur relationnel non valide
SELECT * FROM maTable LIMIT 5
SQLSTATE[HY000]: General error: 933 OCIStmtExecute: ORA-00933: la commande SQL ne se termine pas correctement
SELECT * FROM maTable where rownum <= 5;
SQLSTATE[HY000]: General error: 911 OCIStmtExecute: ORA-00911: caractere non valide
SELECT "id" FROM maTable
SQLSTATE[HY000]: General error: 904 OCIStmtExecute: ORA-00904: "id" : identificateur non valide
SELECT * , id FROM maTable
SQLSTATE[HY000]: General error: 923 OCIStmtExecute: ORA-00923: mot-cle FROM absent a l'emplacement prevu
SELECT * FROM maTable;
SQLSTATE[HY000]: General error: 942 OCIStmtExecute: ORA-00942: Table ou vue inexistante
Car la table a été crée en spécifiant les doubles quotes " sur son nom, il faut y accéder avec les mêmes doubles quotes :
SELECT * FROM "maTable"
Que ce soit pour le nom des tables ou des champs, pour permettre à Oracle d'utiliser à la fois les minuscules et majuscules dans le nom, il faut l'encapsuler (aussi bien à la création CREATE qu'à la lecture avec un SELECT) avec des doubles quotes ".
Sinon par défaut il vous retourne, sa case : UPPER_CASE
Bien que modifiable avec PDO::setAttribute et l'attibut PDO::ATTR_CASE qui force les noms de colonnes à une casse particulière, on ne peut pas mixer du upper et lower case sans double quoter les noms des tables ou des colonnes.
$conPDO->setAttribute (PDO::ATTR_CASE, PDO::CASE_NATURAL); // laisse les noms des colonnes inchangées. Laisse les noms des colonnes comme retournés par le driver de base de données. $conPDO->setAttribute (PDO::ATTR_CASE, PDO::CASE_LOWER); // force les noms des colonnes à être en minuscules. $conPDO->setAttribute (PDO::ATTR_CASE, PDO::CASE_UPPER); // force les noms de colonnes à être en majuscules.
Voir :