Here's a test to prove that 9.3.8 is broken in regards to stored procs with boolean variables.
Dummy package matching Kithran's example :
Code: Select all
create or replace package P_FM_CONTRACT as
procedure GetTotalPayments(
ContractID Varchar2,
DueDateFrom Date := null,
DueDateTo Date := null,
InvDateFrom Date := null,
InvDateTo Date := null,
Posted boolean := null,
PaymentType char := null,
pCount out PLS_Integer,
Finance out Number,
Services out Number,
Insurance out Number);
end;
/
create or replace package body P_FM_CONTRACT as
procedure GetTotalPayments(
ContractID Varchar2,
DueDateFrom Date := null,
DueDateTo Date := null,
InvDateFrom Date := null,
InvDateTo Date := null,
Posted boolean := null,
PaymentType char := null,
pCount out PLS_Integer,
Finance out Number,
Services out Number,
Insurance out Number) is
begin
null;
end;
end;
/
Form Pas Code (Note the param order to the InternalCreateProcCall method differs between ODAC 5.80.x and ODAC 9.3.8. Only errors are shown, calls which succeed log no error line )
Code: Select all
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, MemDS, DBAccess, Ora, StdCtrls;
type
TOps = (opDefault, opPrepare, opCreateProcCall,
opInternalCreateProcCallNoDescr, opInternalCreateProcDescr);
TOraStoredProcHack = class(TOraStoredProc);
TForm1 = class(TForm)
OraSession1: TOraSession;
sprGetTotalPayment: TOraStoredProc;
Memo1: TMemo;
btnRunTests: TButton;
procedure FormShow(Sender: TObject);
procedure btnRunTestsClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
DefaultSQLText : string;
DefaultParams : TOraParams;
procedure DoLog(const Str: string);
function ParamsAsString(Params: TOraParams): string;
procedure ResetStoredProc(ClearParams: boolean);
procedure ProcessTest(Info: string; ClearParams: boolean);
procedure DoClearDataSetParams(Params: TParams; SetBound: boolean);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
TypInfo;
procedure TForm1.FormShow(Sender: TObject);
begin
Memo1.Lines.Clear;
DefaultSQLText := sprGetTotalPayment.SQL.Text;
DefaultParams := TOraParams.Create(nil);
DefaultParams.Assign(sprGetTotalPayment.Params);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
DefaultParams.Free;
end;
procedure TForm1.DoLog(const Str : string);
begin
Memo1.Lines.Add(Str);
end;
function TForm1.ParamsAsString(Params : TOraParams) : string;
var
m : integer;
begin
for m := 0 to Params.Count - 1 do
Result := Result + Params[m].Name + ', ';
end;
procedure TForm1.ResetStoredProc(ClearParams : boolean);
begin
if sprGetTotalPayment.Prepared then
sprGetTotalPayment.UnPrepare;
sprGetTotalPayment.SQL.Text := DefaultSQLText;
if ClearParams then
sprGetTotalPayment.Params.Clear
else
sprGetTotalPayment.Params.Assign(DefaultParams);
end;
procedure TForm1.DoClearDataSetParams(Params : TParams; SetBound : boolean);
var
i:integer;
begin
for i := 0 to Params.Count-1 do
begin
Params[i].Clear;
if SetBound then
Params[i].Bound := True;
end;
end;
procedure TForm1.ProcessTest(Info : string; ClearParams : boolean);
const
SEP = '-----------------------------------------------';
SEP2 = '===============================================';
CONTRNO = '103/A';
var
n : TOps;
procedure LogInfo(AOp : TOps; ASQL : string);
begin
DoLog(GetEnumName(TypeInfo(TOps), integer(AOp)) + ': ' + #13#10);
DoLog('Params Order : ' + ParamsAsString(sprGetTotalPayment.Params) + #13#10);
DoLog(ASQL);
try
DoClearDataSetParams(sprGetTotalPayment.Params, True);
sprGetTotalPayment.ParamByName('ContractID').AsString := ContrNo;
sprGetTotalPayment.ParamByName('Posted').AsBoolean := True;
sprGetTotalPayment.ExecProc;
except
on E:Exception do
DoLog(E.Message);
end;
DoLog(SEP);
end;
begin
DoLog(Info);
for n := Low(TOps) to High(TOps) do
begin
ResetStoredProc(ClearParams);
case n of
opPrepare :
sprGetTotalPayment.Prepare;
opCreateProcCall :
sprGetTotalPayment.CreateProcCall(sprGetTotalPayment.StoredProcName, 0);
opInternalCreateProcCallNoDescr, opInternalCreateProcDescr :
TOraStoredProcHack(sprGetTotalPayment).InternalCreateProcCall(sprGetTotalPayment.StoredProcName, 0, n = opInternalCreateProcDescr); // Version 5.80
// TOraStoredProcHack(sprGetTotalPayment).InternalCreateProcCall(sprGetTotalPayment.StoredProcName, n = opInternalCreateProcDescr); // Version 9.3.8
end;
LogInfo(n, sprGetTotalPayment.SQL.Text);
end;
DoLog(SEP2);
end;
procedure TForm1.btnRunTestsClick(Sender: TObject);
begin
ProcessTest('Params From DFM', False);
ProcessTest('Params Cleared', True);
end;
end.
The Form DFM code : (Note the stored procedure params have been viewed once from the Object Inspector params editor in ODAC 5.80 and saved). This DFM is used for both tests, because we are going from ODAC 5.80 to 9.3.8 and we will not be re-invoking all our 10000s of stored proc param lists in our real life enterprise app.
Code: Select all
object Form1: TForm1
Left = 319
Top = 124
Width = 1305
Height = 750
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnDestroy = FormDestroy
OnShow = FormShow
PixelsPerInch = 96
TextHeight = 13
object Memo1: TMemo
Left = 352
Top = 8
Width = 633
Height = 681
ScrollBars = ssBoth
TabOrder = 0
WordWrap = False
end
object btnRunTests: TButton
Left = 88
Top = 272
Width = 75
Height = 25
Caption = 'Run Tests'
TabOrder = 1
OnClick = btnRunTestsClick
end
object OraSession1: TOraSession
Username = 'PAULZIP'
Password = 'PAULZIP'
Server = 'CURRENT'
Connected = True
Left = 136
Top = 56
end
object sprGetTotalPayment: TOraStoredProc
StoredProcName = 'P_FM_CONTRACT.GETTOTALPAYMENTS'
Session = OraSession1
SQL.Strings = (
'declare'
' v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);'
'begin'
' P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUE' +
'DATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUN' +
'T, :FINANCE, :SERVICES, :INSURANCE);'
'end;')
Left = 200
Top = 56
ParamData = <
item
DataType = ftBoolean
Name = 'POSTED'
ParamType = ptInput
end
item
DataType = ftString
Name = 'CONTRACTID'
ParamType = ptInput
end
item
DataType = ftDateTime
Name = 'DUEDATEFROM'
ParamType = ptInput
end
item
DataType = ftDateTime
Name = 'DUEDATETO'
ParamType = ptInput
end
item
DataType = ftDateTime
Name = 'INVDATEFROM'
ParamType = ptInput
end
item
DataType = ftDateTime
Name = 'INVDATETO'
ParamType = ptInput
end
item
DataType = ftFixedChar
Name = 'PAYMENTTYPE'
ParamType = ptInput
end
item
DataType = ftInteger
Name = 'PCOUNT'
ParamType = ptOutput
end
item
DataType = ftFloat
Name = 'FINANCE'
ParamType = ptOutput
end
item
DataType = ftFloat
Name = 'SERVICES'
ParamType = ptOutput
end
item
DataType = ftFloat
Name = 'INSURANCE'
ParamType = ptOutput
end>
end
end
Output for ODAC 5.80.x
Code: Select all
Params From DFM
opDefault:
Params Order : POSTED, CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
-----------------------------------------------
opPrepare:
Params Order : POSTED, CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
-----------------------------------------------
opCreateProcCall:
Params Order : CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, POSTED, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
-----------------------------------------------
opInternalCreateProcCallNoDescr:
Params Order : POSTED, CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(v_POSTED, :CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
ORA-06550: line 4, column 3:
PLS-00306: wrong number or types of arguments in call to 'GETTOTALPAYMENTS'
ORA-06550: line 4, column 3:
PLS-00306: wrong number or types of arguments in call to 'GETTOTALPAYMENTS'
ORA-06550: line 4, column 3:
PL/SQL: Statement ignored
-----------------------------------------------
opInternalCreateProcDescr:
Params Order : CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, POSTED, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
-----------------------------------------------
===============================================
Params Cleared
opDefault:
Params Order :
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
Parameter 'ContractID' not found
-----------------------------------------------
opPrepare:
Params Order :
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
Parameter 'ContractID' not found
-----------------------------------------------
opCreateProcCall:
Params Order : CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, POSTED, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
-----------------------------------------------
opInternalCreateProcCallNoDescr:
Params Order :
begin
P_FM_CONTRACT.GETTOTALPAYMENTS;
end;
Parameter 'ContractID' not found
-----------------------------------------------
opInternalCreateProcDescr:
Params Order : CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, POSTED, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
-----------------------------------------------
===============================================
Output for ODAC 9.3.8
Code: Select all
Params From DFM
opDefault:
Params Order : POSTED, CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
ORA-06550: line 4, column 3:
PLS-00306: wrong number or types of arguments in call to 'GETTOTALPAYMENTS'
ORA-06550: line 4, column 3:
PLS-00306: wrong number or types of arguments in call to 'GETTOTALPAYMENTS'
ORA-06550: line 4, column 3:
PL/SQL: Statement ignored
-----------------------------------------------
opPrepare:
Params Order : POSTED, CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
ORA-06550: line 4, column 3:
PLS-00306: wrong number or types of arguments in call to 'GETTOTALPAYMENTS'
ORA-06550: line 4, column 3:
PLS-00306: wrong number or types of arguments in call to 'GETTOTALPAYMENTS'
ORA-06550: line 4, column 3:
PL/SQL: Statement ignored
-----------------------------------------------
opCreateProcCall:
Params Order : CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, POSTED, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
-----------------------------------------------
opInternalCreateProcCallNoDescr:
Params Order : POSTED, CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
ORA-06550: line 4, column 3:
PLS-00306: wrong number or types of arguments in call to 'GETTOTALPAYMENTS'
ORA-06550: line 4, column 3:
PLS-00306: wrong number or types of arguments in call to 'GETTOTALPAYMENTS'
ORA-06550: line 4, column 3:
PL/SQL: Statement ignored
-----------------------------------------------
opInternalCreateProcDescr:
Params Order : CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, POSTED, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
-----------------------------------------------
===============================================
Params Cleared
opDefault:
Params Order :
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
Parameter 'ContractID' not found
-----------------------------------------------
opPrepare:
Params Order : CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, POSTED, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
-----------------------------------------------
opCreateProcCall:
Params Order : CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, POSTED, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
-----------------------------------------------
opInternalCreateProcCallNoDescr:
Params Order :
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
Parameter 'ContractID' not found
-----------------------------------------------
opInternalCreateProcDescr:
Params Order : CONTRACTID, DUEDATEFROM, DUEDATETO, INVDATEFROM, INVDATETO, POSTED, PAYMENTTYPE, PCOUNT, FINANCE, SERVICES, INSURANCE,
declare
v_POSTED boolean := sys.DIUTIL.INT_TO_BOOL(:POSTED);
begin
P_FM_CONTRACT.GETTOTALPAYMENTS(:CONTRACTID, :DUEDATEFROM, :DUEDATETO, :INVDATEFROM, :INVDATETO, v_POSTED, :PAYMENTTYPE, :PCOUNT, :FINANCE, :SERVICES, :INSURANCE);
end;
-----------------------------------------------
===============================================
Hopefully you can now replicate the issues and fix 9.3.8.