Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HSQLDB Stored Procedure Error: attempt to assign to non-updatable column

I am using HSQLDB 2.3.2 and am getting a bizarre error when trying to create a stored procedure.

My addresses table:

CREATE TABLE IF NOT EXISTS addresses (
    address_id                  INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL PRIMARY KEY,
    address_line_1              NVARCHAR(500) NOT NULL,
    address_line_2              NVARCHAR(500),
    address_city                NVARCHAR(100) NOT NULL,
    address_postal_code         NVARCHAR(25) NOT NULL,

    CONSTRAINT uc_addresses UNIQUE (address_line_1, address_city)
)

An insert to populate it:

INSERT INTO addresses (
    address_line_1,
    address_city,
    address_postal_code
) VALUES (
    '123 Test Blvd.', 'Testville', '11111'
)

And my proc:

CREATE PROCEDURE sp_get_address_by_id(
        IN address_id INTEGER,
        OUT address_id  INTEGER,
        OUT address_line_1 NVARCHAR(500),
        OUT address_line_2 NVARCHAR(500),
        OUT address_city NVARCHAR(100),
        OUT address_postal_code NVARCHAR(25))
    READS SQL DATA
    BEGIN ATOMIC
        SELECT
            a.address_id,
            a.address_line_1,
            a.address_line_2,
            a.address_city,
            a.address_postal_code
        INTO
            address_id,
            address_line_1,
            address_line_2,
            address_city,
            address_postal_code
        FROM
            addresses a 
        WHERE
            a.address_id = address_id;
    END

When I run this I get:

Error: attempt to assign to non-updatable column
SQLState:  0U000
ErrorCode: -2500

Questions:

  1. What is wrong with my proc (what is producing this error)?
  2. I'm actually looking for a CREATE IF NOT EXISTS-type declaration, so I can run this script over and over again and the procedure will only get created one time if it doesn't already exist. Will this happen or do I need to change the syntax to accomplish IF NOT EXISTS?
like image 466
IAmYourFaja Avatar asked Dec 11 '14 01:12

IAmYourFaja


People also ask

What to do when an error occurs in a stored procedure?

When an error is encountered within a stored procedure, the best you can do (assuming it’s a non-fatal error) is halt the sequential processing of the code and either branch to another code segment in the procedure or return processing to the calling application. Notice that the previous sentence is specific to non-fatal errors.

What are the updatability features of HSQLDB?

HSQLDB supports core SQL updatability features, plus some enhancements from the SQL optional features. A query expression is updatable if it is a SELECT from a single underlying base table (or updatable view) either directly or indirectly. A SELECT statement featuring DISTINCT or GROUP BY or FETCH, LIMIT, OFFSET is not updatable.

What happens when a non-fatal error occurs in a procedure?

When a non-fatal error occurs within a procedure, processing continues on the line of code that follows the one that caused the error. The following example demonstrates how a fatal error affects a procedure. USE tempdb go CREATE PROCEDURE ps_FatalError_SELECT AS SELECT * FROM NonExistentTable PRINT 'Fatal Error' go EXEC ps_FatalError _SELECT

What happens if the <SQL procedure> throws an exception?

If the execution of the <SQL procedure statement> specified in the handler declaration throws an exception itself, then it is handled by the handlers that are currently active at an enclosing (outer) BEGIN ... END block. The <SQL procedure statement> can itself be a compound statement with its own handlers.


1 Answers

Try the syntax below, according to the hsqldb documentation http://hsqldb.org/doc/2.0/guide/sqlroutines-chapt.html#src_psm_assignment

The SET statement is used for assignment. It can be used flexibly with rows or single values.

Also change the address_id parameter to type INOUT and remove the duplicate address_id parameter lines.

CREATE PROCEDURE sp_get_address_by_id(
    INOUT address_id INTEGER,
    OUT address_line_1 NVARCHAR(500),
    OUT address_line_2 NVARCHAR(500),
    OUT address_city NVARCHAR(100),
    OUT address_postal_code NVARCHAR(25))
READS SQL DATA
BEGIN ATOMIC
    SET (address_id,
        address_line_1,
        address_line_2,
        address_city,
        address_postal_code)
    = 
    (
    SELECT
        a.address_id,
        a.address_line_1,
        a.address_line_2,
        a.address_city,
        a.address_postal_code
    FROM
        addresses a 
    WHERE
        a.address_id = address_id
    );
END

You can try adding this as the first statement in your script if you want to drop the procedure if it already exists, so that you can re-run the script many times. You can search the documentation for <specific routine designator> for more info.

DROP SPECIFIC PROCEDURE sp_get_address_by_id IF EXISTS;
like image 70
BateTech Avatar answered Oct 30 '22 16:10

BateTech