help defining a basic type operator

Started by Luca Ferrariover 7 years ago4 messagesgeneral
Jump to latest
#1Luca Ferrari
fluca1978@gmail.com

Hi all,
I'm trying to define a custom data type that would represent a number
of bytes in a lossy human way.
The type is defined as:

typedef struct HFSize
{
double size;
int scaling;
} HFSize;

and the operator function is defined as:

Datum
hfsize_add(PG_FUNCTION_ARGS)
{

HFSize *first = (HFSize *) PG_GETARG_POINTER(0);
HFSize *second = (HFSize *) PG_GETARG_POINTER(1);
HFSize *sum = new_HFSize();

to_bytes( first );
to_bytes( second );

elog( DEBUG1, "sum %s + %s ", to_string( first ), to_string( second ) );
sum->size = first->size + second->size;

elog( DEBUG1, "Final sum %s ", to_string( sum ) );
PG_RETURN_POINTER( sum );
}

The problem is that, even if the last elog shows a correct result, the
final value returned via PG_RETURN_POINTER is something totally
different with the double value set to zero and an apparently random
'scaling':

# set client_min_messages to debug;
SET
testdb=# SELECT '1030'::hfsize + '2030'::hfsize;
DEBUG: Converting to human text format 1030.00-bytes
LINE 1: SELECT '1030'::hfsize + '2030'::hfsize;
^
DEBUG: Converting to human text format 2030.00-bytes
LINE 1: SELECT '1030'::hfsize + '2030'::hfsize;
^
DEBUG: sum 1030.00-bytes + 2030.00-bytes
DEBUG: Final sum 3060.00-bytes
?column?
----------
0.00-64

I've tried also to return one of the two operands from the add
function, so something like:
Datum
hfsize_add(PG_FUNCTION_ARGS)
{

HFSize *first = (HFSize *) PG_GETARG_POINTER(0);
HFSize *second = (HFSize *) PG_GETARG_POINTER(1);
PG_RETURN_POINTER( first );
}

but again the result has a zero value and a random scaling, and most
notably is not the first operand. Also memory addresses (used with %x)
are different from inside and outside the add function.
Is there something I'm missing?

Thanks,
Luca

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Luca Ferrari (#1)
Re: help defining a basic type operator

Luca Ferrari <fluca1978@gmail.com> writes:

I'm trying to define a custom data type that would represent a number
of bytes in a lossy human way.

You did not show us the SQL definition of the type. I don't see anything
obviously wrong in what you showed (other than hfsize_add not setting the
result's scaling), so the problem is somewhere else. Given this C
declaration, the type probably needs to be size 16, double alignment,
pass-by-reference; maybe you messed up part of that?

HFSize *sum = new_HFSize();

What is new_HFSize?

regards, tom lane

#3Luca Ferrari
fluca1978@gmail.com
In reply to: Tom Lane (#2)
Re: help defining a basic type operator

On Mon, Aug 20, 2018 at 4:51 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:

Luca Ferrari <fluca1978@gmail.com> writes:

I'm trying to define a custom data type that would represent a number
of bytes in a lossy human way.

You did not show us the SQL definition of the type. I don't see anything
obviously wrong in what you showed (other than hfsize_add not setting the
result's scaling), so the problem is somewhere else. Given this C
declaration, the type probably needs to be size 16, double alignment,
pass-by-reference; maybe you messed up part of that?

Shame on me: when I issued a create type I didn't realize that I was
miswriting the length attribute from 'internallength' to
'internalsize', and while an error was reported, the type was created.
Fixing the type creation into:

CREATE TYPE hfsize (
internallength = 16,
input = hfsize_input_function,
output = hfsize_output_function
);

solved the problem, so it was a length mismatch.

HFSize *sum = new_HFSize();

What is new_HFSize?

An helper function to allocate a new object (and that was why scaling
did not get referenced in the add function):

HFSize*
new_HFSize()
{
HFSize *size = (HFSize*) palloc( sizeof( HFSize ) );
size->scaling = 0;
size->size = 0.0f;
return size;
}

Thanks,
Luca

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Luca Ferrari (#3)
Re: help defining a basic type operator

Luca Ferrari <fluca1978@gmail.com> writes:

Fixing the type creation into:

CREATE TYPE hfsize (
internallength = 16,
input = hfsize_input_function,
output = hfsize_output_function
);

solved the problem, so it was a length mismatch.

You really need to specify double alignment too; IIRC the default
assumption is only "int" alignment. Intel processors will usually let you
get away with being sloppy about that, but it's still wrong (and there
*are* cases where Intel will complain too).

regards, tom lane