¶
21.9. Stored Procedures
-- -- tpcc.sql -- -- Implementation of the TPC C Benchmark transactions as stored procedures. -- -- These are for use with the tpcc test driver (tpcc) in the Virtuoso sample -- directory. See TPCC.DOC in the virtuoso documentation bundle for comments -- and instructions. -- -- Copyright (C) 1998-2024 OpenLink Software. -- All Rights Reserved. -- -- The copyright above and this notice must be preserved in all -- copies of this source code. The copyright above does not -- evidence any actual or intended publication of this source code. -- -- This is unpublished proprietary trade secret of OpenLink Software. -- This source code may not be copied, disclosed, distributed, demonstrated -- or licensed except as authorized by OpenLink Software. -- -- slevel - The transaction procedure for the Stock Level transaction. -- -- This is executed as an autocommitting history read transaction. The number -- of STOCK rows where quantity is below th threshold. The rows are taken -- from the last 20 orders on a warehouse / district combination. CREATE PROCEDURE SLEVEL ( IN W_ID INTEGER, IN D_ID INTEGER, IN THRESHOLD INTEGER) { DECLARE LAST_O, N_ITEMS INTEGER; SELECT D_NEXT_O_ID INTO LAST_O FROM DISTRICT WHERE D_W_ID = W_ID AND D_ID = D_ID; SELECT COUNT (DISTINCT S_I_ID) INTO N_ITEMS FROM ORDER_LINE, STOCK WHERE OL_W_ID = W_ID AND OL_D_ID = D_ID AND OL_O_ID < LAST_O AND OL_O_ID >= LAST_O - 20 AND S_W_ID = W_ID AND S_I_ID = OL_I_ID AND S_QUANTITY < THRESHOLD; RESULT_NAMES (N_ITEMS); RESULT (N_ITEMS); } -- -- c_by_name, call_c_by_name -- Examples on retrieving CUSTOMER by last name. -- Functionality open coded in actual transaction procedures. -- CREATE PROCEDURE C_BY_NAME ( IN W_ID INTEGER, IN D_ID INTEGER, IN NAME VARCHAR, OUT ID INTEGER) { DECLARE N, C_COUNT INTEGER; DECLARE C_CUR CURSOR FOR SELECT C_ID FROM CUSTOMER WHERE C_W_ID = W_ID AND C_D_ID = D_ID AND C_LAST = NAME ORDER BY C_W_ID, C_D_ID, C_LAST, C_FIRST; SELECT COUNT (*) INTO C_COUNT FROM CUSTOMER WHERE C_W_ID = W_ID AND C_D_ID = D_ID AND C_LAST = NAME; N := 0; OPEN C_CUR; WHENEVER NOT FOUND GOTO NOTFOUND; WHILE (N <= C_COUNT / 2) { FETCH C_CUR INTO ID; N := N + 1; } RETURN; NOTFOUND: SIGNAL ('CNF', 'CUSTOMER NOT FOUND BY NAME'); RETURN; } CREATE PROCEDURE CALL_C_BY_NAME ( IN W_ID INTEGER, IN D_ID INTEGER, IN C_LAST VARCHAR) { DECLARE C_ID INTEGER; C_BY_NAME (W_ID, D_ID, C_LAST, C_ID); } -- -- payment -- This procedure implements the Payment transaction. -- CREATE PROCEDURE BC_C_DATA ( INOUT C_NEW VARCHAR, INOUT C_DATA VARCHAR) { RETURN ( CONCATENATE (C_NEW, SUBSEQ (C_DATA, LENGTH (C_NEW), LENGTH (C_DATA)))); } CREATE PROCEDURE PAYMENT ( IN _W_ID INTEGER, IN _C_W_ID INTEGER, IN H_AMOUNT FLOAT, IN _D_ID INTEGER, IN _C_D_ID INTEGER, IN _C_ID INTEGER, IN _C_LAST VARCHAR) { DECLARE _C_DATA, _C_FIRST, _C_MIDDLE, _C_STREET_1, _C_STREET_2, _C_CITY, _C_STATE, _C_ZIP, _C_PHONE, _C_CREDIT, _C_CREDIT_LIM, _C_DISCOUNT, _C_BALANCE, _C_SINCE, _C_DATA_1, _C_DATA_2 VARCHAR; DECLARE N, _W_YTD, _D_YTD, _C_CNT_PAYMENT INTEGER; DECLARE _D_STREET_1, _D_STREET_2, _D_CITY, _D_STATE, _D_ZIP, _D_NAME VARCHAR; DECLARE _W_STREET_1, _W_STREET_2, _W_CITY, _W_STATE, _W_ZIP, _W_NAME, SCREEN_DATA VARCHAR; IF (_C_ID = 0) { DECLARE NAMECNT INTEGER; WHENEVER NOT FOUND GOTO NO_CUSTOMER; SELECT COUNT(C_ID) INTO NAMECNT FROM CUSTOMER WHERE C_LAST = _C_LAST AND C_D_ID = _D_ID AND C_W_ID = _W_ID; DECLARE C_BYNAME CURSOR FOR SELECT C_ID FROM CUSTOMER WHERE C_W_ID = _C_W_ID AND C_D_ID = _C_D_ID AND C_LAST = _C_LAST ORDER BY C_W_ID, C_D_ID, C_LAST, C_FIRST; OPEN C_BYNAME (EXCLUSIVE); N := 0; WHILE (N <= NAMECNT / 2) { FETCH C_BYNAME INTO _C_ID; N := N + 1; } CLOSE C_BYNAME; } DECLARE C_CR CURSOR FOR SELECT C_FIRST, C_MIDDLE, C_LAST, C_STREET_1, C_STREET_2, C_CITY, C_STATE, C_ZIP, C_PHONE, C_CREDIT, C_CREDIT_LIM, C_DISCOUNT, C_BALANCE, C_SINCE, C_DATA_1, C_DATA_2, C_CNT_PAYMENT FROM CUSTOMER WHERE C_W_ID = _C_W_ID AND C_D_ID = _C_D_ID AND C_ID = _C_ID; OPEN C_CR (EXCLUSIVE); FETCH C_CR INTO _C_FIRST, _C_MIDDLE, _C_LAST, _C_STREET_1, _C_STREET_2, _C_CITY, _C_STATE, _C_ZIP, _C_PHONE, _C_CREDIT, _C_CREDIT_LIM, _C_DISCOUNT, _C_BALANCE, _C_SINCE, _C_DATA_1, _C_DATA_2, _C_CNT_PAYMENT; _C_BALANCE := _C_BALANCE + H_AMOUNT; IF (_C_CREDIT = 'BC') { UPDATE CUSTOMER SET C_BALANCE = _C_BALANCE, C_DATA_1 = BC_C_DATA ( SPRINTF ('%5d%5d%5d%5d%5d%9f', _C_ID, _C_D_ID, _C_W_ID, _D_ID, _W_ID, H_AMOUNT), _C_DATA_1), C_CNT_PAYMENT = _C_CNT_PAYMENT + 1 WHERE CURRENT OF C_CR; SCREEN_DATA := SUBSEQ (_C_DATA_1, 1, 200); } ELSE { UPDATE CUSTOMER SET C_BALANCE = _C_BALANCE, C_CNT_PAYMENT = _C_CNT_PAYMENT + 1 WHERE CURRENT OF C_CR; SCREEN_DATA := ' '; } DECLARE D_CUR CURSOR FOR SELECT D_STREET_1, D_STREET_2, D_CITY, D_STATE, D_ZIP, D_NAME, D_YTD FROM DISTRICT WHERE D_W_ID = _W_ID AND D_ID = _D_ID; OPEN D_CUR (EXCLUSIVE); FETCH D_CUR INTO _D_STREET_1, _D_STREET_2, _D_CITY, _D_STATE, _D_ZIP, _D_NAME, _D_YTD; UPDATE DISTRICT SET D_YTD = _D_YTD + H_AMOUNT WHERE CURRENT OF D_CUR; CLOSE D_CUR; DECLARE W_CUR CURSOR FOR SELECT W_STREET_1, W_STREET_2, W_CITY, W_STATE, W_ZIP, W_NAME, W_YTD FROM WAREHOUSE WHERE W_ID = _W_ID; OPEN W_CUR (EXCLUSIVE); FETCH W_CUR INTO _W_STREET_1, _W_STREET_2, _W_CITY, _W_STATE, _W_ZIP, _W_NAME, _W_YTD; UPDATE WAREHOUSE SET W_YTD = _W_YTD + H_AMOUNT; DECLARE H_DATA VARCHAR; H_DATA := _W_NAME; INSERT INTO HISTORY (H_C_D_ID, H_C_W_ID, H_C_ID, H_D_ID, H_W_ID, H_DATE, H_AMOUNT, H_DATA) VALUES (_C_D_ID, _C_W_ID, _C_ID, _D_ID, _W_ID, NOW (), H_AMOUNT, H_DATA); RESULT ( _C_ID, _C_LAST, NOW (), _W_STREET_1, _W_STREET_2, _W_CITY, _W_STATE, _W_ZIP, _D_STREET_1, _D_STREET_2, _D_CITY, _D_STATE, _D_ZIP, _C_FIRST, _C_MIDDLE, _C_STREET_1, _C_STREET_2, _C_CITY, _C_STATE, _C_ZIP, _C_PHONE, _C_SINCE, _C_CREDIT, _C_CREDIT_LIM, _C_DISCOUNT, _C_BALANCE, SCREEN_DATA); RETURN; NO_CUSTOMER: SIGNAL ('NOCUS', 'NO CUSTOMER IN PAYMENT.'); } -- ol_stock - Part of the New Order transaction - Set the stock level for -- an order line. Compute the price and return it in amount. -- -- Note - Open the cursor on STOCK as exclusive to avoid deadlocks. -- Use positioned update on STOCK for speed. -- -- Fetch the s_dist_01 - 10 columns from STOCK even though they are not used. -- The test specification requires this. The operation is measurably faster if these -- are omitted.-- The ORDER LINE is inserted later for better lock concurrency. CREATE PROCEDURE OL_STOCK ( IN _W_ID INTEGER, IN D_ID INTEGER, INOUT _OL_I_ID INTEGER, IN _OL_SUPPLY_W_ID INTEGER, IN QTY INTEGER, OUT AMOUNT FLOAT, INOUT S_DIST_01 VARCHAR, INOUT S_DIST_02 VARCHAR, INOUT S_DIST_03 VARCHAR, INOUT S_DIST_04 VARCHAR, INOUT S_DIST_05 VARCHAR, INOUT S_DIST_06 VARCHAR, INOUT S_DIST_07 VARCHAR, INOUT S_DIST_08 VARCHAR, INOUT S_DIST_09 VARCHAR, INOUT S_DIST_10 VARCHAR, INOUT DIST_INFO VARCHAR) { IF (_OL_I_ID = 0) RETURN; DECLARE _S_DATA VARCHAR; DECLARE _S_QUANTITY, _S_CNT_ORDER, _S_CNT_REMOTE INTEGER; WHENEVER NOT FOUND GOTO NO_ITEM; DECLARE _I_NAME VARCHAR; SELECT I_PRICE, I_NAME INTO AMOUNT, _I_NAME FROM ITEM WHERE I_ID = _OL_I_ID; DECLARE S_CUR CURSOR FOR SELECT S_QUANTITY, S_DATA, S_CNT_ORDER, S_CNT_REMOTE, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10 FROM STOCK WHERE S_I_ID = _OL_I_ID AND S_W_ID = _OL_SUPPLY_W_ID; WHENEVER NOT FOUND GOTO NO_STOCK; OPEN S_CUR (EXCLUSIVE); FETCH S_CUR INTO _S_QUANTITY, _S_DATA, _S_CNT_ORDER, _S_CNT_REMOTE, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10; IF (_S_QUANTITY < QTY) _S_QUANTITY := _S_QUANTITY - QTY + 91; ELSE _S_QUANTITY := _S_QUANTITY - QTY; IF (_W_ID <> _OL_SUPPLY_W_ID) _S_CNT_REMOTE := _S_CNT_REMOTE + 1; UPDATE STOCK SET S_QUANTITY = _S_QUANTITY, S_CNT_ORDER = _S_CNT_ORDER + 1, S_CNT_REMOTE = _S_CNT_REMOTE WHERE CURRENT OF S_CUR; IF (D_ID = 1) DIST_INFO := S_DIST_01; ELSE IF (D_ID = 2) DIST_INFO := S_DIST_02; ELSE IF (D_ID = 3) DIST_INFO := S_DIST_03; ELSE IF (D_ID = 4) DIST_INFO := S_DIST_04; ELSE IF (D_ID = 5) DIST_INFO := S_DIST_05; ELSE IF (D_ID = 6) DIST_INFO := S_DIST_06; ELSE IF (D_ID = 7) DIST_INFO := S_DIST_07; ELSE IF (D_ID = 8) DIST_INFO := S_DIST_08; ELSE IF (D_ID = 9) DIST_INFO := S_DIST_09; ELSE IF (D_ID = 10) DIST_INFO := S_DIST_10; RESULT (_I_NAME, _S_QUANTITY, 'G', AMOUNT, AMOUNT * QTY); AMOUNT := QTY * AMOUNT; RETURN; NO_STOCK: SIGNAL ('NOSTK', 'NO STOCK ROW FOUND.'); NO_ITEM: SIGNAL ('NOITM', 'NO ITEM ROW FOUND.'); } -- -- ol_insert - Part of New Order transaction. Insert an ORDER LINE. -- -- Note use of inout parameters even though they are not modified here. -- This saves copying the values. CREATE PROCEDURE OL_INSERT ( INOUT W_ID INTEGER, INOUT D_ID INTEGER, INOUT O_ID INTEGER, IN OL_NUMBER INTEGER, INOUT OL_I_ID INTEGER, INOUT OL_QTY INTEGER, INOUT OL_AMOUNT FLOAT, INOUT OL_SUPPLY_W_ID INTEGER, INOUT OL_DIST_INFO VARCHAR, INOUT TAX_AND_DISCOUNT FLOAT) { IF (OL_I_ID = -1) RETURN; OL_AMOUNT := OL_AMOUNT * TAX_AND_DISCOUNT; INSERT INTO ORDER_LINE ( OL_O_ID, OL_D_ID, OL_W_ID, OL_NUMBER, OL_I_ID, OL_SUPPLY_W_ID, OL_QUANTITY, OL_AMOUNT, OL_DIST_INFO) VALUES ( O_ID, D_ID, W_ID, OL_NUMBER, OL_I_ID, OL_SUPPLY_W_ID, OL_QTY, OL_AMOUNT, OL_DIST_INFO); } -- -- cust_info - part of New Order transaction. Return customer info. -- -- CREATE PROCEDURE CUST_INFO ( IN W_ID INTEGER, IN D_ID INTEGER, INOUT _C_ID INTEGER, INOUT _C_LAST VARCHAR, OUT _C_DISCOUNT FLOAT, OUT _C_CREDIT VARCHAR) { WHENEVER NOT FOUND GOTO ERR; SELECT C_LAST, C_DISCOUNT, C_CREDIT INTO _C_LAST, _C_DISCOUNT, _C_CREDIT FROM CUSTOMER WHERE C_W_ID = W_ID AND C_D_ID = D_ID AND C_ID = _C_ID; RETURN; ERR: SIGNAL ('NOCUS', 'NO CUSTOMER'); } -- new_order - Top level procedure of New Order transaction. -- Take a fixed 10 order lines as individually named parameters -- to stay easily portable. CREATE PROCEDURE NEW_ORDER ( IN _W_ID INTEGER, IN _D_ID INTEGER, IN _C_ID INTEGER, IN O_OL_CNT INTEGER, IN O_ALL_LOCAL INTEGER, IN I_ID_1 INTEGER, IN S_W_ID_1 INTEGER, IN QTY_1 INTEGER, IN I_ID_2 INTEGER, IN S_W_ID_2 INTEGER, IN QTY_2 INTEGER, IN I_ID_3 INTEGER, IN S_W_ID_3 INTEGER, IN QTY_3 INTEGER, IN I_ID_4 INTEGER, IN S_W_ID_4 INTEGER, IN QTY_4 INTEGER, IN I_ID_5 INTEGER, IN S_W_ID_5 INTEGER, IN QTY_5 INTEGER, IN I_ID_6 INTEGER, IN S_W_ID_6 INTEGER, IN QTY_6 INTEGER, IN I_ID_7 INTEGER, IN S_W_ID_7 INTEGER, IN QTY_7 INTEGER, IN I_ID_8 INTEGER, IN S_W_ID_8 INTEGER, IN QTY_8 INTEGER, IN I_ID_9 INTEGER, IN S_W_ID_9 INTEGER, IN QTY_9 INTEGER, IN I_ID_10 INTEGER, IN S_W_ID_10 INTEGER, IN QTY_10 INTEGER) { DECLARE OL_A_1, OL_A_2, OL_A_3, OL_A_4, OL_A_5, OL_A_6, OL_A_7, OL_A_8, OL_A_9, OL_A_10 INTEGER; DECLARE _C_DISCOUNT, _D_TAX, _W_TAX, TAX_AND_DISCOUNT FLOAT; DECLARE DATETIME DATE; DECLARE _C_LAST, _C_CREDIT VARCHAR; DECLARE _O_ID INTEGER; DECLARE I_NAME, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10 VARCHAR; DECLARE DISTI_1, DISTI_2, DISTI_3, DISTI_4, DISTI_5, DISTI_6, DISTI_7, DISTI_8, DISTI_9, DISTI_10 VARCHAR; DATETIME := NOW (); -- DECLARE RESULT ROW FROM OL_STOCK. OPTIONAL.; RESULT_NAMES (I_NAME, QTY_1, DISTI_1, OL_A_1, OL_A_2); OL_STOCK ( _W_ID, _D_ID, I_ID_1, S_W_ID_1, QTY_1, OL_A_1, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10, DISTI_1); OL_STOCK ( _W_ID, _D_ID, I_ID_2, S_W_ID_2, QTY_2, OL_A_2, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10, DISTI_2); OL_STOCK ( _W_ID, _D_ID, I_ID_3, S_W_ID_3, QTY_3, OL_A_3, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10, DISTI_3); OL_STOCK ( _W_ID, _D_ID, I_ID_4, S_W_ID_4, QTY_4, OL_A_4, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10, DISTI_4); OL_STOCK ( _W_ID, _D_ID, I_ID_5, S_W_ID_5, QTY_5, OL_A_5, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10, DISTI_5); OL_STOCK ( _W_ID, _D_ID, I_ID_6, S_W_ID_6, QTY_6, OL_A_6, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10, DISTI_6); OL_STOCK ( _W_ID, _D_ID, I_ID_7, S_W_ID_7, QTY_7, OL_A_7, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10, DISTI_7); OL_STOCK ( _W_ID, _D_ID, I_ID_8, S_W_ID_8, QTY_8, OL_A_8, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10, DISTI_8); OL_STOCK ( _W_ID, _D_ID, I_ID_9, S_W_ID_9, QTY_8, OL_A_9, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10, DISTI_9); OL_STOCK ( _W_ID, _D_ID, I_ID_10, S_W_ID_10, QTY_10, OL_A_10, S_DIST_01, S_DIST_02, S_DIST_03, S_DIST_04, S_DIST_05, S_DIST_06, S_DIST_07, S_DIST_08, S_DIST_09, S_DIST_10, DISTI_10); CUST_INFO (_W_ID, _D_ID, _C_ID, _C_LAST, _C_DISCOUNT, _C_CREDIT); DECLARE D_CUR CURSOR FOR SELECT D_TAX, D_NEXT_O_ID FROM DISTRICT WHERE D_W_ID = _W_ID AND D_ID = _D_ID; WHENEVER NOT FOUND GOTO NOWARE; OPEN D_CUR (EXCLUSIVE); FETCH D_CUR INTO _D_TAX, _O_ID; UPDATE DISTRICT SET D_NEXT_O_ID = _O_ID + 1 WHERE CURRENT OF D_CUR; CLOSE D_CUR; INSERT INTO ORDERS (O_ID, O_D_ID, O_W_ID, O_C_ID, O_ENTRY_D, O_OL_CNT, O_ALL_LOCAL) VALUES (_O_ID, _D_ID, _W_ID, _C_ID, DATETIME, O_OL_CNT, O_ALL_LOCAL); INSERT INTO NEW_ORDER (NO_O_ID, NO_D_ID, NO_W_ID) VALUES (_O_ID, _D_ID, _W_ID); SELECT W_TAX INTO _W_TAX FROM WAREHOUSE WHERE W_ID = _W_ID; TAX_AND_DISCOUNT := (1 + _D_TAX + _W_TAX) * (1 - _C_DISCOUNT); OL_INSERT ( _W_ID, _D_ID, _O_ID, 1, I_ID_1, QTY_1, OL_A_1, S_W_ID_1, DISTI_1, TAX_AND_DISCOUNT); OL_INSERT ( _W_ID, _D_ID, _O_ID, 2, I_ID_2, QTY_2, OL_A_2, S_W_ID_2, DISTI_2, TAX_AND_DISCOUNT); OL_INSERT ( _W_ID, _D_ID, _O_ID, 3, I_ID_3, QTY_3, OL_A_3, S_W_ID_3, DISTI_3, TAX_AND_DISCOUNT); OL_INSERT ( _W_ID, _D_ID, _O_ID, 4, I_ID_4, QTY_4, OL_A_4, S_W_ID_4, DISTI_4, TAX_AND_DISCOUNT); OL_INSERT ( _W_ID, _D_ID, _O_ID, 5, I_ID_5, QTY_5, OL_A_5, S_W_ID_5, DISTI_5, TAX_AND_DISCOUNT); OL_INSERT ( _W_ID, _D_ID, _O_ID, 6, I_ID_6, QTY_6, OL_A_6, S_W_ID_6, DISTI_6, TAX_AND_DISCOUNT); OL_INSERT ( _W_ID, _D_ID, _O_ID, 7, I_ID_7, QTY_7, OL_A_7, S_W_ID_7, DISTI_7, TAX_AND_DISCOUNT); OL_INSERT ( _W_ID, _D_ID, _O_ID, 8, I_ID_6, QTY_8, OL_A_8, S_W_ID_8, DISTI_8, TAX_AND_DISCOUNT); OL_INSERT ( _W_ID, _D_ID, _O_ID, 9, I_ID_9, QTY_9, OL_A_9, S_W_ID_9, DISTI_9, TAX_AND_DISCOUNT); OL_INSERT ( _W_ID, _D_ID, _O_ID, 10, I_ID_10, QTY_10, OL_A_10, S_W_ID_10, DISTI_10, TAX_AND_DISCOUNT); END_RESULT (); RESULT (_W_TAX, _D_TAX, _O_ID, _C_LAST, _C_DISCOUNT, _C_CREDIT); RETURN; NOWARE: SIGNAL ('NOWRE', 'WAREHOUSE OR DISTRICTNOT FOUND.'); } -- delivery_1 - Top level procedure for the Delivery transaction -- -- This is called 10 times by the client in each delivery transaction. -- The rules allow Delivery to be implemented as up to 10 separately committed -- transactions. This is done to minimize lock duration. CREATE PROCEDURE DELIVERY_1 ( IN W_ID INTEGER, IN CARRIER_ID INTEGER, IN D_ID INTEGER) { DECLARE NO_CUR CURSOR FOR SELECT NO_O_ID FROM NEW_ORDER WHERE NO_W_ID = W_ID AND NO_D_ID = D_ID; DECLARE DATETIME DATE; DECLARE _O_ID, _C_ID INTEGER; DECLARE OL_TOTAL FLOAT; DATETIME := NOW (); OPEN NO_CUR (EXCLUSIVE, PREFETCH 1); FETCH NO_CUR INTO _O_ID; DELETE FROM NEW_ORDER WHERE CURRENT OF NO_CUR; CLOSE NO_CUR; DECLARE O_CUR CURSOR FOR SELECT O_C_ID FROM ORDERS WHERE O_W_ID = W_ID AND O_D_ID = D_ID AND O_ID = _O_ID; OPEN O_CUR (EXCLUSIVE); FETCH O_CUR INTO _C_ID; UPDATE ORDERS SET O_CARRIER_ID = CARRIER_ID WHERE CURRENT OF O_CUR; CLOSE O_CUR; DECLARE OL_CUR CURSOR FOR SELECT OL_AMOUNT FROM ORDER_LINE WHERE OL_W_ID = W_ID AND OL_D_ID = D_ID AND OL_O_ID = _O_ID; WHENEVER NOT FOUND GOTO LINES_DONE; OL_TOTAL := 0.0; OPEN OL_CUR (EXCLUSIVE); WHILE (1) { DECLARE TMP INTEGER; FETCH OL_CUR INTO TMP; OL_TOTAL := OL_TOTAL + TMP; UPDATE ORDER_LINE SET OL_DELIVERY_D = DATETIME WHERE CURRENT OF OL_CUR; } LINES_DONE: UPDATE CUSTOMER SET C_BALANCE = C_BALANCE + OL_TOTAL, C_CNT_DELIVERY = C_CNT_DELIVERY + 1 WHERE C_W_ID = W_ID AND C_D_ID = D_ID AND C_ID = _C_ID; RETURN _O_ID; } -- ostat - Top level procedure for the Order Status transaction. -- -- CREATE PROCEDURE OSTAT ( IN _W_ID INTEGER, IN _D_ID INTEGER, IN _C_ID INTEGER, IN _C_LAST VARCHAR) { DECLARE _C_FIRST, _C_MIDDLE, _C_BALANCE VARCHAR; DECLARE _O_ID, _OL_I_ID, _OL_SUPPLY_W_ID, _OL_QUANTITY, _O_CARRIER_ID, N INTEGER; DECLARE _OL_AMOUNT FLOAT; DECLARE _OL_DELIVERY_D, _O_ENTRY_D VARCHAR; IF (_C_ID = 0) { DECLARE NAMECNT INTEGER; WHENEVER NOT FOUND GOTO NO_CUSTOMER; SELECT COUNT (*) INTO NAMECNT FROM CUSTOMER WHERE C_LAST = _C_LAST AND C_D_ID = _D_ID AND C_W_ID = _W_ID; DECLARE C_BYNAME CURSOR FOR SELECT C_BALANCE, C_LAST, C_MIDDLE, C_ID FROM CUSTOMER WHERE C_W_ID = _W_ID AND C_D_ID = _D_ID AND C_LAST = _C_LAST ORDER BY C_W_ID, C_D_ID, C_LAST, C_FIRST; OPEN C_BYNAME; N := 0; WHILE (N <= NAMECNT / 2) { FETCH C_BYNAME INTO _C_BALANCE, _C_FIRST, _C_MIDDLE, _C_ID; N := N + 1; } CLOSE C_BYNAME; } ELSE { SELECT C_BALANCE, C_FIRST, C_MIDDLE, C_LAST INTO _C_BALANCE, _C_FIRST, _C_MIDDLE, _C_LAST FROM CUSTOMER WHERE C_W_ID = _W_ID AND C_D_ID = _D_ID AND C_ID = _C_ID; } WHENEVER NOT FOUND GOTO NO_ORDER; SELECT O_ID, O_CARRIER_ID, O_ENTRY_D INTO _O_ID, _O_CARRIER_ID, _O_ENTRY_D FROM ORDERS WHERE O_W_ID = _W_ID AND O_D_ID = _D_ID AND O_C_ID = _C_ID ORDER BY O_W_ID DESC, O_D_ID DESC, O_C_ID DESC, O_ID DESC; DECLARE O_LINE CURSOR FOR SELECT OL_I_ID, OL_SUPPLY_W_ID, OL_QUANTITY, OL_AMOUNT, OL_DELIVERY_D FROM ORDER_LINE WHERE OL_W_ID = _W_ID AND OL_D_ID = _D_ID AND OL_O_ID = _O_ID; WHENEVER NOT FOUND GOTO LINES_DONE; OPEN O_LINE; RESULT_NAMES ( _OL_SUPPLY_W_ID, _OL_I_ID, _OL_QUANTITY, _OL_AMOUNT, _OL_DELIVERY_D); WHILE (1 = 1) { FETCH O_LINE INTO _OL_I_ID, _OL_SUPPLY_W_ID, _OL_QUANTITY, _OL_AMOUNT, _OL_DELIVERY_D; RESULT ( _OL_SUPPLY_W_ID, _OL_I_ID, _OL_QUANTITY, _OL_AMOUNT, _OL_DELIVERY_D); } LINES_DONE: END_RESULT (); RESULT_NAMES ( _C_ID, _C_LAST, _C_FIRST, _C_MIDDLE, _O_ENTRY_D, _O_CARRIER_ID, _C_BALANCE, _O_ID); RESULT ( _C_ID, _C_LAST, _C_FIRST, _C_MIDDLE, _O_ENTRY_D, _O_CARRIER_ID, _C_BALANCE, _O_ID); RETURN; NO_CUSTOMER: SIGNAL ('NOCUS', 'NO CUSTOMER IN ORDER STATUS'); NO_ORDER: RETURN 0; }