Advertisement
Guest User

oracleaid

a guest
Aug 21st, 2007
335
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PL/SQL 17.46 KB | None | 0 0
  1. CREATE OR REPLACE PACKAGE     data_browser AUTHID current_user AS
  2.   FUNCTION escape(iUrl IN VARCHAR2) RETURN VARCHAR2 deterministic;
  3.   PROCEDURE browse(iSchema IN VARCHAR2, iTableName IN VARCHAR2, iPage PLS_INTEGER, iSize PLS_INTEGER, iSearch IN VARCHAR2 DEFAULT NULL);
  4.   PROCEDURE edit(iSchema IN VARCHAR2, iTableName IN VARCHAR2, iRowId VARCHAR2);
  5.   PROCEDURE save(iSchema IN VARCHAR2, iTableName IN VARCHAR2, iRowData IN VARCHAR2);
  6.   PROCEDURE DELETE(iSchema IN VARCHAR2, iTableName IN VARCHAR2, iRowId IN VARCHAR2);
  7. END data_browser;
  8. /
  9. CREATE OR REPLACE PACKAGE BODY     data_browser  AS
  10.   -- const
  11.   c_page CONSTANT PLS_INTEGER := 20;
  12.   c_buffer_len CONSTANT PLS_INTEGER := 4000;
  13.   c_field_max_size CONSTANT PLS_INTEGER := 200;
  14.  
  15.   c_app_call CONSTANT VARCHAR2(300) := 'f?p=' || NV('APP_ID');
  16.   c_page_next CONSTANT VARCHAR2(300) := c_app_call || ':2:' || V('SESSION') || '::NO::p2_page,p2_size,p2_search:';
  17.   c_page_edit CONSTANT VARCHAR2(300) := c_app_call || ':3:' || V('SESSION') || '::NO::p3_rowid:';
  18.  
  19.   -- global vars
  20.   v_table all_tables.table_name%TYPE := 'none';
  21.   v_schema all_tables.owner%TYPE := 'none';
  22.   v_page_no PLS_INTEGER;
  23.   v_page_size PLS_INTEGER;
  24.  
  25.   v_sql VARCHAR2(32767);
  26.   v_search VARCHAR2(4000);
  27.  
  28.   -- collections
  29.   v_cols_pk DBMS_UTILITY.lname_array;
  30.   v_cols DBMS_UTILITY.lname_array;
  31.   v_col_types DBMS_UTILITY.lname_array;
  32.   v_col_lens DBMS_UTILITY.lname_array;
  33.   v_vals apex_application_global.vc_arr2;
  34.  
  35.   -- strings parallel to collections
  36.   v_col_list VARCHAR2(4000) := NULL;
  37.   v_col_pk_list VARCHAR2(4000) := NULL;
  38.  
  39.   -- lobs
  40.   v_xslt clob;
  41.   v_html clob;
  42.  
  43.   -- handles
  44.   v_queryCtx dbms_xmlquery.ctxType;
  45.   v_cur_hdl  INTEGER;
  46.  
  47. --------------------------------------------------------------------------------
  48.   FUNCTION escape(iUrl IN VARCHAR2)
  49.     RETURN VARCHAR2 deterministic
  50.   AS
  51.   BEGIN
  52.     RETURN UTL_URL.escape(iUrl, TRUE);
  53.   END escape;
  54.  
  55. --------------------------------------------------------------------------------
  56.   PROCEDURE set_pk_col_list
  57.   AS
  58.     i PLS_INTEGER;
  59.   BEGIN
  60.     v_cols_pk.DELETE;
  61.     SELECT column_name
  62.       BULK COLLECT INTO v_cols_pk
  63.       FROM all_constraints aa, all_cons_columns cc
  64.       WHERE aa.table_name = v_table AND
  65.         aa.owner = v_schema AND
  66.         constraint_type = 'P' AND
  67.         aa.constraint_name = cc.constraint_name AND
  68.         aa.table_name = cc.table_name AND
  69.         aa.owner = cc.owner
  70.       ORDER BY cc.position;
  71.     IF v_cols_pk.COUNT = 0 THEN
  72.       raise_application_error(-20667, 'No primary key columns found.');
  73.     END IF;
  74.     DBMS_UTILITY.table_to_comma(v_cols_pk, i, v_col_pk_list);
  75.   END set_pk_col_list;
  76.  
  77. --------------------------------------------------------------------------------
  78.   PROCEDURE set_col_list
  79.   AS
  80.     i PLS_INTEGER;
  81.   BEGIN
  82.     v_cols.DELETE;
  83.     v_col_types.DELETE;
  84.     v_col_lens.DELETE;
  85.     SELECT column_name, data_type, data_length
  86.       BULK COLLECT INTO v_cols, v_col_types, v_col_lens
  87.       FROM all_tab_columns
  88.       WHERE table_name = v_table AND
  89.         owner = v_schema
  90.       ORDER BY column_id;
  91.     IF v_cols.COUNT = 0 THEN
  92.       raise_application_error(-20667, 'No columns found.');
  93.     END IF;
  94.     DBMS_UTILITY.table_to_comma(v_cols, i, v_col_list);  
  95.   END set_col_list;
  96.  
  97. --------------------------------------------------------------------------------
  98.   FUNCTION get_where_clause
  99.     RETURN VARCHAR2
  100.   AS
  101.     s VARCHAR2(4000) := ' where rownum <= :v_r_next_page ';
  102.   BEGIN
  103.     IF v_search IS NOT NULL THEN
  104.       s := s || ' and  instr(upper(' || REPLACE(v_col_list, ',', ' || ') || '), :v_search) > 0 ';
  105.     END IF;
  106.     RETURN s;
  107.   END;
  108.  
  109. --------------------------------------------------------------------------------
  110.   PROCEDURE build_sql_browse
  111.   AS
  112.   BEGIN
  113.     -- construct sql
  114.    /* XSU does not like bind variables outside of the where clause (in "select case" columns  or complex "where" conditions).
  115.       It throws ORA-29532: Java call terminated by uncaught Java exception: java.sql.SQLException: Missing IN or OUT parameter at index:: 1
  116.       So - simplify SQL */
  117.      
  118.     v_sql :=
  119.       'select /*+ first_rows(' || TO_CHAR(v_page_size + 1) || ') */ a.*, ' ||
  120.       '    case when min(r_num) over () = 1 then 1 else 0 end first_page, ' ||
  121.       '    case when max(r_num) over () = r_max then 1 else 0 end last_page ' ||      
  122.       '  from (select ' ||  
  123.       v_col_list || ', data_browser.escape(rowid) r_id, rownum r_num, max(rownum) over () r_max from ' ||
  124.       v_schema|| '.' || v_table;
  125.  
  126.     -- add search
  127.     v_sql := v_sql || get_where_clause;
  128.  
  129.     -- order by
  130.     v_sql := v_sql || ' order by ' || v_col_pk_list;
  131.  
  132.     v_sql := v_sql || ') a where r_num between :v_r_min and :v_r_max';
  133.  
  134.   END build_sql_browse;
  135.  
  136. --------------------------------------------------------------------------------
  137.   PROCEDURE make_xslt_browse
  138.   AS
  139.     i PLS_INTEGER;
  140.     s VARCHAR2(32767);
  141.     v_link_next VARCHAR2(100);
  142.     v_link_prev VARCHAR2(100);
  143.   BEGIN
  144.     -- main template  
  145.     s := '<?xml version="1.0" encoding="ISO-8859-1"?>
  146.      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  147.      <xsl:template match="/">
  148.        <table class="t3standard" summary="Report">
  149.        <xsl:apply-templates/>
  150.        <xsl:apply-templates select="//ROW[1]" mode="pagination"/>
  151.        </table>
  152.       </xsl:template>';
  153.  
  154.     -- rowset
  155.     s := s ||
  156.       '<xsl:template match="ROWSET"> ' ||
  157.       '<h2 class="t3RegionHeader">' || v_schema || '.' || v_table || '</h2>' ||
  158.       '<tr> ';
  159.  
  160.     -- column headers
  161.     s := s || '<th class="t3header" >&nbsp;</th>';
  162.     FOR i IN v_cols.FIRST..v_cols.LAST
  163.     LOOP
  164.       s := s || '<th class="t3header" >' || v_cols(i) || '</th>';
  165.     END LOOP;
  166.     s := s || '</tr> <xsl:apply-templates></xsl:apply-templates> </xsl:template>';
  167.  
  168.     -- row template
  169.     s := s || '<xsl:template match="ROW"> <xsl:for-each select="."> <tr>' ;
  170.    
  171.     -- column values
  172.     s := s || '<td class="t3data" ><a href="' || c_page_edit || '{R_ID}" ><img src="/i/themes/theme_3/ed-item.gif" alt="Edit" /></a></td>';
  173.     FOR i IN v_cols.FIRST..v_cols.LAST
  174.     LOOP
  175.       s := s || '<td class="t3data"> <xsl:value-of select="' || v_cols(i) || '"/></td> ';
  176.     END LOOP;
  177.    
  178.     -- close the rows
  179.     s := s || ' </tr> </xsl:for-each> </xsl:template>';
  180.  
  181.     -- pagination template
  182.     v_link_next := c_page_next || TO_CHAR(v_page_no + 1) || ',' || v_page_size || ',' || v_search;
  183.     v_link_prev := c_page_next || TO_CHAR(v_page_no - 1) || ',' || v_page_size || ',' || v_search;
  184.  
  185.     -- an after rows table with controls
  186.     s := s || '<xsl:template match="ROW" mode="pagination">
  187.      <tr> <td colspan="99" class="t3afterrows">
  188.        <table style="float:left;text-align:right;" summary="pagination">
  189.       <xsl:if test="FIRST_PAGE=0">
  190.              <td>  
  191.                <table style="float:left;" border="0" cellspacing="0" cellpadding="0" summary="">
  192.                  <tr>
  193.                    <td> <a href="' || v_link_prev || '"> <img src="/i/jtfupree.gif" width="16" height="16" alt="Previous" /> </a> </td>' ||
  194.                    '<td> <a href="' || v_link_prev || '" class="fielddata"> Previous</a> </td>
  195.                  </tr>
  196.                </table>
  197.              </td>  
  198.      </xsl:if>
  199.       <xsl:if test="LAST_PAGE=0">
  200.              <td>
  201.                <table style="float:left;" border="0" cellspacing="0" cellpadding="0" summary="">
  202.                  <tr>
  203.                    <td> <a href="' || v_link_next || '"> <img src="/i/jtfunexe.gif" width="16" height="16" alt="Next" /> </a> </td>' ||
  204.                    '<td> <a href="' || v_link_next || '" class="fielddata"> Next</a> </td>
  205.                  </tr>
  206.                </table>
  207.              </td>
  208.      </xsl:if>
  209.        </table>
  210.        </td>
  211.      </tr>
  212.       </xsl:template>';    
  213.  
  214.     -- close the xslt
  215.     s := s || '</xsl:stylesheet>';
  216.     DBMS_LOB.writeappend(v_xslt, LENGTH(s), s);
  217.   END make_xslt_browse;
  218.  
  219. --------------------------------------------------------------------------------
  220.   PROCEDURE make_xslt_edit
  221.   AS
  222.     i PLS_INTEGER;
  223.     s VARCHAR2(32767);
  224.   BEGIN
  225.     -- static part
  226.     s := '<?xml version="1.0" encoding="ISO-8859-1"?>
  227.      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  228.        <xsl:template match="/">
  229.            <table class="t3PageBody" summary="Edit">
  230.              <xsl:for-each select="/ROWSET/ROW">';
  231.  
  232.     -- column labels and edit boxes
  233.     FOR i IN v_cols.FIRST..v_cols.LAST
  234.     LOOP
  235.       s := s || '<tr class="t3Body"><td align="right"><a class="t3optionalwithhelp">' || v_cols(i) || '</a></td>' ||
  236.         '<td> <input type="text" class = "ub_input" name="F01" id="ub_' || v_cols(i) ||
  237.         '" size="' || CASE WHEN v_col_lens(i) < c_field_max_size THEN  v_col_lens(i) ELSE c_field_max_size END ||
  238.         '" maxlength="' || v_col_lens(i) ||'" value="{'|| v_cols(i) || '}" /> </td></tr>';
  239.     END LOOP;
  240.    
  241.     -- hidden inputs - scn and rowid
  242.     s := s || '<tr class="t3Body">
  243.      <td> <input type="hidden" class = "ub_input" name="F01" id="ub_row_id" size="30" maxlength="100" value="{R_ID}" /> </td>
  244.      <td> <input type="hidden" class = "ub_input" name="F01" id="ub_row_scn" size="30" maxlength="100" value="{R_SCN}" /> </td>
  245.    </tr>';
  246.  
  247.     -- close the stylesheet
  248.     s := s || '</xsl:for-each></table></xsl:template></xsl:stylesheet>';
  249.  
  250.     DBMS_LOB.writeappend(v_xslt, LENGTH(s), s);    
  251.   END make_xslt_edit;
  252.  
  253. --------------------------------------------------------------------------------
  254.   PROCEDURE set_table(iSchema IN VARCHAR2, iTableName IN VARCHAR2)
  255.   AS
  256.   BEGIN
  257.     v_table := UPPER(iTableName);
  258.     v_schema := UPPER(iSchema);      
  259.   END;
  260.  
  261. --------------------------------------------------------------------------------
  262.   PROCEDURE prepare_select(iPage IN NUMBER, iSize IN NUMBER, iSearch IN VARCHAR2)
  263.   AS
  264.   BEGIN  
  265.     -- save arguments
  266.     v_page_no := iPage;
  267.     v_page_size := iSize;
  268.     v_search := UPPER(TRIM(iSearch));
  269.  
  270.     -- analyze the table  
  271.     set_col_list;
  272.     set_pk_col_list;
  273.  
  274.     -- prepare the sql-to-xml query
  275.     build_sql_browse;
  276.     make_xslt_browse;
  277.   END prepare_select;
  278.  
  279. --------------------------------------------------------------------------------
  280.   PROCEDURE init_lobs
  281.   AS
  282.   BEGIN
  283.     DBMS_LOB.createtemporary(v_xslt, FALSE);
  284.     DBMS_LOB.createtemporary(v_html, FALSE);
  285.   END init_lobs;
  286.  
  287. --------------------------------------------------------------------------------
  288.   PROCEDURE cleanup_lobs
  289.   AS
  290.   BEGIN
  291.     DBMS_LOB.freetemporary(v_xslt);
  292.     DBMS_LOB.freetemporary(v_html);
  293.   END cleanup_lobs;
  294.  
  295. --------------------------------------------------------------------------------
  296.   PROCEDURE display_html
  297.   AS
  298.   BEGIN
  299.     IF LENGTH(v_html) > 32767 THEN
  300.       raise_application_error(-20767, 'Cannot display a page larger than 32K.');
  301.     END IF;
  302.     --dbms_output.put_line(v_html);
  303.     htp.p(v_html);
  304.   END display_html;
  305.  
  306. --------------------------------------------------------------------------------
  307.   PROCEDURE display(iMsg IN VARCHAR2)
  308.   AS
  309.   BEGIN
  310.     --dbms_output.put_line(iMsg);
  311.     htp.p(iMsg);
  312.   END display;
  313.  
  314. --------------------------------------------------------------------------------
  315.   PROCEDURE display_error
  316.   AS
  317.   BEGIN
  318.     display('<br>Error stack: ' || DBMS_UTILITY.format_error_stack || '.<br>');
  319.     display('<br>Call stack: ' || REPLACE(DBMS_UTILITY.format_call_stack, CHR(10), '<br>') || '.<br>');
  320.     display('<br>Error backtrace: ' || DBMS_UTILITY.format_error_backtrace || '.<br>');
  321.   END display_error;
  322.  
  323. --------------------------------------------------------------------------------
  324.   PROCEDURE browse(iSchema IN VARCHAR2, iTableName IN VARCHAR2, iPage PLS_INTEGER, iSize PLS_INTEGER, iSearch VARCHAR2 DEFAULT NULL)
  325.   AS  
  326.   BEGIN
  327.     init_lobs;
  328.     set_table(iSchema, iTableName);
  329.     prepare_select(iPage, iSize, iSearch);
  330.    
  331.     -- create a new query context
  332.     v_queryCtx := dbms_xmlquery.newContext(v_sql);
  333.     dbms_xmlquery.setxslt(v_queryCtx, v_xslt);
  334.  
  335.     dbms_xmlquery.setraiseexception(v_queryCtx, TRUE);
  336.     dbms_xmlquery.propagateoriginalexception(v_queryCtx, TRUE);
  337.  
  338.     dbms_xmlquery.setBindValue(v_queryCtx, 'v_r_min', (iPage - 1) * iSize + 1);
  339.     dbms_xmlquery.setBindValue(v_queryCtx, 'v_r_max', iPage * iSize);
  340.     dbms_xmlquery.setBindValue(v_queryCtx, 'v_r_next_page', iPage * iSize + 1);
  341.     IF v_search IS NOT NULL THEN
  342.       dbms_xmlquery.setBindValue(v_queryCtx, 'v_search', v_search);
  343.     END IF;  
  344.     dbms_xmlquery.getxml(v_queryCtx, v_html);  
  345.     dbms_xmlquery.closeContext(v_queryCtx);
  346.     display_html;
  347.     cleanup_lobs;
  348.   EXCEPTION
  349.     WHEN OTHERS THEN
  350.       display_error;
  351.       cleanup_lobs;
  352.   END browse;
  353.  
  354. --------------------------------------------------------------------------------
  355.   PROCEDURE edit(iSchema IN VARCHAR2, iTableName IN VARCHAR2, iRowId VARCHAR2)
  356.   AS
  357.   BEGIN
  358.     init_lobs;
  359.     set_table(iSchema, iTableName);
  360.     set_col_list;
  361.     make_xslt_edit;
  362.     -- if rowid is null - we are creating a new record  
  363.     IF iRowId IS NULL THEN
  364.       v_sql := 'select ' || LPAD('null', v_cols.COUNT * 4 + 1 * (v_cols.COUNT - 1), 'null,') || ', null R_SCN, null R_ID from ' ||
  365.         iSchema || '.' || iTableName || ' a  where rownum = 1';
  366.     -- if rowid is NOT null - we are editing a record
  367.     ELSE
  368.       v_sql := 'select ' || v_col_list || ', ora_rowscn R_SCN, rowid R_ID from ' ||
  369.         iSchema || '.' || iTableName || ' a  where rowid = :r_id';
  370.     END IF;
  371.     v_queryCtx := dbms_xmlquery.newContext(v_sql);
  372.     dbms_xmlquery.setxslt(v_queryCtx, v_xslt);
  373.  
  374.     IF iRowId IS NOT NULL THEN
  375.       dbms_xmlquery.setBindValue(v_queryCtx, 'r_id', UTL_URL.unescape(iRowId));
  376.     END IF;
  377.  
  378.     dbms_xmlquery.getxml(v_queryCtx, v_html);  
  379.     dbms_xmlquery.closeContext(v_queryCtx);
  380.     display_html;
  381.     cleanup_lobs;
  382.   EXCEPTION
  383.     WHEN OTHERS THEN
  384.       display_error;
  385.       cleanup_lobs;
  386.   END edit;
  387.  
  388. --------------------------------------------------------------------------------
  389.   PROCEDURE run_sql_save(iRowId IN ROWID, iScn IN VARCHAR2)
  390.   AS
  391.     i PLS_INTEGER;
  392.     r PLS_INTEGER;
  393.   BEGIN
  394.     -- build an insert statement  
  395.     IF iRowId IS NULL THEN
  396.       v_sql := 'insert into ' || v_schema || '.' || v_table || ' (' || v_col_list ||
  397.         ') values (';
  398.       -- add bind variables
  399.       FOR i IN 1..v_cols.COUNT
  400.       LOOP
  401.         v_sql := v_sql || ':v_' || i || ',';
  402.       END LOOP;
  403.       -- remove the last comma
  404.       v_sql := SUBSTR(v_sql, 1, LENGTH(v_sql) - 1);
  405.       -- close parenthesis
  406.       v_sql := v_sql || ')';
  407.  
  408.     -- or an update statement
  409.     ELSE  
  410.       v_sql := 'update ' || v_schema || '.' || v_table || ' set ';
  411.       -- add column_names and bind variables
  412.       FOR i IN 1..v_cols.COUNT
  413.       LOOP
  414.         v_sql := v_sql || v_cols(i) || '=:v_' || i || ',';
  415.       END LOOP;
  416.       -- remove the last comma
  417.       v_sql := SUBSTR(v_sql, 1, LENGTH(v_sql) - 1);
  418.       -- add the where clause
  419.       v_sql := v_sql || ' where rowid = :v_r_id and ora_rowscn = :v_r_scn';
  420.     END IF;
  421.    
  422.     -- parse the statement  
  423.     v_cur_hdl := DBMS_SQL.open_cursor;
  424.     DBMS_SQL.parse(v_cur_hdl, v_sql, DBMS_SQL.native);
  425.  
  426.     -- supply binds
  427.     -- update, fixed vars: rowid and row scn are the penultimate and the last entries
  428.     IF iRowId IS NOT NULL THEN  
  429.       DBMS_SQL.bind_variable(v_cur_hdl, ':v_r_id', iRowId);
  430.       DBMS_SQL.bind_variable(v_cur_hdl, ':v_r_scn', iScn);
  431.     END IF;
  432.  
  433.     -- transient vars: one per column
  434.     -- indexes of column names and value elements must match
  435.     FOR i IN 1..v_cols.COUNT
  436.     LOOP
  437.       DBMS_SQL.bind_variable(v_cur_hdl, ':v_' || i, v_vals(i));
  438.     END LOOP;
  439.    
  440.     -- execute
  441.     r := DBMS_SQL.EXECUTE(v_cur_hdl);
  442.     DBMS_SQL.close_cursor(v_cur_hdl);
  443.  
  444.     -- check results
  445.     IF (r != 1) THEN
  446.       raise_application_error(-20778, 'Expected to process 1 row. Instead, processed "' || r || '".');
  447.     END IF;
  448.  
  449.     -- finish    
  450.     COMMIT;  
  451.   EXCEPTION
  452.     WHEN OTHERS THEN
  453.       display_error;
  454.       ROLLBACK;
  455.       RAISE;
  456.   END run_sql_save;  
  457.  
  458. --------------------------------------------------------------------------------
  459.   PROCEDURE save(iSchema IN VARCHAR2, iTableName IN VARCHAR2, iRowData IN VARCHAR2)
  460.   AS
  461.      vRowId ROWID;
  462.   BEGIN
  463.     -- prepare collections
  464.     set_table(iSchema, iTableName);
  465.     set_col_list;
  466.    
  467.     -- extract data  
  468.     v_vals := apex_util.string_to_table(iRowData);
  469.  
  470.     -- check: the number of values should match the number of columns + 2 (rowid and rowscn)
  471.     IF (v_vals.COUNT != v_cols.COUNT + 2) THEN
  472.       raise_application_error(-20667, 'Expected "' || v_cols.COUNT + 2 ||
  473.         '" elements in the array of values. Instead, got "' || v_vals.COUNT ||
  474.         '". Data="' || iRowData || '". Columns="' || v_col_list || '".');
  475.     END IF;
  476.    
  477.     -- unescape rowid
  478.     vRowId := UTL_URL.unescape(v_vals(v_vals.LAST - 1));
  479.  
  480.     -- run the statement
  481.     run_sql_save(vRowId, v_vals(v_vals.LAST));
  482.   EXCEPTION
  483.     WHEN OTHERS THEN
  484.       display_error;
  485.       display(iRowData);
  486.       RAISE;
  487.   END save;
  488.  
  489. --------------------------------------------------------------------------------
  490.   PROCEDURE DELETE(iSchema IN VARCHAR2, iTableName IN VARCHAR2, iRowId IN VARCHAR2)
  491.   AS
  492.   BEGIN
  493.     EXECUTE IMMEDIATE 'delete from ' || iSchema || '.' || iTableName ||
  494.       ' where rowid = :v_r_id' using UTL_URL.unescape(iRowId);
  495.     COMMIT;  
  496.   END DELETE;
  497. END data_browser;
  498. /
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement