A package, called dsql, is defined which contains two procedures:
The result output parameter is a PL/SQL table of strings.
The individual columns in a row of the result of the query
are concatenated into a long string with the bar character
| between two values.
-- p20.sql
CREATE OR REPLACE PACKAGE dsql AS
TYPE dd_rec_type IS RECORD (
table_name varchar2(30),
column_name varchar2(30),
data_type varchar2(9));
TYPE dd_table_type IS TABLE OF dd_rec_type
INDEX BY BINARY_INTEGER;
TYPE string1024_table IS TABLE OF varchar2(1024)
INDEX BY BINARY_INTEGER;
TYPE string9_table IS TABLE OF varchar2(9)
INDEX BY BINARY_INTEGER;
TYPE number_table IS TABLE OF number
INDEX BY BINARY_INTEGER;
PROCEDURE get_columns(startch IN char,
dd_table OUT dd_table_type,
n OUT number);
procedure get_query_results(query_string IN varchar2,
ncols IN number,
column_types IN string9_table,
result OUT string1024_table,
nrows OUT number);
END dsql;
/
show errors
CREATE OR REPLACE PACKAGE BODY dsql AS
PROCEDURE get_columns(startch in char,
dd_table OUT dd_table_type,
n OUT number) AS
handle Integer;
dbms_return Integer;
tablename varchar(30);
colname varchar(30);
datatype varchar(9);
counter integer := 0;
begin
handle := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(handle,
'select distinct table_name,column_name,data_type ' ||
'from user_tab_columns ' ||
'where table_name like ''' ||
startch ||
'%''' ||
'order by table_name,column_name', DBMS_SQL.V7);
DBMS_SQL.DEFINE_COLUMN(handle, 1, tablename, 30);
DBMS_SQL.DEFINE_COLUMN(handle, 2, colname, 30);
DBMS_SQL.DEFINE_COLUMN(handle, 3, datatype, 9);
dbms_return := DBMS_SQL.EXECUTE(handle);
counter := 0;
loop
if DBMS_SQL.FETCH_ROWS(handle) = 0 then
exit;
else
DBMS_SQL.COLUMN_VALUE(handle, 1, tablename);
DBMS_SQL.COLUMN_VALUE(handle, 2, colname);
DBMS_SQL.COLUMN_VALUE(handle, 3, datatype);
counter := counter + 1;
dd_table(counter).table_name := tablename;
dd_table(counter).column_name := colname;
dd_table(counter).data_type := datatype;
end if;
end loop;
n := counter;
DBMS_SQL.CLOSE_CURSOR(handle);
EXCEPTION
WHEN OTHERS THEN
DBMS_SQL.CLOSE_CURSOR(handle);
n := -1;
END get_columns;
procedure get_query_results(query_string IN varchar2,
ncols IN number,
column_types IN string9_table,
result OUT string1024_table,
nrows OUT number) AS
y1 string1024_table;
y2 number_table;
counter Integer;
i Integer;
handle Integer;
dbms_return Integer;
temp string1024_table;
BEGIN
for i in 1 .. ncols loop
y1(i) := '';
y2(i) := 0;
end loop;
counter := 0;
handle := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(handle,query_string,DBMS_SQL.V7);
for i in 1 .. ncols loop
if ((column_types(i) = 'VARCHAR2') or
(column_types(i) = 'CHAR')) then
DBMS_SQL.DEFINE_COLUMN(handle, i, y1(i) , 300);
else
DBMS_SQL.DEFINE_COLUMN(handle, i, y2(i));
end if;
end loop;
dbms_return := DBMS_SQL.EXECUTE(handle);
loop
if DBMS_SQL.FETCH_ROWS(handle) = 0 then
exit;
else
for i in 1 .. ncols loop
if ((column_types(i) = 'VARCHAR2') or
(column_types(i) = 'CHAR')) then
DBMS_SQL.COLUMN_VALUE(handle, i, y1(i));
else
DBMS_SQL.COLUMN_VALUE(handle, i, y2(i));
end if;
end loop;
counter := counter + 1;
temp(counter) := '';
for i in 1 .. ncols loop
if ((column_types(i) = 'VARCHAR2') or
(column_types(i) = 'CHAR')) then
temp(counter) := temp(counter) ||
rtrim(y1(i)) || '|';
else
temp(counter) := temp(counter) ||
rtrim(y2(i)) || '|';
end if;
end loop;
end if;
end loop;
nrows := counter;
result := temp;
DBMS_SQL.CLOSE_CURSOR(handle);
EXCEPTION
WHEN OTHERS THEN
DBMS_SQL.CLOSE_CURSOR(handle);
nrows := -1;
END get_query_results;
end dsql;
/
show errors
The following package, called dsql_driver contains two procedures to drive the two procedures in the dsql package.
-- p21.sql
CREATE OR REPLACE PACKAGE dsql_driver AS
procedure drive_get_columns(startch IN char);
procedure drive_get_query_results(
query_string IN varchar2,
ncols IN number,
column_types IN dsql.string9_table);
END dsql_driver;
/
CREATE OR REPLACE PACKAGE BODY dsql_driver AS
procedure drive_get_columns(startch IN char) AS
dd_table dsql.dd_table_type;
i binary_integer;
n number;
prev varchar2(30);
newentry boolean;
BEGIN
dsql.get_columns(startch,dd_table,n);
dbms_output.put_line('N = ' || n);
dbms_output.put_line('Tables Starting with ' ||
startch);
dbms_output.put_line('------------------------');
prev := '';
newentry := false;
for i in 1 .. dd_table.count loop
if (i = 1) then
dbms_output.put(dd_table(i).table_name || '(');
prev := dd_table(i).table_name;
elsif (prev != dd_table(i).table_name) then
dbms_output.put_line(');');
dbms_output.put(dd_table(i).table_name || '(');
prev := dd_table(i).table_name;
newentry := false;
end if;
if (newentry) then
dbms_output.put(', ');
end if;
newentry := true;
dbms_output.put(dd_table(i).column_name || ':');
dbms_output.put(dd_table(i).data_type);
end loop;
dbms_output.put_line(');');
END;
procedure drive_get_query_results
(query_string IN varchar2,
ncols IN number,
column_types IN dsql.string9_table) AS
result dsql.string1024_table;
nrows number;
i binary_integer;
BEGIN
dsql.get_query_results(query_string,ncols,column_types,
result,nrows);
for i in 1 .. nrows loop
dbms_output.put_line(result(i));
end loop;
END;
END dsql_driver;
/
show errors
The following anonymous PL/SQL block calls the driver procedure for the get_query_results procedure.
-- p22.sql
DECLARE
query_string varchar2(256);
ncols number;
column_types dsql.string9_table;
BEGIN
query_string := 'select cno,cname,city ' ||
'from customers,zipcodes ' ||
'where customers.zip = zipcodes.zip';
ncols := 3;
column_types(1) := 'NUMBER';
column_types(2) := 'VARCHAR2';
column_types(3) := 'VARCHAR2';
dsql_driver.drive_get_query_results(query_string,
ncols,
column_types);
END;
/
The following is a sample SQL*PLUS session to illustrate the above example.
SQL> execute display_table('customers');
1111 Charles 123 Main St. 67226 316-636-5555
2222 Bertram 237 Ash Avenue 67226 316-689-5555
3333 Barbara 111 Inwood St. 60606 316-111-1234
PL/SQL procedure successfully completed.
SQL> execute display_table('abcd');
NOT A VALID TABLE NAME
PL/SQL procedure successfully completed.
SQL> start p22
1111|Charles|Wichita|
2222|Bertram|Wichita|
3333|Barbara|Fort Dodge|
PL/SQL procedure successfully completed.
SQL>