1. Trang chủ
  2. » Công Nghệ Thông Tin

Oracle Built−in Packages- P14 docx

5 260 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 5
Dung lượng 80,15 KB

Nội dung

instructed by your DBA. Note that you cannot defer the parsing of this statement, as is possible with OCI. Statements in DBMS_SQL are parsed immediately. Oracle documentation does mention that this "may change in future versions; you should not rely on this behavior." This means that at some point in the future, Oracle Corporation may allow parsing to be deferred to the execute phase, thereby reducing network traffic. If this change occurs, let's hope that a flag is offered to preserve earlier functionality. NOTE: The common understanding among long−time Oracle programmers is that when you parse DDL, it always executes, so a call to the EXECUTE procedure is not necessary when calling DBMS_SQL.PARSE for a DDL statement. You should not take this shortcut! Oracle will not guarantee that this behavior will continue in future releases. If you want to make sure that your DDL has executed, call the DBMS_SQL.EXECUTE procedure. 2.3.3.2 Parsing very long SQL statements PL/SQL8 offers a second, overloaded version of PARSE, which comes in handy when you have very large SQL statements. If your SQL statement exceeds the largest possible contiguous allocation on your system (and it is machine−dependent) or 32Kbytes (the maximum size for VARCHAR2), then use this version of the PARSE procedure: PROCEDURE DBMS_SQL.PARSE (c IN INTEGER, statement IN DBMS_SQL.VARCHAR2S, lb IN INTEGER, ub IN INTEGER, lfflg IN BOOLEAN, language_flag IN INTEGER); The parameters for this procedure are summarized in the following table. Parameter Description c The pointer to the cursor or memory area for this SQL statement. statement The SQL statement to be parsed and associated with the cursor. In this case, you will be passing a PL/SQL table of the DBMS_SQL.VARCHAR2S type. lb The lower bound or first row in the statement table to be parsed. ub The upper bound or last row in the statement table to be parsed. lfflg If TRUE, then a line−feed should be concatenated after each row in the table. language_flag A flag determining how Oracle will handle the statement. Valid options are DBMS_SQL.V6, DBMS_SQL.V7, and DBMS_SQL.NATIVE. Use DBMS_SQL.NATIVE unless otherwise instructed by your DBA. My own parse_long_one procedure offers an example of using the array−based version of the PARSE procedure: /* Filename on companion disk: parslong.sp */ CREATE OR REPLACE PROCEDURE parse_long_one (select_list IN VARCHAR2, from_list IN VARCHAR2, where_clause IN VARCHAR2, maxlen IN BINARY_INTEGER := 256, /* Can change the max. */ dbg IN BOOLEAN := FALSE /* Built−in debugging toggle */ ) IS /* Open the cursor as I declare the variable */ cur BINARY_INTEGER := DBMS_SQL.OPEN_CURSOR; [Appendix A] What's on the Companion Disk? 2.3.3 Parsing the SQL Statement 56 /* Declare the index−by table based on the DBMS_SQL TYPE. */ sql_table DBMS_SQL.VARCHAR2S; /* Local module to extract up to the next maxlen chars. */ FUNCTION next_row (string_in IN VARCHAR2, start_inout IN OUT BINARY_INTEGER, len_in IN BINARY_INTEGER) RETURN VARCHAR2 IS v_start BINARY_INTEGER := start_inout; BEGIN start_inout := LEAST (len_in + 1, start_inout + maxlen); RETURN SUBSTR (string_in, v_start, maxlen); END; /* Local module to transfer string to index−by table. */ PROCEDURE fill_sql_table (string_in IN VARCHAR2) IS v_length BINARY_INTEGER; v_start BINARY_INTEGER := 1; BEGIN IF string_in IS NOT NULL THEN v_length := LENGTH (string_in); LOOP sql_table (NVL (sql_table.LAST, 0)+1) := next_row (string_in, v_start, v_length); EXIT WHEN v_start > v_length; END LOOP; END IF; END; BEGIN /* Move each portion of the SELECT string to the table. */ fill_sql_table (select_list); fill_sql_table (from_list); fill_sql_table (where_clause); /* Parse everything from first to last row of table. */ DBMS_SQL.PARSE (cur, sql_table, sql_table.FIRST, sql_table.LAST, FALSE, DBMS_SQL.NATIVE); /* Execute and fetch rows if doing something for real */ /* If debugging, then display contents of the table. */ IF dbg THEN DBMS_OUTPUT.PUT_LINE ('Parsed into lines of length ' || TO_CHAR (maxlen)); FOR rowind IN sql_table.FIRST sql_table.LAST LOOP DBMS_OUTPUT.PUT_LINE (sql_table(rowind)); END LOOP; END IF; /* Close the cursor when done. */ DBMS_SQL.CLOSE_CURSOR (cur); END; / Here is a little test script (and the results of execution) for this procedure: SQL> BEGIN parse_long_one ('select empno, ename, sal, hiredate, mgr, comm ', 'from emp ', 'where empno = empno and sal = sal', 10, TRUE); [Appendix A] What's on the Companion Disk? 2.3.3 Parsing the SQL Statement 57 END; / Parsed into lines of length 10 select emp no, ename, sal, hire date, mgr, comm from emp where empn o = empno and sal = sal / Notice that the SELECT statement is broken without any concern for keeping identifiers intact. The lfflg value passed in to the PARSE procedure is set to FALSE so linefeeds are not concatenated. As a result, the broken identifiers are concatenated back together and the SQL statement parses without any difficulty. 2.3.4 Binding Values into Dynamic SQL The SQL (or PL/SQL) statement you execute is constructed as a string at runtime. In most scenarios, you are using dynamic SQL because all the information about the SQL statement is not known at compile time. You therefore have values that you want to pass into the SQL statement at runtime. You have two ways of doing this: concatenation and binding. With concatenation, you convert all elements of the SQL statement into strings and concatenate them together. With binding, you insert placeholders in your string (identifiers prefaced with a colon) and then explicitly bind or associate a value with that placeholder before executing the SQL statement. If you concatenate the value into the string, then you are not really binding values and you do not have to make calls to the BIND_VARIABLE or BIND_ARRAY procedures. Here is an example of the parsing of a dynamically constructed string relying on concatenation: DBMS_SQL.PARSE (cur, 'SELECT * FROM emp WHERE ename LIKE ' || v_ename); At runtime the string is cobbled together and passed to the SQL engine for parsing. With binding, you would write code like this: DBMS_SQL.PARSE (cur, 'SELECT * FROM emp WHERE ename LIKE :varname'); DBMS_SQL.BIND_VARIABLE (cur, 'varname', var_name_in); Binding involves writing more code, but offers much more flexibility and power. The following comparison between concatenation and binding techniques will help you decide which to use: • When you concatenate, you convert to a string format. This can become awkward and error−prone. With binding, you do not perform any conversions. Instead, the native datatypes are employed. • When you execute DDL statements dynamically, you cannot use bind variables. Your only choice is to concatenate together the strings and then pass that to the engine. This makes sense, since, at least in the current version of DBMS_SQL, there is no such thing as deferred parsing. When you parse, you also execute DDL. • [Appendix A] What's on the Companion Disk? 2.3.4 Binding Values into Dynamic SQL 58 You can execute the same dynamic cursor more than once, and each time you bind in different values to the SQL statement. This is not possible if you concatenate the values into the string at the time of parsing. • With bind variables, you can take advantage of the new array−processing features of PL/SQL8's DBMS_SQL package. You can bind an entire array of scalar values into the SQL string and then apply each of those values in a single SQL execution. So if you decide that you really do want to bind variables into your dynamic SQL, use one of the programs described in the following sections. 2.3.4.1 The DBMS_SQL.BIND_VARIABLE procedure The BIND_VARIABLE procedure binds a scalar value to a placeholder in your SQL statement. A placeholder is an identifier prefaced by a colon, as in :myval. Call BIND_VARIABLE after DBMS_SQL.PARSE, but before calls to EXECUTE and EXECUTE_AND_FETCH. This procedure is overloaded to allow you to bind a number of different types of data. This is the header: PROCEDURE DBMS_SQL.BIND_VARIABLE (c IN INTEGER, name IN VARCHAR2, value IN <datatype>); The parameters for this procedure are summarized in the following table. Parameter Description c The handle or pointer to the cursor originally returned by a call to OPEN_CURSOR. name The name of the placeholder included in the SQL statement passed to PARSE. value The value to be bound to the placeholder variable. <datatype> may be any of the following: BFILE BLOB CLOB CHARACTER SET ANY_CS DATE MLSLABEL /*Trusted Oracle only*/ NUMBER VARCHAR2 CHARACTER SET ANY_CS_ARRAY Here is an example of binding the current date/time into a placeholder called "now:" DBMS_SQL.BIND_VARIABLE (cur, 'now', SYSDATE); Here is an example of binding the literal value "Liberation Theology" into a placeholder called "progress:" DBMS_SQL.BIND_VARIABLE (cur, ':progress', 'Liberation Theology'); Notice that you can include or leave out the colon when you specify the placeholder name. The DBMS_SQL package also offers more specific variants of BIND_VARIABLE for less−common datatypes, PROCEDURE DBMS_SQL.BIND_VARIABLE (c IN INTEGER, name IN VARCHAR2, [Appendix A] What's on the Companion Disk? 2.3.4 Binding Values into Dynamic SQL 59 value IN VARCHAR2 CHARACTER SET ANY_CS, [,out_value_size IN INTEGER]); PROCEDURE DBMS_SQL.BIND_VARIABLE_CHAR (c IN INTEGER, name IN VARCHAR2, value IN CHAR CHARACTER SET ANY_CS, [,out_value_size IN INTEGER]); PROCEDURE DBMS_SQL.BIND_VARIABLE_RAW (c IN INTEGER, name IN VARCHAR2, value IN RAW [,out_value_size IN INTEGER]); PROCEDURE DBMS_SQL.BIND_VARIABLE_ROWID (c IN INTEGER, name IN VARCHAR2, value IN ROWID); where out_value_size is the maximum size expected for the value that might be passed to this variable. Square brackets indicate optional parameters. If you do not provide a value for out_value_size, the size is the length of the current value provided. 2.3.4.1.1 Examples For every placeholder you put in your SQL string, you must make a call to BIND_VARIABLE (or BIND_ARRAY). For example, the SELECT statement in the call to PARSE below contains two bind variables, :call_date and :call_type: DBMS_SQL.PARSE (the_cursor, 'SELECT COUNT(*) freq FROM call WHERE call_date = :call_date ' || 'AND call_type_cd = :call_type', DBMS_SQL.V7); I will therefore need to issue the following two calls to BIND_VARIABLE before I can execute the query, DBMS_SQL.BIND_VARIABLE (the_cursor, 'call_date', :call.last_date_called); DBMS_SQL.BIND_VARIABLE (the_cursor, 'call_type', :call.call_status); where the two bind values are items in an Oracle Forms screen. Since BIND_VARIABLE is overloaded, I can call it with either a date value or a string, and PL/SQL will execute the appropriate code. Notice that the name of the bind variable does not have to match any particular column name in the SELECT statement, and it does not have to match the name of the PL/SQL variable that may hold the value. The name is really just a placeholder into which a value is substituted. You can also include the colon in the placeholder name when you bind the value to the variable: DBMS_SQL.BIND_VARIABLE (the_cursor, ':call_date', :call.last_date_called); If you want to avoid having to make these separate calls to BIND_VARIABLE, you can substitute these values into the SQL statement yourself at the time the statement is parsed. The code shows the same SELECT statement, but without any bind variables. DBMS_SQL.PARSE (the_cursor, 'SELECT COUNT(*) freq FROM call WHERE call_date = ''' || TO_CHAR (:call.last_date_called) || ''' AND call_type_cd = ''' || :call.call_status || '''', DBMS_SQL.V7); [Appendix A] What's on the Companion Disk? 2.3.4 Binding Values into Dynamic SQL 60 . immediately. Oracle documentation does mention that this "may change in future versions; you should not rely on this behavior." This means that at some point in the future, Oracle Corporation. flag is offered to preserve earlier functionality. NOTE: The common understanding among long−time Oracle programmers is that when you parse DDL, it always executes, so a call to the EXECUTE procedure. not necessary when calling DBMS_SQL.PARSE for a DDL statement. You should not take this shortcut! Oracle will not guarantee that this behavior will continue in future releases. If you want to make

Ngày đăng: 07/07/2014, 00:20