I realized that having just copied and modified my old SQL example
[now snipped from the quoted reply], that I had overlooked the added
requirement in this scenario to account for the input pDecPrecision
value. That requirement actually complicates arithmetic expressions
which would need to maintain the precision; the scale and precision for
the builtin casting functions of the SQL can not be variables, which
could make that easier. A simple alternative is to just rebuild the
character string representation of the decimal numeric from the HEX() of
the raw packed BCD data, and have that string [with a minus symbol and
decimal point, as required,] cast directly to the DECIMAL(30,09). The
following example uses a string expression, but includes an updated [and
this time hopefully correct] arithmetic expression in comments; pHex as
raw, pDecLen as decLen, and pDecPrecision as decPrc:
d rtn30p09 s 30p09
d rawLen s 5i00
d rawDig s 5i00
d rawHex s 32a varying
/free
rawLen=%div(decLen:2)+1; // byte length of raw data
rawDig=decLen; // assume odd decLen; no extra zero
if %rem(decLen:2)=0; // even decLen; revise assumption
rawDig=decLen+1; // account extra zero, left pad
endif;
Exec SQL
Set Option Commit=*NONE, Naming=*SYS, DecmPt=*PERIOD;
Exec SQL
set :rawHex=hex( substr( :raw, 1, :rawLen ) );
Exec SQL
set :rtn30p9=cast(
case when right( :rawHex, 1 ) in ('B', 'D')
then '-' else '' end
concat insert( left( :rawHex, :rawDig )
, :rawDig - :decPrc + 1 , 0 , '.' )
/* -- or by arithmetic; replaces snipped version
( dec( left( :rawHex, :rawDig ) , 21, 0 )
* case when right( :rawHex, 1 ) in ('B', 'D')
then -1. else 1. end
) / ( dec( 10**(:decPrc), 10, 00 ) )
*/
as decimal(30, 09) ) ;
// deal with sqlcode\sqlstate as necessary; e.g. overflow
// if more than 21 significant digits
return rtn30p09;
Using the cast to decimal from a string also allows for the input
precision to approach or even match the max length of 21 digits for the
integer portion; truncated, as coded above. Of course the typed decimal
data *DTAARA support only allows up to DEC(24, 9) where each numeric
value is the maximum.
Regards, Chuck
On 23 Apr 2012 11:55, CRPence wrote:
<<SNIP>>
On 23 Apr 2012 09:04, Matt Lavinder wrote:
<<SNIP>>
I am trying to write a generic procedure to retrieve a data area
that is a decimal value. Currently, we have to adjust the procedure
every time we need to handle a new size, and then we have to add
variables and specific code for that size.
I am trying to use the QWCRDTAA to retrieve the value and
ultimately want return a decimal of 30p 9 that contains what ever
was found in the data area. Problem is, the data comes back as hex
from QWCRDTAA (the raw decimal data). Obviously I could just MOVE
the data if I wanted to define decimals of all possible sizes, but
then I am back to the very thing I am trying to avoid.
As a part of my procedure, I pass in the definition of the data
area, so I know that at run time. What is the quickest way to get
that raw/hex data into a decimal variable I can work with? If you
were to put the logic I am looking for into a procedure, the
prototype to convert this character/hex data would need to look
something like this:
D HexToPacked pi 30p 9
D pHex 2000a
D pDecLen 5i 0
D pDecPrecision 5i 0
<<SNIP>>
As an Amazon Associate we earn from qualifying purchases.