Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Piotr.

Asked: September 18, 2002 - 8:43 am UTC

Last updated: May 23, 2012 - 10:13 am UTC

Version: 9.2.0

Viewed 1000+ times

You Asked

1. Perl and Oracle.
I liked your statement:
<quote author="Tom Kyte">
I firmly believe the best java programs are those that have ZERO
"selects/inserts/updates/deletes" in them. Hence, using ref cursors is the way
to go. Lets you tune without bothering those java programmers.
</quote>
And I want to do alike...
There is no problem as far as Java is concerned either pure JDBC (at least in JDK 1.4) or JDBC with some Oracle specific stuff in the code. I'd like to follow that approach as well while programming in Perl. Thus I want to be able to do the following:
a) pass in/out an array of values (bulk store/fetch/update)
b) pass in/out object types (also with an array of such)

But the Perl DBI does not have any methods to do so. Do you know if this is at all possible even at the cost of using Perl-Oracle DBD directly? If so could you give an example or a link to a such?

2. Languages' API and performance.

The query:
select * from table_with_million_rows where rownum<=100

lives as straight select and also in a stored procedure returning refcursor. My client programs are written in Java (using both thin and OCI driver), Perl (only OCI is available) and PL/SQL. This query is (deliberately) softparsed and executed 100 times and all 100 rows are fetched and immediately discarded (I time only the SQL stuff). In both Perl DBI and Java JDBC client software the multiple row fetch is set to 10 rows and the network sniffer indeed shows that there were 10 client-server round-trips.

Each row is on average 100 bytes and at the time of tests I made sure to be the only user logged on DB.

Average timings on my system are:
-----------------------------------------------------------------------------------------
language driver straight query stored procedure returning cursor [msec]
-----------------------------------------------------------------------------------------
Java 1.3 thin Oracle9i 17.1 21.3
Java 1.3 OCI Oracle8i 14.8 17.2
Perl 5.8 OCI Oracle8i 7.7 85.4
PL/SQL internal 13.4 14.7

Client machine: AMD Athlon 1533 MHz (3060 Bogomips), 1 GB RAM
OS: Linux Debian 2.4.19
Oracle: Oracle 8i Client

Server machine: Pentium 3 400 MHz (800 Bogomips), 1 GB RAM, 9x SCSI 10 GB, 2x EIDE 30GB
OS: Linux Debian 2.4.18
Oracle: Oracle 9.2.0.0.0 Enterprise Edition

Network: 100 Mbit Ethernet
-----------------------------------------------------------------------------------------
This 85 msec in Perl results from a known performance bug in Perl-Oracle DBD and hopefully will be fixed. But anyway tests show that the straight query is always by 5-20% faster than exactly the same query hidden in stored procedure and returned as refcursor. I tried less or more complicated queries (seems like: the more complicated query in terms of parse effort and optimizer plan complexity/per fetched row number, the less the difference in performance, stored procedure call overhead is constant and tend to get neglectable when query complexity rises)

Assuming that there is this 5-20% performance hit between straight select and refcursor returned to the client would you still recommend to use stored procedures over straight queries? For testing and tuning it is great but in production it would better to use straight select, wouldn't it? Also how would you explain that Perl DBI/DBD (although its not "really pure" Perl but shared library written in "C" and scripted by Perl) running on remote machine is by 40% faster than PL/SQL running inside the DB server?

And here are the most important code excerpts:
-----------------------------------------------------------------------
JAVA

// run() methods are called from timer engine also 100 times

class Doit implements Timeable {
public void run(Object o) throws Exception {
Connection con=(Connection)o;
CallableStatement stmt=con.prepareCall("{ ? = call test.test_ref }");
stmt.registerOutParameter(1,OracleTypes.CURSOR);
stmt.execute();
ResultSet rs=(ResultSet)stmt.getObject(1);
while (rs.next());
// discard;
stmt.close();
}
}

class Doit2 implements Timeable {
public void run(Object o) throws Exception {
Connection con=(Connection)o;
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select * from table_with_million_rows where rownum<=100");
while (rs.next());
// discard;
stmt.close();
}
}

-----------------------------------------------------------------------
PERL

# These routines are called 100 times

sub doit {
my $sth=$dbh->prepare("begin ?:=test.test_ref; end;");
my $crs;
$sth->bind_param_inout(1,\$crs,0,{ora_type=>ORA_RSET});
$sth->execute();
while (my $row=$crs->fetchrow_arrayref()) {
# discard;
}
$sth->finish();
}

sub doit2 {
my $sth=$dbh->prepare("select * from table_with_million_rows where rownum<=100");
$sth->execute();
while (my $row=$sth->fetchrow_arrayref()) {
# discard;
}
$sth->finish();
}

-----------------------------------------------------------------------
PL/SQL

declare
t1 number default dbms_utils.get_time;
t2 number;
begin
for i in 1..100 loop
for x in (select * from table_with_million_rows where rownum<=100)
loop
-- discard;
null;
end loop;
end loop;
t2:=dbms_utils.get_time;
dbms_output.put_line('Time: '|| (t2-t1)*10/100 || ' msec');
end;

declare
t1 number default dbms_utility.get_time;
t2 number;
type rc is ref cursor;
cur rc;
x table_with_million_rows%rowtype;
begin
for i in 1..100 loop
cur:=test.test_ref;
loop
fetch cur into x;
exit when cur%notfound;
-- discard;
end loop;
close cur;
end loop;
t2:=dbms_utility.get_time;
dbms_output.put_line('Time: '|| (t2-t1)*10/100 || ' msec');
end;


-- packaged function returning refcursor

CREATE OR REPLACE PACKAGE test IS
type rctype is ref cursor;
FUNCTION test_ref RETURN rctype;
END test;
/
CREATE OR REPLACE PACKAGE BODY test AS

FUNCTION test_ref return rctype IS
rc rctype;
BEGIN
open rc for select * from table_with_million_rows where rownum<=100;
return rc;
END test_ref;


END test;
/

3. SQL*Loader vs. external tables
We have the CSV format using SOH (ASCII 0x01) and STX (ASCII 0x02) as field terminator and record delimiter respectively (in this example it is not necessary but we have data that may contain any printable characters including newline, tabs, spaces, form feeds, etc.). The SQL*Loader control file looks:

LOAD DATA
INFILE bds_2_pblk.csv "str X'02'"
INTO TABLE bds_2_pblk
REPLACE
FIELDS TERMINATED BY X'01'
TRAILING NULLCOLS
(BDS_ID,PBLK_ID)

And it all works fine. But when I want to use Oracle 9i's external tables:

create directory load_dir as '/var/tmp';

create table test_loader
(bds_id number, pblk_id number)
organization external
(
type oracle_loader
default directory load_dir
access parameters
( records delimited by X'02'
fields terminated by X'01'
)
location ('bds_2_pblk.csv')
)

ORA-29913: error in executing ODCIEXTTABLEOPEN callout
ORA-29400: data cartridge error
KUP-00554: error encountered while parsing access parameters
KUP-01005: syntax error: found "identifier": expecting one of: "double-quoted-string, hexprefix, newline, single-quoted-string"
KUP-01008: the bad identifier was: X
KUP-01007: at line 1 column 22
ORA-06512: at "SYS.ORACLE_LOADER", line 14
ORA-06512: at line 1

I tried (almost) everything and it just doesn't work! I get syntax error either already at "create table..." or yet another at the "select * from test_loader" when I enclose X in double quotes moreover files like TEST_LOADER_XXXX.bad/TEST_LOADER_XXXX.log are created and the error says:

ORA-29913: error in executing ODCIEXTTABLEFETCH callout
ORA-30653: reject limit reached
ORA-06512: at "SYS.ORACLE_LOADER", line 14
ORA-06512: at line 1

I reckon the problem is 99.99% trivial and reduces itself to the magic word HEXPREFIX in error KUP-01005. Am I right? So what is the syntax of hexprefix in external table statement? I thought SQLLDR and external tables are technically the same thing. But are they really? Internally maybe but at least syntactically they are not.
Sure I could use the hint from your book (multiple character separators e.g. '||\n') but in first place we would like to use the existing format. And I searched through the Internet and found nothing. You seem to be my last hope :-) A derivative question: How can I incorporate control characters in PL/SQL string literals? Maybe I'm blind but there is no way to do this according to the PL/SQL manuals! Well chr(n) and concatenation would do the trick but I want that in literal strings.

4. When archive logs get full.
What happens when the database is running in archive mode and the disk(s) where archive logs are stored gets full? With online logs they simply get reused in a circular fashion. Will they (archive logs) be overwritten in a circular fashion as well. If not what does the Oracle do about that? Do archived logs go to a 'bit-bucket'?


and Tom said...

wow, lots of text here. lets see what I can say...

first -- sorry so long, but that's what happens with large multi-part q's. I had everything but the external table, filed it away (and subsequently *forgot* about it) -- then found it again and researched it.....

1) I know how to do ref cursors (see
</code> http://asktom.oracle.com/~tkyte/ResultSets/index.html <code>
) there is an example there. Beyond that, I've never ever used perl and hence do not have lots (like no) examples....

2) It is not all about raw performance. i would prefer to pay for a 5-10% faster CPU then lose the capability of tuning (once that code gets out of the database -- into the hands of the java guys who think "this database thing isn't worth thinking about" the chances of EVER fixing it are

a) slim
b) or none

I would use ref cursors, yes. Hopefully, those timings are in thousands of seconds -- else you have a fundemental problem. If they are seconds, then 17 seconds to return 100 rows? that should be INSTANTANEOUS.


3)

ops$tkyte@ORA920.US.ORACLE.COM> !cat test.c
void main()
{
printf( "123%c456%c789%c123%c", 0x01, 0x02, 0x01, 0x02 );
}

used that to generate the data


ops$tkyte@ORA920.US.ORACLE.COM> create or replace directory load_dir as '/tmp'
2 /
Directory created.

ops$tkyte@ORA920.US.ORACLE.COM> drop table test_loader;
Table dropped.

ops$tkyte@ORA920.US.ORACLE.COM> create table test_loader
2 ( bds_id number, pblk_id number )
3 organization external
4 (
5 type oracle_loader
6 default directory load_dir
7 access parameters
8 (
9 records delimited by 0x'02'
10 fields terminated by 0x'01'
11 )
12 location ( 'bds_2_pblk.csv' )
13 )
14 /

Table created.

ops$tkyte@ORA920.US.ORACLE.COM>
ops$tkyte@ORA920.US.ORACLE.COM> select * from test_loader;

BDS_ID PBLK_ID
---------- ----------
123 456
789 123


4) the database stops -- we need those for recovery, overwriting them would make it IMPOSSIBLE for us to recover from backups hence the only sensible thing to do is stop. you have to put them elsewhere then we go again

Rating

  (23 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Very good

Piotr Jarmuz, September 26, 2002 - 4:28 am UTC

Thanx! Especially for external tables tip.

It was timed in miliseconds and it was INSTANTANEOUS :-).

I agree. The benefits from shifting tuning efforts from developer's shoulders to some Oracle savvy seem to compensate for this 5-10% overhead at least in OLTP applications.

If you never used Perl you perhaps should have a try.
I'm sure you'd love it ;-).

To me Perl, Oracle and Apache are just made one for another.

It would be nice if next Oracle version (10i ???) could have Perl Virtual Machine embedded in it. The Oracle-Perl world out there would most appreciate it.


Tom Kyte
September 26, 2002 - 7:59 am UTC

I've looked at perl.

To me, If I cannot read a language without digging through a ton of manuals, I don't want to touch it ;)

I'll stick with

sql
plsql
java
c
(and sed,awk,grep of course...)

A reader, September 26, 2002 - 10:34 am UTC

Piotr Jarmuz:

Could you please explain / point us to some websites that has more info, on "Pearl virtual machine" - never heard of it before.

PVM

Piotr Jarmuz, September 27, 2002 - 5:38 am UTC

You can read about PVM here:

</code> http://www.ebb.org/bkuhn/writings/technical/thesis/node25.html http://www.perldoc.com/perl5.6/pod/perlfaq1.html http://www.netthink.co.uk/downloads/internals/index.html http://opensource.devx.com/articles/PerlFAQ/PerlFAQ-1.shtml <code>

It also explains the difference between the JVM and PVM, efficiency, internal representation of data, etc.

Regards

A reader, September 27, 2002 - 9:56 am UTC

Thank you verymuch.

Delimited By more than one character

Sri, April 03, 2003 - 3:06 pm UTC

Dear Tom,

I want to use more than one character as my "delimited by". Say, I want to use a @ and a NewLine as delimiter. I tried giving
records delimited by 0x'400a'
where 40 is the hex for @ and 0a is the one for Newline. I have the .dat file as follows -

1|John|Marketing@
2|Blake|Logistics@
3|Smith|Personnel And
Human Resources@
4|Harry|Finance@

and the external table definition is as follows: -
CREATE TABLE Emp_Ext
(Emp_No Number(3),
EName Varchar2(50),
Dept Varchar2(100)
)
ORGANIZATION EXTERNAL
( TYPE ORACLE_LOADER
DEFAULT DIRECTORY MyData_Dir
ACCESS PARAMETERS
( RECORDS DELIMITED BY 0x'400a'
FIELDS TERMINATED BY '|'
MISSING FIELD VALUES ARE NULL )
LOCATION ('Emp.dat')
)
/

The select * from Emp_Ext is returning only one row. Please help me in solving this. Thank you.


Tom Kyte
April 03, 2003 - 3:26 pm UTC

ops$tkyte@ORA920> !cat /tmp/Emp.dat
1|John|Marketing@
2|Blake|Logistics@
3|Smith|Personnel And
Human Resources@
4|Harry|Finance@

ops$tkyte@ORA920>
ops$tkyte@ORA920> create or replace directory mydata_dir as '/tmp'
  2  /

Directory created.

ops$tkyte@ORA920>
ops$tkyte@ORA920> CREATE TABLE Emp_Ext
  2  (Emp_No    Number(3),
  3   EName     Varchar2(50),
  4   Dept      Varchar2(100)
  5  )
  6  ORGANIZATION EXTERNAL
  7  ( TYPE ORACLE_LOADER
  8    DEFAULT DIRECTORY MyData_Dir
  9    ACCESS PARAMETERS
 10    ( RECORDS DELIMITED BY 0x'400a'
 11      FIELDS TERMINATED BY '|'
 12      MISSING FIELD VALUES ARE NULL )
 13    LOCATION ('Emp.dat')
 14  )
 15  /

Table created.

ops$tkyte@ORA920> column ename format a20
ops$tkyte@ORA920> column dept format a30
ops$tkyte@ORA920> select * from emp_ext;

    EMP_NO ENAME                DEPT
---------- -------------------- ------------------------------
         1 John                 Marketing
         2 Blake                Logistics
         3 Smith                Personnel And
                                Human Resources

         4 Harry                Finance

works for me...

tried it in:

9012
9201
9203

you might have your data in the wrong directory or something -- in anycase, review the logs that go with external tables. 

Still not working...

Sri, April 03, 2003 - 4:11 pm UTC

Dear Tom,

Thank you for your quick response.

But when I ran the same query, I am getting the following result: -

EMP_NO ENAME DEPT
---------- -------------------- ------------------------------
1 John Marketing@

2

My Emp.Log file is as follows: -

LOG file opened at 04/03/03 16:00:42

Field Definitions for table EMP_EXT
Record format DELIMITED, delimited by 400a
Data in file has same endianness as the platform

Fields in Data Source:

EMP_NO CHAR (255)
Terminated by "|"
Trim whitespace same as SQL Loader
ENAME CHAR (255)
Terminated by "|"
Trim whitespace same as SQL Loader
DEPT CHAR (255)
Terminated by "|"
Trim whitespace same as SQL Loader

Really can't understand why it is not working for me. I am using Oracle 9i (9.0.1.1.1). Is there any knows issues for external tables for this particular version Tom?

By the way, I was wondering why that 1 line space is there in between 3rd and 4th record in your output.

Thank you.


Tom Kyte
April 03, 2003 - 9:12 pm UTC

just due to sqlplus formatting -- the data is OK:

ops$tkyte@ORA9I> column ename format a20
ops$tkyte@ORA9I> column dept format a30
ops$tkyte@ORA9I> select '"' || emp_no || '"'empno, '"' || ename || '"'ename, '"' || dept || '"'dept from emp_ext
  2  /

EMPNO                  ENAME                DEPT
---------------------- -------------------- ------------------------------
"1"                    "John"               "Marketing"
"2"                    "Blake"              "Logistics"
"3"                    "Smith"              "Personnel And
                                            Human Resources"

"4"                    "Harry"              "Finance"



I used 9.0.1.2 -- I don't have 9.0.1.1 -- don't know of anything as specific as this being a problem.
 

A reader, April 03, 2003 - 5:22 pm UTC

could you please explain why you "firmly believe the best java programs are those that have ZERO "selects/inserts/updates/deletes" in them."?

Tom Kyte
April 03, 2003 - 9:17 pm UTC

because PLSQL should have it all....

because then I can fix it without having to dig into the java code.

because then we can tune it.

because then we can figure out what uses what.

because then we can have people who understand databases do the database stuff.

because we can make them use bind variables for the sql (just have to force them to use binds for the stored procedure calls)


and so on...

PERL is nice , but ...

pasko, April 04, 2003 - 2:28 am UTC

Hi Tom and Piotr...

Thanks for a great thread above...

I am also using PERL sometimes to interface Oracle with some Web GUI clients and i have to always use REF cursors as we can not pass PL/SQL Tables..

Perl is also very good for Pattern matching stuff...

I have also observed that although all Package 'IN' parameters should be seen as BIND Variables in v$sql view ,
that's not the case when using PERL ...

I was surprized the other Day when i looked at this view and saw no BIND values ( :b1 , :b2 etc.. ) at all from all pERL WEB client programs...


i see :

BEGIN :curResult :=
my_package.ret_ref_cur_function('real value1' ,
'real value 2' ); END;

instead of :

BEGIN :curResult := my_package.ret_ref_cur_function( :my_bind1 , :my_bind2 ); END;


I know it's messing up our shared pool...

Has anyone any idea how come perl does not use BIND variables even when using stored subprograms in a Package ?


Thanks in advance.






Nothing wrong with Perl bind variables!

Piotr Jarmuz, April 14, 2003 - 11:30 am UTC

Hello,

I checked at my site and it all works great:
For example I look at library cache:

select sql_text from v$sql where upper(sql_text) like '%JOEYS%'

And I see in one of the rows something like this:

begin joeys.touch_message(:p1,:p2); end;

It DOES use bind variables. And the Perl code for this call is as follows:

$query="begin joeys.touch_message(?,?); end;";
eval {
$sth=$dbh_proddb->prepare_cached($query);
$sth->bind_param(1,$usr_id);
$sth->bind_param(2,$msg_id);
$sth->execute();
$sth->finish();
$dbh_proddb->commit();
}; if $@ {
$dbh_proddb->rollback();
handle_error();
...
}

Note:

It uses client side caching so I only do at most one hard parse and some soft parses in all the Apache processes next requests use cached handle so no parse at all.
More exactly if there are N Apache children and each does M requests on average, this aproach gives:
i) 1 hard parse
ii) N-1 soft parses
iii)(M-1)*N no parse at all!


Not bad as for a "stateless" environment ;)

Beside look like I don't use autocommit "feature" and control commits and rollbacks explicitly

As for the versions, we use:
1. Oracle 9iR2 EE client and server
2. Oracle DBD 1.06
3. Perl DBI 1.34

The only problematic issue I know about Perl Oracle DBD is that it is slow when working with ref cursors returned from stored procedures due to not prefetching on such refcursors. Might be fixed in the latest release. I got a newsletter recently about that but I did not have much time to explore it yet...

Best regards


Perl Vs. Java

A reader, August 20, 2003 - 2:01 pm UTC

Hi Tom,
Now that there is Java in the database
would you suggest to still continue be using perl.

:) Thank you

Tom Kyte
August 21, 2003 - 5:05 pm UTC

if you got perl

if you know perl

if you like perl

if perl is satisfying your needs


seems like you should be using perl (i wouldn't, i don't have it, know it, like it)...

but the same could be said of java
or vb
or C
or even plsql

Thanks :)

A reader, August 21, 2003 - 6:54 pm UTC


Perl vs. Java

Piotr Jarmuz, September 06, 2003 - 11:44 pm UTC

Paraphrasing W. Churchil words:

There are too many companies with too many programers that have invested too much money in such a CRAPPY implementation! While Perl is Open Source...

But hey! Linux is too!

Java as language is coherent, complete but the implementation... it sucks! Oracle's Autora is little different but still...

I think it sucks...

Think of Perl as SCRIPTED "C"... It's no more no less but a scripted C.

I might even set out to rewrite the JVM... soon...

BTW...
My Perl-Oracle integration is done...

Your book EO1O1 page: 1044 made me sure: there IS 1:1
UGA to extproc agent...

Regards.


Tom Kyte
September 07, 2003 - 6:05 pm UTC

(you probably don't want to know how much i shudder when I see perl code, i like java better then perl)....

so, it seems to be a matter of preference...

Arrange a meeting...

Piotr Jarmuz, September 07, 2003 - 12:22 am UTC

Oracle vs. Perl
Larry vs. Larry

Larry Ellison - Larry Wall ;)

Regards.

GRID IS COMMING...

awk like function using PL/SQL

A reader, March 16, 2005 - 7:50 am UTC

Hi

I have this function which acts like AWK print $1, $2 etc

CREATE OR REPLACE FUNCTION AWK(P_STRING VARCHAR2, P_POSITION NUMBER, P_DELIMIT VARCHAR2)
RETURN VARCHAR2
AS
type array is table of VARCHAR2(1000);
l_array array := array();
l_string VARCHAR2(1000) := p_string;
l_pos NUMBER;
l_count NUMBER;
BEGIN
LOOP
EXIT WHEN l_string is null;
l_pos := instr(l_string, p_delimit);
l_array.extend;
l_array(l_array.count) := trim(substr(l_string, 1, l_pos - 1));
l_string := substr(l_string, l_pos + 1);
END LOOP;
l_string := l_array(p_position);
RETURN l_string;
END AWK;
/

it works happily when I pass

AWK('1#2#3#', 2, '#')

however it goes to infinite loop if I pass

AWK('1#2#3', 2, '#')

Is there a away to overcome this?

Tom Kyte
March 16, 2005 - 8:36 am UTC

when parsing a delimited string, I typically process:


l_string long := p_string || p_delimit;

to ensure there is always a "last" delimiter. else you have to make the logic to find the next l_pos to be

l_pos := instr(l_string,p_delimit);
if ( nvl(l_pos,0) = 0 ) then l_pos := length(l_string)+1; end if;



I did it

A reader, March 16, 2005 - 9:23 am UTC

I modify and added an IF it works now cheers

CREATE OR REPLACE FUNCTION AWK(P_STRING VARCHAR2, P_POSITION NUMBER, P_DELIMIT VARCHAR2)
RETURN VARCHAR2
AS
type array is table of VARCHAR2(1000);
l_array array := array();
l_string VARCHAR2(1000) := p_string;
l_pos NUMBER;
l_count NUMBER;
BEGIN
LOOP
EXIT WHEN l_string is null;
l_pos := instr(l_string, p_delimit);
l_array.extend;
IF ( l_pos > 0 )
THEN
l_array(l_array.count) := trim(substr(l_string, 1, l_pos - 1));
l_string := substr(l_string, l_pos + 1);
ELSE
l_array(l_array.count) := trim(substr(l_string, 1));
l_string := NULL;
END IF;
END LOOP;
l_string := l_array(p_position);
RETURN l_string;
EXCEPTION
WHEN SUBSCRIPT_BEYOND_COUNT
THEN
RAISE_APPLICATION_ERROR(-20001, 'There arent ' || p_position || ' fields');
END AWK;
/


use l_string long := p_string || p_delimit; may be a bug?

A reader, March 17, 2005 - 12:09 pm UTC

Hi

if we use

l_string long := p_string || p_delimit;

then when we loop we will have a extra loop therefore an extra element which may be a bug correct?

External table

Srinath N, May 13, 2005 - 8:39 am UTC

i have created external file table and copied the data file in the server. while select the following error displays.

SQL> select * from emp_ext t;

select * from emp_ext t

ORA-29913: error in executing ODCIEXTTABLEOPEN callout
ORA-29400: data cartridge error
KUP-00554: error encountered while parsing access parameters
KUP-01005: syntax error: found "minussign": expecting one of: "enclosed, exit, (, ltrim, lrtrim, ldrtrim, missing, notrim, optionally, rtrim, reject"
KUP-01007: at line 3 column 1
ORA-06512: at "SYS.ORACLE_LOADER", line 14
ORA-06512: at line 1

pls clarify this 

Tom Kyte
May 13, 2005 - 10:35 am UTC

your create table has a syntax error in the external table part.

awk like function

Adrian, May 26, 2005 - 2:30 pm UTC

Unless you're trying to exercise your PL/SQL table skills, there's no reason to use them for strings. Here's another version:

FUNCTION awk( p_string varchar2, p_position number, p_delimit varchar2 ) RETURN VARCHAR2 AS
l_string varchar2(1000);
l_count integer;
l_left integer;
l_right integer;
e_range exception;
BEGIN
-- find out how many items are in the list
l_count := length(p_string) - length(replace(p_string,p_delimit)) + 1;
-- validate position
if p_position < 1
or p_position > l_count then
raise e_range;
end if;
-- extract the item at the specified position
if p_position = 1 then
-- first item
l_right := instr( p_string, p_delimit );
l_string := substr( p_string, 1, l_right - 1 );
--
elsif p_position = l_count then
-- last item
l_left := instr( p_string, p_delimit, -1 );
l_string := substr( p_string, l_left + 1 );
--
else
-- somewhere in between
l_left := instr( p_string, p_delimit, 1, (p_position - 1) );
l_right := instr( p_string, p_delimit, l_left + 1 );
l_string := substr( p_string, l_left + 1, l_right - l_left - 1 );
end if;
--
RETURN l_string;
--
EXCEPTION WHEN e_range THEN
RAISE_APPLICATION_ERROR(-20001, 'Position '||p_position||' is out of range [1..'||l_count||']');
END AWK;


OK

Rajesh, June 20, 2007 - 7:53 am UTC

Hi Tom,
I tried using awk for setting a field separator which exists as "," to ":".
But this is not working.
Please let me know how to make this work.


Test$ : cat > a.txt
10,20,30,40
50,60,70,80
^Z[1] + Stopped (SIGTSTP) cat > a.txt

Test$ :

Test$ : cat a.txt
10,20,30,40
50,60,70,80

Test$ : awk ' BEGIN { FS = ":" } ; { print $0 } ' a.txt > aa.txt

Test$ : cat aa.txt
10,20,30,40
50,60,70,80

Test$ : awk ' BEGIN { FS == ":" } ; { print $0 } ' a.txt > aa.txt
Test$ : cat aa.txt
10,20,30,40
50,60,70,80

Test$ : awk ' BEGIN { FS == ":" } END { print $0 } ' a.txt > aa.txt

Test$ : cat aa.txt

Test$ :

A reader, December 26, 2008 - 4:12 am UTC

Hi Tom

I have a perl script which does the following

It first counts the rows of a table(say realtor this one has over million records) and dumps that
value into another table (say abc)
Then it starts doing an insert into a table(say test)(direct insert from this table realtor)

Can you please suggest me a way how I can do these things simultaneously ? that is while the
insertion is going on I want the counting to happen too using perl?

Any help will be greatly Appreciated

Thanks
Tom Kyte
December 29, 2008 - 3:31 pm UTC

sigh

look at the other place you asked this same exact question.

perl

A reader, December 29, 2008 - 11:20 pm UTC


Don't post samething twice or more

Parthiban Nagarajan, December 30, 2008 - 7:22 am UTC

Hello, "A reader from India"

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1474804744643#1383621800346529759
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:5448988086977#1386987500346643088

If your question is not answered, then it will not be answered anywhere else; Don't repeat the questions here and there; Keep patience...; Tom is not here to answer all questions; Tom is not here to answer as soon as you post it, at least; Tom may have some other work; Don't make his database bigger and bigger ;)

Phrasebook Design Pattern or SQL::Library

Parthiban Nagarajan, May 23, 2012 - 6:06 am UTC

Hi Tom

How much would you favor
(1) the Phrasebook Design Pattern - http://www.perl.com/pub/2002/10/22/phrasebook.html
(2) SQL::Library - http://search.cpan.org/~dgorley/SQL-Library-0.0.3/lib/SQL/Library.pm

Both are more or less similar in a way that they store the SQL statements in a separate file.
But, I know that you would still recommend to use only the REF cursors.
So, can we use (either of) them not for storing SQL but PL/SQL?

Please advise on the pros and cons.

Thanks and regards
Tom Kyte
May 23, 2012 - 10:13 am UTC

well the introduction for phrasebook sounded like an advertisement for stored procedures:

Why is this "a problem"? It looks like nice code, doesn't it? Actually, if you look at the code above, you will see two languages: Perl and SQL. This makes the code not that readable. Besides, SQL statements that are only slightly different may appear in several places, and this will make it more difficult to maintain. In addition, suppose you have an SQL expert who should optimize your SQL calls. How do you let him work on the SQL; should he look through your Perl code for it? And what if that guy is so ignorant that he doesn't even know Perl?

I'm sorry, but that concept (phrasebook) underwhelmed me.



sql-library even more so. I felt like I was transported back to 1990 and I was writing windows 3.0 code again (.ini files?)


If you wanted to satisfy the goal set up by phrasebook, it seems like you really really really want stored procedures.

you get the separation they desire.

you get the ability to have different people work on sql versus <whatever 3gl you want>

you get the benefit of the security aspects of stored procedures (programs do not need select/insert/update/delete access - just execute on a transaction)

you get the benefit of the dependency mechanism. "hey - what processes use this table over here" - a simple query answers that.

you get the benefit of reduced parsing (stored procedures cache open statements in a wonderful way!)

you get the benefit of knowing your SQL uses binds correctly (although you have to make sure the developers still bind to the stored procedure call!)

and so on.



and I wouldn't see the need to use either to store plsql calls. to me:

$statement = $sql->get("RUN_MY_PROCEDURE",
                        { description => "administrator of manuals",
                          id => 77 });



isn't really different from

$sth = $dbh->prepare($statement) ; 
bind/bind/bind
$rc=$sth->execute();


and I'm sure you could write a routine that would do the prepare/bind/bind for you in a single call if you wanted.

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library