views:

48

answers:

1

I am trying to create a function to populate 2 tables, the second query containing the new id from the first insert.

an example of some of my tables:

CREATE TABLE message
(
  message_id bigserial NOT NULL,
  member_id bigint NOT NULL,
  message character varying(8192) NOT NULL,
  ...
)

CREATE TABLE feed_message
(
  feed_id bigint NOT NULL,
  message_id bigint NOT NULL
)

what i am trying to do is insert a new message in the message table, and use the generated message_id to populate the feed_message table

i tried writing a function using the pltcl language but i cant figure out how to use the SPI_getvalue to get the just created tupil

this is what i have so far:

/* message_post(entity, id, member_id, title, message, reactionTo) */
CREATE OR REPLACE FUNCTION message_post ()
 RETURNS VOID
 LANGUAGE pltcl
AS $BODY$
 ret_status = spi_exec -count 1 "INSERT INTO message (member_id, title, message) VALUES ($3, $4, $5)"
 IF (ret_status == SPI_OK_SELECT && SPI_processed > 0) {
  //get the tupil from *SPI_tuptable
  set message_id <the new message_id>
 }
 spi_exec -count 1 "INSERT INTO $1_message ($1_id, message_id) VALUES ($2,$message_id)"
$BODY$;

/* useage */
SELECT message_post('feed',12,1,'title','message');
+1  A: 

You've got a few places where your Tcl usage (PL/Tcl can be considered to be a dialect, with wrapping) is just plain wrong. I'd guess that this is correct, based on the examples in the PL/Tcl documentation.

CREATE OR REPLACE FUNCTION message_post(text,integer,integer,text,text)
RETURNS VOID AS $$
   set ret_status [spi_exec -count 1 \
         "INSERT INTO message (member_id, title, message) \
               VALUES ($3, '[quote $4]', '[quote $5]')"]
   if {$ret_status > 0} {
      set message_id [spi_lastoid]
      spi_exec -count 1 "INSERT INTO ${1}_message (${1}_id, message_id) \
                         VALUES ($2, $message_id)"
   }
$$ LANGUAGE pltcl;

However, I would not consider this to be idiomatic! After all, it's doing quote and other things like that. As I understand it, this is better:

CREATE OR REPLACE FUNCTION message_post(text,integer,integer,text,text)
RETURNS VOID AS $$
   # Precompile the INSERTs if they didn't already exist
   if {![info exists GD(post_message_plan)]} {
      set GD(post_message_plan) [spi_prepare \
            {INSERT INTO message (member_id, title, message) VALUES ($1, $2, $3)} \
            {integer text text}]
   }
   if {![info exists GD(assoc_message_plan:$1)]} {
      set GD(assoc_message_plan:$1) [spi_prepare \
            "INSERT INTO ${1}_message (${1}_id, message_id) VALUES (\$1, \$2)" \
            {integer integer}]
   }
   # Run the pair of INSERTs
   if {[spi_execp -count 1 $GD(post_message_plan) [list $3 $4 $5]] > 0} {
      spi_execp -count 1 $GD(assoc_message_plan:$1) [list $2 [spi_lastoid]]
   }
$$ LANGUAGE pltcl;

Other things to note: I believe it is spi_lastoid that you're looking for for finding the message id, and I've not actually checked whether your SQL is correct. Also, I may have the types of the arguments to various things wrong. (PostgreSQL and Tcl have quite different ideas about what types are.)

Donal Fellows
it looks like it should work, but the [spi_lastoid] is empty, and a 0 is inserted instead of the new message_id
Paul Scheltema
@Paul: Oh well, you'll just have to do something else to get the last inserted row id; I don't have a deployment of postgres handy though, so can't really advise. I just read the docs. :-)
Donal Fellows
and after recreating the tables WITH(ODIS) it all works
Paul Scheltema