ファイヤープロジェクト
NULLの扱いと指示子
2004-05-09T21:15+09:00   matsu
埋め込みSQLにおけるNULLの扱いについて調査してみた.
埋め込みSQLには以下のように変数を使用することができた.
EXEC SQL INSERT INTO hoge VALUES (1,:name);
nameにはプログラムで設定した値が格納され,DBにはその値を設定したSQLが発行される.この変数にNULLを設定する場合には,指示子を変数の後に付ける.
EXEC SQL INSERT INTO hoge VALUES (1,:name :nullFlag);
変数と指示子の間にコンマはない.この指示子によって,変数がNULLか否かを設定できる.すなわち,上の埋め込みSQLはnullFlagが0の場合はnameに設定されている値が設定され,nullFlagが負の値の場合はnameの値の代わりにNULLが設定されてSQLが発行される.これはSELECTやFETCHでも同じである.
EXEC SQL FETCH hogecursor INTO :id, :name :nullFlag;
変数nameが指示子nullFlagと一緒に記述されているので,nameの値がNULLか否かをまずnullFlagでチェックして,NULLでなければnameの値を取り出せる.この例では変数idは指示子とともに記述していない.このように指示子は変数毎に指定できる.取り出しの場合,指示子は以下の意味を持つ.
負の値
変数の値がNULL
0
正常
正の値
実際の値を切り詰めて変数に格納
DBに格納されている値の大きさより変数の領域が小さいと,正の値が設定される.このため,NOT NULL制約のあるフィールドであっても,さまざまなサイズのデータを格納するフィールドを扱う際にも指示子を使用する場合がある.
指示子を使用してNULLを扱うサンプルを以下に示す.
このサンプルでは,フィールドの値をNULLとしてインサートしたり,そのレコードをフェッチしてフィールドがNULLかどうかをチェックする.以下は実行結果.
$> ./query-null  -d tcp:postgresql://dbserver/firstdb -u matsu -p hogefuga
[17940]: ECPGdebug: set to 1
[17940]: ECPGconnect: opening database firstdb on dbserver port <DEFAULT> for user matsu
[17940]: ECPGexecute line 51: QUERY: create table hoge ( id integer primary key , name char( 8 ))
  on connection dbConnection
[17940]: CREATE TABLE / PRIMARY KEY will create implicit index 'hoge_pkey'
  for table 'hoge'[17940]: raising sqlcode 0
[17940]: ECPGexecute line 51 Ok: CREATE
!!!!!SQLSTATE!!!!!! YE000
!!!!!SQLCODE!!!!! 0
[17940]: ECPGexecute line 67: QUERY: insert into hoge values( 1 , 'HOGE' )
  on connection dbConnection
[17940]: ECPGexecute line 67 Ok: INSERT 964351 1
[17940]: ECPGexecute line 77: QUERY: insert into hoge values( 2 , null )
  on connection dbConnection
[17940]: ECPGexecute line 77 Ok: INSERT 964352 1
[17940]: ECPGexecute line 93: QUERY: declare hogecursor cursor for
  select  id  , name   from hoge    on connection dbConnection
[17940]: ECPGexecute line 93 Ok: DECLARE
[17940]: ECPGexecute line 102: QUERY: fetch hogecursor on connection dbConnection
[17940]: ECPGexecute line 102: Correctly got 1 tuples with 2 fields
[17940]: ECPGget_data line 102: RESULT: 1 offset: 4 array: 3
[17940]: ECPGget_data line 102: RESULT: HOGE     offset: 9 array: 3
fetched id = 1 name = HOGE    
[17940]: ECPGexecute line 102: QUERY: fetch hogecursor on connection dbConnection
[17940]: ECPGexecute line 102: Correctly got 1 tuples with 2 fields
[17940]: ECPGget_data line 102: RESULT: 2 offset: 4 array: 3
[17940]: ECPGget_data line 102: RESULT:  offset: 9 array: 3
fetched id = 2 name IS NULL
[17940]: ECPGexecute line 102: QUERY: fetch hogecursor on connection dbConnection
[17940]: ECPGexecute line 102: Correctly got 0 tuples with 2 fields
[17940]: raising sqlcode 100 in line 102, 'No data found in line 102.'.
[17940]: ECPGexecute line 126: QUERY: close hogecursor on connection dbConnection
[17940]: ECPGexecute line 126 Ok: CLOSE
[17940]: ECPGexecute line 129: QUERY: drop table hoge  on connection dbConnection
[17940]: ECPGexecute line 129 Ok: DROP
[17940]: ECPGtrans line 138 action = commit connection = dbConnection
[17940]: ecpg_finish: Connection dbConnection closed.
インサートは二回ともnameは"HOGE"となっているが,二回目のインサートでは指示子によりnameにはnullを指定するSQLが発行されている.
[17940]: ECPGexecute line 77: QUERY: insert into hoge values( 2 , null )
  on connection dbConnection
さらに上のレコードをフェッチした場合は指示子により負の値に設定されているので,プログラムはその処理ルートに入って出力している.
fetched id = 2 name IS NULL
matsu(C)
Since 2002
Mail to matsu