Tải bản đầy đủ
1 Compiling PL/SQL Code in SQL*Plus

1 Compiling PL/SQL Code in SQL*Plus

Tải bản đầy đủ

[Appendix A] Appendix: PL/SQL Exercises

15.1.1 Compiling Stored Code
When you compile a PL/SQL program in SQL*Plus from a file, the following actions occur:
1.
SQL*Plus strips out all blank lines (!) and passes them on to the SQL layer ("create or replace" is a
DDL statement).
2.
The PL/SQL program is compiled. The source code in the file is loaded into the data dictionary in the
SYS.SOURCE$, which has the following structure:
Name
−−−−−−−−−−−−−−
OBJ#
LINE
SOURCE

Null?
−−−−−−−−
NOT NULL
NOT NULL

Type
−−−−
NUMBER
NUMBER
VARCHAR2(2000)

When the compile is complete, the SYS.OBJECT$ table is updated with the date and time of the
compile and the status (VALID or INVALID).
3.
If there are compile errors, then that information is written to the SYS.ERROR$ table, which has the
following structure:
Name
−−−−−−−−−−−−−−
OBJ#
SEQUENCE
LINE
POSITION
TEXTLENGTH
TEXT

Null?
−−−−−−−−
NOT NULL
NOT NULL
NOT NULL
NOT NULL
NOT NULL
NOT NULL

Type
−−−−
NUMBER
NUMBER
NUMBER
NUMBER
NUMBER
VARCHAR2(2000)

The LINE column shows the line on which the error was found. The POSITION column contains the
character offset to the token on which the error was found. Sadly, that line number reflects the "stripped"
version of my program. So it doesn't correlate back to the source code in the file.

15.1.2 What SHOW ERRORS Does
The SHOW ERRORS command simply dumps the contents of SYS.ERROR$ (known, by the way, to mere
mortals as the USER_ERRORS view) for the most recently compiled module. You can also display lines from
USER_ERRORS for a specific program by specifying the type and name of the program, as shown:
SQL> show errors procedure greetings

This comes in handy when you have compiled (or tried to compile) multiple modules from a single script file.
I am really glad that Oracle Corporation provides SHOW ERRORS, but I sure wish it were more useful. Even
getting the line number on which the error occurs is not all that helpful. Sure, I can check my source code
(usually in an operating system file). Yet my file line numbers will probably not match the stored code line
numbers since SQL*Plus removes blank lines at compile time. I can write a query against USER_SOURCE to
see my stored code, but what would be really great is if the SHOW ERRORS command at least showed the
source code with which PL/SQL had its problem.
Wishful thinking does not, however, help a developer very much. I could wait until Oracle Corporation gets
around to enhancing SHOW ERRORS, or maybe I could do something about it myself right now. I have
learned over the years[1] two important lessons:
15.1.1 Compiling Stored Code

411

[Appendix A] Appendix: PL/SQL Exercises
[1] This dates from 1991 when I built my own debugger for SQL*Forms, XRay Vision, in
SQL*Forms itself.
1.
Don't wait for Oracle Corporation to provide the finishing touches on products that improve developer
productivity and general quality of life. Those enhancement requests are usually way down on the list
of priorities.
2.
I can usually build some kind of utility that goes a long way towards addressing a deficiency in the
Oracle tools. It's not the same as Oracle really doing it right and it's not as polished or
"shrink−wrapped" as a real third−party vendor solution, but it can still have a noticeable impact on
my productivity.
The next section offers an alternative to SHOW ERRORS that handles many of the problems of this builtin
command. This package should come in very handy, and it should also serve as a lesson (maybe even an
inspiration) to all of my readers out there: don't whine, design! If you've got a complaint and you've got a
need, take development into your own hands and build yourself a solution.

14.4 Using PLVtmr in
Scripts

15.2 Displaying Compile
Errors

Copyright (c) 2000 O'Reilly Associates. All rights reserved.

15.1.1 Compiling Stored Code

412

Chapter 15
PLVvu: Viewing Source
Code and Compile Errors

15.2 Displaying Compile Errors
The err procedure of the PLVvu package offers a very useful alternative to the SQL*Plus SHOW ERRORS
command. The header for this procedure is:
PROCEDURE err
(name_in IN VARCHAR2 := NULL, overlap_in IN INTEGER := overlap);

You provide the name of the program unit for which you want errors displayed and the err procedure not
only displays all errors found in the USER_ERRORS view, but it also shows you exactly which lines of code
are causing the problem. The second argument specifies the numbers of lines of code to display around the
line with the compile error. The default value is the value set by the set_overlap procedure (described in
a later section).
If you do not supply a program name, PLVvu.err will show you the compile errors for the most
recently−compiled program unit. It determines this information by searching for the object in ALL_OBJECTS
whose last_ddl_time equals the MAX (last_ddl_time).
The format for specifying a program unit is explained fully in Chapter 11, PLVobj: A Packaged Interface to
ALL_OBJECTS. Briefly, you can supply only the name, the type:name (as in "b:PLVio" for the body of the
PLVio package), or even the type:schema.name (as in "s:scott.showemps" to see the specification of the
showemps package owned by SCOTT).
The err procedure tries to be smart about displaying the surrounding lines of code. Suppose, for example,
that you have errors on two consecutive lines (318 and 319) and you have specified 10 lines of overlap. You
would not want to see lines 309 through 318 as well as 319 through 328, twice, would you? The logic
required to handle this complexity is covered in Section 15.4.2, "Implementing the SHOW ERRORS
Alternative"
PL/Vision also provides a script named sherr.sql so that you do not have to type the full execute
command for the PLVvu.err procedure at the SQL*Plus prompt. The following two requests to show errors
are, therefore, equivalent:
SQL> exec PLVvu.err
SQL> @sherr

If you want to pass the name of a particular program to PLVvu.err, you will not be able to use the
sherr.sql script.

15.2.1 Impact of PLVvu.err
Consider the SQL*Plus session shown below. First, we have the output from SHOW ERRORS. It reveals that
compile errors were found on lines 333 and 349. As usual, it is very difficult to determine from these error
messages what is actually wrong with my program and how I should go about finding the source of the
problems. It is hard to even tell what the problem is because SHOW ERRORS does not display the line of
code in which the error was found.
413

[Appendix A] Appendix: PL/SQL Exercises
SQL> show errors
Errors for PACKAGE BODY PLVGEN:
LINE/COL ERROR
−−−−−−−− −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
333/53
PLS−00103: Encountered the symbol ";" when expecting one of
the following:
. ( ) , * @ % & | = − + < / > in mod not rem => ..
an exponent (**) <> or != or ~= >= <= <> and or like etc.
) was inserted before ";" to continue.
349/4
PLS−00103: Encountered the symbol "BEGIN" when expecting one
of the following:
begin end function package pragma procedure form
Replacing "BEGIN" with "begin".

Now let's check out the PLVvu alternative. In the following SQL*Plus session, instead of typing SHOW
ERRORS, I call the PLVvu.err procedure. Since I do not provide a program name, it automatically locates
the last compiled object, finds some errors, and displays the information.
SQL> exec PLVvu.err
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
PL/Vision Error Listing for PACKAGE BODY PLVGEN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Line# Source
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
331
put_line;
332
END IF;
333
PLVio.put_line (indent_stg (plus_in) || stg_in;
ERR
*
PLS−00103: Encountered the symbol ";" when expecting one of
the following: . ( ) , * @ % & | = − + < / > in mod not rem
=> ..
an exponent (**) <> or != or ~= >= <= <> and or
like etc. ) was inserted before ";" to continue.
334
IF blanks_in IN (c_both, c_after)
335
THEN
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
347
plus_in IN INTEGER := 0,
348
blanks_in IN VARCHAR2 := c_none);
349
IS
ERR
*
PLS−00103: Encountered the symbol "BEGIN" when expecting one
of the following: begin end function package pragma
procedure form Replacing "BEGIN" with "begin".
350
BEGIN
351
IF using_cmnt
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

Well, that certainly looks different! The same two error messages show up (immediately after the word ERR
on the left margin of the output). But in addition to those error messages, the PLVvu.err procedure displays
the line of source code with which PL/SQL had a problem, as well as two lines before and after that
problematic line of code.
With this added data, it is very easy for me to see what went wrong:
1.
I left off the right parenthesis in my call to PLVio.put_line.
2.
I included a semicolon at the end of line 348 −− this usually happens when I copy the header for a
program out of the package specification and then paste it into the body and forget to remove the
semicolon.

414

[Appendix A] Appendix: PL/SQL Exercises
Notice that in both these cases the lines of code that were in error were not the lines of code indicated by the
compiler. Hey, no compiler's perfect, right? In any case, I am able to immediately return to my source code
and make the corrections. I have found that the PLVvu.err procedure can save me a solid 30 seconds each
time I run into a compile error −− and believe me, I run into lots of compile errors with my code. This utility
alone saves me an incredible amount of development time.

15.2.2 Setting the Code Overlap
You can specify the number of lines to display around the line in error by using the set_overlap
procedure:
PROCEDURE set_overlap (size_in IN INTEGER := c_overlap);

The default value for the single size argument is provided by the package constant, c_overlap, which has a
value of 5. So if you never call set_overlap, PLVvu will display five lines of code before and after a line
with a compile error.
The following line of code changes the overlap to only two lines:
PLVvu.set_overlap (2);

And this call to set_overlap changes the overlap back to the default, since no value is provided.
PLVvu.set_overlap;

You can obtain the current value of the overlap by calling the overlap function:
FUNCTION overlap RETURN INTEGER;

If you don't like the default value of five lines, you might include a call to PLVvu.set_overlap in your
login.sql to make sure that it is always set the way you like it in SQL*Plus.

15.1 Compiling PL/SQL
Code in SQL*Plus

15.3 Displaying Source
Code

Copyright (c) 2000 O'Reilly Associates. All rights reserved.

15.2.2 Setting the Code Overlap

415

Chapter 15
PLVvu: Viewing Source
Code and Compile Errors

15.3 Displaying Source Code
PLVvu provides two procedures to display source code: the code and code_after programs. The code
program displays all the lines of code for the specified program unit found between the start and end lines
specified. The code_after program displays the specified number of lines found after the n th occurrence
of a particular string. They are both explained below.

15.3.1 Displaying Code by Line Number
The header for the code program is:
PROCEDURE code
(name_in IN VARCHAR2 := NULL,
start_in IN INTEGER := 1,
end_in IN INTEGER := NULL,
header_in IN VARCHAR2 := 'Code for');

The first argument is the name of the program unit. If you do not supply a program, PLVvu.code will use
the object last compiled into the database.
The format for specifying a program unit is explained in Chapter 11. Briefly, you can supply only the name,
the type:name (as in "b:PLVio" for the body of the PLVio package), or even the type:schema.name (as in
"s:scott.showemps" to see the specification of the showemps package owned by SCOTT).
The second and third arguments provide the range of line numbers of the code to be displayed. The default is
all lines, with the start value of 1 and the end value NULL. The final argument provides a prefix for the
output's header.
If you want to see all the lines of source code for a program unit, simply pass the program name and leave all
the other arguments as the default. This approach is shown below:
SQL> exec PLVvu.code('s:testcase');
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Code for PACKAGE TESTCASE
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Line# Source
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
1 package testcase
2 is
3
procedure save (string_in in varchar2);
4 end testcase;

The next call to PLVvu.code requests that it display lines 85 through 95 of the body of the PLVvu package.
SQL> exec PLVvu.code ('b:PLVvu', 85, 95, 'Contents of');
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Contents of PACKAGE BODY PLVVU
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

416

[Appendix A] Appendix: PL/SQL Exercises
Line# Source
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
85
THEN
86
p.l ('ERR' || LPAD ('*', err_rec.position+4));
87
PLVprs.display_wrap
88
(PLVchr.stripped (err_rec.text, PLVchr.newline_char),
89
60, '
');
90
END IF;
91
CLOSE err_cur;
92
END;
93
/*−−−−−−−−−−−−−−− Public Modules −−−−−−−−−−−−−−−−−*/
94
PROCEDURE set_overlap
95
(size_in IN INTEGER := c_overlap)

The code.sql SQL*Plus script allows you to skip some of the typing (and all of those irritating single
quotes) when you use PLVvu.code. The last execution of PLVvu.code, for example, could be shortened
to:
SQL> @code b:PLVvu 85 95

15.3.2 Displaying Code by Keyword
The code procedure is very useful and saves you the effort of putting together a quick SQL*Plus script to
view lines of source code. However, scanning source code by line number ranges is not the only way you
might want to locate and view your code. Another common method is to search for a keyword and then
display the lines of code before, after, or around that keyword.
The code_after procedure displays the specified lines of code appearing after the nth occurrence of a
keyword you provide. The header for code_after is:
PROCEDURE code_after
(name_in IN VARCHAR2 := NULL,
start_with_in IN VARCHAR2,
num_lines_in IN INTEGER := overlap,
nth_in IN INTEGER := 1)

The first argument is the name of the program unit. If you do not supply a program, PLVvu.code will use
the object last compiled into the database.
The format for specifying a program unit is explained in Chapter 11. Briefly, you can supply only the name,
the type:name (as in "b:PLVio" for the body of the PLVio package), or even the type:schema.name (as in
"s:scott.showemps" to see the specification of the showemps package owned by SCOTT).
The second argument supplies the string for which code_after will search. The num_lines_in
argument is the number of lines after the keyword is found that will be displayed (default provided by the
current value of the overlap count). The last argument, nth_in, specifies the number of occurrences to be
located before displaying the subsequent lines of code.
The following calls to code_after demonstrate the use of these different arguments. In the first example, I
ask to see the default number of lines (5) following the first occurrence of SUBSTR. In the second call to
code_after, I request to see only three lines following the fifth occurrence of SUBSTR.
SQL> exec PLVvu.code_after('b:PLVio','SUBSTR');
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Code Starting with "SUBSTR" in PACKAGE BODY PLVIO
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Line# Source
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
330
(SUBSTR (srcrep.select_sql, 1, loc−1) ||
331
srcrep.where_clause || ' ' ||

15.3.2 Displaying Code by Keyword

417

[Appendix A] Appendix: PL/SQL Exercises
332
333
334
335

SUBSTR (srcrep.select_sql, loc));
ELSE
RETURN srcrep.select_sql;
END IF;

SQL> exec PLVvu.code_after('b:PLVio','SUBSTR', 3, 5);
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Code Starting with "SUBSTR" in PACKAGE BODY PLVIO
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Line# Source
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
704
SUBSTR
705
(string_repos.text_in,
706
string_repos.start_pos);
707
string_repos.start_pos :=

Now you know how to use the code and code_after procedures to display your source code. Section
15.4, "Implementing PLVvu" shows you the techniques used to obtain this information.
Special Notes on PLVvu
Currently PLVvu only reads from the ALL_SOURCE data dictionary view to show source text with the code
and code_after procedures. You cannot, for example, redirect the "source repository" to a file.

15.2 Displaying Compile
Errors

15.4 Implementing PLVvu

Copyright (c) 2000 O'Reilly Associates. All rights reserved.

15.3.2 Displaying Code by Keyword

418

Chapter 15
PLVvu: Viewing Source
Code and Compile Errors

15.4 Implementing PLVvu
PLVvu is a very handy utility; it is also an excellent example of the kind of software you can build yourself to
get more out of the Oracle data dictionary. This section goes behind the scenes of PLVvu to help you
understand how I built the package −− and, perhaps as importantly, how the package evolved over time into
its final PL/Vision format.
First we'll look at the general task of finding and displaying source code stored in the data dictionary. Then
we'll examine the steps required to build an alternative to SHOW ERRORS.

15.4.1 How to Find Source Code
When you "create or replace" a program (procedure, function, or package) into the Oracle database, the source
code is saved to the SYS.SOURCE$ table. You can view the contents of this table for all of your stored
programs by accessing USER_SOURCE view. The structure of this view is:
SQL> desc user_source
Name
Null?
−−−−−−−−−−−−−− −−−−−−−−
NAME
NOT NULL
TYPE
LINE
NOT NULL
TEXT

Type
−−−−−−−−−−−−−
VARCHAR2(30)
VARCHAR2(12)
NUMBER
VARCHAR2(2000)

The Name column contains the name of the object. The name is always stored in uppercase unless you enclose
the name of your program in double quotation marks at creation time. I will assume in my help
implementation that you don't do this and that your program name is always uppercased. Type is a string
describing the type of source code, either PROCEDURE, FUNCTION, PACKAGE, or PACKAGE BODY
(always uppercase). The line is the line number and the text is the line of text. Notice that a line of text may be
up to 2000 bytes in length.
You can also access another data dictionary view, ALL_SOURCE, to see the source of all programs you can
access, even if you do not own those program units. It isn't hard to write a SQL statement to view the contents
of this table. The following SQL script (found in showsrc.sql) gets the basic idea across:
SELECT
FROM
WHERE
AND
/

TO_CHAR (line) || text Line_of_code
user_source
name=UPPER ('&1')
line BETWEEN &2 AND &3

However, if you want to make it easy for developers to run such scripts in a flexible manner, you will
probably want to move to a PL/SQL−based solution, as I did.
The implementation of the PLVvu.code procedure is shown below:
PROCEDURE code

419

[Appendix A] Appendix: PL/SQL Exercises
(name_in IN VARCHAR2 := NULL,
start_in IN INTEGER := 1,
end_in IN INTEGER := NULL,
header_in IN VARCHAR2 := 'Code for')
IS
line_rec PLVio.line_type;
line_num INTEGER;
BEGIN
set_object (name_in);
PLVio.asrc (start_in, end_in);
disp_header (header_in);
LOOP
PLVio.get_line (line_rec, line_num);
EXIT WHEN line_rec.eof;
disp_text
(line_rec.line# + start_in − 1, line_rec.text);
END LOOP;
PLVio.closesrc;
END;

As you can see, PLVvu relies heavily on other PL/Vision packages. It calls a private procedure,
set_object, to set the current object for PLVio. The set_object procedure in turn calls the
PLVobj.setcurr program for either the name specified or the last object. The code procedure then calls
PLVio.asrc to set the source repository to the ALL_SOURCE view and specifies that only lines between
start_in and end_in be queried. It displays a header and then loops through each record retrieved with a
call to the PLVio.get_line procedure. It calls a local procedure, disp_text, to format and display the
code. When done, it closes the source repository with a call to the PLVio.closesrc procedure.
This code is certainly more complex than the single query of the showsrc.sql script. It is, on the other
hand, much more powerful and flexible. For example, this approach makes it quite feasible to enhance the
PLVvu.code procedure to read the source code from an operating system file (remove the call to
PLVio.asrc and let the user establish her own source repository outside of PLVvu.code). Now how
would you do that with a straight SQL solution?

15.4.2 Implementing the SHOW ERRORS Alternative
I could start off by showing you the source code for PLVvu.err and simply step you through this final,
polished version of the program. That approach would, however, be both misleading and intimidating. The
programs that you see in these pages have been massaged quite thoroughly over a period of months. If I
simply explain my final version without giving you a sense of the process by which I arrived at this pristine
result, you will be much less likely to develop the skills needed to come up with solutions to your own, very
specific problems.[2] As a result, I will make every effort to show you the techniques of problem−solving and
iterative coding I have employed en route to producing this package.
[2] In the process of writing this chapter, I performed an unplanned code review of my
PLVvu package and performed major surgery on it, improving performance and code reuse.
When I wrote "final, polished version" two paragraphs back, I had no idea how much room
for improvement was left in PLVvu!
15.4.2.1 Merging source and error information
One of the critical early steps in designing a new package or new kind of utility is to validate the feasibility of
the idea. In the case of PLVvu.err, my core idea is:
The USER_SOURCE view contains the source code, including line number. The
USER_ERRORS view contains the compile error information, which includes line numbers
15.4.2 Implementing the SHOW ERRORS Alternative

420

[Appendix A] Appendix: PL/SQL Exercises
as well. So it seems as if I should be able to combine these two sources of information into a
single useful presentation like the one you saw earlier.
Let's see if I can actually do this. First, I need the SQL statement that will retrieve the source code from the
USER_SOURCE view. The following SQL*Plus script displays all the code associated with the specified
program unit (&1 and &2 are parameters, allowing values to be passed into the script).
COLUMN
COLUMN
SELECT
FROM
WHERE
AND
ORDER

line FORMAT 99999
text FORMAT A80
line, text
user_source
name = UPPER ('&2')
type = UPPER ('&1')
BY line;

I can call this script (I'll name it showcode.sql) in SQL*Plus as follows:
SQL> start showcode procedure greetings
LINE TEXT
−−−−−− −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
1 procedure greetings
2 is
3 begin
4
dbms_output.put_line ('hello world!')
5 end;

Do you notice anything amiss in the above procedure? There is no semicolon at the end of line 4! In fact when
I tried to "create or replace" this procedure, I was informed that:
Warning: Procedure created with compilation errors.

and my good friend SHOW ERRORS revealed the following:
LINE/COL ERROR
−−−−−−−− −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
5/1
PLS−00103: Encountered the symbol "END" when expecting one of
the following:
:= . ( % ;
Resuming parse at line 5, column 5.

If SHOW ERRORS can show the information, that means that there is a row in the USER_ERRORS view.
Let's use SQL similar to the code in showcode.sql to show the error information stored in the view. The
following script (showerr.sql) succeeds in producing output which matches SHOW ERRORS:
COLUMN linedesc FORMAT A8 HEADING 'LINE/COL'
COLUMN text FORMAT A62 HEADING 'ERROR'
SELECT TO_CHAR (line) || '/' || TO_CHAR(position) linedesc,
text
FROM user_errors
WHERE name = UPPER ('&2')
AND type = UPPER ('&1')
ORDER BY line;

15.4.2.2 Showing the line in error
So these two SQL statements separately give me what I need −− but I need to combine them. The big
question is now: can I merge these two SQL statements successfully? To merge data in SQL, I perform a join.
The following SELECT will, therefore, return a line of text from USER_SOURCE for every row in the
USER_ERRORS view.
SELECT TO_CHAR (S.line) || '/' || TO_CHAR(E.position) linedesc,

15.4.2 Implementing the SHOW ERRORS Alternative

421