Iaabdenbithen Karim Iaabdenbithen Karim - 7 months ago 43
SQL Question

Postgresql syntax error at or near "+"

I got the following postgresql function:

CREATE OR REPLACE FUNCTION insert_address() RETURNS TRIGGER AS
$BODY$

DECLARE row_count INTEGER;
DECLARE max_id INTEGER;
DECLARE key_ INTEGER;

BEGIN
SELECT count(*) FROM ADDRESS INTO row_count;

IF row_count = 0
THEN SET NEW.id_address = 1;
ELSE SELECT count(table_name)
FROM FREE_KEYS
WHERE table_name = 'ADDRESS' INTO row_count;

IF row_count = 0
THEN SELECT max(id_address) FROM ADDRESS INTO max_id;
SET NEW.id_address = max_id + 1;

ELSE SELECT min(free_key) FROM FREE_KEYS WHERE table_name = 'ADDRESS' INTO key_;
SET NEW.id_address = key_;
DELETE FROM FREE_KEYS WHERE table_name = 'ADDRESS' AND free_key = key_;
END IF;
END IF;
END;
$BODY$ LANGUAGE plpgsql;


i don't understand why the assignment operation returns the following error:

ERROR: syntax error at or near "+"
LINE 700: SET NEW.id_address = max_id + 1;

Answer

You have two main errors in your function:

  1. There is no SET in PL/pgSQL. Assignment is done using :=
  2. The INTO clause for a variable has to come after the list of columns in the SELECT statement.


CREATE OR REPLACE FUNCTION insert_address() RETURNS TRIGGER AS
$BODY$

DECLARE row_count INTEGER;
DECLARE max_id INTEGER;
DECLARE key_ INTEGER;

BEGIN
  SELECT count(*) 
      INTO row_count --<< the INTO has to be after the column list
  FROM ADDRESS;

  IF row_count = 0
  THEN 
    NEW.id_address := 1;  --<< there is no SET in PL/pgSQL
  ELSE 
    SELECT count(table_name)
      INTO row_count   --<< the INTO has to be after the column list
    FROM FREE_KEYS
    WHERE table_name = 'ADDRESS';

    IF row_count = 0 
    THEN 
      SELECT max(id_address) 
         INTO max_id  --<< the INTO has to be after the column list
      FROM ADDRESS;

      NEW.id_address := max_id + 1;
    ELSE 
      SELECT min(free_key) 
         INTO key_    --<< the INTO has to be after the column list
      FROM FREE_KEYS 
      WHERE table_name = 'ADDRESS';

      NEW.id_address := key_;
      DELETE FROM FREE_KEYS WHERE table_name = 'ADDRESS' AND free_key = key_;

    END IF;
  END IF;

END;
$BODY$ LANGUAGE plpgsql;

But the biggest problem is the function itself. This is not going to work in an environment with more then one concurrent transaction. You can't "generate" new IDs using select max() it simply won't work unless you lock the whole table for every insert.

Comments