Page 1 of 1
ORA-01009 missing mandatory parameter- Simple Update Of Single Field
Posted: Fri 05 Aug 2005 21:46
by Frank Bishop
I am trying to perform a simple update of a field within a oracle 10g database
using delphi 6 ent and ODAC 5.50
? why does sqlplus require a ; charactor while ODAC Doesn't?
? is thier any suggestions for improved error checking and making the code more bullet proof?
? Didnt I read somewhere an issue with using the net option to do writes
to the database?
PS Thanks for your wonderful product
A beginners guide to datasets and oracle querys / interaction would be
helpful any suggestion for info on the web?
{******************************************************************************}
procedure Build_Query(s : string);
begin
Queryme.Clear;
Queryme.Add('UPDATE');
Queryme.Add('AMASSET');
Queryme.Add('SET');
Queryme.Add('FIELD1 = ' + chr(39) + 'UPDATETHIS' + chr(39));
Queryme.Add('WHERE');
Queryme.Add('ASSETTAG = ' + chr(39) + s + chr(39));
form1.memo1.Clear;
form1.memo1.lines := queryme;
form1.oraquery1.sqlUpdate := queryme;
end;
{******************************************************************************}
procedure Run_Update_Query;
begin
// first insure the dataset is closed
form1.OraDataSource1.DataSet.Close;
// connect
form1.orasession1.server := '10.34.1.146:1521:ATEST';
form1.orasession1.username := 'acugjsr';
form1.orasession1.Password := 'nadayo23';
form1.orasession1.Options.Net := true;
if form1.orasession1.connected true then form1.orasession1.Connect;
form1.OraQuery1.CachedUpdates := true;
try
Begin
form1.oraquery1.Execute;
End;
except
On E : Exception do form1.memo1.Lines.add('Error');
On E : EOraError do form1.memo1.Lines.add('Error Ora');
end; { try except block }
form1.oraquery1.CommitUpdates;
form1.orasession1.disconnect;
end;
{******************************************************************************}
procedure TForm1.Button1Click(Sender: TObject);
begin
Build_Query('YILDIRIM1-1339Z11');
Run_Update_Query;
end; { Procedure }
{******************************************************************************}
Posted: Mon 08 Aug 2005 06:33
by Paul
ODAC with TOraSession.Options.Net = True does not support national characters in SQL text. You must use parameters. Please see restrictions of Net option in "Working with ODAC Net".
Try to use OraErrorHandler component to change error messages. Please see MasterDetail demo project.
You can handle TOraSession.OnError event and show your message.
ODAC uses common foundations of Borland VCL. You can read about ODAC specific properties in ODAC help. Please see demo projects how to use ODAC components.
I've Spent All Day Trying To Find An Anser But
Posted: Mon 08 Aug 2005 20:41
by Frank Bishop
Still No Luck
I Reviewed The Working With ODAC Net And Still Recieve The
ORA-01009: missing mandatory parameter
error. I guess my question is
What missing Parameter?
I've been trying varations of the TORAQuery Componet
but still the same error 1009
I've search on the web but cant seem make it through all the Java error dumps and come out with anything usefull
A few places discussed using the FOR clause to limit the number of array elements.
see notes below
Another thing I ran across discussed using paretheses
see notes below
My query is a bit simple
it changes only a single field in a single row
UPDATE AMASSET
SET FIELD1 = 'New Value'
WHERE AMASSET.ASSETTAG = 'YILDIRIM-2-JTXKC11'
I tried setting multiple values but that didnt help
I tried varing the blocking non blocking
When I cut and paste the update stament into SQLPLUS and add a ;
and a commit;
the update runs fine
Any ideas of a possible solution to error 1009, a way to collect more information or an alternate way I might
change the value of a single field programatically
Would help me out alot
Frank Bishop
Notes
--------------
Some Info In Programmer's Guide to the Oracle Precompilers.
--------------------------------------------------------------------------------
Using the FOR Clause
You can use the optional FOR clause to set the number of array elements processed by a SQL statement. The FOR clause is especially useful in UPDATE, INSERT, and DELETE statements. With these statements you might not want to use the entire array (the default). The FOR clause lets you limit the elements used to just the number you need, as the following example shows:
EMP_NAME : name_array(1..100);
SALARY : ORACLE.FLOAT_ARRAY(1..100);
ROWS_TO_INSERT : integer;
...
-- populate the host arrays
ROWS_TO_INSERT := 25; -- set FOR-clause variable
...
EXEC SQL FOR :ROWS_TO_INSERT -- will process only 25 rows
INSERT INTO emp (ename, sal)
VALUES (:EMP_NAME, :SALARY);
The FOR clause must use an integer host variable to count array elements. For example, the following FOR clause is invalid:
EXEC SQL FOR 25 -- literal not allowed
INSERT INTO emp (ename, empno, sal)
VALUES (:EMP_NAME, :EMP_NUMBER, :SALARY);
The number of array elements processed is determined by comparing the dimension of the smallest host or indicator array with the FOR-clause variable. The lesser value is used.
If the value of the FOR-clause variable is negative, no rows are processed. In this case, a zero is returned to SQLCODE in the SQLCA indicating that Oracle carried out the operation successfully. However, if the value of the FOR-clause variable is zero, no rows are processed, and Oracle issues the error message
ORA-01009: missing mandatory parameter
because zero is treated like an unspecified value.
--------------------------------------------------------------------------------
Some Websphere Stuff
Oracle
Surrounding a query with () causes the Ora-01009 error or an empty result set (113709.RN)
If you are using the Oracle thin driver and the OCI driver, surrounding a query with parentheses ("()") results in the error "ORA-01009: missing mandatory parameter" and an empty result set (no data). This is an Oracle error (917674) and was fixed in the 817.2 fixset. To avoid the problem, either install Oracle fixset 817.2 or avoid surrounding queries with parentheses.
Posted: Tue 09 Aug 2005 06:41
by Paul
I see your mistake. You assigned oraquery1.sqlUpdate only.
form1.oraquery1.sqlUpdate := queryme;
But when you call form1.oraquery1.Execute you executes SQL text written in form1.oraquery1.SQL. It is empty. Please use oraquery1.SqlUpdate property for update SQL that will be executed during Edit/Post operation. Please see ODAC help for more details about names of parameters in SQLUpdate.
Posted: Tue 09 Aug 2005 14:09
by Frank Bishop
I have reviewed the parameters for sqlupdate and modified my code to
utilize oraquery1.sqlupdate
Simplified the code into 1 procedure
And played around with trying to get parameterized querys to function.
Thinking that may work were the simplier update query doesnt
Also I downloaded and installed the 2.6 version of ora tools but couldnt find the query statement editor tool?
Anyway here is the one routine. Note the section I feel fuzzy about
{******************************************************************************}
procedure TForm1.Button1Click(Sender: TObject);
begin
// Generate The Update Query Programatically
form1.oraquery1.sqlUpdate.Clear;
form1.oraquery1.sqlUpdate.Add('UPDATE AMASSET');
form1.oraquery1.sqlUpdate.Add('SET FIELD1 = ' + chr(39) + '12345' + chr(39));
form1.oraquery1.sqlUpdate.Add('WHERE ASSETTAG = ' + chr(39) + 'YILDIRIM-2-JTXKC11' + chr(39));
// Show Whats Going On (cut and paste to verfiy database connection-operation okay)
form1.memo1.Clear;
form1.memo1.lines := form1.oraquery1.sqlUpdate;
// Connect To The Database
form1.orasession1.server := '10.3.1.146:1521:ACTEST';
form1.orasession1.username := 'acusr';
form1.orasession1.Password := 'nyiso123';
form1.orasession1.Options.Net := true;
if form1.orasession1.connected true then form1.orasession1.Connect;
// THIS IS THE SECTION I NEED SOME HELP WITH
// form1.OraQuery1.Prepare;
// form1.OraQuery1.Active := true;
// first insure the dataset is closed ? why is this needed ?
// form1.OraDataSource1.DataSet.Close;
// form1.OraQuery1.CachedUpdates := true;
form1.oraquery1.Execute;
form1.oraquery1.CommitUpdates;
// Clean Up
form1.orasession1.Disconnect;
end; { Procedure }
{******************************************************************************}
So the sqlupdate is the initial query
the session makes the connection
the datset returns the rows of data
What is the prepare used for
if i use sql plus to make requests for data and
modifications of data how can I do this in ODAC
Frank
PS Thanks again for your very timely help in this matter.
Posted: Tue 09 Aug 2005 14:39
by Paul
You must write your query to oraquery1.SQL
Code: Select all
form1.oraquery1.SQL.Clear;
form1.oraquery1.SQL.Add('UPDATE AMASSET');
form1.oraquery1.SQL.Add('SET FIELD1 = ' + chr(39) + '12345' + chr(39));
form1.oraquery1.SQL.Add('WHERE ASSETTAG = ' + chr(39) + 'YILDIRIM-2-JTXKC11' + chr(39));
form1.oraquery1.Execute;
Posted: Wed 10 Aug 2005 14:22
by Frank Bishop
First I'd like to say thanks for sticking with me on this one.
I dont understand I thought the sqlupdate was used/needed to put the datset into a writable state
So I quickly tried your sugestion. Still no good
In one of the previous fourms I noticed a suggestion to create a fresh
copy of the program so I did this this morning. A few interesting items.
Created a new project
added a orasession componet
added a oraquery componet
added a oradatasource componet
added a button and a memo componet
added OraError to the uses clause and the following code
for the button click event
{******************************************************************************}
procedure TForm1.Button1Click(Sender: TObject);
begin
// Set Up Parameters For Visual Componets
form1.Oradatasource1.DataSet := OraQuery1;
// Next line required to avoid "Not in cached update mode" pop up message
form1.OraQuery1.CachedUpdates := true;
form1.OraQuery1.Session := OraSession1;
// Connect To The Database
form1.orasession1.server := '10.3.3.146:1521:ACPOD';
form1.orasession1.username := 'a56sr';
form1.orasession1.Password := 'nwero123';
form1.orasession1.Options.Net := true;
if form1.orasession1.connected true then
form1.orasession1.Connect;
// Generate The Update Query Programatically
// ( Doesnt Work Memory Acess Violation )
form1.oraquery1.SQL.Clear;
form1.oraquery1.SQL.Add('UPDATE AMASSET');
form1.oraquery1.SQL.Add('SET FIELD1 = ' + chr(39) + '12345' + chr(39));
form1.oraquery1.SQL.Add('WHERE ASSETTAG = ' + chr(39) + 'YILDIRIM-2-JTXKC11' + chr(39));
(*
// Generate The Select Query Programatically ( Works Good )
form1.oraquery1.SQL.Clear;
form1.oraquery1.SQL.Add('SELECT * FROM AMASSET');
form1.oraquery1.SQL.Add('WHERE ASSETTAG = ' + chr(39) + 'YILDIRIM-2-JTXKC11' + chr(39));
*)
// Show User Whats Going To Happen
form1.memo1.Clear;
form1.memo1.lines := form1.oraquery1.SQL;
// Run The SQL Update Code
try
form1.oraquery1.Execute;
except
On E : EOraError do
form1.memo1.Lines.add(inttostr(E.ErrorCode) + ' ' + E.Message);
end; { try except block }
try
form1.oraquery1.CommitUpdates;
except
On E : EOraError do
form1.memo1.Lines.add(inttostr(E.ErrorCode) + ' ' + E.Message);
end; { try except block }
(*
// Show The User The Results For Select Query
form1.memo1.Lines.add('Serial Number : ' + Uppercase(VarToStr(OraDataSource1.DataSet.FieldValues['SERIALNO'])));
form1.memo1.Lines.add('Asset Tag : ' + Uppercase(VarToStr(OraDataSource1.DataSet.FieldValues['FIELD1'])));
*)
// Clean Up
form1.orasession1.Disconnect;
end; { Procedure }
{******************************************************************************}
by swapping the (* *) blocks for the // Generate The Update Query Programatically section I was able to demonstate the ability to read from the database yet not to write to it
{******************************************************************************}
Output From Select Read Test
SELECT * FROM AMASSET
WHERE ASSETTAG = 'YILDIRIM-2-JTXKC11'
Serial Number : JTXKC11
Asset Tag : 12345
{******************************************************************************}
Output From Update Write Test
pop up message
Access violation at address 0046F44E in
module Project1.exe Read of address 00000000
{******************************************************************************}
The ORA-01009 error seems to have disappeared ?
A cut and paste test of the memo componet works
fine in sqlplus if I add a ; at the end press enter
then type commit; and press enter
SQL*Plus: Release 10.1.0.2.0 - Production on Wed Aug 10 10:18:20 2005
Copyright (c) 1982, 2004, Oracle. All rights reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.1.0.2.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL>
SQL> UPDATE AMASSET
2 SET FIELD1 = '12345'
3 WHERE ASSETTAG = 'YILDIRIM-2-JTXKC11';
1 row updated.
SQL> commit;
Commit complete.
SQL>
Frank Bishop
Posted: Wed 10 Aug 2005 19:36
by Frank Bishop
Ihave made some process on the problem
One of the oracle DBA'a suggested that the ORA-01009 error
may be a result of trouble with the newline or carrige return statements
between the portions of the query
so
for the read I use Oraquery.SQL
form1.oraquery1.SQL.Add('SELECT * FROM AMASSET');
form1.oraquery1.SQL.Add('WHERE ASSETTAG = ' + chr(39) + 'YILDIRIM-2-JTXKC11' + chr(39));
And for the write Oraquery.SQLUpdate
but in the write I change the query to be a single line
form1.oraquery1.SQL.Add('UPDATE AMASSET SET FIELD1 = ' + chr(39) + '12345' + chr(39) + ' WHERE ASSETTAG = ' + chr(39) + 'YILDIRIM-2-JTXKC11' + chr(39));
This resolved my problem
The issue was the lack of a space before the WHERE in the update query
making '12345'WHERE part of the query
Making the change like this
form1.oraquery1.SQL.Add('UPDATE AMASSET ');
form1.oraquery1.SQL.Add('SET FIELD1 = ' + chr(39) + '12345' + chr(39));
form1.oraquery1.SQL.Add(' WHERE ASSETTAG = ' + chr(39) + 'YILDIRIM-2-JTXKC11' + chr(39));
Doesnt seem to work
so either 1 line
or somthing like this
form1.oraquery1.SQLUpdate.Add(
'UPDATE' + chr(13) + chr(10) +
'AMASSET'+ chr(13) + chr(10) +
'SET FIELD1 = ' + chr(39) + '12345' + chr(39) + chr(13) + chr(10) +
'WHERE ASSETTAG = ' + chr(39) + 'YILDIRIM-2-JTXKC11' + chr(39));
seems to do the trick
Thanks for helping me solve this problem
Kudo's to the ODAC Forum Team
Oracle - You have some work to do on your error messages
PS any thoughts or info on how the OraQuery.SQL.Add or OraQuery.SQLUpdate.Add methods function let me know
I'll check back on the thread in a few days
I have alot of work implementing database writes into my project
Thanks Again
Frank Bishop
Posted: Wed 10 Aug 2005 19:38
by Frank Bishop
Special Thanks To Paul for not giving up
Posted: Wed 10 Aug 2005 20:35
by Paul
Your example is correct, but form1.oraquery1.CommitUpdates must be used with CachedUpdates=True in pair with ApplyUpdates,RestoreUpdates,CommitUpdates,CancelUpdates and cannot be used in your example. Please see ODAC help. I think you want to write form1.orasession1.Commit. Correct this line and you will receive working example.
Posted: Wed 10 Aug 2005 20:46
by Frank Bishop
Thanks
I noticed that although the code runs without exceptions the database is not being changed
Looks like I have some reading and tweaking to do!
I'll look a bit closer first thing in the morning and get back to you.
initially I changed the
form1.oraquery.commitupdates;
to
form1.session1.commit;
but it didnt appear to take
I need to look closer at the code and
do a few more tests when I can concentrate a bit better.
Stay Tunned to the thread
Fank
Posted: Thu 11 Aug 2005 15:57
by Frank Bishop
Well I seem to be more lost than ever
I tried a number of approches
I know this is not right but just so you can see
{ I connect to the database }
// Build The Query
form1.oraquery1.SQLUpdate.Clear;
form1.oraquery1.SQLUpdate.Add('UPDATE AMASSET SET FIELD1 = ' + chr(39) + form1.edit1.text + chr(39) + ' WHERE ASSETTAG = ' + chr(39) + 'YETTER1' + chr(39));
// Show User Whats Going To Happen
form1.memo1.Clear;
form1.memo1.lines := form1.oraquery1.SQLUpdate;
// Run The SQL Update Code
form1.Oraquery1.Execute;
form1.OraQuery1.CachedUpdates := true;
form1.OraQuery1.ApplyUpdates;
form1.OraQuery1.CommitUpdates;
form1.OraSession1.ApplyUpdates;
form1.OraSession1.Commit;
(* adding this generates an error
try
form1.OraQuery1.DataSource.DataSet.Close;
except
On E : Exception do form1.memo1.Lines.add(E.Message);
end; { try except block }
*)
{ I disconnect fom the database }
The problem is that I can read from the database
but can't write to the database
(if I cut and paste the update SQL code and follow it with a commit in sqlplus It works okay )
Frank
I got somthing to work
Posted: Thu 11 Aug 2005 17:50
by Frank Bishop
The code below works
Any suggestions on
Cleaning it up
Or Adding more bullet profing
Are appreciated - but after all this
I think we both want to put this thread to bed.
{******************************************************************************}
// Write
procedure TForm1.Button2Click(Sender: TObject);
begin
get_random_string(random_string_value);
// Connect To The Database
form1.orasession1.server := '10.3.1.146:1521:ACTEST';
form1.orasession1.username := 'acusr';
form1.orasession1.Password := 'nyiso123';
form1.orasession1.Options.Net := true;
if form1.orasession1.connected true then form1.orasession1.Connect;
Oraquery1.ReadOnly := false;
// Build The Query
form1.oraquery1.SQLUpdate.Clear;
form1.oraquery1.SQLUpdate.Add('UPDATE AMASSET SET FIELD1 = '
+ chr(39) + random_string_value + chr(39) + ' WHERE ASSETTAG = ' + chr(39)
+ 'YETTER1-8RMSV21' + chr(39));
// Show User Whats Going To Happen
form1.memo1.Clear;
form1.memo1.lines := form1.oraquery1.SQLUpdate;
form1.OraQuery1.CachedUpdates := true;
form1.OraQuery1.Open;
form1.OraQuery1.Edit;
form1.OraSession1.StartTransaction;
try
form1.OraQuery1.ApplyUpdates;
form1.OraSession1.Commit;
except
form1.OraSession1.Rollback;
raise;
end;
form1.OraQuery1.CommitUpdates;
// Clean Up
form1.Orasession1.Disconnect;
end;
{******************************************************************************}