pgstream-0.1.0.3: cbits/array_conversion.c
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <arpa/inet.h>
#include <postgresql/libpq-fe.h>
#define INT4OID 23
#define FLOAT4OID 700
#define FLOAT8OID 701
#define NUMERICOID 1700
// XXX: Check endianness problems on OS X? Production is invariable Linux so
// probably shouldn't matter.
// int4[]
struct array_int4 {
int32_t ndim;
int32_t _ign;
Oid elemtype;
int32_t size;
int32_t index;
int32_t data;
};
// float4[]
struct array_float {
int32_t ndim;
int32_t _ign;
Oid elemtype;
int32_t size;
int32_t index;
float data;
};
// float4[]
struct array_double {
int32_t ndim;
int32_t _ign;
Oid elemtype;
int32_t size;
int32_t index;
double data;
};
// Postgres binary uses network byte order, we have to swap the bytes for the
// floating point values.
static inline float swap( const float inFloat )
{
float retVal;
char *in = ( char * ) & inFloat;
char *out = ( char * ) & retVal;
out[0] = in[3];
out[1] = in[2];
out[2] = in[1];
out[3] = in[0];
return retVal;
}
#define INT_SEP -1
int extract_int4_array (char *raw_array, int32_t *values, int size)
{
struct array_int4 *array = (struct array_int4 *) raw_array;
int32_t *val = &(array->data);
int32_t ival;
if (ntohl(array->ndim) != 1 || ntohl(array->elemtype) != INT4OID) {
return -1;
}
int array_elements = ntohl(array->size);
int n = 0;
val = &(array->data);
for (int i = 0; i < array_elements; ++i) {
ival = ntohl (*val);
if (ival != INT_SEP) {
++val;
values[n] = ntohl(*val);
n += 1;
}
++val;
}
return size;
}
#define FLOAT_SEP 6.0e-45
int extract_float_array(char *raw_array, float *values, int size)
{
struct array_float *array = (struct array_float *) raw_array;
float *val = &(array->data);
int32_t ival;
if (ntohl(array->ndim) != 1 || ntohl(array->elemtype) != FLOAT4OID) {
return -1;
}
int array_elements = ntohl(array->size);
int n = 0;
val = &(array->data);
for (int i = 0; i < array_elements; ++i) {
ival = swap(*val);
if (ival != FLOAT_SEP) {
++val;
values[n] = swap(*val);
n += 1;
}
++val;
}
return size;
}
#define DOUBLE_SEP 6.0e-45
int extract_double_array(char *raw_array, double *values, int size)
{
struct array_double *array = (struct array_double *) raw_array;
double *val = &(array->data);
int32_t ival;
if (ntohl(array->ndim) != 1 || ntohl(array->elemtype) != FLOAT8OID) {
return -1;
}
int array_elements = ntohl(array->size);
int n = 0;
val = &(array->data);
for (int i = 0; i < array_elements; ++i) {
ival = swap(*val);
if (ival != DOUBLE_SEP) {
++val;
values[n] = swap(*val);
n += 1;
}
++val;
}
return size;
}