Postgres 10 и некорректно сформированный массив при использовании EXECUTE - PullRequest
0 голосов
/ 16 марта 2019

Я пытаюсь создать функцию на Postgres 10, которая будет проверять, существуют ли все заданные идентификаторы в целевой таблице.

CREATE OR REPLACE FUNCTION "public"."has_mismatching_ids"(
  _ids TEXT[],
  _column_name TEXT,
  _table_name TEXT,
  _schema_name TEXT DEFAULT 'public'
)
    RETURNS BOOLEAN AS
$$
DECLARE
  result TEXT[] := '{}';
  _query TEXT := '';
BEGIN
  IF _ids IS NULL THEN
      RETURN false;
  END IF;

  _query := CONCAT('SELECT UNNEST($1) EXCEPT SELECT "', _column_name, '" FROM "', _schema_name ,'"."', _table_name ,'"');
  EXECUTE _query INTO result USING $1;
  RAISE NOTICE 'Executed';

  IF array_length(result, 1) > 0 THEN
      RETURN true;
  END IF;

  RETURN false;
END;
$$
LANGUAGE plpgsql
    STABLE
    SECURITY INVOKER;

Это моя функция, которая возвращает правильно значение true, если существуют все идентификаторы,но он выдает исключение, если какой-либо из идентификаторов не существует.

CREATE TABLE "public"."categories" ("category_id" TEXT NOT NULL PRIMARY KEY);
INSERT INTO "public"."categories" ("category_id") VALUES ('foo');
INSERT INTO "public"."categories" ("category_id") VALUES ('bar');

Это работает

SELECT FROM "public"."has_mismatching_ids"(ARRAY['foo'], 'category_id', 'categories', 'public');
NOTICE:  Executed
 has_mismatching_ids 
---------------------
 f
(1 row)

, но это не удается даже

SELECT FROM "public"."has_mismatching_ids"(ARRAY['foo2'], 'category_id', 'categories', 'public');
ERROR:  malformed array literal: "foo2"
DETAIL:  Array value must start with "{" or dimension information.
CONTEXT:  PL/pgSQL function public.has_mismatching_ids(text[],text,text,text) line 14 at EXECUTE

и странным образомэто работает также, если я пишу функцию, которая использует явные имена и без EXECUTE

SELECT UNNEST(ARRAY['foo', 'foo3']) EXCEPT SELECT "category_id" FROM "public"."categories";
unnest 
--------
 foo3
(1 row)

Почему моя динамическая функция не работает при сравнении со значениями, которые не существуют в целевой таблице?

1 Ответ

0 голосов
/ 17 марта 2019

Вы можете использовать простой SQL для сравнения, если существует весь элемент массива.

CREATE OR replace FUNCTION "public"."has_mismatching_ids"( 
  _ids text[],
  _column_name text, 
  _table_name text, 
  _schema_name text DEFAULT 'public' ) 
returns     boolean AS $$
DECLARE res BOOLEAN;
BEGIN 
  IF _ids IS NULL then 
  RETURN false; 
END IF;
EXECUTE format ( 'SELECT  COUNT(*) = cardinality($1)   
      FROM  %I.%I WHERE  %I  = ANY($2)', 
  _schema_name,_table_name,_column_name )
 INTO res using _ids, _ids;
RETURN res;
END;
$$ language plpgsql stable security invoker;

Демо

...