ASG
IBM
Zystems
Cressida
Icon
Netflexity
 
  MQSeries.net
Search  Search       Tech Exchange      Education      Certifications      Library      Info Center      SupportPacs      LinkedIn  Search  Search                                                                   FAQ  FAQ   Usergroups  Usergroups
 
Register  ::  Log in Log in to check your private messages
 
RSS Feed - WebSphere MQ Support RSS Feed - Message Broker Support

MQSeries.net Forum Index » WebSphere Message Broker (ACE) Support » WMB 6 \ unset REFERENCE in procedures

Post new topic  Reply to topic
 WMB 6 \ unset REFERENCE in procedures « View previous topic :: View next topic » 
Author Message
hopsala
PostPosted: Sun Oct 19, 2008 5:29 am    Post subject: WMB 6 \ unset REFERENCE in procedures Reply with quote

Guardian

Joined: 24 Sep 2004
Posts: 960

The REFERENCE saga continues...

Let's say I created a procedure that returns a common reference NameRef from a given position treeRoot:
Code:
CREATE PROCEDURE get_NameRef (
 IN treeRoot REFERENCE,
 OUT NamedRef REFERENCE)
BEGIN
 MOVE NamedRef TO treeRoot.MRM.Data.Name;
 IF NOT LASTMOVE(jobDataRef) THEN
  THROW USER EXCEPTION VALUES('Unable to reference');
 END IF;
END;

And I call it like so:
Code:
DECLARE NameRef REFERENCE InputRoot;
CALL get_NameRef(Environment.OriginalRequest, NameRef);

DECLARE whatever CHARACTER 'MiaWallace';


You will note that I check LASTMOVE within my function, because I don't want to do it every time I call get_NameRef. However, to put it simply - this just doesn't work. (p.s the initial reference to InputRoot is irrelevent, and is only used since the fr%^@ing syntax demands an initial value for references)

If the target MOVE field doesn't exist, LASTMOVE returns TRUE!
In this case, if "Environment.OriginalRequest.MRM.Data.Name" doesn't exist. Apparently, since NameRef is not a regular variable but a parameter, it remains in some sort of limbo state..

Moreover, an exception is thrown (since NameRef is never set) but not when the procedure ends or on LASTMOVE, rather in the next line of the code that called it! That is, you'll get the following exception:
Quote:
RecoverableException
File = F:\\build\\S000_P\\src\\DataFlowEngine\\ImbRdl\\ImbRdlStatementGroup.cpp
Line = 589
Function = SqlStatementGroup::execute
Type = ComIbmComputeNode
Name = CENSURED#FCMComposite_1_7
Label = CENSURED
Catalog = BIPv600
Severity = 3
Number = 2488
Text = Error detected, rethrowing
Insert
Type = 5
Text = flow1.Main
Insert
Type = 5
Text = 19.3
Insert
Type = 5
Text = DECLARE whatever CHARACTER 'MiaWallace';
RecoverableException
File = F:/build/S000_P/export/x86_nt_4/usr/include\\ImbRdlReference.inl
Line = 60
Function = SqlReference::fieldPosition
Type =
Name =
Label =
Catalog = BIPv600
Severity = 3
Number = 2111
Text = Illegal use
Insert
Type = 2
Text = 0

From which it is impossible to understand what the problem was.

There is a workaround for this, namely to add the line "MOVE NamedRef TO TreeRoot" at the beginning of the procedure, so that LASTMOVE returns FALSE, but I must say it's quite ugly and easy to forget. Also, i'm getting tired of working around REFERENCEs rather than working with them...

Any suggestions? Is this a bug, or another wonderous working-as-designed edge case? Peeved as I am, I'd be glad to hear other opinions.
Back to top
View user's profile Send private message
fjb_saper
PostPosted: Sun Oct 19, 2008 1:21 pm    Post subject: Reply with quote

Grand High Poobah

Joined: 18 Nov 2003
Posts: 20756
Location: LI,NY

I would not be surprised if the folks from Hursley tell us working as designed. You declared the input parm as a reference but you are effectively passing a tree node to it. If that tree node does not exist or the reference you would be passing to it were invalid you can expect the same result.

Now imagine you would declare a proper reference to pass as input value:
declare myinref reference to Environment.OriginalRequest;
Wouldn't you verify in the next line that it got assigned properly?
IF LASTMOVE(myinref) THEN ....

Of course this puts the burden of safety to the caller. If you want to foolproof your procedure as you have discovered it is prudent to verify that the target is a valid reference before using it... for that matter you should also verify that the source is a valid reference...

I also noticed that you move the reference. I would have expected a SET command to move not the reference but the content.... but you might have had another purpose in mind there and this is valid as any...

Enjoy
_________________
MQ & Broker admin
Back to top
View user's profile Send private message Send e-mail
mqjeff
PostPosted: Sun Oct 19, 2008 1:56 pm    Post subject: Re: WMB 6 \ unset REFERENCE in procedures Reply with quote

Grand Master

Joined: 25 Jun 2008
Posts: 17447

hopsala wrote:
IF NOT LASTMOVE(jobDataRef) THEN


?
Back to top
View user's profile Send private message
mgk
PostPosted: Mon Oct 20, 2008 1:27 am    Post subject: Reply with quote

Padawan

Joined: 31 Jul 2003
Posts: 1642

Hi,

Firstly it would be interesting to know which level of the code you are on, as I do not get the exception you report when I try your code (after changing 'jobDataRef' to 'NamedRef'; I assume this was a typo).

Secondly, I can see why you are having difficulties as OUT REFERENCE parameters to procedures and functions are not documented as well as they could be, so I will try and explain them here and arrange for a doc update as well.

All parameters to functions and procedures are pass by value, so they are copied into local temp variables before the routine is executed, and copied back again afterwards if they are OUT or INOUT parameters.

However, when you have an OUT REFERENCE the question arises "where should it point to" as the SQL rules for all OUT parameters state that they are NULL on entry to the routine. The ESQL answer to this question is actually "nowhere", ie they to are NULL (and this is one area that needs a doc update) on entry to the routine. And when you MOVE a NULL OUT REFERENCE to a location that does exist all is fine and LASTMOVE returns TRUE. However, if you move a NULL OUT REFERENCE to a location that does not exist, the LASTMOVE function returns NULL (UNKNOWN) to follow the ESQL general rule that the result of an expression involving NULL is NULL.

Therefore, in this case to avoid this you could write your code as:
Code:
IF LASTMOVE(NamedRef) THEN
  //Do Work
ELSE
  //Lastmove returned false or NULL
  THROW USER EXCEPTION VALUES('Unable to reference');
END IF;


or you could write it as:
Code:
IF NOT LASTMOVE(NamedRef) OR NamedRef IS NULL THEN
 THROW USER EXCEPTION VALUES('Unable to reference');
END IF;


I was also interested to know why you choose to use an OUT reference in this case, as (from the code you posted) if would have been simpler to use an INOUT REFERENCE for NamedRef (which would also avoid NULL OUT REFERENCES).

I hope this helps.


Regards,
_________________
MGK
The postings I make on this site are my own and don't necessarily represent IBM's positions, strategies or opinions.
Back to top
View user's profile Send private message
hopsala
PostPosted: Wed Oct 22, 2008 8:33 am    Post subject: Reply with quote

Guardian

Joined: 24 Sep 2004
Posts: 960

mgk -
the null tip is just what I needed! Indeed, this isn't documented at all. Also, the fact that one cannot set reference vars to null (I don't really understand why this is, btw) threw me off, and I thought reference vars can never be null.

Anyway, your first code snippet won't work, because as I said LASTMOVE returns true in my scenario. Your second snippet should work, and i'll try it in a few days when I get back to the site.

The parameter is not an INOUT var because the idea is that I return it. I would have returned it as a function return value, but reference return types are (surprise surprise..) not allowed. I thought it would be wrong to use the inout type for mere technical reasons, and mislead everyone who'll use the procedure in future as to the real purpose of the parameter.

jeff -
'jobDataRef' was indeed a typo. It does not appear in the original code.

fjb, assuming I got your meaning -
I wanted the burden to be on the procedure, not the caller, hence my code is the way it is. And I did mean to set the reference, not the content.

All -
Here's what I'm trying to do: At one point I noticed that I keep writing the same reference strings again and again in different nodes & flows of the same project. I thought it would make sense to have a few common procedures, which will always return the right reference point in the tree, rather than copy-paste the same "X.Y.Z.." again and again. I thought OUT reference vars would be the way to do it, but of course I may be wrong..

Cheers for all the help!
Back to top
View user's profile Send private message
mgk
PostPosted: Wed Oct 22, 2008 8:43 am    Post subject: Reply with quote

Padawan

Joined: 31 Jul 2003
Posts: 1642

Hi,

Quote:
Anyway, your first code snippet won't work, because as I said LASTMOVE returns true in my scenario


I tested the code I posted and it worked for me, and LASTMOVE returned NULL, not TRUE. If you try this agains and find it returns TRUE in the case you posted above, then I consider this a defect, in which case you need to move to a later fixpac or raise a PMR.

Quote:
this isn't documented at all.
I will get this changed as soon as I can.

Regards,
_________________
MGK
The postings I make on this site are my own and don't necessarily represent IBM's positions, strategies or opinions.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic  Reply to topic Page 1 of 1

MQSeries.net Forum Index » WebSphere Message Broker (ACE) Support » WMB 6 \ unset REFERENCE in procedures
Jump to:  



You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
Protected by Anti-Spam ACP
 
 


Theme by Dustin Baccetti
Powered by phpBB © 2001, 2002 phpBB Group

Copyright © MQSeries.net. All rights reserved.