Skip to Main Content
  • Questions
  • Flexible Parameter Passing in mod_plsql

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, mo.

Asked: November 16, 2002 - 1:35 pm UTC

Last updated: November 21, 2008 - 2:58 pm UTC

Version: 8.1.7

Viewed 1000+ times

You Asked

Tom:

Thanks a lot about pointing me this neat web feature:

1. Is this what you use always in asktom site?

2. I was trying to see more examples of this but the above link you refer to
</code> http://www.olab.com/doc/books/plsql/pl_invk.htm <code>
does not seem to work?

3. Let us say I have the following html form and after user fills it out I want
to post values to a save procedure:

htp.formtext(p_lastname,30,30,null);
htp.formtext(p_firstname,30,30,null);
htp.formtext(p_city,30,30,null);
htp.formtext(p_state,10,10,null);
htp.formtext(p_zip,5,5,null);
FOR x in (1..5) LOOP
htp.formtext(p_itemno,2,2,null);
htp.formtext(p_description,30,30,null);
htp.formtext(p_qty,5,5,null);
htp.formtext(p_unit_price,5,5,null);
END LOOP;

---------*this is how I used to do it.

create or replace procedure save_form (
p_lastname VARCHAR2 DEFAULT NULL,
p_firstname VARCHAR2 DEFAULT NULL,
p_city VARCHAR2 DEFAULT NULL,
p_state VARCHAR2 DEFAULT NULL,
p_zip VARCHAR2 DEFAULT NULL,
p_itemno TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,
p_description TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,
p_qty TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,
p_unit_price TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,)

as

v_personid number(5);

begin
select person_id into v_personid from dual;

insert into person (personid,lastname,
firstname,state,zip )
values
(v_personid,p_lastname,p_firstname,
p_city,p_state,p_zip);
If (SQL%ROWCOUNT > 0) THEN
FOR i in 1..p_description.count
LOOP
insert into items (personid,itemno,description,
qty,unit_price)
values
(v_personid,p_itemno(i),
p_description(i),p_qty(i),
p_unit_price(i) );
END LOOP;
ELSE
rollback;
END IF;

END;
-----Now to use flexible parameters is this how you do it?

create or replace procedure save_form (
name_array TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,
values_array TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY)

as

v_personid number(5);

begin
select person_id into v_personid from dual;

insert into person (personid,lastname,
firstname,city,state,zip )
values
(v_personid,
value_array(1),value_array(2),
value_array(3),value_array(4),
value_array(5) );
If (SQL%ROWCOUNT > 0) THEN
FOR i in 1..name_array.count
LOOP
If (name_array(i)='p_description') THEN
insert into items (personid,itemno,description,
qty,unit_price)
values
(v_personid,value_array(i),
value_array(i+1),value_array(i+2),
value_array(i+3) );
END LOOP;
ELSE
rollback;
END IF;

END;

4. Would not using flexible parameters make code much easier to maintain. If you change forms by adding or deleteing text fields you do not have to worry about adding/deleteing the parameters in the save/update procedure?

5. when would you use a four parameter interface instead of two?

Thank you,




and Tom said...

1) nope, i like formal named parameters. I like things clear, explicit. I type fast -- I don't mind having real argument lists that help me validate my inputs and outputs. generic code is fine, generic code breaks lots. Less chance for error if you are explicit.

2) </code> http://docs.oracle.com/cd/A97329_03/web.902/a90855/feature.htm#1005765 <code>

is the only source I'm aware of. OLAB was the name of the app server groups webserver a couple of years ago -- long time ago.

3) sort of -- you'll need checks to see how many rows are actually in your form so you don't end up inserting lots of empty rows into items -- your current logic doesn't look right but thats a programmer bug -- you can fix that up.

4) i seriously 100% doubt it -- sincerely.

I would hate to inherit a zillion lines of spagehtti code that indirectly referenced everything through arrays like that.

You tell me -- which is really clear to you as to what it expects as input:

create or replace procedure save_form (
p_lastname VARCHAR2 DEFAULT NULL,
p_firstname VARCHAR2 DEFAULT NULL,
p_city VARCHAR2 DEFAULT NULL,
p_state VARCHAR2 DEFAULT NULL,
p_zip VARCHAR2 DEFAULT NULL,
p_itemno TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,
p_description TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,
p_qty TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,
p_unit_price TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,)

create or replace procedure save_form (
name_array TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,
values_array TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY


I would find maintaining version 1 about a million times easier I believe then version 2.


Your logic of "If
you change forms by adding or deleteing text fields you do not have to worry
about adding/deleteing the parameters in the save/update procedure?" is fundementally flawed.

Tell me -- if you add something (a new field) to your FORM and you do not modify you save_form routine -- whats going to happen???? (bug). You have to edit the code anyway to add the logic to deal with this new field (ESPECIALLY IF THIS FIELD is added to the middle of the form, sort of shifts all of your indexes no? yes, in fact it would destroying the logic in there... hmmm.) You have to update the code when you do this anyhow -- so what pain is there in documenting for programmers in the future who would otherwise have the unenviable job of getting this "array based" code to try and figure out what it does. (i would hate it myself)

5) never -- as it says clearly:


2.5.2.2 Four parameter interface
The four parameter interface is supported for compatibility.


it is the was OAS (iAS's precursor) did it.


Rating

  (16 ratings)

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

Comments

flexible parameter

mo, November 16, 2002 - 3:45 pm UTC

Excellent answer. BTW I enjoy reading your book. It is like reading a story.

1. The only thing i am not sure of is how you retrieve values for the passed parameters. DO yu always refer to the named part of the array to get the value or you you use a pointer like:

For this:
name_array ==> (`x', `y', `z')
values_array ==> ('john', '10', 'doe')


Is it like :

insert into table (fname,id,lname) values (x,y,z);
or
insert into table (x,y,z) values (name_array(1),name_array(2),name_array(3));

Tom Kyte
November 16, 2002 - 4:50 pm UTC

the arrays are "correlated" -- if you have the two arrays as you depict above then the name_array tells you that value_array(1) has the VALUE of the field 'X' from your form.

You need to figure out how YOU want to process that.

You should realize it clearly cannot be

insert into table (fname,id,lname) values (x,y,z);

you have no variables x, y, z -- you have an array that has values of names -- x, y, and.

It is very doubtful you want to use

insert into table (x,y,z) values (name_array(1),name_array(2),name_array(3));


as well -- you don't want to insert the strings 'x', 'y', 'z' do you???

You see -- this is why I believe named, formal parameters are better.

the code is definitely more clear
there is no ambiguity
you won't get confused about what value you are dealing with.

example why you'd use flexible

Scott Wesley, February 06, 2003 - 11:46 pm UTC

G'day Tom

Would you have an example in mind where flexible parameter passing would be the preferred method.
It seems that you'd either need to really trust the calling procedure, and/or have lot's of if statements in the called procedure to verify the names and values of each element in the array, and then decide what to do with them.
Flexible parameter passing exists, so *surely* there must be a good reason / example of where to use it?

Please don't refer to olab, because the link is unavailable.

Thanks.

Tom Kyte
February 07, 2003 - 7:58 am UTC

Nope, I've never really used it personally.

As I said I prefer formal, named parameters. Peoples fondness for this stems from not wanting to type in formal named parameter lists. Some people are just more comfortable with it because they language they were using only supported this "cgi-environment" way of doing it.

I've used it

Steve, February 07, 2003 - 8:56 am UTC

Don't like it - but I have used it in the past. I needed it where I had a web form where the number of parameters to be passed were unknown (there was a javascript routine which dynamically changed the number of inputs based on the users initial input).

Now I know you're thinking Tom about Javascript, but the web developers and client insisted it be done that way, and I have to say it did work pretty well but I wouldn't want to use flexible parameter passing as a matter of course.

multiple parameters of same name

Scott, July 07, 2003 - 4:13 am UTC

G'day

Is flexible parameter passing also used to enable you to pass multiple values for the same parameter name?

eg:
</code> http:// <hostname>/pls/DAD_name/procedure_name?x=1&x=4 <code>

I remember reading somewhere about receiving the information via an array.

Have I remembered correctly? (where could I get further info) or was I dreaming?

I'm investigating the feasibility (and how to) of submitting a multi row web form.

Tom Kyte
July 07, 2003 - 7:31 am UTC

No, you can send arrays of values without it.

the flexible parameter passing is setup so you can get all of the values as a pair of correlated arrays -- instead of formal named parameters.

You could always pass arrays -- even using formal named parameters.


<form method=post action=foo.bar>
<input type=text name=abc>
<input type=text name=abc>
<input type=text name=abc>
<input type=text name=abc>
<input type=submit>
</form>


can invoke the package:


create or replace package foo
as
type array is table of varchar2(4000) index by binary_integer;
procedure bar( l_data in array );
end;
/






How to pass % wild card ?

Fan, January 05, 2004 - 6:15 pm UTC


</code> http://127.0.0.1/poc/poc_cart/webpkg.searchbasic? <code>
in_term=%ask%&p_skip=15&p_max=15

tom,
I got a problem trying to pass in URL link like above,
'%ask%' to do wildcard search, I am not doing it right, am I ?
How do i escape it ?

Thanks

Tom Kyte
January 06, 2004 - 8:05 am UTC

You have to escape url strings (it is called URL encoding)

A % in a url would be %25 (25 being the hex ascii code for %)

A blank can be %20

and so on...

I use a function like this:

ops$tkyte@ORA920PC> create or replace function urlencode( p_str in varchar2 ) return varchar2
  2  as
  3          l_tmp   varchar2(12000);
  4          l_len   number default length(p_str);
  5          l_bad   varchar2(100) default ' >%}\~];?@&<#{|^[`/:=$+''"' || chr(10);
  6          l_char  char(1);
  7  begin
  8          if ( p_str is NULL ) then
  9                  return NULL;
 10          end if;
 11
 12          for i in 1 .. l_len loop
 13                  l_char :=  substr(p_str,i,1);
 14                  if ( instr( l_bad, l_char ) > 0 )
 15                  then
 16                          l_tmp := l_tmp || '%' || to_char(ascii(l_char), 'fm0X');
 17                  else
 18                          l_tmp := l_tmp || l_char;
 19                  end if;
 20          end loop;
 21
 22          return l_tmp;
 23  end;
 24  /
 
Function created.
 
ops$tkyte@ORA920PC> select urlencode( '%ask a question%' ) from dual;
 
URLENCODE('%ASKAQUESTION%')
-----------------------------------------------------------------------------------------------------------------------------------
%25ask%20a%20question%25


there is a function htf.escape_url, but it doesn't get all of the characters you need (like a space) 

urlencode parameter values only ?

fan, January 06, 2004 - 10:10 am UTC

Thanks Tom for the encode function..
Looks like this function is to be used ONLY on
parameters ?

Can not use on the complete mod_plsql call like :

webpkg.searchbasic?in_term=%ask%&p_skip=15&p_max=15

or the string after "?" (in_term=%ask%&p_skip=15&p_max=15)

thanks



Tom Kyte
January 06, 2004 - 10:40 am UTC

correct -- only on parameters


you only need (only CAN) to urlencode the ? if it is in the parameter, same with & and so on.

chicken and egg problem staring at you here.

In order to parse a URL, it must be encoded

If we were able to encode the above "webpkg.searchbasic?in_term=%ask%&p_skip=15&p_max=15" we'd be able to parse it as a URL.

but in order to parse it as a URL, it must be encoded (goto 1 :)

you must build the string using urlencode on each of the parameters.

stored procedure default value

a reader, June 26, 2004 - 6:04 am UTC

I have a procedure:
Process_Attn(p_year IN NUMBER,
p_month IN NUMBER,
p_calias IN VARCHAR2,
p_apflag IN VARCHAR2 DEFAULT 'GEN',
p_comp_id IN VARCHAR2 DEFAULT '%',
o_status OUT VARCHAR2)

I was getting ORA-00600 error when I was calling a this procedure from form6i.
But this procedure runs successfully when executed from sqlplus or toad.

I did a change in procedure defination and removed the default values of parameter:
Process_Attn(p_year IN NUMBER,
p_month IN NUMBER,
p_calias IN VARCHAR2,
p_apflag IN VARCHAR2,
p_comp_id IN VARCHAR2,
o_status OUT VARCHAR2)

Now, procedure is running successfully from form6i.
Can you please explain this behaviour.

Tom Kyte
June 26, 2004 - 6:59 pm UTC

ora-600 = please contact support.

Ash, August 30, 2004 - 10:37 am UTC

Sorry for my ugly english -- it's not my native language.

What I should do, if i don't know count of html-inputs on my form?

For example, if i generate checkbox for all rows in resultset and count of rows is unknown?

One more sorry for my english. Thanks.

Tom Kyte
August 30, 2004 - 10:43 am UTC

checkboxes are a pain.

I use drop downs and plsql tables. The drop down list always supplies a value, unlike checkboxes.

so, you would simply get a row back in each array slot that corresponds to a row in your display. If nothing was chosen, the array(i) entry would have NA or whatever you put into it. else array(i) would have some "value"


that is the method i use, you are free to use the above mentioned technique of "flexible" parameter passing as well.

what so bad about web checkboxes ?

robert, November 15, 2004 - 9:27 pm UTC

I don't understand the bad rap about checkboxes

Given a group of checkboxes like this:

<INPUT TYPE="checkbox" NAME="p_cstatus" VALUE="1"></TD>
<INPUT TYPE="checkbox" NAME="p_cstatus" VALUE="2"></TD>
<INPUT TYPE="checkbox" NAME="p_cstatus" VALUE="3"></TD>
<INPUT TYPE="checkbox" NAME="p_cstatus" VALUE="7"></TD>
<INPUT TYPE="checkbox" NAME="p_cstatus" VALUE="8"></TD>

If 2nd and 4th ones checked I will have array(2,7)
I just check in my pl/sql :

PROCEDURE websearch
(p_cstatus IN wwv_utl_api_types.vc_arr DEFAULT empty_vc_arr)
IS
BEGIN
IF p_cstatus.COUNT != 0 THEN
l_string := array2string(p_cstatus) ;
END IF:
.......





Tom Kyte
November 16, 2004 - 6:36 am UTC

it is a matter of preference -- I didn't say they wouldn't work, I said "i don't use them, i use a drop down list with "on" "off" values"

that is all.

parameter length

sam, September 12, 2006 - 11:47 pm UTC

Tom:

is there a limit on the parameter length in 9IAS (mod_plsql).

when i migrate an 8i procedure that has a 22 character long parameter name to 9i, it seems that 9i drops the name to 16 characters and generates an error.

Is there a database parameter that controls this in 9.2.



Tom Kyte
September 13, 2006 - 7:20 am UTC

not that I am aware of, I haven't observed this - I haven't heard of this (and it wouldn't be a database parameter).

it should permit 30 characters names, the version of the database shouldn't have anything to do with it.

parameter

A reader, September 13, 2006 - 11:56 am UTC

it seems the verison of mod_plsql has to with it. Does this thing require a TAR to clarify?

It is strange! you keep the parameter length long and submit it, it tells you that parameter is not in procedure. You look at what is being submitted and the prameter name submitted is cut at the 16 th character.

Tom Kyte
September 13, 2006 - 3:05 pm UTC

if it is truly truncating the name - yes, a tar would be called for.

parameters

A reader, April 28, 2008 - 7:22 pm UTC

Tom:

If a perl client sends this url format to an oracle stored procedure what would be the best way to save that as 5 different records separated by commas.

p_file_name IN TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,
p_file_size IN TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,
p_file_md5 IN TYPES.ARRAY DEFAULT TYPES.EMPTY_ARRAY,


Would you have issues with this kind of format and trying to parse it by commas. would not it be better to parse it in perl and vuild the URL correctly.


p_file_name=name1,name2,name3,name4,name5&p_file_size=size1,size2,size3,size4,size5&p_file_md5=md51,md52,md53,md54,md55

thanks
Tom Kyte
April 29, 2008 - 8:42 am UTC

seems like a pain, but sure, obviously you *could* do that.

but it seems like it would be more work both in the perl client as well as your code.

easy enough to write a small function "comma_list_to_array" that returns an array for you, so the plsql would not be penalized too much, just extra cpu to parse.

parameters

A reader, April 29, 2008 - 8:48 am UTC

Tom:

I assume the function would read a string and split value based on comma separator. If the string itself has a comma then there has to be some kind off escape character or something otherwise it wont work. right.

would you be using a simple substr and instr functions or regular expressions for this function.

kind of strange that if the client has ordered list, it cant create the URL string in ordered fashion or assign values to the form variables and post the form.
Tom Kyte
April 29, 2008 - 8:52 am UTC

... has to be some kind off
escape character or something otherwise it wont work. right.
...

obviously. You can start with a package a wrote a long long long time ago, delimited http://asktom.oracle.com/tkyte/SkipCols/index.html


... kind of strange that if the client has ordered list, it cant create the URL
string in ordered fashion or assign values to the form variables and post the
form. ...

the client would be disfunctional if this is true.
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:702862901988#815834300346235549

please let us try to keep this conversation in ONE PLACE "reader"

excellent knowledge source.

Gopal Misra, October 06, 2008 - 5:51 am UTC

Hi Tom, I found this topic so useful. Thanks got explaining thing with best examples.

Is there a limit to a passed array?

Dan Schoch, November 18, 2008 - 12:09 pm UTC

Thank you so much for your example re: using arrays rather than "flexible parameter passing". I agree, I prefer the named parameters, etc., as you mention.

It's working great in the program I'm writing now--except, I seem to be hitting a limitation. It's probably something else, but it seems that I can't have more than 180 elements in the array I'm passing. I'm reading a table with about 200 elements, displaying it in an HTML table, then provide the user with the ability to modify the values in 4 (out of 6) columns displayed (3 dropdowns, 1 text box). When I have more than 180 rows, it bombs with a HTTP 400.

Is there a limit to the size of the array?

Thanks again for your help--you've save me countless times with your explanations and examples.

-Dan-
Tom Kyte
November 21, 2008 - 2:58 pm UTC

can you turn on a bit of mod_plsql tracing to see what the ORA error might be?

Fleixble Parameters

A reader, February 15, 2012 - 9:34 pm UTC

Excellent!

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