5

postgresql バージョン 8.2.22 を使用していましたが、postgresql 9.1.3 にアップグレードすると、アップグレードは正常に完了しました。

しかし今、一部のキャストは以前と同じように機能していません!

Postgres 8.2.22 では

次の 2 つのクエリを実行すると、どちらも正しく動作します。

POSTGRES8222=# select TO_NUMBER('12345678',9999999999.99);

to_number
=========   
 12345678
(1 row)

POSTGRES8222=# select a ||'$'|| b from test;
 ?column?
----------
 1$abcdef
 2$ghijkl
 3$3456
(3 rows)

Postgres 9.1.3 へのアップグレード後

同じクエリを実行すると、エラーがスローされます。

select TO_NUMBER('12345678',9999999999.99);

ERROR:  function to_number(unknown, numeric) does not exist
LINE 1: select TO_NUMBER('12345678',9999999999.99);
               ^
HINT:  No function matches the given name and argument types. You might 
need to add explicit type casts.

EXCEPTION
org.postgresql.util.PSQLException: ERROR: function to_number(numeric, numeric) 
does not exist

Hint: No function matches the given name and argument types. You might need 
to add explicit type casts.

Position: 150



select a ||'$'|| b from test;
ERROR:  operator is not unique: numeric || unknown
LINE 1: select a ||'$'|| b from test;
                 ^
HINT:  Could not choose a best candidate operator. You might need to 
add explicit type casts.

********** Error **********
ERROR: operator is not unique: numeric || unknown
SQL state: 42725
Hint: Could not choose a best candidate operator. You might need to  
add explicit type casts.
Character: 10

postgresql でのキャストが以前のように機能しないのはなぜですか?

4

1 に答える 1

7

PostgreSQL 8.3以降、自動キャストは少なくなっています。これは2つの理由で変更されました。

  1. 多くの新しい強力なタイプが導入されており、自動キャストにより、これらは「ファーストクラス」タイプと同じようにリテラルを使用できなくなりました。パーサーがデータ型を推測しようとしたケースを絞り込むことで、ユーザーがプラグインできる新しい型をより自然な方法で使用できるようになりました。

  2. 多くのバグレポートは、自動キャストが発生していることに気づかなかったときに、誤って自動キャストの「メリット」を享受し、アプリケーションのコーディングエラーを見つけるのが困難であることが判明しました。8.3がリリースされた後、自分のコードに以前は必要なかったキャストが必要だと不満を言う人がいたのとほぼ同じ数の人が、自分のコードに隠されたバグを発見したと言って投稿しました。

暗黙のタイプキャストを追加して、この「問題」を「解決」しようとしたようです。これは地雷原です。私はそれをお勧めしません。安全に使用できる機能を制限し、他の誰もやらないような風変わりな小さなバグに終止符を打つことはなく、誰も簡単に手伝うことはできません。暗黙の変換をそれほど多く想定しないようにコードを修正することをお勧めします。

混乱するかもしれないことの1つは、PostgreSQLでは文字列リテラルで'1.2'ないということです。これは不明なタイプのリテラルです。

test =#select pg_typeof( '1.2');
 pg_typeof
-----------
 わからない
(1行)

PostgreSQLは、可能な限りリテラルの型を解決することを控えています。これは、私が説明したすべての新しいデータ型でうまく機能します。最後の手段として、タイプを解決する必要があり、他に手がかりがない場合は、タイプとして扱いtextます。

test =#select pg_typeof(case when true then '1.2' else null end);
 pg_typeof
-----------
 文章
(1行)

test =#select pg_typeof(case when true then '1.2' else 2.3 end);
 pg_typeof
-----------
 数値
(1行)

問題2の「aftertypecast」は失敗しています。これは、追加したすべての暗黙の型キャストで、複数の可能な演算子が存在するためです|| これは、実行した暗黙のタイプキャストに応じて選択でき、それらの中から選択する原則的な方法はありませんでした。その行を次のように変更すると、再び機能するはずです。

select a || '$'::text || b from test;

これらの暗黙のキャストを追加せず、最初の問題コードを次のように変更しない方が、よりクリーンで安全であると私は主張しています。

select TO_NUMBER('12345678',9999999999.99);

に:

select TO_NUMBER('12345678', '9999999999.99');

結局のところ、その2番目のパラメーターはフォーマット文字列であり、数値ではありません。次のようなことをしたい場合は、引用符を省略することはできません。

test =#select to_number('12、454.8-'、' 99G999D9S');
 to_number
-----------
  -12454.8
(1行)
于 2012-08-17T20:28:11.373 に答える