Initial 64-bit integer package.

This commit is contained in:
Thomas G. Lockhart 1997-05-17 14:24:09 +00:00
parent 5bc1024225
commit 0c3b6e670a
5 changed files with 841 additions and 0 deletions

64
contrib/int8/Makefile Normal file
View File

@ -0,0 +1,64 @@
#-------------------------------------------------------------------------
#
# Makefile--
# Makefile for Postgres 64-bit integer extensions
#
# Thomas G. Lockhart <Thomas.Lockhart@jpl.nasa.gov>
#
# 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

101
contrib/int8/README Normal file
View File

@ -0,0 +1,101 @@
Postgres int8
Thomas G. Lockhart <Thomas.Lockhart@jpl.nasa.gov>
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);

361
contrib/int8/int8.c Normal file
View File

@ -0,0 +1,361 @@
/*-------------------------------------------------------------------------
*
* int8.c--
* Internal 64-bit integer operations
*
*-------------------------------------------------------------------------
*/
#include <stdio.h> /* for sprintf proto, etc. */
#include <stdlib.h> /* for strtod, etc. */
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#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() */

288
contrib/int8/int8.source Normal file
View File

@ -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';

27
contrib/int8/itest.sql Normal file
View File

@ -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;