Postgres создает локальную временную таблицу (при удалении фиксации) из динамической строки sql

У меня есть строка запроса, сгенерированная в UDF postgres, я хотел бы поместить ее результат во временную таблицу для выполнения соединений (я использую LIMIT и OFFSET, и я не хочу объединяться с другими таблицами только для завершения обрезать данные в конце -- т. е. оператор LIMIT в плане запроса). Я пытаюсь создать временную таблицу со следующим оператором.

CREATE LOCAL TEMP TABLE query_result ON COMMIT DROP AS EXECUTE query_string_;

Но я получаю следующее уведомление об ошибке:

********** Error **********

ERROR: prepared statement "query_string_" does not exist
SQL state: 26000
Context: SQL statement "CREATE LOCAL TEMP TABLE query_result ON COMMIT DROP AS EXECUTE query_string_"
PL/pgSQL function "search_posts_unjoined" line 48 at SQL statement

Кроме того, я попытался подготовить стейтменов, но не смог правильно понять синтаксис.

Рассматриваемый UDF:

CREATE OR REPLACE FUNCTION search_posts_unjoined(
    forum_id_ INTEGER,
    query_    CHARACTER VARYING,
    offset_ INTEGER DEFAULT NULL,
    limit_ INTEGER DEFAULT NULL,
    from_date_ TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL,
    to_date_ TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL,
    in_categories_ INTEGER[] DEFAULT '{}'
    )
RETURNS SETOF forum_posts AS $$
DECLARE
    join_string CHARACTER VARYING := ' ';
    from_where_date CHARACTER VARYING := ' ';
    to_where_date CHARACTER VARYING := ' ';
    query_string_ CHARACTER VARYING := ' ';
    offset_str_ CHARACTER VARYING := ' ';
    limit_str_ CHARACTER VARYING := ' ';
BEGIN
    IF NOT from_date_ IS NULL THEN
        from_where_date := ' AND fp.posted_at > ''' || from_date_ || '''';
    END IF;

    IF NOT to_date_ IS NULL THEN
        to_where_date := ' AND fp.posted_at < ''' || to_date_ || '''';
    END IF;

    IF NOT offset_ IS NULL THEN
        offset_str_ := ' OFFSET ' || offset_; 
    END IF;

    IF NOT limit_ IS NULL THEN
        limit_str_ := ' LIMIT ' || limit_;
    END IF;

    IF NOT limit_ IS NULL THEN
    END IF;

    CREATE LOCAL TEMP TABLE un_cat(id) ON COMMIT DROP AS (select * from unnest(in_categories_)) ;

    if in_categories_ != '{}' THEN
        join_string := ' INNER JOIN un_cat uc ON uc.id = fp.category_id ' ;
    END IF;

    query_string_ := '
    SELECT fp.*
    FROM forum_posts fp' ||
        join_string
    ||
    'WHERE fp.forum_id = ' || forum_id_ || ' AND
    to_tsvector(''english'',fp.post_text) @@ to_tsquery(''english'','''|| query_||''')' || 
        from_where_date || 
        to_where_date ||
        offset_str_ ||
        limit_str_ 
    ||  ';';

    CREATE LOCAL TEMP TABLE query_result ON COMMIT DROP AS EXECUTE query_string_;

    RAISE NOTICE '%', query_string_;

    RETURN QUERY
    EXECUTE query_string_;
END;
$$ LANGUAGE plpgsql;

И это работает, когда рассматриваемое утверждение удалено.


person Hassan Syed    schedule 31.08.2012    source источник


Ответы (1)


Вместо этого используйте:

EXECUTE '
CREATE TEMP TABLE query_result ON COMMIT DROP AS '|| query_string_;
  • EXECUTE весь оператор.
    Синтаксическая форма CREATE TABLE foo AS EXECUTE <query> недопустима.

  • LOCAL — это просто шумовое слово, которое в данном контексте игнорируется.

Дополнительные дополнительные сведения см. в руководстве.

person Erwin Brandstetter    schedule 31.08.2012
comment
Ааа, радости уровней косвенности =D Высоко ценится. - person Hassan Syed; 31.08.2012