1

MySQL 5.2、CentOS 6.4。

列名とテーブル名が最初のパスとは異なる値に変更されると、最初のパスの後に動的な列とテーブル名を使用して PREPARE によって作成された一時テーブルで MySQL SELECT * が失敗します。

回避策は、パスごとに同じ列エイリアスを使用することです。

DROP PROCEDURE IF EXISTS test1;
DELIMITER $$
CREATE PROCEDURE test1( column_name VARCHAR(20), table_name VARCHAR(20) )
BEGIN
    SET @prepared_stmt_arg = 'prepared_stmt_arg_value';

    DROP TABLE IF EXISTS tmp1;
    CREATE TEMPORARY TABLE tmp1
        SELECT 1 AS col_tmp1;

    DROP TABLE IF EXISTS tmp2;
    CREATE TEMPORARY TABLE tmp2
        SELECT 2 AS col_tmp2;

    # drop tmp table if it exists
    DROP TABLE IF EXISTS tmp_test1;

    # prepared statement
    SET @prepared_stmt = 
        CONCAT("
            CREATE TEMPORARY TABLE tmp_test1
                SELECT ? AS prepared_stmt_arg, ", column_name, " # AS constant_col_alias
                    FROM ", table_name, "
            "); # END statement

    # display prepared statement before executing it
    SELECT @prepared_stmt;

    # prepare the statement
    PREPARE ps FROM @prepared_stmt;

    # execute
    EXECUTE ps USING @prepared_stmt_arg;

    # deallocate
    DEALLOCATE PREPARE ps;

    # display
    SELECT * FROM tmp_test1;

END $$
DELIMITER ;

プロシージャの最後にある SELECT ステートメントが失敗します。(エラー メッセージを表示するには、下にスクロールする必要がある場合があります。)

mysql> CALL test1('col_tmp1', 'tmp1');
+---------------------------------------------------------------------------------------------------------------------------------+
| @prepared_stmt                                                                                                                  |
+---------------------------------------------------------------------------------------------------------------------------------+
|
                                CREATE TEMPORARY TABLE tmp_test1
                                        SELECT ? AS prepared_stmt_arg, col_tmp1 # AS constant_col_alias
                                                FROM tmp1
                                 |
+---------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

+-------------------------+----------+
| prepared_stmt_arg       | col_tmp1 |
+-------------------------+----------+
| prepared_stmt_arg_value |        1 |
+-------------------------+----------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> CALL test1('col_tmp2', 'tmp2');
+---------------------------------------------------------------------------------------------------------------------------------+
| @prepared_stmt                                                                                                                  |
+---------------------------------------------------------------------------------------------------------------------------------+
|
                                CREATE TEMPORARY TABLE tmp_test1
                                        SELECT ? AS prepared_stmt_arg, col_tmp2 # AS constant_col_alias
                                                FROM tmp2
                                 |
+---------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

ERROR 1054 (42S22): Unknown column 'dev.tmp_test1.col_tmp1' in 'field list'

ただし、列エイリアスのコメントを外す (直前の # を削除するAS constant_col_alias) と、すべて正常に機能します。([Query OK] を表示するには、下にスクロールする必要がある場合があります。)

mysql> CALL test1('col_tmp1', 'tmp1');
+-------------------------------------------------------------------------------------------------------------------------------+
| @prepared_stmt                                                                                                                |
+-------------------------------------------------------------------------------------------------------------------------------+
|
                                CREATE TEMPORARY TABLE tmp_test1
                                        SELECT ? AS prepared_stmt_arg, col_tmp1 AS constant_col_alias
                                                FROM tmp1
                                 |
+-------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

+-------------------------+--------------------+
| prepared_stmt_arg       | constant_col_alias |
+-------------------------+--------------------+
| prepared_stmt_arg_value |                  1 |
+-------------------------+--------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql> CALL test1('col_tmp2', 'tmp2');
+-------------------------------------------------------------------------------------------------------------------------------+
| @prepared_stmt                                                                                                                |
+-------------------------------------------------------------------------------------------------------------------------------+
|
                                CREATE TEMPORARY TABLE tmp_test1
                                        SELECT ? AS prepared_stmt_arg, col_tmp2 AS constant_col_alias
                                                FROM tmp2
                                 |
+-------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

+-------------------------+--------------------+
| prepared_stmt_arg       | constant_col_alias |
+-------------------------+--------------------+
| prepared_stmt_arg_value |                  2 |
+-------------------------+--------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)
4

1 に答える 1

1

バージョン 5.6 までのバグまたは機能 (必要に応じて) のようです。

バグ #32868を参照してください。ストアド ルーチンはメタデータの変更を検出しません。

回避策:
CREATE OR REPLACE VIEW tmpviewAS SELECT 1;を実行して、ストアド ルーチン キャッシュをフラッシュします。

SQLFiddleデモ MySql 5.1.X はこちら SQLFiddle デモMySql 5.5.Xこちら

CREATE OR REPLACE VIEWtmpviewをコメントアウトするAS SELECT 1と、エラーが発生します。

ここにSQLFiddleのデモがあります MySql 5.6.X は、それがもはや問題ではないことを示しています


これで、少なくとも次のオプションを使用できます。

  1. SELECT *代わりに明示的な列名を使用しないでください。
  2. 提案された回避策を使用する
  3. 5.6.X へのアップグレード
于 2013-08-25T23:54:37.883 に答える