Showing posts with label SQL*Plus. Show all posts
Showing posts with label SQL*Plus. Show all posts

Tuesday, June 3, 2008

How PL/SQL Could Be More Like PHP

This is really a trick subject line -- PL/SQL already has the capability to be very much like PHP. PL/SQL Server Pages lets you write template HTML files including PL/SQL parameters, expressions, and blocks, and turn them into stored procedures that produce HTML output using HTP.P() procedure calls. The angle-bracket syntax around the expressions and blocks is very similar to that of PHP. And a PL/SQL coder has a headstart when it comes to optimizing DB performance and avoiding security problems.

PL/SQL Server Pages was the first web-related feature that I documented at Oracle. When I started using it myself, eating my own dogfood so to speak, that's when the potential functionality enhancements sprang to mind.

PHP is so popular because it's all based around text files, you can modify your source with any kind of HTML tool, and you don't have to do anything special to get the code to run, just put the files in the right places.

PL/SQL Server pages are also based around text files, you can also run them through HTML Tidy, and edit them in DreamWeaver or what have you. However, to use them requires the loadpsp command. With this command, you specify the user ID and password on the command line. That's not the ideal mode of loading code if you normally sit at the SQL*Plus command prompt, already logged in, and load new/changed stored procedures via '@script_name'.

With PHP, the way to load code into different parts of the application structure is to put the files in different subdirectories. The equivalent for PL/SQL Server Pages would be to use a template file to generate a packaged subprogram, an internal procedure, or a method for an object type. But, to my knowledge, loadpsp can only create a top-level procedure, which best practice says you should keep to a minimum.

Now, all of this could be worked around if loadpsp could generate the source code for the procedure and stop there, leaving the file behind instead of loading it into the database. You could set up a makefile to transform each .psp file into a .sql file. You could load the .sql files into the database from inside SQL*Plus without doing a separate login each time. You could set up a script using a SQL*Plus HOST command to go through both steps. Perhaps that would incite the SQL*Plus dev team to create a new directive similar to '@' that would run loadpsp and then '@' the resulting output file. If the output file could start with 'PROCEDURE ... IS', leaving off the initial 'CREATE OR REPLACE', you could use my favorite trick of:

package body foo is
@procedure1;
@procedure2;
...

to load PSP-generated pages as packaged procedures or object methods.

I never quite bought into the idea that with PHP, coders and designers would happily edit the same files, passing them back and forth and limiting their edits to either the HTML tags or the code blocks depending on their role. In my experience, every expert tends to have ingrained assumptions that don't work well with top-down planning. The designer tasked with making a more attractive-looking page will go off and write HTML that's structured very differently from the existing page, that PL/SQL blocks and widgets can't be neatly dropped into. The PL/SQL coder tasked with adding some dynamic elements to the page will chafe at working inside markup produced by some HTML authoring tool they disdain; sometimes, it's too painful even to read past the DOCTYPE tag. :-)

Wednesday, May 14, 2008

Query vs. CREATE TABLE AS SELECT

Half the time, I want to know some answer that can be determined with a query. The other half of the time, I want to start from that answer and use it as an intermediate step towards some larger solution. (That's not even considering the third half... :-)

So, I have a bunch of .sql files that do SELECT statements. Sometimes, I end up editing those .sql files into new ones that do CREATE TABLE AS SELECT... using the same query. I don't like the proliferation of .sql files that are slight variations of each other. That's the aspect of SQL coding that I would most like to see be object-oriented, the many SQL scripts that differ from each other only in terms of connection string, table name, or other minor detail.

Now, I know the WITH clause is there for pulling out a query to reuse its results as part of a bigger query. But sometimes the natural-feeling technique is to do CREATE TABLE AS SELECT colname... and then several other queries with clauses WHERE colname IN SELECT * FROM newly_created_table.

I had a sense there must be some shortcut to turning the original query into a CTAS construct. And there is! Remember how SQL*Plus will happily substitute the contents of a script anywhere you start a line with an '@' sign? Well, turns out you can use this technique to substitute a script as the last half of a SQL statement:

- Create a .sql file that has a single SELECT statement.
- Issue a CTAS statement like so:

create table t1 as
@script_with_select_statement

The trick is to make sure the SQL script has no blank lines, as they will cause SQL*Plus to stop processing the command prematurely. '--' comments are OK, so you can comment and format the script using -- lines where you would normally use blank lines.

CTAS is a bit of a blunt instrument, especially if the same situation comes up again and again. I may adapt this technique to use with CREATE GLOBAL TEMPORARY TABLE t1... and INSERT INTO t1 SELECT... constructs.

Thursday, June 28, 2007

Upgrading SQL*Plus Client

Sometimes the old ways are best, sometimes not. I have some rarely-used machines where I had never bothered to upgrade my client installation, and so were still running the 9i SQL*Plus. The older SQL*Plus could still compile all my PL/SQL source that used the latest and greatest 10g features, so what's the big deal?

As it turns out, there are a number of cases where having a downlevel SQL*Plus produces cryptic errors. I went looking in the docs, but I don't think there is any comprehensive listing of these cases. (It would be difficult to make an exhaustive list; it might not help much with troubleshooting because the errors are so cryptic; and I'm sure the workaround -- just upgrade! -- is stated many times in many places. Still, I would have liked to have found a list that showed all the errors that could occur, so I could find it by searching.)

For me, the feature that prompted me to finally upgrade was the alternative quoting syntax. It worked fine in a PL/SQL block:

begin
  insert into some_table (title) values (q'{Administrator's Guide}');

But not if I used the quoting feature directly in SQL, i.e. in a query from the SQL*Plus command line or in a SQL script with INSERT etc. not wrapped inside a PL/SQL block:

SQL> select title from some_table where title like q'{Administrator's}';
ERROR:
ORA-01756: quoted string not properly terminated

Thursday, January 18, 2007

SQL*Plus Tip: Turn a File into a String Literal

Consider for a moment this code, using SQL*Plus's '@' command to import a file:

select
'
@foo.htm;
'
from dual;

We've just turned the entire contents of foo.htm into a string literal. Of course, it won't work if foo.htm contains any single quote characters. No problem in 10g, using the alternative quoting mechanism:

select
q'{
@bar;
}'
from dual;

Now we're OK as long as the file doesn't contain the sequence }'. We could pick other characters if needed to avoid collisions with the file contents.

Think about this for a minute. Any file less than 32K could be turned into a PL/SQL VARCHAR2 variable. We could run REGEXP_REPLACE functions to substitute variable content inside the string.

This could be very useful. There is always some tension between coders and designers on web projects. Everyone wants to be able to freely edit their pieces without interference from the other. This technique allows someone to mark up a div, table, style, or other HTML block in its own file, and a PL/SQL coder to pick it up and use it without any extra overhead.

I've never been entirely comfortable with solutions that start with an HTML file and embed little code blocks inside, like with PL/SQL Server Pages. That seems to me to give too much opportunity for fatal error to the person editing the HTML file. When was the last time you asked somebody to make a tiny edit to an HTML file, and they only changed the part you wanted them to. My point exactly; chances are, they went wild changing all your list tags, adding style attributes, and who knows what else. I'd rather have my program logic pumping out divs, table cells, form fields, etc. with only the small block of tagging for each container subject to outside editing.

SQL*Plus Tip: @ vs. @@

I built huge amounts of PL/SQL code with SQL*Plus, using the '@' command to import source files, without ever running across the '@@' command. But one day I found a limitation in '@', and in one fell swoop changed all my SQL and PL/SQL scripts to use '@@' and have never looked back.

You need '@@' if you ever want to compile source code by running SQL*Plus from a different directory. For example, I had source files that would call each other like so:

@variables;
@file1;
@file2;

and it all worked fine, as long as I went into the directory where all the files were and ran SQL*Plus from there.

But to automate my build process, I started running various scripts from a different directory, such as:

sqlplus $credentials source/file1.sql

For file1.sql to be able to import file2.sql and so on, I needed to use '@@'. With '@@', all the import commands are processed relative to the directory where the original file sits, not the directory where you run SQL*Plus.

SQL*Plus Tip: Splitting Up Package Code

With PL/SQL packages, I run into the perennial problem. Logically, a package works best as a single huge thing, grouping perhaps hundreds of related procedures together. But logistically, source code sometimes works better as small individual files.

First up, always put the package spec and package body in separate files. That way, you can recompile the body without invalidating other procedures that call into the package.

You can take advantage of SQL*Plus's lack of a true parser by splitting big PL/SQL package files (typically the bodies) into smaller ones. The '@' and '@@' commands work inside a package, where you might not expect them to. For example:

create or replace package foo
as
@foo_declarations;
@foo_procedures;
@foo_functions;
end;

Tuesday, January 16, 2007

Tahiti Views, My Oracle Blog

I figured I should keep my work-related blog posts separate from my personal ones, so here's my new Oracle-related blog, "Tahiti Views". Project Tahiti is the code name for my work at Oracle, hardly a secret anymore since tahiti.oracle.com debuted in 2000.

Here I'll blog about all things Oracle, documentation, usability, web application development, and combinations thereof.

As you might suspect, all material here is my own personal opinion, not anything official from Oracle.