2017-01-09 7 views
0

PLPGSQL関数では、レコードが存在するかどうかを確認する行がいくつかあります。レコードがない場合でも、FOUND変数はTRUEに設定されています。非常に奇妙なこと。レコードがない場合はFOUND変数が 'true'に設定されます

query:='SELECT i.identity_id FROM app.identity as i,' || quote_ident(schema_name) || '.users as u,' || quote_ident(schema_name) || '.udata as ud WHERE i.identity_id=' || p_identity_id || ' and u.identity_id=i.identity_id and ud.identity_id=i.identity_id'; 
     RAISE WARNING 'query=%',query; 
     PERFORM query; 
     RAISE WARNING 'FOUND=%',FOUND; 
     IF FOUND 
     THEN 
      RAISE WARNING 'Record found, rising an exception'; 
      RAISE EXCEPTION USING ERRCODE = 'AA002'; 
     END IF; 

これが出力されます:私はテストしてい

線である

WARNING: query=SELECT i.identity_id FROM app.identity as i,"comp-1049007476".users as u,"comp-1049007476".udata as ud WHERE i.identity_id=-1615382132 and u.identity_id=i.identity_id and ud.identity_id=i.identity_id 
WARNING: FOUND=t 
WARNING: Record found, rising an exception 

そして、これはpg_logです:

2017-01-09 09:47:21.906 CST > LOG: execute <unnamed>: SELECT app.create_identity($1::varchar,'') as identity_id 
< 2017-01-09 09:47:21.906 CST > DETAIL: parameters: $1 = '[email protected]' 
< 2017-01-09 09:47:21.908 CST > WARNING: new_identity_id=-1615382132 
< 2017-01-09 09:47:21.908 CST > CONTEXT: PL/pgSQL function app.create_identity(character varying,character varying) line 18 at RAISE 
< 2017-01-09 09:47:21.917 CST > LOG: execute <unnamed>: select app.add_user(  
         $1::integer, 
         $2::varchar,      
         $3::integer,      
         $4::varchar,      
         $5::varchar,      
         $6::varchar,      
         $7::varchar,      
         $8::varchar,      
         $9::varchar,      
         $10::varchar,      
         $11::integer,      
         $12::integer,      
         $13::integer,      
         $14::integer,      
         $15::integer,      
         $16::integer,      
         $17::smallint,     
         $18::boolean,      
         $19::boolean,      
         $20::boolean,      
         $21::boolean,      
         $22::boolean      
         ) 
< 2017-01-09 09:47:21.917 CST > DETAIL: parameters: $1 = '905220468', $2 = '763715373817831', $3 = '-1049007476', $4 = 'Some User', $5 = '44444', $6 = '', $7 = '', $8 = '', $9 = '', $10 = '', $11 = '-1615382132', $12 = '0', $13 = '1', $14 = '0', $15 = '0', $16 = '0', $17 = '0', $18 = 't', $19 = 'f', $20 = 'f', $21 = 'f', $22 = 'f' 
< 2017-01-09 09:47:21.919 CST > WARNING: query=SELECT i.identity_id FROM app.identity as i,"comp-1049007476".users as u,"comp-1049007476".udata as ud WHERE i.identity_id=-1615382132 and u.identity_id=i.identity_id and ud.identity_id=i.identity_id 
< 2017-01-09 09:47:21.919 CST > CONTEXT: PL/pgSQL function app.add_user(integer,character varying,integer,character varying,character varying,character varying,character varying,character varying,character varying,character varying,integer,integer,integer,integer,integer,integer,smallint,boolean,boolean,boolean,boolean,boolean) line 25 at RAISE 
< 2017-01-09 09:47:21.919 CST > WARNING: FOUND=t 
< 2017-01-09 09:47:21.919 CST > CONTEXT: PL/pgSQL function app.add_user(integer,character varying,integer,character varying,character varying,character varying,character varying,character varying,character varying,character varying,integer,integer,integer,integer,integer,integer,smallint,boolean,boolean,boolean,boolean,boolean) line 27 at RAISE 
< 2017-01-09 09:47:21.919 CST > WARNING: Record found, rising an exception 
< 2017-01-09 09:47:21.919 CST > CONTEXT: PL/pgSQL function app.add_user(integer,character varying,integer,character varying,character varying,character varying,character varying,character varying,character varying,character varying,integer,integer,integer,integer,integer,integer,smallint,boolean,boolean,boolean,boolean,boolean) line 30 at RAISE 
< 2017-01-09 09:47:21.919 CST > ERROR: Identity already registered 

は、なぜ私はレコードがその確信しています存在しない?まあ、私は私が知っている値を入れています表にはありませんが、念のために、私は確認してください。

dev=> SELECT i.identity_id FROM app.identity as i,"comp-1049007476".users as u,"comp-1049007476".udata as ud WHERE i.identity_id=-1615382132 and u.identity_id=i.identity_id and ud.identity_id=i.identity_id; 
identity_id 
------------- 
(0 rows) 

dev=> 

を参照してください、0を記録。ですから、BIGの質問は、なぜFOUND変数が嘘ですか?ここで何が起きてるの?念のため、

CREATE OR REPLACE FUNCTION app.add_user(sess_identity_id int,session_str varchar,sess_company_id int, 
    p_full_name   varchar, 
    p_mob_phone   varchar, 
    p_home_phone  varchar, 
    p_work_phone  varchar, 
    p_phone_ext   varchar, 
    p_position   varchar, 
    p_notes    varchar, 
    p_identity_id  integer, 
    p_user_id   integer, 
    p_group_id   integer, 
    p_shift_id   integer, 
    p_boss_id   integer, 
    p_crreated_by  integer, 
    p_timezone   smallint, 
    p_utype    boolean, 
    p_create_root  boolean, 
    p_has_subord  boolean, 
    p_inactive   boolean, 
    p_generic   boolean 
) 
RETURNS integer as $$ 
DECLARE 
    v_session     bigint; 
    schema_name     varchar; 
    query      varchar; 
    current_ts     integer; 
    v_user_id     integer; 
    v_generic     integer; 
    v_udata_id     integer; 
    _c       text; 
BEGIN 
     SELECT extract(epoch from now())::integer into current_ts; 
     SELECT session_str::bigint INTO v_session; 
     schema_name:='comp' || sess_company_id; 

     IF NOT EXISTS (
      SELECT 1 FROM app.session WHERE app.session.identity_id=sess_identity_id AND app.session.session=v_session 
     ) THEN 
      RAISE EXCEPTION USING ERRCODE = 'AA001'; 
     END IF; 

     query:='SELECT i.identity_id FROM app.identity as i,' || quote_ident(schema_name) || '.users as u,' || quote_ident(schema_name) || '.udata as ud WHERE i.identity_id=' || p_identity_id || ' and u.identity_id=i.identity_id and ud.identity_id=i.identity_id'; 
     RAISE WARNING 'query=%',query; 
     PERFORM query; 
     RAISE WARNING 'FOUND=%',FOUND; 
     IF FOUND 
     THEN 
      RAISE WARNING 'Record found, rising an exception'; 
      RAISE EXCEPTION USING ERRCODE = 'AA002'; 
     END IF; 

     query:='SELECT u.user_id,u.generic FROM ' || quote_ident(schema_name) || '.users as u,identity as i WHERE i.email=p_email AND i.identity_id=u.identity_id'; 
     RAISE WARNING 'query=%',query; 
     EXECUTE query INTO v_user_id,v_generic; 
     IF NOT FOUND 
     THEN 
      EXECUTE 'INSERT INTO $1.users(
       identity_id, 
       group_id, 
       shift_id, 
       boss_id, 
       created_by, 
       date_inserted 
       timezone, 
       utype, 
       create_root, 
       has_subord, 
       inactive, 
       generic 
      ) VALUES ($2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13) RETURNING user_id' 
       INTO v_user_id 
       USING schema_name,p _identity_id,p_group_id,p_shift_id,p_boss_id,p_created_by,p_date_inserted,p_timezone,p_utype,p_create_root,p_has_subord,p_inactive,p_generc; 
     END IF; 
     if NOT v_generic THEN 
      RAISE EXCEPTION USING ERRCODE = 'AA003'; 
     END IF; 
     EXECUTE 'INSERT INTO $1.udata(user_id,identity_id,date_insert,full_name,mob_phone,home_phone,work_phone,phone_ext,position,notes) VALUES ($2,$3,$4,$5,$6,$7,$8,$9,$10,$11)' 
       INTO v_udata_id 
       USING schema_name,v_user_id,p_identity_id,current_ts,p_full_name,p_mob_phone,p_home_phone,p_work_phone,p_phone_ext,p_position,p_notes; 
     RETURN v_udata_id; 
EXCEPTION 
    WHEN SQLSTATE 'AA001' THEN 
     RAISE EXCEPTION USING ERRCODE = 'AA001', message = 'Invalid session'; 
    WHEN SQLSTATE 'AA002' THEN 
     RAISE EXCEPTION USING ERRCODE = 'AA002', message = 'Identity already registered'; 
    WHEN SQLSTATE 'AA003' THEN 
     RAISE EXCEPTION USING ERRCODE = 'AA003', message = 'Not a generic user, can not add email address'; 
    WHEN OTHERS THEN 
     RAISE NOTICE 'add_user() failed with... error: % %',SQLSTATE,SQLERRM; 
     GET STACKED DIAGNOSTICS _c = PG_EXCEPTION_CONTEXT; 
     RAISE NOTICE 'context: >>%<<', _c; 
     RAISE EXCEPTION USING MESSAGE = 'An error which is not handled by function'; 
END 
$$ LANGUAGE plpgsql; 

とテーブル構造:

これは私の関数の完全なコードです

dev=> \d+ app.identity; 
            Table "app.identity" 
    Column  |   Type   | Modifiers | Storage | Stats target | Description 
---------------+------------------------+-----------+----------+--------------+------------- 
identity_id | integer    | not null | plain |    | 
created_by | integer    |   | plain |    | 
email   | character varying(128) |   | extended |    | 
date_inserted | integer    |   | plain |    | 
password  | character varying(32) |   | extended |    | 
validated  | smallint    |   | plain |    | 
Indexes: 
    "identity_pkey" PRIMARY KEY, btree (identity_id) 
    "identity_email_key" UNIQUE CONSTRAINT, btree (email) 

dev=> \d+ "comp-1049007476".users; 
                 Table "comp-1049007476.users" 
    Column  | Type |         Modifiers         | Storage | Stats target | Description 
---------------+----------+---------------------------------------------------------------------------+---------+--------------+------------- 
user_id  | integer | not null default nextval('"comp-1049007476".users_user_id_seq'::regclass) | plain |    | 
identity_id | integer | default 0                 | plain |    | 
group_id  | integer | default 0                 | plain |    | 
shift_id  | integer | default 0                 | plain |    | 
boss_id  | integer | default 0                 | plain |    | 
created_by | integer | default 0                 | plain |    | 
date_inserted | integer | default 0                 | plain |    | 
timezone  | smallint | default 0                 | plain |    | 
utype   | boolean | default false                | plain |    | 
create_root | boolean | default false                | plain |    | 
has_subord | boolean | default false                | plain |    | 
inactive  | boolean | default false                | plain |    | 
generic  | boolean | default false                | plain |    | 

dev-> \d+ "comp-1049007476".udata 
                   Table "comp-1049007476.udata" 
    Column  |   Type   |         Modifiers         | Storage | Stats target | Description 
---------------+------------------------+----------------------------------------------------------------------------+----------+--------------+------------- 
udata_id  | integer    | not null default nextval('"comp-1049007476".udata_udata_id_seq'::regclass) | plain |    | 
user_id  | integer    | default 0                 | plain |    | 
identity_id | integer    | default 0                 | plain |    | 
date_inserted | integer    | default 0                 | plain |    | 
full_name  | character varying(64) | default ''::character varying            | extended |    | 
mob_phone  | character varying(16) | default ''::character varying            | extended |    | 
home_phone | character varying(16) | default ''::character varying            | extended |    | 
work_phone | character varying(16) | default ''::character varying            | extended |    | 
phone_ext  | character varying(8) | default ''::character varying            | extended |    | 
position  | character varying(64) | default ''::character varying            | extended |    | 
notes   | character varying(128) | default ''::character varying            | extended |    | 

dev-> 
+0

多分 'GET DIYNOSTICS someyourvariable = ROW_COUNT;'と変数を表示しようとすると、いくつかのレコードがあるかどうかを調べるでしょう。 – JosMac

+0

3行目: 'PERFORM'は' EXECUTE'でなければなりませんが、Pavelの応答を見てください。 – Jasen

+0

@Jasen 'EXECTE'は' FOUND'変数に影響しません。 – Nulik

答えて

5

基本的な問題はPERFORM文の使用法です。このステートメントは、結果処理なしの関数評価用に設計されています。動的SQL(SQLが文字列として入力される)用に設計されていません。

PLpgSQLはほとんどすべての文をSELECTに変換します。 PERFORMも例外ではありません。

PERFORM fx(10,20); 

をに変換される:

SELECT fx(10,20); 

あなたコード:

variable := 'SELECT * FROM foo'; 
PERFORM variable; 

をに変換される:

SELECT 'SELECT * FROM foo'; -- it is same like SELECT 'hello'; 

このクエリは、一つの行を返し、変数FOUNDであるべきです本当。だから何も変わっていない。

PLpgSQLでは、静的SQLと動的SQLが大きく異なる必要があります。動的SQL(クエリは実行時にアセンブルされます)は、EXECUTEステートメントでのみサポートされています。

使用法PERFORM variableは、このステートメントの間違った使い方ですが、実行時エラーなしで評価できる有効なSQL文を生成します。

+0

ありがとう!!!それは何が起こっているのかについての完全な説明であり、私はそれを得ました。しかし、 'FOUND'変数には影響しないので、' EXECUTE'を使うことはできません。それで私は 'PEFORM'を使用しようとしていたのです... – Nulik

+0

万が一、私のスキーマ名を連結することによって' PEROFRM'コマンドのクエリをどのように構築することができますか? quote_ident(schema_name)|| '?? PERFORMで文字列連結を使用しようとすると、多くのエラーが発生します。 – Nulik

+0

私のスキーマ名には特殊文字が含まれているので、quote_ident()関数を使用する必要がありますが、これを 'PERFORM'文に挿入することはできません。 – Nulik

関連する問題