添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Description In the most complicated dynamic SQL scenarios (method 4), you may not know how many bind variables you have in your statement. This means you need to use DBMS_SQL.BIND_VARIABLE but you still need to know how many and their names. This package finds the placeholders and returns the information in an array. And it also knows about the differences in placeholder binding for dynamic SQL vs dynamic PLSQL. For the latter, assignment of value to placeholder is by NAME, not POSITION (as is the case with SQL). PL/SQL General Contributor Steven Feuerstein Created Wednesday March 23, 2016 Statement
CREATE OR REPLACE PACKAGE dyn_placeholder  
Dynamic PL/SQL Placeholder Analyzer Package  
Author: Steven Feuerstein, [email protected]  
Created: December 20, 2005  
Overview: Helps you analyze strings for placeholders, which is defined as the  
colon character ":" followed by anything but =.  
Most programs have a parameter named dyn_plsql_in. If your string is part of  
a dynamic PL/SQL block, you should pass TRUE for this argument. If you pass  
NULL and the string ends with a semi-colon, then I will assume it is a  
dynamic PL/SQL block. Why bother with this? In a dynamic SQL block, you need  
to provide a bind variable for each placeholder, even if there are multiple  
with the same name. In a dynamic PL/SQL block, you only provide a value for  
the first occurrence of each placeholder (by name).  
Note: these programs do not take into account : characters that occur  
within a comment or within a literal.  
   /* Return two pieces of information about each placeholder:  
      1. The name (without the colon) upper-cased.  
      2. The location in the string (starting with the colon)  
   TYPE placeholder_rt IS RECORD (  
      name VARCHAR2 ( 100 )  
    , POSITION PLS_INTEGER  
   -- Associative array type to hold information about all placeholders.  
   TYPE placeholder_aat IS TABLE OF placeholder_rt  
      INDEX BY PLS_INTEGER;  
   -- Return the number of placeholders found in the string.  
   FUNCTION count_in_string (  
      string_in      IN   VARCHAR2  
    , dyn_plsql_in   IN   BOOLEAN DEFAULT FALSE  
      RETURN PLS_INTEGER DETERMINISTIC;  
   /* Return the nth placeholder in the string. */ 
   FUNCTION nth_in_string (  
      string_in      IN   VARCHAR2  
    , nth_in         IN   PLS_INTEGER  
    , dyn_plsql_in   IN   BOOLEAN DEFAULT FALSE  
      RETURN placeholder_rt DETERMINISTIC;  
   -- Return all the placeholders in an associative array.  
   FUNCTION all_in_string (  
      string_in      IN   VARCHAR2  
    , dyn_plsql_in   IN   BOOLEAN DEFAULT FALSE  
      RETURN placeholder_aat DETERMINISTIC;  
   -- Display all the placeholders.  
   PROCEDURE show_placeholders (  
      list_in        IN   placeholder_aat  
    , dyn_plsql_in   IN   BOOLEAN DEFAULT FALSE  
   PROCEDURE show_placeholders (  
      string_in      IN   VARCHAR2  
    , dyn_plsql_in   IN   BOOLEAN DEFAULT FALSE  
   FUNCTION eq (  
      rec1_in       IN   placeholder_rt  
    , rec2_in       IN   placeholder_rt  
    , nullq_eq_in   IN   BOOLEAN DEFAULT TRUE  
      RETURN BOOLEAN DETERMINISTIC;  
END dyn_placeholder;
Package created.
FUNCTION only_identifier_from ( string_in IN VARCHAR2 , position_in IN PLS_INTEGER RETURN VARCHAR2 c_delimiters CONSTANT VARCHAR2 ( 100 ) := '!@%^&*()-=+\|`~{[]};:''",<.>/? ' || CHR ( 10 ) || CHR ( 13 ) || CHR ( 9 ); l_end PLS_INTEGER; BEGIN l_end := INSTR ( TRANSLATE ( string_in , c_delimiters , RPAD ( CHR ( 2 ) , LENGTH ( c_delimiters ) , CHR ( 2 ) , CHR ( 2 ) , position_in IF l_end = 0 RETURN SUBSTR ( string_in, position_in ); RETURN SUBSTR ( string_in, position_in, l_end - position_in ); END IF; END only_identifier_from; FUNCTION all_in_string ( string_in IN VARCHAR2 , dyn_plsql_in IN BOOLEAN DEFAULT FALSE RETURN placeholder_aat c_is_dynplsql CONSTANT BOOLEAN := NVL ( dyn_plsql_in, SUBSTR ( string_in, -1 ) = ';' ); l_start PLS_INTEGER := 1; l_loc PLS_INTEGER; l_placeholders placeholder_aat; PROCEDURE add_placeholder ( loc_in IN PLS_INTEGER ) l_row PLS_INTEGER := l_placeholders.FIRST; c_last CONSTANT PLS_INTEGER := l_placeholders.LAST; l_name VARCHAR2 ( 32767 ); l_already_used BOOLEAN := FALSE; BEGIN l_name := UPPER ( only_identifier_from ( string_in, loc_in + 1 )); IF c_is_dynplsql WHILE ( NOT l_already_used AND l_row <= c_last ) l_already_used := l_name = l_placeholders ( l_row ).NAME; l_row := l_row + 1; END LOOP; END IF; IF NOT l_already_used l_row := l_placeholders.COUNT + 1; l_placeholders ( l_row ).NAME := l_name; l_placeholders ( l_row ).POSITION := loc_in; END IF; END add_placeholder; BEGIN l_loc := INSTR ( string_in, ':', l_start ); EXIT WHEN l_loc = 0 OR l_loc IS NULL; IF SUBSTR ( string_in, l_loc + 1, 1 ) != '=' add_placeholder ( l_loc ); END IF; l_start := l_loc + 1; END LOOP; RETURN l_placeholders; END all_in_string; FUNCTION count_in_string ( string_in IN VARCHAR2 , dyn_plsql_in IN BOOLEAN DEFAULT FALSE RETURN PLS_INTEGER l_placeholders placeholder_aat; BEGIN l_placeholders := all_in_string ( string_in , dyn_plsql_in); RETURN l_placeholders.COUNT; END count_in_string; FUNCTION nth_in_string ( string_in IN VARCHAR2 , nth_in IN PLS_INTEGER , dyn_plsql_in IN BOOLEAN DEFAULT FALSE RETURN placeholder_rt l_placeholders placeholder_aat; BEGIN l_placeholders := all_in_string ( string_in ); IF nth_in > l_placeholders.COUNT RETURN NULL; RETURN l_placeholders ( nth_in ); END IF; END nth_in_string; PROCEDURE show_placeholders ( list_in IN placeholder_aat , dyn_plsql_in IN BOOLEAN DEFAULT FALSE l_index PLS_INTEGER := list_in.FIRST; BEGIN WHILE ( l_index IS NOT NULL ) DBMS_OUTPUT.put_line ( list_in ( l_index ).NAME || ' - ' || list_in ( l_index ).POSITION l_index := list_in.NEXT ( l_index ); END LOOP; END show_placeholders; PROCEDURE show_placeholders ( string_in IN VARCHAR2 , dyn_plsql_in IN BOOLEAN DEFAULT FALSE BEGIN show_placeholders ( all_in_string ( string_in, dyn_plsql_in )); END show_placeholders; FUNCTION eq ( rec1_in IN placeholder_rt , rec2_in IN placeholder_rt , nullq_eq_in IN BOOLEAN DEFAULT TRUE RETURN BOOLEAN BEGIN RETURN ( ( rec1_in.NAME = rec2_in.NAME OR ( rec1_in.NAME IS NULL AND rec2_in.NAME IS NULL ) AND ( rec1_in.POSITION = rec2_in.POSITION OR ( rec1_in.POSITION IS NULL AND rec2_in.POSITION IS NULL END eq; END dyn_placeholder;
Package Body created.
begin
   dyn_placeholder.show_placeholders (
      'update abc where col1 = :mycol and col2 = :mycol2 where col3 like :wildcard');
                        
MYCOL - 25
MYCOL2 - 43
WILDCARD - 67
begin
   dyn_placeholder.show_placeholders (
      'update abc where col1 = :mycol and col2 = :mycol where col3 like :wildcard');
                        
MYCOL - 25
MYCOL - 43
WILDCARD - 66
dyn_placeholder.show_placeholders ( 'begin update abc where col1 = :mycol and col2 = :mycol where col3 like :wildcard; end;', dyn_plsql_in => TRUE); © 2024 Oracle Corporation Privacy | Terms of Use