From 0c3b6e670a0b3616bb0b04592c53cdb9fbab549f Mon Sep 17 00:00:00 2001 From: "Thomas G. Lockhart" Date: Sat, 17 May 1997 14:24:09 +0000 Subject: [PATCH] Initial 64-bit integer package. --- contrib/int8/Makefile | 64 +++++++++ contrib/int8/README | 101 +++++++++++++ contrib/int8/int8.c | 361 +++++++++++++++++++++++++++++++++++++++++++++++ contrib/int8/int8.source | 288 +++++++++++++++++++++++++++++++++++++ contrib/int8/itest.sql | 27 ++++ 5 files changed, 841 insertions(+) create mode 100644 contrib/int8/Makefile create mode 100644 contrib/int8/README create mode 100644 contrib/int8/int8.c create mode 100644 contrib/int8/int8.source create mode 100644 contrib/int8/itest.sql diff --git a/contrib/int8/Makefile b/contrib/int8/Makefile new file mode 100644 index 0000000000..13528fc185 --- /dev/null +++ b/contrib/int8/Makefile @@ -0,0 +1,64 @@ +#------------------------------------------------------------------------- +# +# Makefile-- +# Makefile for Postgres 64-bit integer extensions +# +# Thomas G. Lockhart +# +# This is a first attempt at 64-bit arithmetic for Postgres. +# It takes advantage of "long long int" support in GNU C on 32-bit machines. +# The modules are built and installed as user-defined types, +# so destination directories are pointing away from the standard +# Postgres areas. You will need to modify the paths to fit your machine. +# +# On my Linux box, I had to find an extra library for the division function (?). +# For Alpha boxes, both the DEC and GNU compilers should need "long int" only. +# +#------------------------------------------------------------------------- + +ifndef PGDIR +PGDIR= /opt/postgres/current +endif + +SRCDIR= $(PGDIR)/src + +include $(SRCDIR)/Makefile.global + +# Comment out this re-declaration of LIBDIR +# if you are installing as the postgres superuser +# into a specific database or into template1. +LIBDIR= /home/tgl/lib + +CFLAGS+= -I$(PGDIR)/include -I$(PGDIR)/src/include -I$(LIBPQDIR) + +# This extra library is for the 64-bit division routine on my Linux box +# and probably will need to be commented-out for most other platforms. +CLIBS+= /usr/lib/gcc-lib/i486-linux/2.7.2/libgcc.a + +TARGETS= int8.sql int8$(DLSUFFIX) + +all: $(TARGETS) + +int8$(DLSUFFIX): int8.o + $(CC) -shared -o int8$(DLSUFFIX) int8.o $(CLIBS) + +install: + $(MAKE) all + cp -p int8$(DLSUFFIX) $(LIBDIR) + +%.sql: %.source + if [ -z "$$USER" ]; then USER=$$LOGNAME; fi; \ + if [ -z "$$USER" ]; then USER=`whoami`; fi; \ + if [ -z "$$USER" ]; then echo 'Cannot deduce $$USER.'; exit 1; fi; \ + rm -f $@; \ + C=`pwd`; \ + O=$C; \ + if [ -d ${LIBDIR} ]; then O=${LIBDIR}; fi; \ + sed -e "s:_CWD_:$$C:g" \ + -e "s:_OBJWD_:$$O:g" \ + -e "s:_DLSUFFIX_:$(DLSUFFIX):g" \ + -e "s/_USER_/$$USER/g" < $< > $@ + +clean: + rm -f $(TARGETS) int8.o + diff --git a/contrib/int8/README b/contrib/int8/README new file mode 100644 index 0000000000..7d52370f68 --- /dev/null +++ b/contrib/int8/README @@ -0,0 +1,101 @@ + Postgres int8 + +Thomas G. Lockhart + +This is a first attempt at 64-bit integer arithmetic for Postgres. The code +should support any 64-bit architecture and any 32-bit machine using a recent +GNU C compiler. At the moment, DEC-Alpha and Linux/gcc are explicitly +supported. The code uses "long long int" support in GNU C on 32-bit machines. +This type is an extension to ANSI-C, and may not appear on any other compiler. + +The modules are built and installed as user-defined types, so destination + directories are pointing away from the standard Postgres areas. + +Other compilers and architectures should be supportable, so please let me know +what changes were required to run on your machine, and I will fold those into +this standard distribution. + +Good luck! + + - Tom + + + Installation + +You will need to modify the Makefile paths to fit your machine. Since this +is packaged as a "user-installable" type, the libraries and source code +can reside outside of the standard Postgres areas. + +If you are compiling on a DEC-Alpha, then the code might compile +and run without change. (I do a lot of code development on Alphas, +but do not have a Postgres installation to test). + + make + make install + psql dbname < int8.sql + +If you are running gcc on a 32-bit machine, you will probably need to: + - remove the extra library reference in the Makefile. + - if there are unresolved symbols when you try running, then find + the right library. The one I had chosen might be a clue. + +If you are not running gcc on a 32-bit machine, you will need to: + - redeclare the 64 bit data type. + - modify the scanf and printf() arguments to use the appropriate + 64-bit int arguments. + +On my Linux box, I had to find an extra library for the division function. +For Alpha boxes, both the DEC and GNU compilers should need "long int" only. +I have a reference to "__alpha" in the C source code, but have not tested it + and am not certain that this is the correct pre-defined symbol for that machine. + +itest.sql is a small test file which exercises some of the I/O, functions, + and boolean operators. + +int8: + = + <> + < + > + <= + >= + + - unary minus + + addition + - subtraction + * multiplication + / division + + int4() convert to 4-byte integer + float8() convert to double float + +Routines defined are: + +int64 *int8in(char *str); +char *int8out(int64 *val); + +bool int8eq(int64 *val1, int64 *val2); +bool int8ne(int64 *val1, int64 *val2); +bool int8lt(int64 *val1, int64 *val2); +bool int8gt(int64 *val1, int64 *val2); +bool int8le(int64 *val1, int64 *val2); +bool int8ge(int64 *val1, int64 *val2); + +bool int84eq(int64 *val1, int32 val2); +bool int84ne(int64 *val1, int32 val2); +bool int84lt(int64 *val1, int32 val2); +bool int84gt(int64 *val1, int32 val2); +bool int84le(int64 *val1, int32 val2); +bool int84ge(int64 *val1, int32 val2); + +int64 *int8um(int64 *val); +int64 *int8pl(int64 *val1, int64 *val2); +int64 *int8mi(int64 *val1, int64 *val2); +int64 *int8mul(int64 *val1, int64 *val2); +int64 *int8div(int64 *val1, int64 *val2); + +int64 *int48(int32 val); +int32 int84(int64 *val); + +int64 *dtoi8(float8 *val); +float8 *i8tod(int64 *val); diff --git a/contrib/int8/int8.c b/contrib/int8/int8.c new file mode 100644 index 0000000000..93822cb480 --- /dev/null +++ b/contrib/int8/int8.c @@ -0,0 +1,361 @@ +/*------------------------------------------------------------------------- + * + * int8.c-- + * Internal 64-bit integer operations + * + *------------------------------------------------------------------------- + */ +#include /* for sprintf proto, etc. */ +#include /* for strtod, etc. */ +#include +#include +#include +#include +#include +#include + +#include "postgres.h" +#include "utils/palloc.h" + +#define MAXINT8LEN 25 + +#define USE_LOCAL_CODE 1 + +#if defined(__alpha) || defined(__GNUC__) +#define HAVE_64BIT_INTS 1 +#endif + +#ifndef HAVE_64BIT_INTS +typedef char[8] int64; + +#elif defined(__alpha) +typedef long int int64; +#define INT64_FORMAT "%ld" + +#elif defined(__GNUC__) +typedef long long int int64; +#define INT64_FORMAT "%Ld" + +#else +typedef long int int64; +#define INT64_FORMAT "%ld" +#endif + +int64 *int8in(char *str); +char *int8out(int64 *val); + +bool int8eq(int64 *val1, int64 *val2); +bool int8ne(int64 *val1, int64 *val2); +bool int8lt(int64 *val1, int64 *val2); +bool int8gt(int64 *val1, int64 *val2); +bool int8le(int64 *val1, int64 *val2); +bool int8ge(int64 *val1, int64 *val2); + +bool int84eq(int64 *val1, int32 val2); +bool int84ne(int64 *val1, int32 val2); +bool int84lt(int64 *val1, int32 val2); +bool int84gt(int64 *val1, int32 val2); +bool int84le(int64 *val1, int32 val2); +bool int84ge(int64 *val1, int32 val2); + +int64 *int8um(int64 *val); +int64 *int8pl(int64 *val1, int64 *val2); +int64 *int8mi(int64 *val1, int64 *val2); +int64 *int8mul(int64 *val1, int64 *val2); +int64 *int8div(int64 *val1, int64 *val2); + +int64 *int48(int32 val); +int32 int84(int64 *val); +#if FALSE +int64 *int28(int16 val); +int16 int82(int64 *val); +#endif + +float64 i8tod(int64 *val); +int64 *dtoi8(float64 val); + +#if USE_LOCAL_CODE + +#ifndef PALLOC +#define PALLOC(p) palloc(p) +#endif + +#ifndef PALLOCTYPE +#define PALLOCTYPE(p) palloc(sizeof(p)) +#endif + +#endif + +/*********************************************************************** + ** + ** Routines for 64-bit integers. + ** + ***********************************************************************/ + +/*---------------------------------------------------------- + * Formatting and conversion routines. + *---------------------------------------------------------*/ + +/* int8in() + */ +int64 *int8in(char *str) +{ + int64 *result = PALLOCTYPE(int64); + +#if HAVE_64BIT_INTS + if (!PointerIsValid(str)) + elog (WARN,"Bad (null) int8 external representation",NULL); + + if (sscanf(str, INT64_FORMAT, result) != 1) + elog(WARN,"Bad int8 external representation '%s'",str); + +#else + elog(WARN,"64-bit integers are not supported",NULL); + result = NULL; +#endif + + return(result); +} /* int8in() */ + + +/* int8out() + */ +char *int8out(int64 *val) +{ + char *result; + + int len; + char buf[MAXINT8LEN+1]; + +#if HAVE_64BIT_INTS + if (!PointerIsValid(val)) + return(NULL); + + if ((len = snprintf( buf, MAXINT8LEN, INT64_FORMAT, *val)) < 0) + elog (WARN,"Unable to format int8",NULL); + + result = PALLOC(len+1); + + strcpy(result, buf); + +#else + elog(WARN,"64-bit integers are not supported",NULL); + result = NULL; +#endif + + return( result); +} /* int8out() */ + + +/*---------------------------------------------------------- + * Relational operators for int8s. + *---------------------------------------------------------*/ + +/* int8relop() + * Is val1 relop val2? + */ +bool int8eq(int64 *val1, int64 *val2) +{ + return(*val1 == *val2); +} /* int8eq() */ + +bool int8ne(int64 *val1, int64 *val2) +{ + return(*val1 != *val2); +} /* int8ne() */ + +bool int8lt(int64 *val1, int64 *val2) +{ + return(*val1 < *val2); +} /* int8lt() */ + +bool int8gt(int64 *val1, int64 *val2) +{ + return(*val1 > *val2); +} /* int8gt() */ + +bool int8le(int64 *val1, int64 *val2) +{ + return(*val1 <= *val2); +} /* int8le() */ + +bool int8ge(int64 *val1, int64 *val2) +{ + return(*val1 >= *val2); +} /* int8ge() */ + + +/* int84relop() + * Is 64-bit val1 relop 32-bit val2? + */ +bool int84eq(int64 *val1, int32 val2) +{ + return(*val1 == val2); +} /* int84eq() */ + +bool int84ne(int64 *val1, int32 val2) +{ + return(*val1 != val2); +} /* int84ne() */ + +bool int84lt(int64 *val1, int32 val2) +{ + return(*val1 < val2); +} /* int84lt() */ + +bool int84gt(int64 *val1, int32 val2) +{ + return(*val1 > val2); +} /* int84gt() */ + +bool int84le(int64 *val1, int32 val2) +{ + return(*val1 <= val2); +} /* int84le() */ + +bool int84ge(int64 *val1, int32 val2) +{ + return(*val1 >= val2); +} /* int84ge() */ + + +/*---------------------------------------------------------- + * Arithmetic operators on 64-bit integers. + *---------------------------------------------------------*/ + +int64 *int8um(int64 *val) +{ + int64 *result = PALLOCTYPE(int64); + + if (!PointerIsValid(val)) + return NULL; + + *result = (- *val); + + return(result); +} /* int8um() */ + +int64 *int8pl(int64 *val1, int64 *val2) +{ + int64 *result = PALLOCTYPE(int64); + + if ((!PointerIsValid(val1)) || (!PointerIsValid(val2))) + return NULL; + + *result = *val1 + *val2; + + return(result); +} /* int8pl() */ + +int64 *int8mi(int64 *val1, int64 *val2) +{ + int64 *result = PALLOCTYPE(int64); + + if ((!PointerIsValid(val1)) || (!PointerIsValid(val2))) + return NULL; + + *result = *val1 - *val2; + + return(result); +} /* int8mi() */ + +int64 *int8mul(int64 *val1, int64 *val2) +{ + int64 *result = PALLOCTYPE(int64); + + if ((!PointerIsValid(val1)) || (!PointerIsValid(val2))) + return NULL; + + *result = *val1 * *val2; + + return(result); +} /* int8mul() */ + +int64 *int8div(int64 *val1, int64 *val2) +{ + int64 *result = PALLOCTYPE(int64); + + if ((!PointerIsValid(val1)) || (!PointerIsValid(val2))) + return NULL; + + *result = *val1 / *val2; + + return(result); +} /* int8div() */ + + +/*---------------------------------------------------------- + * Conversion operators. + *---------------------------------------------------------*/ + +int64 *int48(int32 val) +{ + int64 *result = PALLOCTYPE(int64); + + *result = val; + + return(result); +} /* int48() */ + +int32 int84(int64 *val) +{ + int32 result; + + if (!PointerIsValid(val)) + elog(WARN,"Invalid (null) int64, can't convert int8 to int4",NULL); + + if ((*val < INT_MIN) || (*val > INT_MAX)) + elog(WARN,"int8 conversion to int4 is out of range",NULL); + + result = *val; + + return(result); +} /* int84() */ + +#if FALSE +int64 *int28(int16 val) +{ + int64 *result; + + if (!PointerIsValid(result = PALLOCTYPE(int64))) + elog(WARN,"Memory allocation failed, can't convert int8 to int2",NULL); + + *result = val; + + return(result); +} /* int28() */ + +int16 int82(int64 *val) +{ + int16 result; + + if (!PointerIsValid(val)) + elog(WARN,"Invalid (null) int8, can't convert to int2",NULL); + + result = *val; + + return(result); +} /* int82() */ +#endif + +float64 i8tod(int64 *val) +{ + float64 result = PALLOCTYPE(float64data); + + *result = *val; + + return(result); +} /* i8tod() */ + +int64 *dtoi8(float64 val) +{ + int64 *result = PALLOCTYPE(int64); + + if ((*val < (-pow(2,64)+1)) || (*val > (pow(2,64)-1))) + elog(WARN,"Floating point conversion to int64 is out of range",NULL); + + *result = *val; + + return(result); +} /* dtoi8() */ + diff --git a/contrib/int8/int8.source b/contrib/int8/int8.source new file mode 100644 index 0000000000..3f0e175670 --- /dev/null +++ b/contrib/int8/int8.source @@ -0,0 +1,288 @@ +--------------------------------------------------------------------------- +-- +-- int8.sql- +-- This file defines operators for 64-bit integers. +-- +--------------------------------------------------------------------------- + +LOAD '_OBJWD_/int8.so'; + +CREATE FUNCTION int8in(opaque) + RETURNS int8 + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE FUNCTION int8out(opaque) + RETURNS opaque + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE TYPE int8 ( + internallength = 8, + input = int8in, + output = int8out +); + + +----------------------------- +-- Create operators +----------------------------- + +CREATE FUNCTION int8um(int8) + RETURNS int8 + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR - ( + rightarg = int8, + procedure = int8um +); + +CREATE FUNCTION int8pl(int8,int8) + RETURNS int8 + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR + ( + leftarg = int8, + rightarg = int8, + procedure = int8pl, + commutator = + +); + +CREATE FUNCTION int8mi(int8,int8) + RETURNS int8 + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR - ( + leftarg = int8, + rightarg = int8, + procedure = int8mi +); + +CREATE FUNCTION int8mul(int8,int8) + RETURNS int8 + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR * ( + leftarg = int8, + rightarg = int8, + procedure = int8mul, + commutator = * +); + +CREATE FUNCTION int8div(int8,int8) + RETURNS int8 + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR / ( + leftarg = int8, + rightarg = int8, + procedure = int8div +); + +-- +-- 64-bit comparison operators +-- + +CREATE FUNCTION int8eq(int8,int8) + RETURNS bool + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR = ( + leftarg = int8, + rightarg = int8, + procedure = int8eq, + commutator = = +); + +CREATE FUNCTION int8ne(int8,int8) + RETURNS bool + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR <> ( + leftarg = int8, + rightarg = int8, + procedure = int8ne, + commutator = <> +); + +CREATE FUNCTION int8lt(int8,int8) + RETURNS bool + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR < ( + leftarg = int8, + rightarg = int8, + procedure = int8lt +); + +CREATE FUNCTION int8gt(int8,int8) + RETURNS bool + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR > ( + leftarg = int8, + rightarg = int8, + procedure = int8gt +); + +CREATE FUNCTION int8le(int8,int8) + RETURNS bool + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR <= ( + leftarg = int8, + rightarg = int8, + procedure = int8le +); + +CREATE FUNCTION int8ge(int8,int8) + RETURNS bool + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR >= ( + leftarg = int8, + rightarg = int8, + procedure = int8ge +); + +-- +-- 64-bit/32-bit comparison operators +-- + +CREATE FUNCTION int84eq(int8,int4) + RETURNS bool + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR = ( + leftarg = int8, + rightarg = int4, + procedure = int84eq, + commutator = = +); + +CREATE FUNCTION int84ne(int8,int4) + RETURNS bool + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR <> ( + leftarg = int8, + rightarg = int4, + procedure = int84ne, + commutator = <> +); + +CREATE FUNCTION int84lt(int8,int4) + RETURNS bool + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR < ( + leftarg = int8, + rightarg = int4, + procedure = int84lt +); + +CREATE FUNCTION int84gt(int8,int4) + RETURNS bool + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR > ( + leftarg = int8, + rightarg = int4, + procedure = int84gt +); + +CREATE FUNCTION int84le(int8,int4) + RETURNS bool + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR <= ( + leftarg = int8, + rightarg = int4, + procedure = int84le +); + +CREATE FUNCTION int84ge(int8,int4) + RETURNS bool + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE OPERATOR >= ( + leftarg = int8, + rightarg = int4, + procedure = int84ge +); + +-- +-- Conversion functions +-- + +CREATE FUNCTION int48(int4) + RETURNS int8 + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE FUNCTION int84(int8) + RETURNS int4 + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +--CREATE FUNCTION int28(int2) +-- RETURNS int8 +-- AS '_OBJWD_/int8.so' +-- LANGUAGE 'c'; +-- +--CREATE FUNCTION int82(int8) +-- RETURNS int2 +-- AS '_OBJWD_/int8.so' +-- LANGUAGE 'c'; + +CREATE FUNCTION i8tod(int8) + RETURNS float8 + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +CREATE FUNCTION dtoi8(float8) + RETURNS int8 + AS '_OBJWD_/int8.so' + LANGUAGE 'c'; + +-- +-- Generic conversion routines +-- + +CREATE FUNCTION int8(int4) + RETURNS int8 + AS 'select int48($1)' + LANGUAGE 'sql'; + +CREATE FUNCTION int8(float8) + RETURNS int8 + AS 'select dtoi8($1)' + LANGUAGE 'sql'; + +CREATE FUNCTION float8(int8) + RETURNS float8 + AS 'select i8tod($1)' + LANGUAGE 'sql'; + +CREATE FUNCTION int4(int8) + RETURNS int4 + AS 'select int84($1)' + LANGUAGE 'sql'; + diff --git a/contrib/int8/itest.sql b/contrib/int8/itest.sql new file mode 100644 index 0000000000..4a6f298656 --- /dev/null +++ b/contrib/int8/itest.sql @@ -0,0 +1,27 @@ +-- +-- Test int8 64-bit integers. +-- +drop table qtest; +create table qtest(q1 int8, q2 int8); + +insert into qtest values('123','456'); +insert into qtest values('123','4567890123456789'); +insert into qtest values('4567890123456789','123'); +insert into qtest values('4567890123456789','4567890123456789'); +insert into qtest values('4567890123456789','-4567890123456789'); + +select * from qtest; + +select q1, -q1 as minus from qtest; + +select q1, q2, q1 + q2 as plus from qtest; +select q1, q2, q1 - q2 as minus from qtest; +select q1, q2, q1 * q2 as multiply from qtest + where q1 < 1000 or (q2 > 0 and q2 < 1000); +--select q1, q2, q1 * q2 as multiply qtest +-- where q1 < '1000'::int8 or (q2 > '0'::int8 and q2 < '1000'::int8); +select q1, q2, q1 / q2 as divide from qtest; + +select q1, float8(q1) from qtest; +select q2, float8(q2) from qtest; +select q1, int8(float8(q1)) from qtest; -- 2.11.0