Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion sql/pgmp.pysql
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ CREATE TYPE mpz (
func('mpz', 'text int4', 'mpz', cname='pmpz_in_base')
func('text', 'mpz int4', 'cstring', cname='pmpz_out_base')

func('mpz_2c', 'bytea', 'mpz', cname='pmpz_from_bytea_signed')

!! PYOFF


Expand Down Expand Up @@ -118,6 +120,7 @@ castfrom('int8', implicit='I')
castfrom('float4', implicit='A')
castfrom('float8', implicit='A')
castfrom('numeric', implicit='A')
castfrom('bytea', implicit='A')

def castto(typname, implicit=False):
"""Create a cast from `base_type` to a different type"""
Expand All @@ -134,6 +137,7 @@ castto('int4', implicit='A')
castto('int2', implicit='A')
castto('float4', implicit='A')
castto('float8', implicit='A')
castto('bytea', implicit='A')

!! PYOFF

Expand Down Expand Up @@ -288,7 +292,7 @@ CREATE OPERATOR <> (

def bop(sym, fname, comm, neg):
"""Create an operator on `base_type` returning a bool"""
func('%s_%s' % (base_type, fname),
func('%s_%s' % (base_type, fname),
base_type + " " + base_type, argout='boolean')
fname1 = fname[0] + 't'

Expand Down
124 changes: 124 additions & 0 deletions src/pmpz_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,3 +390,127 @@ PGMP_PG_FUNCTION(pmpz_to_float8)
PG_RETURN_FLOAT8((float8)out);
}

PGMP_PG_FUNCTION(pmpz_from_bytea)
{
bytea *data = PG_GETARG_BYTEA_PP(0);
int data_len = VARSIZE_ANY_EXHDR(data);
char *data_body = VARDATA_ANY(data);
mpz_t result_z;

mpz_init(result_z);

if(data_len == 0) {
PGMP_RETURN_MPZ(result_z);
}

if(!(data_len & 7)) {
mpz_import(result_z, data_len / 8, 1, 8, 1, 0, (uint64_t *)data_body);
} else if(!(data_len & 3)) {
mpz_import(result_z, data_len / 4, 1, 4, 1, 0, (uint32_t *)data_body);
} else if(!(data_len & 1)) {
mpz_import(result_z, data_len / 2, 1, 2, 1, 0, (uint16_t *)data_body);
} else {
mpz_import(result_z, data_len, 1, 1, 1, 0, data_body);
}

PGMP_RETURN_MPZ(result_z);
}

PGMP_PG_FUNCTION(pmpz_from_bytea_signed)
{
bytea *data = PG_GETARG_BYTEA_PP(0);
int data_len = VARSIZE_ANY_EXHDR(data);
char *data_body = VARDATA_ANY(data);
char *data_buf;
bool is_neg;
mpz_t result_z;

mpz_init(result_z);

if(data_len == 0) {
PGMP_RETURN_MPZ(result_z);
}

is_neg = data_body[0] & 0x80;

if(is_neg) {
data_buf = palloc(data_len);

if(!(data_len & 7)) {
size_t limbs_count = data_len / 8;
uint64_t *limbs_in = (uint64_t *)data_body;
uint64_t *limbs_out = (uint64_t *)data_buf;
for(size_t i = 0; i < limbs_count; i++) {
limbs_out[i] = ~(limbs_in[i]);
}
} else if(!(data_len & 3)) {
size_t limbs_count = data_len / 4;
uint32_t *limbs_in = (uint32_t *)data_body;
uint32_t *limbs_out = (uint32_t *)data_buf;
for(size_t i = 0; i < limbs_count; i++) {
limbs_out[i] = ~(limbs_in[i]);
}
} else if(!(data_len & 1)) {
size_t limbs_count = data_len / 2;
uint16_t *limbs_in = (uint16_t *)data_body;
uint16_t *limbs_out = (uint16_t *)data_buf;
for(size_t i = 0; i < limbs_count; i++) {
limbs_out[i] = ~(limbs_in[i]);
}
} else {
for(size_t i = 0; i < data_len; i++) {
data_buf[i] = ~(data_body[i]);
}
}
} else {
data_buf = data_body;
}

if(!(data_len & 7)) {
mpz_import(result_z, data_len / 8, 1, 8, 1, 0, (uint64_t *)data_buf);
} else if(!(data_len & 3)) {
mpz_import(result_z, data_len / 4, 1, 4, 1, 0, (uint32_t *)data_buf);
} else if(!(data_len & 1)) {
mpz_import(result_z, data_len / 2, 1, 2, 1, 0, (uint16_t *)data_buf);
} else {
mpz_import(result_z, data_len, 1, 1, 1, 0, data_buf);
}

if (is_neg) {
pfree(data_buf);

mpz_add_ui(result_z, result_z, 1);
mpz_neg(result_z, result_z);
}

PGMP_RETURN_MPZ(result_z);
}

PGMP_PG_FUNCTION(pmpz_to_bytea)
{
const mpz_t z;
bytea *result;
char *result_body_u8;
int body_len;

PGMP_GETARG_MPZ(z, 0);

body_len = (mpz_sizeinbase(z, 16) + 1) / 2;

result = malloc(VARHDRSZ + body_len);
result_body_u8 = VARDATA(result);

if(!(body_len & 7)) {
mpz_export((uint64_t *)result_body_u8, NULL, 1, 8, 1, 0, z);
} else if(!(body_len & 3)) {
mpz_export((uint32_t *)result_body_u8, NULL, 1, 4, 1, 0, z);
} else if(!(body_len & 1)) {
mpz_export((uint16_t *)result_body_u8, NULL, 1, 2, 1, 0, z);
} else {
mpz_export(result_body_u8, NULL, 1, 1, 1, 0, z);
}

SET_VARSIZE(result, VARHDRSZ + body_len);

PG_RETURN_BYTEA_P(result);
}