読者です 読者をやめる 読者になる 読者になる

HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

xx_fetch_array()関数の恐怖

PHP PostgreSQL MySQL

いや、まぁ恐怖ってほどのことでもないのだけど。
こんなクエリ(何)書かないだろうし。

select table_schema as "1", table_name as "2", column_name as "3"
 from information_schema.columns
 where table_schema = 'information_schema'
     and table_name = 'tables'

PostgreSQL用にはpg_fetch_array()関数、MySQL用にはmysql_fetch_array()関数がある。
pg_fetch_array()は、PGSQL_ASSOC、PGSQL_NUM、PGSQL_BOTH(デフォルト)を指定することができ、それぞれ「連想配列」、「数値添え字配列」、「連想&数値添え字配列」を返す。
mysql_fetch_array()は、MYSQL_ASSOC、MYSQL_NUM、MYSQL_BOTH(デフォルト)を指定することができ、それぞれ「連想配列」、「数値添え字配列」、「連想&数値添え字配列」を返す。

そこで、次のようなプログラムを実行してみる。
xx_fetch_array.php

<?php
$query_1 = "
    select table_schema, table_name, column_name
     from information_schema.columns
     where table_schema = 'information_schema'
         and table_name = 'tables'";
$query_2 = "
    select table_schema as \"1\", table_name as \"2\", column_name as \"3\"
     from information_schema.columns
     where table_schema = 'information_schema'
         and table_name = 'tables'";
$query_3 = "
    select table_schema as \"1\", table_name as \"2\", column_name as \"3\"
     from information_schema.columns
     where table_schema = 'information_schema'
         and table_name = 'tables'";
?>

pg_fetch_array.php

<pre><?php
    require_once('xx_fetch_array.php');

    $pg_sql = pg_connect(
        'host=localhost'
        . ' port=5432'
        . ' dbname=postgres'
        . ' user=postgres'
        . ' password=admin');

    $res = pg_query($pg_sql, $query_1);
//    print($query_1 . "\n");
    print_r(pg_fetch_array($res));

    $res = pg_query($pg_sql, $query_2);
//    print($query_2 . "\n");
    print_r(pg_fetch_array($res));

    $res = pg_query($pg_sql, $query_3);
//    print($query_3 . "\n");
    print_r(pg_fetch_array($res, NULL, PGSQL_ASSOC));

    pg_close($pg_sql);
?></pre>

mysql_fetch_array.php

<pre><?php
    require_once('xx_fetch_array.php');

    $mysql = mysql_connect(
        'localhost:3306',
        'root',
        'admin');
    mysql_select_db('test', $mysql);

    $res = mysql_query($query_1, $mysql);
//    print($query_1 . "\n");
    print_r(mysql_fetch_array($res));

    $res = mysql_query($query_2, $mysql);
//    print($query_2 . "\n");
    print_r(mysql_fetch_array($res));

    $res = mysql_query($query_3, $mysql);
//    print($query_3 . "\n");
    print_r(mysql_fetch_array($res, PGSQL_ASSOC));

    mysql_close($mysql);
?></pre>

pg_fetch_array.phpmysql_fetch_array.phpを実行すると、次のような結果が得られる。
pg_fetch_array.phpの実行結果。

Array
(
    [0] => information_schema
    [table_schema] => information_schema
    [1] => tables
    [table_name] => tables
    [2] => table_catalog
    [column_name] => table_catalog
)
Array
(
    [0] => information_schema
    [1] => tables
    [2] => table_catalog
    [3] => table_catalog
)
Array
(
    [1] => information_schema
    [2] => tables
    [3] => table_catalog
)

mysql_fetch_array.phpの実行結果。

Array
(
    [0] => information_schema
    [table_schema] => information_schema
    [1] => tables
    [table_name] => tables
    [2] => TABLE_CATALOG
    [column_name] => TABLE_CATALOG
)
Array
(
    [0] => information_schema
    [1] => information_schema
    [2] => tables
    [3] => TABLE_CATALOG
)
Array
(
    [1] => information_schema
    [2] => tables
    [3] => TABLE_CATALOG
)

着目すべきは、それぞれの2つ目の結果。PostgreSQLの場合は、結果配列の中に「連想」⇒「添え字」の順で格納しているようで、連想配列のキー("1"、"2"、"3")に対応する値が正しくない。一方、MySQLの場合は、結果配列の中に「添え字」⇒「連想」の順で格納しているようで、添え字配列のキー(0、1、2)に対応する値が正しくない。
まぁ、キーに指定するものとして「"1"」と「1」は同じものとみなされるので、同じ列名があれば当然に上書きされてしまう。
列名のエイリアスに「"1"」「"2"」などは指定しないだろうが、PGSQL_ASSOC、PGSQL_NUM、MYSQL_ASSOC、MYSQL_NUMを明示して「連想」か「添え字」のいずれかのみを使用するようにするのが安全な使い方なのだろうと思う。
ちなみに、次のような関数が提供されているので、実はxx_fetch_array()系の関数の出番はないという(謎)。