Skip to content
Open
37 changes: 20 additions & 17 deletions defined_units.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,30 @@ const char *base_units[N_UNITS] = {
"mol",
"cd",
"B",
"cycle",
"pixel",
};

/* Compromise: Allow the rational exponents but don't use more storage: 1, n/2, n/4 */
const struct derived_unit_t si_derived_units[] = { /* https://en.wikipedia.org/wiki/International_System_of_Units#Derived_units */
/* The second is part of this table so we can easily detect its usage for printing it using the hh:mm:ss syntax */
{ "s", { 0, 0, 1, 0, 0, 0, 0, 0,} }, /* second time s */
{ "Hz", { 0, 0, -1, 0, 0, 0, 0, 0,} }, /* hertz frequency s^-1 */
{ "N", { 1, 1, -2, 0, 0, 0, 0, 0,} }, /* newton force, weight kg·m·s^-2 */
{ "Pa", { -1, 1, -2, 0, 0, 0, 0, 0,} }, /* pascal pressure, stress N/m^2 kg·m^-1·s^-2 */
{ "J", { 2, 1, -2, 0, 0, 0, 0, 0,} }, /* joule energy, work, heat N·m kg·m^2·s^-2 */
{ "W", { 2, 1, -3, 0, 0, 0, 0, 0,} }, /* watt power, radiant flux J/s kg·m^2·s^-3 */
{ "C", { 0, 0, 1, 1, 0, 0, 0, 0,} }, /* coulomb electric charge s·A */
{ "V", { 2, 1, -3, -1, 0, 0, 0, 0,} }, /* volt voltage W/A kg·m^2·s^-3·A^-1 */
{ "F", { -2, -1, 4, 2, 0, 0, 0, 0,} }, /* farad electric capacitance C/V kg^-1·m^-2·s^4·A^2 */
{ "Ω", { 2, 1, -3, -2, 0, 0, 0, 0,} }, /* ohm electric resistance, impedance V/A kg·m^2·s^-3·A^-2 */
{ "S", { -2, -1, 3, 2, 0, 0, 0, 0,} }, /* siemens electrical conductance A/V kg^-1·m^-2·s^3·A^2 */
{ "Wb", { 2, 1, -2, -1, 0, 0, 0, 0,} }, /* weber magnetic flux V·s kg·m^2·s^-2·A^-1 */
{ "T", { 0, 1, -2, -1, 0, 0, 0, 0,} }, /* tesla magnetic flux density Wb/m^2 kg·s^-2·A^-1 */
{ "H", { 2, 1, -2, -2, 0, 0, 0, 0,} }, /* henry inductance Wb/A kg·m^2·s^-2·A^-2 */
{ "lx", { -2, 0, 0, 0, 0, 0, 1, 0,} }, /* lux illuminance lm/m^2 m^-2·cd */
{ "Gy", { 2, 0, -2, 0, 0, 0, 0, 0,} }, /* gray absorbed dose (of ionizing radiation) J/kg m^2·s^-2 */
{ "kat", { 0, 0, -1, 0, 0, 1, 0, 0,} }, /* katal catalytic activity mol·s^-1 */
{ "s", { 0*ONES_DIGIT, 0*ONES_DIGIT, 1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* second time s */
{ "Hz", { 0*ONES_DIGIT, 0*ONES_DIGIT, -1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 1*ONES_DIGIT, 0*ONES_DIGIT}, }, /* hertz frequency s^-1 */
{ "N", { 1*ONES_DIGIT, 1*ONES_DIGIT, -2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* newton force, weight kg·m·s^-2 */
{ "Pa", {-1*ONES_DIGIT, 1*ONES_DIGIT, -2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* pascal pressure, stress N/m^2 kg·m^-1·s^-2 */
{ "J", { 2*ONES_DIGIT, 1*ONES_DIGIT, -2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* joule energy, work, heat N·m kg·m^2·s^-2 */
{ "W", { 2*ONES_DIGIT, 1*ONES_DIGIT, -3*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* watt power, radiant flux J/s kg·m^2·s^-3 */
{ "C", { 0*ONES_DIGIT, 0*ONES_DIGIT, 1*ONES_DIGIT, 1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* coulomb electric charge s·A */
{ "V", { 2*ONES_DIGIT, 1*ONES_DIGIT, -3*ONES_DIGIT, -1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* volt voltage W/A kg·m^2·s^-3·A^-1 */
{ "F", {-2*ONES_DIGIT, -1*ONES_DIGIT, 4*ONES_DIGIT, 2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* farad electric capacitance C/V kg^-1·m^-2·s^4·A^2 */
{ "Ω", { 2*ONES_DIGIT, 1*ONES_DIGIT, -3*ONES_DIGIT, -2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* ohm electric resistance, impedance V/A kg·m^2·s^-3·A^-2 */
{ "S", {-2*ONES_DIGIT, -1*ONES_DIGIT, 3*ONES_DIGIT, 2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* siemens electrical conductance A/V kg^-1·m^-2·s^3·A^2 */
{ "Wb", { 2*ONES_DIGIT, 1*ONES_DIGIT, -2*ONES_DIGIT, -1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* weber magnetic flux V·s kg·m^2·s^-2·A^-1 */
{ "T", { 0*ONES_DIGIT, 1*ONES_DIGIT, -2*ONES_DIGIT, -1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* tesla magnetic flux density Wb/m^2 kg·s^-2·A^-1 */
{ "H", { 2*ONES_DIGIT, 1*ONES_DIGIT, -2*ONES_DIGIT, -2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* henry inductance Wb/A kg·m^2·s^-2·A^-2 */
{ "lx", {-2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* lux illuminance lm/m^2 m^-2·cd */
{ "Gy", { 2*ONES_DIGIT, 0*ONES_DIGIT, -2*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* gray absorbed dose (of ionizing radiation) J/kg m^2·s^-2 */
{ "kat",{ 0*ONES_DIGIT, 0*ONES_DIGIT, -1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 1*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT, 0*ONES_DIGIT}, }, /* katal catalytic activity mol·s^-1 */
{ 0 }
};

Expand Down
35 changes: 34 additions & 1 deletion unit--7.sql.in
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,13 @@ CREATE FUNCTION unit_send(unit)
AS '$libdir/unit'
LANGUAGE C IMMUTABLE STRICT;

CREATE FUNCTION unit_send_array(unit)
RETURNS double precision[]
AS '$libdir/unit'
LANGUAGE C IMMUTABLE STRICT;

CREATE TYPE unit (
internallength = 16,
internallength = 18,
input = unit_in,
output = unit_out,
receive = unit_recv,
Expand Down Expand Up @@ -141,6 +146,16 @@ CREATE FUNCTION byte(double precision DEFAULT 1.0)
AS '$libdir/unit', 'unit_byte'
LANGUAGE C IMMUTABLE STRICT;

CREATE FUNCTION cycle(double precision DEFAULT 1.0)
RETURNS unit
AS '$libdir/unit', 'unit_cycle'
LANGUAGE C IMMUTABLE STRICT;

CREATE FUNCTION pixel(double precision DEFAULT 1.0)
RETURNS unit
AS '$libdir/unit', 'unit_pixel'
LANGUAGE C IMMUTABLE STRICT;

-- functions without operators

CREATE FUNCTION value(unit)
Expand Down Expand Up @@ -311,6 +326,24 @@ CREATE FUNCTION unit_at_double(unit, text)
AS '$libdir/unit', 'unit_at_double'
LANGUAGE C IMMUTABLE STRICT;

CREATE FUNCTION unit_compatible(unit, text)
RETURNS boolean
SET search_path = @extschema@
AS '$libdir/unit', 'unit_compatible'
LANGUAGE C IMMUTABLE STRICT;

CREATE FUNCTION unit_smallest_pow()
RETURNS double precision
SET search_path = @extschema@
AS '$libdir/unit', 'unit_smallest_pow'
LANGUAGE C IMMUTABLE STRICT;

CREATE FUNCTION unit_valid(text)
RETURNS boolean
SET search_path = @extschema@
AS '$libdir/unit', 'unit_valid'
LANGUAGE C IMMUTABLE STRICT;

CREATE OPERATOR @@ (
leftarg = unit,
rightarg = text,
Expand Down
131 changes: 122 additions & 9 deletions unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ GNU General Public License for more details.

#include "postgres.h"
#include "fmgr.h"
#include "catalog/pg_type.h"
#include "libpq/pqformat.h" /* send/recv */
#include "utils/builtins.h" /* cstring_to_text (needed on 9.5) */
#include "utils/guc.h"
Expand Down Expand Up @@ -75,7 +76,7 @@ unit_get_definitions(void)
strlcpy(unit_name->name, base_units[i], UNIT_NAME_LENGTH);
unit_name->unit_shift.unit.value = 1.0;
memset(unit_name->unit_shift.unit.units, 0, N_UNITS);
unit_name->unit_shift.unit.units[i] = 1;
unit_name->unit_shift.unit.units[i] = ONES_DIGIT;
unit_name->unit_shift.shift = 0.0;
}
}
Expand Down Expand Up @@ -209,6 +210,20 @@ static char *superscripts[] = {
static void
print_exponent (char **output_p, int e)
{
/* Rational Exponent. Two least significant bits represent 1/2 and 1/4 .*/
if (ONES_DIGIT > 1 && abs(e)%ONES_DIGIT)
{
/* /2 or /4 */
*output_p += sprintf(*output_p,"^%.2f",e/((double)ONES_DIGIT));
return;
}

/* Integer Exponent */
e /= ONES_DIGIT;
if(e == 1)
{
return;
}
if (unit_output_superscript) {
char ascii_exp[5];
int i = 0;
Expand Down Expand Up @@ -571,6 +586,30 @@ unit_send(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}

PG_FUNCTION_INFO_V1(unit_send_array);

Datum
unit_send_array(PG_FUNCTION_ARGS)
{
int i;
Unit *unit = (Unit *) PG_GETARG_POINTER(0);
Datum values[1 + N_UNITS];
ArrayType *result;


/* 0 element is the value */
values[0] = Float8GetDatum(unit->value);

/* Rest are double values the represent the power */
for(i = 1; i < N_UNITS + 1; ++i)
{
values[i] = Float8GetDatum((double)unit->units[i-1]/ONES_DIGIT);
}

result = construct_array(values, 1 + N_UNITS, FLOAT8OID, 8, true, 'd');
PG_RETURN_POINTER(result);
}

/* constructors */

PG_FUNCTION_INFO_V1 (dbl2unit);
Expand All @@ -594,7 +633,7 @@ unit_meter (PG_FUNCTION_ARGS)

result = (Unit *) palloc0(sizeof(Unit));
result->value = PG_GETARG_FLOAT8(0);
result->units[UNIT_m] = 1;
result->units[UNIT_m] = ONES_DIGIT;
PG_RETURN_POINTER(result);
}

Expand All @@ -607,7 +646,7 @@ unit_kilogram (PG_FUNCTION_ARGS)

result = (Unit *) palloc0(sizeof(Unit));
result->value = PG_GETARG_FLOAT8(0);
result->units[UNIT_kg] = 1;
result->units[UNIT_kg] = ONES_DIGIT;
PG_RETURN_POINTER(result);
}

Expand All @@ -620,7 +659,7 @@ unit_second (PG_FUNCTION_ARGS)

result = (Unit *) palloc0(sizeof(Unit));
result->value = PG_GETARG_FLOAT8(0);
result->units[UNIT_s] = 1;
result->units[UNIT_s] = ONES_DIGIT;
PG_RETURN_POINTER(result);
}

Expand All @@ -633,7 +672,7 @@ unit_ampere (PG_FUNCTION_ARGS)

result = (Unit *) palloc0(sizeof(Unit));
result->value = PG_GETARG_FLOAT8(0);
result->units[UNIT_A] = 1;
result->units[UNIT_A] = ONES_DIGIT;
PG_RETURN_POINTER(result);
}

Expand All @@ -646,7 +685,7 @@ unit_kelvin (PG_FUNCTION_ARGS)

result = (Unit *) palloc0(sizeof(Unit));
result->value = PG_GETARG_FLOAT8(0);
result->units[UNIT_K] = 1;
result->units[UNIT_K] = ONES_DIGIT;
PG_RETURN_POINTER(result);
}

Expand All @@ -659,7 +698,7 @@ unit_mole (PG_FUNCTION_ARGS)

result = (Unit *) palloc0(sizeof(Unit));
result->value = PG_GETARG_FLOAT8(0);
result->units[UNIT_mol] = 1;
result->units[UNIT_mol] = ONES_DIGIT;
PG_RETURN_POINTER(result);
}

Expand All @@ -672,7 +711,7 @@ unit_candela (PG_FUNCTION_ARGS)

result = (Unit *) palloc0(sizeof(Unit));
result->value = PG_GETARG_FLOAT8(0);
result->units[UNIT_cd] = 1;
result->units[UNIT_cd] = ONES_DIGIT;
PG_RETURN_POINTER(result);
}

Expand All @@ -685,7 +724,33 @@ unit_byte (PG_FUNCTION_ARGS)

result = (Unit *) palloc0(sizeof(Unit));
result->value = PG_GETARG_FLOAT8(0);
result->units[UNIT_B] = 1;
result->units[UNIT_B] = ONES_DIGIT;
PG_RETURN_POINTER(result);
}

PG_FUNCTION_INFO_V1 (unit_cycle);

Datum
unit_cycle (PG_FUNCTION_ARGS)
{
Unit *result;

result = (Unit *) palloc0(sizeof(Unit));
result->value = PG_GETARG_FLOAT8(0);
result->units[UNIT_cycle] = ONES_DIGIT;
PG_RETURN_POINTER(result);
}

PG_FUNCTION_INFO_V1 (unit_pixel);

Datum
unit_pixel (PG_FUNCTION_ARGS)
{
Unit *result;

result = (Unit *) palloc0(sizeof(Unit));
result->value = PG_GETARG_FLOAT8(0);
result->units[UNIT_pixel] = ONES_DIGIT;
PG_RETURN_POINTER(result);
}

Expand Down Expand Up @@ -1065,6 +1130,54 @@ unit_at_double(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8((a->value - bu.shift) / bu.unit.value);
}


PG_FUNCTION_INFO_V1(unit_compatible);
Datum
unit_compatible(PG_FUNCTION_ARGS)
{
Unit *a = (Unit *) PG_GETARG_POINTER(0);
char *b = text_to_cstring(PG_GETARG_TEXT_PP(1));
UnitShift bu;
if (unit_parse(b, &bu) > 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for unit: \"%s\", %s",
b, yyerrstr)));
PG_RETURN_BOOL(memcmp(a->units, bu.unit.units, N_UNITS)==0);
}

PG_FUNCTION_INFO_V1(unit_smallest_pow);
Datum
unit_smallest_pow(PG_FUNCTION_ARGS)
{
PG_RETURN_FLOAT8(1.0/ONES_DIGIT);
}


PG_FUNCTION_INFO_V1 (unit_valid);

Datum
unit_valid (PG_FUNCTION_ARGS)
{
char *str = text_to_cstring(PG_GETARG_TEXT_PP(0));
UnitShift result;
bool parse_error_p;

PG_TRY();
{
parse_error_p = unit_parse(str, &result) <= 0;
}
PG_CATCH();
{
parse_error_p = false;
FlushErrorState();
}
PG_END_TRY();

PG_RETURN_BOOL(parse_error_p);
}


/* comparisons */

static int
Expand Down
24 changes: 14 additions & 10 deletions unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@
#include <utils/hsearch.h>

/* indices */
#define UNIT_m 0 /* meter */
#define UNIT_kg 1 /* kilogram */
#define UNIT_s 2 /* second */
#define UNIT_A 3 /* ampere */
#define UNIT_K 4 /* kelvin */
#define UNIT_mol 5 /* mole */
#define UNIT_cd 6 /* candela */
#define UNIT_B 7 /* byte */

#define N_UNITS 8
#define UNIT_m 0 /* meter */
#define UNIT_kg 1 /* kilogram */
#define UNIT_s 2 /* second */
#define UNIT_A 3 /* ampere */
#define UNIT_K 4 /* kelvin */
#define UNIT_mol 5 /* mole */
#define UNIT_cd 6 /* candela */
#define UNIT_B 7 /* byte */
#define UNIT_cycle 8 /* cycle */
#define UNIT_pixel 9 /* pixel */

#define N_UNITS 10

#define ONES_DIGIT (1<<2)

/* defined units */

Expand Down
Loading