Re: Converting a long long to an int8.
Posted in 2004
Topics: Connectivity: ESQL/C, 4GL & Embedded SQL, Server Administration
OK,
Now I am really confused.
The Guide says you can only store values in the following range.
INT8, SERIAL8 8 -9,223,372,036,854,775,807 to
9,223,372,036,854,775,807
But if I use the following:
theMono = 0xFFFFFFFFFFFFFFFF;
mono.data[0] = (signedMono & 0x00000000FFFFFFFF);
mono.data[1] = (signedMono & 0xFFFFFFFF00000000) >> 32;
mono.sign = 1;
It happliy sets the column value to 18446744073709551615.
So suddenly I think it will just take my unsigned 64 bit number without any
messing about finding out its value as a signed 64 bit etc...
HOWEVER
If I try the above with sign set to zero, I get a blank value in dbaccess,
if I then use -1 I still get a blank in dbaccess.
If, however I use 1 I get the value described, 18446744073709551615, but if
I THEN use -1, I get the same positive value.
It seems to me that there is something more to the sign component than just
setting the sign of the absolute value in data. Also there seems to be
something more to the range than described in the guide.
----- Forwarded by Andrew Hardy/MAIN/MC1 on 15/07/2004 13:17 -----
|---------+---------------------------->
| | Andrew Hardy |
| | |
| | 15/07/2004 11:55 |
| | |
|---------+---------------------------->
>--------------------------------------------------------------------------------------------------------------------------------------------------|
| |
| To: Jonathan Leffler <jleffler@earthlink.net> |
| cc: informix-list@iiug.org |
| Subject: Re: Converting a long long to an int8. |
>--------------------------------------------------------------------------------------------------------------------------------------------------|
Ok!
After some experimentation I now have code below. Looks like although the
structure holds a 64 bit number you cannot use it to set an int8 column in
the database with just any value you have to get the absolute value of your
unsigned 64 as a twos compliment number as if it were signed set the data
to that ( element 1 being the MS 32 bits!) then set the sign!
Why if int8 is provided is there no pre-provided wrapped way to do this?
Below seems to work, am I on the right track ?
Many thanks again for all your help.
Andrew H.
EXEC SQL BEGIN DECLARE SECTION;
char sql_line[SQL_SIZE];
int ip;
int port;
ifx_int8_t mono;
EXEC SQL END DECLARE SECTION;
unsigned long long theMono;
long long signedMono;
ip = 100;
port = 100;
theMono = 0xF0F0F0F0F0F0F0F0;
signedMono = theMono;
if ( signedMono < 0 )
{
signedMono = -signedMono;
mono.data[0] = (signedMono & 0x00000000FFFFFFFF);
mono.data[1] = (signedMono & 0xFFFFFFFF00000000) >> 32;
mono.sign = -1;
}
else
{
mono.data[0] = (signedMono & 0x00000000FFFFFFFF);
mono.data[1] = (signedMono & 0xFFFFFFFF00000000) >> 32;
mono.sign = 1;
}
etc, etc, etc.......................
----- Forwarded by Andrew Hardy/MAIN/MC1 on 15/07/2004 11:47 -----
|---------+---------------------------->
| | "Andrew Hardy" |
| | <Andrew.Hardy@mar|
| | coni.com> |
| | Sent by: |
| | owner-informix-li|
| | st@iiug.org |
| | |
| | |
| | 15/07/2004 09:43 |
| | |
|---------+---------------------------->
>--------------------------------------------------------------------------------------------------------------------------------------------------|
| |
| To: Jonathan Leffler <jleffler@earthlink.net> |
| cc: informix-list@iiug.org |
| Subject: Re: Converting a long long to an int8. |
>--------------------------------------------------------------------------------------------------------------------------------------------------|
Sorry to be a pain, my question was actually about converting an unsigned
long long TO an int8.
For that, would I do something like the code below then ?
What sign would I set ?
What is the difference between int8 and ifx_int8_t ?
Thanks again for your help.
Andrew H.
void someSQLFunction()
{
EXEC SQL BEGIN DECLARE SECTION;
char sqlLine[SQL_SIZE];
int a;
int b;
ifx_int8_t testInt8;
EXEC SQL END DECLARE SECTION;
unsigned long long x;
x = 0xF0F0F0F0F0F0F0F0;
testInt8.data[0] = (x & 0xFFFFFFFF00000000) >> 32;
testInt8.data[1] = (x & 0x00000000FFFFFFFF);
/*
Not sure what to set this to. It seems to me that if, as is
suggested below, any 64 bit content can be
positive or negative, then you will end up with values bigger than
C can hold in 64 bits. But the Guide
seems to indicate by the range it states that you can only hold
signed values not unsigned!
*/
testInt8.sign = ??;
sprintf (sql_line, "INSERT INTO TAB1 (f1, f2, f3) VALUES
(?,?,?)");
EXEC SQL PREPARE writeIt FROM :sql_line;
EXEC SQL EXECUTE writeIt USING :a, :b, :testInt8;
.....
.....
}
|---------+---------------------------->
| | Jonathan Leffler |
| | <jleffler@earthli|
| | nk.net> |
| | Sent by: |
| | owner-informix-li|
| | st@iiug.org |
| | |
| | |
| | 15/07/2004 06:08 |
| | Please respond to|
| | Jonathan Leffler |
| | |
|---------+---------------------------->
>--------------------------------------------------------------------------------------------------------------------------------------------------|
|@@NL
Andrew Hardy wrote:
> OK, Now I am really confused.
OK - well, I'm dealing with your our cumulative posts in one answer.
I'm sure I should really reverse the contents of the posting - you use
Lotus Notes which positively encourages top-posting.
History lesson.
* Back in 1995, not all 32-bit platforms had vendor-provided compilers
that supported 'long long'. GCC was an exception - but not usually
provided by a vendor. The C90 standard has no support for 64-bit
data types; it wasn't until C99 that 'long long' was standardized
officially.
* For a combination of those reasons, it was decided to provide a
C data structure to handle INT8 types. It was probably necessary
at the time -- even though it was not within 5 years or so.
* For reasons which still elude me, the decision was made to store
the data structure on disk, rather than the more compact 8-byte
quantity; that's why the collength column of syscolumns tells you
10 bytes for an INT8 or SERIAL8. Personally, I think that was an
inexcusable decision; reversing it is going to painful (but if it
can be done, in-place alter will be a huge help).
C integer lesson:
* For all computers that matter (to IDS and Informix), the CPU uses
2's complement arithmetic and 8-bit bytes. If you have a slot for
N bytes (N = 1, 2, 4 or 8), it can contain any bit pattern permitted
by the type. If you choose to treat the bit pattern as a signed
quantity, then it can hold values in the range:
-2**(N-1) .. +(2**(N-1)-1).
If you choose to treat it as an unsigned quantity, then it can hold
values in the range:
0 .. +(2**N - 1).
* The same bit pattern can have two different meanings. If the MSB
(most significant bit) is 0, then it represents the same value,
whether treated as signed or unsigned. If the MSB is 1, then the
meaning is radically different. For example, with N = 2, 0xFFFF
(16 bits set to 1) means 65335 as an unsigned and -1 as a signed.
> The Guide says you can only store values in the following range.
>
> INT8, SERIAL8 8 -9,223,372,036,854,775,807 to
> 9,223,372,036,854,775,807
Yes - INT8 and SERIAL8 are both signed quantities, as are all the
Informix integer types.
> But if I use the following:
>
> theMono = 0xFFFFFFFFFFFFFFFF;
> mono.data[0] = (signedMono & 0x00000000FFFFFFFF);
> mono.data[1] = (signedMono & 0xFFFFFFFF00000000) >> 32;
> mono.sign = 1;
>
> It happliy sets the column value to 18446744073709551615.
How do you deduce that the column value is that? I suspect that if you
used DB-Access rather than your code, it would report -1. I also
suspect that if you wrote SELECT column_value FROM mystery_table
WHERE column_value = 18446744073709551615; you would get no data
returned, but if you filtered on -1, you would. As far as IDS is
concerned, the bit-pattern you generated is -1; your code may choose
to interpret it as 18446744073709551615, but the DBMS won't. (No, the
constant shouldn't overflow; it is just a big 20-digit DECIMAL
constant with zero scale (decimal places)).
> So suddenly I think it will just take my unsigned 64 bit number without any
> messing about finding out its value as a signed 64 bit etc...
>
> HOWEVER
>
> If I try the above with sign set to zero, I get a blank value in dbaccess,
Read the header int8.h. It says:
int2 sign; /* 0 = NULL, 1 = positive, -1 = negative */
So, when you set the sign to zero, you are telling the DBMS the value
is NULL, and DB-Access shows that as blank.
> if I then use -1 I still get a blank in dbaccess.
> If, however I use 1 I get the value described, 18446744073709551615, but if
> I THEN use -1, I get the same positive value.
>
> It seems to me that there is something more to the sign component than just
> setting the sign of the absolute value in data. Also there seems to be
> something more to the range than described in the guide.
In the SMALLINT (16-bit) and INT (32-bit) types, the ranges supported
by Informix are symmetric about 0:
-32767..+32767
There's a bit pattern not accounted for: 0x8000 = -32768 under signed
notation. You can't store that value in a SMALLINT column; at least,
not directly, but if you store a NULL, that bit pattern is used. The
corresponding bit pattern is 0x80000000 for 32-bit. If 64-bit
integers were stored on disk as I'd like, then they'd use the
corresponding pattern, 0x8000000000000000 (assuming I counted digits
correctly).
Andrew Hardy also asked:
>
> Ok!
>
> After some experimentation I now have code below. Looks like although the
> structure holds a 64 bit number you cannot use it to set an int8 column in
> the database with just any value you have to get the absolute value of your
> unsigned 64 as a twos compliment number as if it were signed set the data
> to that ( element 1 being the MS 32 bits!) then set the sign!
Yes - that's why I provided code for 'long long' and not 'unsigned
long long'.
> Why if int8 is provided is there no pre-provided wrapped way to do this?
See history lesson above. And short-sightedness. I'm still working
on getting this fixed (though I believe it is fixed but not
documented). I'm at home right now and can't verify that.
> Below seems to work, am I on the right track ?
Yes, you're on the right track, but it is simpler to create the
function so it takes a signed long long, and when you need to pass
your unsigned long long to it, you do so, relying on the compiler to
interpret your bit patterns for you. And your code would run into
problems with the 0x8000000000000000 value - because when you negate
it, you end up with the number you first thought of. That's a
peculiar property and asymmetry of 2's complement arithmetic.
> Many thanks again for all your help.
You're welcome.
> EXEC SQL BEGIN DECLARE SECTION;
> char sql_line[SQL_SIZE];
> int ip;
> int port;
> ifx_int8_t mono;
> EXEC SQL END DECLARE SECTION;
>
> unsigned long long theMono;
> long long signedMono;
>
> ip = 100;
> port = 100;
>
> theMono = 0xF0F0F0F0F0F0F0F0;
>
> signedMono = theMono;
> if ( signedMono < 0 )
> {
> signedMono = -signedMono;
> mono.data[0] = (signedMono & 0x00000000FFFFFFFF);
> mono.data[1] = (signedMono & 0xFFFFFFFF00000000) >> 32;
> mono.sign = -1;
> }
> else
> {
> mono.data[0] = (signedMono & 0x00000000FFFFFFFF);
> mono.data[1] = (signedMono & 0xFFFFFFFF00000000) >> 32;
> mono.sign = 1;
> }
>
> etc, etc, etc.......................
Andrew Hardy also (and earlier) asked:
>
> Sorry to be a pain, my question was actually about converting an unsigned
> long long TO an int8.
Covered above.
> For that, would I do something like the code below then ?
> What sign would I set ?
> What is the difference between int8 and ifx_int8_t ?
INT8 is the name in SQL; ifx_int8_t is the name in ESQL/C.
> Thanks again for your help.
> void someSQLFunction()
> {
> EXEC SQL BE