Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

A transact SQL to PL/SQL code conversion

Status
Not open for further replies.

sybaseguru

Instructor
Feb 20, 2003
324
GB
We have an application running using transact sql. This application is being migrated to Oracle9i. It uses the next rowid table to go and fetch value for the primary key of a give table. We will be modifying the design to be more appropriate to Oracle. The table holding the next rowid value has two columns, nxr_name nxr_next_rowid. These are the table and and next rowid to be used respectively. The transact sql code is as follows:

Code:
----------
-- RETURN values
--
--    >0  next rowID [success]                                                --
--    -1  missing/empty parameter                                             --
--  -100  UPDATE failed                                                       --
--  -101  table does not exist in 'hts_next_rowid'                            --

CREATE PROCEDURE
           get_next_rowid_rv_sp
              @table_name    db_obj_name_t,
              @nr            int           = 1
AS                                      -- 380.95
BEGIN
      SET  nocount  ON                  -- performance enhancement
                                        -- check arguments passed
       IF  (ISNULL(@table_name, "") = "")
           BEGIN
                PRINT  "get_next_rowid_rv_sp:  Must supply argument @table_name"
               RETURN  -1
           END
                                        -- check the table exists
       IF  NOT EXISTS (   SELECT  1
                            FROM  hts_next_rowid
                           WHERE  nxr_name = @table_name)
           BEGIN
                PRINT  "get_next_rowid_rv_sp:  '%1!' does not have an entry in 'hts_next_rowid'",
                       @table_name
               RETURN  -101
           END
       IF  (ISNULL(@nr, 0) < 1)         -- make sure value is set correctly
               SELECT  @nr = 1
  DECLARE  @rv  int,
           @tc  int
                                        -- start a transaction to prevent
                                        -- another process from reading an
                                        -- incorrect value
                                        -- determine if we need to open a new
                                        -- transaction or do a savepoint
   SELECT  @tc = @@trancount
       IF  (@tc > 0)
           SAVE TRANSACTION
                       get_next_rowid_rv_sp_trans
     ELSE
           BEGIN TRANSACTION
                       get_next_rowid_rv_sp_trans
   UPDATE  hts_next_rowid
      SET  nxr_next_rowid = nxr_next_rowid + @nr
    WHERE  nxr_name = @table_name
       IF  (@@error != 0)
           BEGIN
                PRINT  &quot;get_next_rowid_rv_sp:  UPDATE failed&quot;
           ROLLBACK TRANSACTION
                       get_next_rowid_rv_sp_trans
               RETURN  -100
           END
   SELECT  @rv = nxr_next_rowid - @nr
     FROM  hts_next_rowid
    WHERE  nxr_name = @table_name
       IF  (@tc = 0)
           COMMIT TRANSACTION
                      get_next_rowid_rv_sp_trans
   RETURN  @rv
END                                                                                                                                                
go

This code basically goes and returns the nxr_next_rowid and make sure that the row is locked until the nxr_next_rowid value is incremented.
The PL/SQL code for this turns up to be

Code:
CREATE OR REPLACE FUNCTION get_next_rowid
(
        i_table_name      IN      hts_next_rowid.nxr_name%TYPE DEFAULT NULL,
        i_nr              IN      NUMBER DEFAULT 1
)
RETURN NUMBER
AS
-- RETURN values
--
--    >0  next rowID [success]                                                --
--    -1  missing/empty parameter                                             --
--  -100  UPDATE failed                                                       --
--  -101  table does not exist in 'hts_next_rowid'                            
--
  e_table_name	EXCEPTION;
  v_table_name	hts_next_rowid.nxr_name%TYPE DEFAULT NULL;
  v_nr	NUMBER := i_nr;
  v_nxr_next_rowid hts_next_rowid.nxr_next_rowid%TYPE DEFAULT NULL;
  e_update EXCEPTION;
  e_select EXCEPTION;
BEGIN
  BEGIN		-- Input parameter validation
    -- check for inputs
    IF i_table_name IS NULL
    THEN
      RAISE e_table_name;
    END IF;
    IF i_nr <= 1
    THEN
    --  DBMS_OUTPUT.PUT_LINE('get_next_rowid_sp: Warning i_nr = '||i_nr||', set to 1');
      v_nr := 1;
    END IF;
  EXCEPTION
    WHEN e_table_name
    THEN
      DBMS_OUTPUT.PUT_LINE('get_next_rowid_sp: Missing/empty parameter, must supply table name');
      RETURN -1;
  END;		-- End input parameter validation
  BEGIN		-- Check that row exists in next_rowid 
    SELECT nxr_name
    INTO v_table_name
    FROM hts_next_rowid
    WHERE nxr_name = i_table_name;
  EXCEPTION
    WHEN NO_DATA_FOUND
    THEN
      DBMS_OUTPUT.PUT_LINE('get_next_rowid_sp: No record found in hts_next_rowid table for '||i_table_name||'!');
      RETURN -101;
  END;         -- end check that row exists in next_rowid
  BEGIN  -- select for update block
    SELECT nxr_name 
    INTO v_table_name
    FROM hts_next_rowid
    WHERE nxr_name = i_table_name FOR UPDATE; -- lock the row
    UPDATE hts_next_rowid
    SET nxr_next_rowid = nxr_next_rowid + v_nr
    WHERE nxr_name = i_table_name;
    IF SQL%ROWCOUNT = 0 OR SQLCODE != 0
    THEN
      RAISE e_update;
    END IF;
    SELECT nxr_next_rowid - v_nr
    INTO v_nxr_next_rowid 
    FROM hts_next_rowid
    WHERE nxr_name = i_table_name;
    IF SQL%ROWCOUNT = 0 OR SQLCODE != 0
    THEN
      RAISE e_select;
    END IF;
    commit;
    RETURN v_nxr_next_rowid;
  EXCEPTION
    WHEN e_update
    THEN
      DBMS_OUTPUT.PUT_LINE('get_next_rowid_sp: Could not update nxr_next_rowid in hts_next_rowid table for '||i_table_name||'!');
      RETURN -100;
    WHEN e_select
    THEN
      DBMS_OUTPUT.PUT_LINE('get_next_rowid_sp: Could not get nxr_next_rowid in hts_next_rowid table for '||i_table_name||'!');
      RETURN -100;
    WHEN OTHERS
    THEN
      RAISE_APPLICATION_ERROR(SQLCODE,SQLERRM,true);
      RETURN -100;
  END;  -- end select for update
EXCEPTION
  WHEN OTHERS
  THEN
        DBMS_OUTPUT.PUT('Exception encountered! (');
        DBMS_OUTPUT.PUT_LINE(SQLCODE || '): ' || SQLERRM);
	RETURN -100;
END get_next_rowid;

This compiles OK. However, I feel that we can improve the code better. Your comments specifically with regard to exceptions code etc is appreciated and if you think there are better ways of coding it please feel free to show it.

thanks

 
Hi.
Hmm, i personally don't like SELECT FOR UPDATE (in fact i hate it). Mabey I get it wrong, but i don't see any rollback in your e_update exception - so your row will stay locked!
Why not let Oracle do the locking and use UPDATE with a returning clause.

Stefan
 
Stefan,

Valid point about the rollback. If we look at this code

Code:
    SELECT nxr_name 
    INTO v_table_name
    FROM hts_next_rowid
    WHERE nxr_name = i_table_name FOR UPDATE; -- lock the row
    UPDATE hts_next_rowid
    SET nxr_next_rowid = nxr_next_rowid + v_nr
    WHERE nxr_name = i_table_name;
    IF SQL%ROWCOUNT = 0 OR SQLCODE != 0
    THEN
      RAISE e_update;
    END IF;
    SELECT nxr_next_rowid - v_nr
    INTO v_nxr_next_rowid 
    FROM hts_next_rowid
    WHERE nxr_name = i_table_name;
    IF SQL%ROWCOUNT = 0 OR SQLCODE != 0
    THEN
      RAISE e_select;
    END IF;
    commit;

We need to ensure that we lock the row until we get the nxr_next_rowid value. I thought about it a while. I am not sure what other mechanism would ensure that. How would you go about it. thanks
 
Use:

UPDATE hts_next_rowid
SET nxr_next_rowid = nxr_next_rowid + v_nr
WHERE nxr_name = i_table_name
RETURNING nxr_next_rowid - v_nr INTO v_nxr_next_rowid;

No explicit locking needed this way.

Stefan
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top