Обработка исключений в функции PostgreSQL с помощью Django

нужно написать следующую процедуру хранения в Postgres. Этот SP просто принимает входящие параметры, вставляет их в таблицу и возвращает текущий идентификатор. Еще я также объявил дополнительную переменную, которая скажет, успешно ли работает sp или нет.

Я новичок в Postgres и мало что знаю о способе Postgres сделать это. Я хочу что-то вроде BEGIN TRY, END TRY и BEGIN CATCH, END CATCH, как мы делаем в MSSQL.

CREATE OR REPLACE FUNCTION usp_save_message(msg_sub character varying(80), msg_content text, msg_type character(12), msg_category character(255),msg_created_by character(255),msg_updated_by character(255))
  RETURNS msg_id character, success boolean AS
$BODY$
DECLARE
    msg_id character;
    success boolean;
BEGIN
  BEGIN TRY:
  set success = 0
  set msg_id = INSERT INTO tbl_messages(
            message_subject, message_content, message_type, message_category, 
            created_on, created_by, updated_on, updated_by)
    VALUES (msg_sub, msg_cont, msg_type,msg_category, LOCALTIMESTAMP, 
            msg_created_by, LOCALTIMESTAMP, msg_updated_by) RETURNING message_id;
   set success = 1
   RETURN msg_id,success;
END;
$BODY$
LANGUAGE plpgsql VOLATILE

Я хочу что-то вроде этого:

begin proc()
BEGIN
  BEGIN TRY:
        set success = 0
        execute the query
        set success = 1
  END TRY
  BEGIN CATCH:
   set success = 0
  END CATCH
  set success = 1
END

Больше мне нужно поймать оба этих возвращаемых значения в представлениях django.

Я обновил вопрос, и теперь он такой же, как сейчас;

Вот стол,

CREATE TABLE tbl_messages
(
  message_subject character varying(80),
  message_content text,
  message_type character(12),
  message_category character(255),
  created_on timestamp without time zone,
  created_by character(255),
  updated_on timestamp without time zone,
  updated_by character(255),
  message_id serial NOT NULL,
  CONSTRAINT tbl_messages_pkey PRIMARY KEY (message_id)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE tbl_messages
  OWNER TO gljsxdlvpgfvui;

Вот функция, которую я создал;

CREATE FUNCTION fn_save_message(IN msg_sub character varying, IN msg_cont text, IN msg_type character varying, IN msg_category character varying, IN msg_created_by character varying, IN msg_updated_by character varying, OUT success boolean, OUT msg_id integer) RETURNS integer AS
$BODY$BEGIN
  BEGIN
    INSERT INTO tbl_messages
        (message_subject, message_content, message_type, message_category, 
       created_on, created_by, updated_on, updated_by)
    VALUES 
      (msg_sub, msg_cont, msg_type, msg_category, LOCALTIMESTAMP, 
       msg_created_by, LOCALTIMESTAMP, msg_updated_by)
    returning message_id
    into msg_id;

    success := true;
  EXCEPTION 
    WHEN others then 
      success := false;
      msg_id := null;
  END;
  return msg_id,success;
END;$BODY$
LANGUAGE plpgsql VOLATILE NOT LEAKPROOF
COST 100;
ALTER FUNCTION public.fn_save_message(IN character varying, IN text, IN character varying, IN character varying, IN character varying, IN character varying)
  OWNER TO gljsxdlvpgfvui;

Но он все еще не работает ... я не знаю, что id сделал неправильно, любой эксперт по django / postgres, пожалуйста, помогите мне.


person Muhammad Taqi    schedule 06.01.2015    source источник
comment
Весь этот SP не нужен. В pgsql вы можете просто выполнить INSERT... RETURNING msg_id и обрабатывать неудачные вставки как обычно.   -  person David Chan    schedule 06.01.2015
comment
Нет такой вещи, как процедура хранения. Вы имеете в виду хранимую процедуру, эквивалентом которой является функция в Postgres. Сначала вам нужно изучить основы в отличном руководстве: CREATE FUNCTION и plpgsql.   -  person Erwin Brandstetter    schedule 07.01.2015


Ответы (1)


Есть несколько проблем с вашей функцией:

  1. Операторы должны заканчиваться ; - всегда
  2. Присвоение переменных выполняется с помощью := (см.: http://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-ASSIGNMENT)
  3. Вы не можете вернуть более одного значения из функции (если только вы не создадите функцию, возвращающую множество, не вернете объект или не используете out параметров)
  4. Логические значения: true или false. Не 0 или 1 (это числа)
  5. Результат автоматически сгенерированного значения идентификатора лучше получить с помощью оператора lastval() или `` INSERT... RETURNING expression INTO ...not through aSET`.

Обработка исключений выполняется с помощью предложения exception как описано в руководстве

Итак, вам нужно что-то вроде этого:

DECLARE
....

BEGIN
  BEGIN
    INSERT INTO tbl_messages
        (message_subject, message_content, message_type, message_category, 
       created_on, created_by, updated_on, updated_by)
    VALUES 
      (msg_sub, msg_cont, msg_type,msg_category, LOCALTIMESTAMP, 
       msg_created_by, LOCALTIMESTAMP, msg_updated_by)
    returning message_id
    into msg_id;

    success := true;
  EXCEPTION 
    WHEN others then 
      success := false;
      msg_id := null;
  END;
  return msg_id;
END;

Но, как я уже сказал: вы не можете вернуть более одного значения из функции. Единственный способ сделать это — объявить OUT параметров, но лично я нахожу их немного сложными для обработки в клиентах SQL.

У вас есть следующие возможности сообщить об ошибке вызывающему абоненту:

  1. позволить вызывающему обрабатывать исключение/ошибку, которая может возникнуть (что я и предпочитаю)
  2. определите новый пользовательский тип данных, который содержит message_id и флаг успеха, и верните его (но это означает, что вы потеряете сообщение об ошибке!)
  3. вернуть NULL для message_id, чтобы указать, что что-то пошло не так (но это также означает, что вы потеряете информацию об ошибке)
  4. Используйте параметры out для передачи обоих значений. Пример доступен в руководстве: http://www.postgresql.org/docs/current/static/xfunc-sql.html#XFUNC-OUTPUT-PARAMETERS
person a_horse_with_no_name    schedule 06.01.2015
comment
OUT — это один (хороший) способ вернуть несколько столбцов. Другие способы: вернуть составной тип (тип строки); вернуть анонимную запись (требуется список определений столбцов при вызове); используйте RETURNS TABLE (который может возвращать 0-n строк) - person Erwin Brandstetter; 07.01.2015
comment
Я обновил вопрос с вашей помощью, пожалуйста, просмотрите его. - person Muhammad Taqi; 07.01.2015