mirror of
https://github.com/pgvector/pgvector.git
synced 2026-07-03 03:00:56 +08:00
Added minivec type
This commit is contained in:
4
Makefile
4
Makefile
@@ -4,8 +4,8 @@ EXTVERSION = 0.7.4
|
||||
MODULE_big = vector
|
||||
DATA = $(wildcard sql/*--*--*.sql)
|
||||
DATA_built = sql/$(EXTENSION)--$(EXTVERSION).sql
|
||||
OBJS = src/bitutils.o src/bitvec.o src/halfutils.o src/halfvec.o src/hnsw.o src/hnswbuild.o src/hnswinsert.o src/hnswscan.o src/hnswutils.o src/hnswvacuum.o src/ivfbuild.o src/ivfflat.o src/ivfinsert.o src/ivfkmeans.o src/ivfscan.o src/ivfutils.o src/ivfvacuum.o src/sparsevec.o src/vector.o
|
||||
HEADERS = src/halfvec.h src/sparsevec.h src/vector.h
|
||||
OBJS = src/bitutils.o src/bitvec.o src/halfutils.o src/halfvec.o src/hnsw.o src/hnswbuild.o src/hnswinsert.o src/hnswscan.o src/hnswutils.o src/hnswvacuum.o src/ivfbuild.o src/ivfflat.o src/ivfinsert.o src/ivfkmeans.o src/ivfscan.o src/ivfutils.o src/minivec.o src/ivfvacuum.o src/sparsevec.o src/vector.o
|
||||
HEADERS = src/halfvec.h src/minivec.h src/sparsevec.h src/vector.h
|
||||
|
||||
TESTS = $(wildcard test/sql/*.sql)
|
||||
REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS))
|
||||
|
||||
@@ -2,10 +2,10 @@ EXTENSION = vector
|
||||
EXTVERSION = 0.7.4
|
||||
|
||||
DATA_built = sql\$(EXTENSION)--$(EXTVERSION).sql
|
||||
OBJS = src\bitutils.obj src\bitvec.obj src\halfutils.obj src\halfvec.obj src\hnsw.obj src\hnswbuild.obj src\hnswinsert.obj src\hnswscan.obj src\hnswutils.obj src\hnswvacuum.obj src\ivfbuild.obj src\ivfflat.obj src\ivfinsert.obj src\ivfkmeans.obj src\ivfscan.obj src\ivfutils.obj src\ivfvacuum.obj src\sparsevec.obj src\vector.obj
|
||||
HEADERS = src\halfvec.h src\sparsevec.h src\vector.h
|
||||
OBJS = src\bitutils.obj src\bitvec.obj src\halfutils.obj src\halfvec.obj src\hnsw.obj src\hnswbuild.obj src\hnswinsert.obj src\hnswscan.obj src\hnswutils.obj src\hnswvacuum.obj src\ivfbuild.obj src\ivfflat.obj src\ivfinsert.obj src\ivfkmeans.obj src\ivfscan.obj src\ivfutils.obj src\ivfvacuum.obj src\minivec.obj src\sparsevec.obj src\vector.obj
|
||||
HEADERS = src\halfvec.h src\minivec.h src\sparsevec.h src\vector.h
|
||||
|
||||
REGRESS = bit btree cast copy halfvec hnsw_bit hnsw_halfvec hnsw_sparsevec hnsw_vector ivfflat_bit ivfflat_halfvec ivfflat_vector sparsevec vector_type
|
||||
REGRESS = bit btree cast copy halfvec hnsw_bit hnsw_halfvec hnsw_sparsevec hnsw_vector ivfflat_bit ivfflat_halfvec ivfflat_vector minivec sparsevec vector_type
|
||||
REGRESS_OPTS = --inputdir=test --load-extension=$(EXTENSION)
|
||||
|
||||
# For /arch flags
|
||||
|
||||
@@ -1,6 +1,32 @@
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "ALTER EXTENSION vector UPDATE TO '0.8.0'" to load this file. \quit
|
||||
|
||||
CREATE TYPE minivec;
|
||||
|
||||
CREATE FUNCTION minivec_in(cstring, oid, integer) RETURNS minivec
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION minivec_out(minivec) RETURNS cstring
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION minivec_typmod_in(cstring[]) RETURNS integer
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION minivec_recv(internal, oid, integer) RETURNS minivec
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION minivec_send(minivec) RETURNS bytea
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE TYPE minivec (
|
||||
INPUT = minivec_in,
|
||||
OUTPUT = minivec_out,
|
||||
TYPMOD_IN = minivec_typmod_in,
|
||||
RECEIVE = minivec_recv,
|
||||
SEND = minivec_send,
|
||||
STORAGE = external
|
||||
);
|
||||
|
||||
CREATE FUNCTION array_to_sparsevec(integer[], integer, boolean) RETURNS sparsevec
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
|
||||
@@ -647,6 +647,34 @@ CREATE OPERATOR CLASS halfvec_l1_ops
|
||||
FUNCTION 1 l1_distance(halfvec, halfvec),
|
||||
FUNCTION 3 hnsw_halfvec_support(internal);
|
||||
|
||||
-- minivec type
|
||||
|
||||
CREATE TYPE minivec;
|
||||
|
||||
CREATE FUNCTION minivec_in(cstring, oid, integer) RETURNS minivec
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION minivec_out(minivec) RETURNS cstring
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION minivec_typmod_in(cstring[]) RETURNS integer
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION minivec_recv(internal, oid, integer) RETURNS minivec
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE FUNCTION minivec_send(minivec) RETURNS bytea
|
||||
AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
|
||||
|
||||
CREATE TYPE minivec (
|
||||
INPUT = minivec_in,
|
||||
OUTPUT = minivec_out,
|
||||
TYPMOD_IN = minivec_typmod_in,
|
||||
RECEIVE = minivec_recv,
|
||||
SEND = minivec_send,
|
||||
STORAGE = external
|
||||
);
|
||||
|
||||
-- bit functions
|
||||
|
||||
CREATE FUNCTION hamming_distance(bit, bit) RETURNS float8
|
||||
|
||||
336
src/minivec.c
Normal file
336
src/minivec.c
Normal file
@@ -0,0 +1,336 @@
|
||||
#include "postgres.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "catalog/pg_type.h"
|
||||
#include "common/shortest_dec.h"
|
||||
#include "fmgr.h"
|
||||
#include "minivec.h"
|
||||
#include "lib/stringinfo.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "port.h" /* for strtof() */
|
||||
#include "sparsevec.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/float.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/numeric.h"
|
||||
#include "vector.h"
|
||||
|
||||
/*
|
||||
* Ensure expected dimensions
|
||||
*/
|
||||
static inline void
|
||||
CheckExpectedDim(int32 typmod, int dim)
|
||||
{
|
||||
if (typmod != -1 && typmod != dim)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_EXCEPTION),
|
||||
errmsg("expected %d dimensions, not %d", typmod, dim)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure valid dimensions
|
||||
*/
|
||||
static inline void
|
||||
CheckDim(int dim)
|
||||
{
|
||||
if (dim < 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_EXCEPTION),
|
||||
errmsg("minivec must have at least 1 dimension")));
|
||||
|
||||
if (dim > MINIVEC_MAX_DIM)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("minivec cannot have more than %d dimensions", MINIVEC_MAX_DIM)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure finite element
|
||||
*/
|
||||
static inline void
|
||||
CheckElement(fp8 value)
|
||||
{
|
||||
if (Fp8IsNan(value))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_EXCEPTION),
|
||||
errmsg("NaN not allowed in minivec")));
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and initialize a new half vector
|
||||
*/
|
||||
MiniVector *
|
||||
InitMiniVector(int dim)
|
||||
{
|
||||
MiniVector *result;
|
||||
int size;
|
||||
|
||||
size = MINIVEC_SIZE(dim);
|
||||
result = (MiniVector *) palloc0(size);
|
||||
SET_VARSIZE(result, size);
|
||||
result->dim = dim;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for whitespace, since array_isspace() is static
|
||||
*/
|
||||
static inline bool
|
||||
minivec_isspace(char ch)
|
||||
{
|
||||
if (ch == ' ' ||
|
||||
ch == '\t' ||
|
||||
ch == '\n' ||
|
||||
ch == '\r' ||
|
||||
ch == '\v' ||
|
||||
ch == '\f')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert textual representation to internal representation
|
||||
*/
|
||||
FUNCTION_PREFIX PG_FUNCTION_INFO_V1(minivec_in);
|
||||
Datum
|
||||
minivec_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *lit = PG_GETARG_CSTRING(0);
|
||||
int32 typmod = PG_GETARG_INT32(2);
|
||||
fp8 x[MINIVEC_MAX_DIM];
|
||||
int dim = 0;
|
||||
char *pt = lit;
|
||||
MiniVector *result;
|
||||
|
||||
while (minivec_isspace(*pt))
|
||||
pt++;
|
||||
|
||||
if (*pt != '[')
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("invalid input syntax for type minivec: \"%s\"", lit),
|
||||
errdetail("Vector contents must start with \"[\".")));
|
||||
|
||||
pt++;
|
||||
|
||||
while (minivec_isspace(*pt))
|
||||
pt++;
|
||||
|
||||
if (*pt == ']')
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_EXCEPTION),
|
||||
errmsg("minivec must have at least 1 dimension")));
|
||||
|
||||
for (;;)
|
||||
{
|
||||
float val;
|
||||
char *stringEnd;
|
||||
|
||||
if (dim == MINIVEC_MAX_DIM)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("minivec cannot have more than %d dimensions", MINIVEC_MAX_DIM)));
|
||||
|
||||
while (minivec_isspace(*pt))
|
||||
pt++;
|
||||
|
||||
/* Check for empty string like float4in */
|
||||
if (*pt == '\0')
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("invalid input syntax for type minivec: \"%s\"", lit)));
|
||||
|
||||
errno = 0;
|
||||
|
||||
/* Postgres sets LC_NUMERIC to C on startup */
|
||||
val = strtof(pt, &stringEnd);
|
||||
|
||||
if (stringEnd == pt)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("invalid input syntax for type minivec: \"%s\"", lit)));
|
||||
|
||||
x[dim] = Float4ToFp8Unchecked(val);
|
||||
|
||||
/* Check for range error like float4in */
|
||||
if ((errno == ERANGE && isinf(val)) || (Fp8IsNan(x[dim]) && !isnan(val)))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||
errmsg("\"%s\" is out of range for type minivec", pnstrdup(pt, stringEnd - pt))));
|
||||
|
||||
CheckElement(x[dim]);
|
||||
dim++;
|
||||
|
||||
pt = stringEnd;
|
||||
|
||||
while (minivec_isspace(*pt))
|
||||
pt++;
|
||||
|
||||
if (*pt == ',')
|
||||
pt++;
|
||||
else if (*pt == ']')
|
||||
{
|
||||
pt++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("invalid input syntax for type minivec: \"%s\"", lit)));
|
||||
}
|
||||
|
||||
/* Only whitespace is allowed after the closing brace */
|
||||
while (minivec_isspace(*pt))
|
||||
pt++;
|
||||
|
||||
if (*pt != '\0')
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("invalid input syntax for type minivec: \"%s\"", lit),
|
||||
errdetail("Junk after closing right brace.")));
|
||||
|
||||
CheckDim(dim);
|
||||
CheckExpectedDim(typmod, dim);
|
||||
|
||||
result = InitMiniVector(dim);
|
||||
for (int i = 0; i < dim; i++)
|
||||
result->x[i] = x[i];
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
#define AppendChar(ptr, c) (*(ptr)++ = (c))
|
||||
#define AppendFloat(ptr, f) ((ptr) += float_to_shortest_decimal_bufn((f), (ptr)))
|
||||
|
||||
/*
|
||||
* Convert internal representation to textual representation
|
||||
*/
|
||||
FUNCTION_PREFIX PG_FUNCTION_INFO_V1(minivec_out);
|
||||
Datum
|
||||
minivec_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
MiniVector *vector = PG_GETARG_MINIVEC_P(0);
|
||||
int dim = vector->dim;
|
||||
char *buf;
|
||||
char *ptr;
|
||||
|
||||
/*
|
||||
* Need:
|
||||
*
|
||||
* dim * (FLOAT_SHORTEST_DECIMAL_LEN - 1) bytes for
|
||||
* float_to_shortest_decimal_bufn
|
||||
*
|
||||
* dim - 1 bytes for separator
|
||||
*
|
||||
* 3 bytes for [, ], and \0
|
||||
*/
|
||||
buf = (char *) palloc(FLOAT_SHORTEST_DECIMAL_LEN * dim + 2);
|
||||
ptr = buf;
|
||||
|
||||
AppendChar(ptr, '[');
|
||||
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
AppendChar(ptr, ',');
|
||||
|
||||
/*
|
||||
* Use shortest decimal representation of single-precision float for
|
||||
* simplicity
|
||||
*/
|
||||
AppendFloat(ptr, Fp8ToFloat4(vector->x[i]));
|
||||
}
|
||||
|
||||
AppendChar(ptr, ']');
|
||||
*ptr = '\0';
|
||||
|
||||
PG_FREE_IF_COPY(vector, 0);
|
||||
PG_RETURN_CSTRING(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert type modifier
|
||||
*/
|
||||
FUNCTION_PREFIX PG_FUNCTION_INFO_V1(minivec_typmod_in);
|
||||
Datum
|
||||
minivec_typmod_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
||||
int32 *tl;
|
||||
int n;
|
||||
|
||||
tl = ArrayGetIntegerTypmods(ta, &n);
|
||||
|
||||
if (n != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid type modifier")));
|
||||
|
||||
if (*tl < 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("dimensions for type minivec must be at least 1")));
|
||||
|
||||
if (*tl > MINIVEC_MAX_DIM)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("dimensions for type minivec cannot exceed %d", MINIVEC_MAX_DIM)));
|
||||
|
||||
PG_RETURN_INT32(*tl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert external binary representation to internal representation
|
||||
*/
|
||||
FUNCTION_PREFIX PG_FUNCTION_INFO_V1(minivec_recv);
|
||||
Datum
|
||||
minivec_recv(PG_FUNCTION_ARGS)
|
||||
{
|
||||
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
||||
int32 typmod = PG_GETARG_INT32(2);
|
||||
MiniVector *result;
|
||||
int16 dim;
|
||||
int16 unused;
|
||||
|
||||
dim = pq_getmsgint(buf, sizeof(int16));
|
||||
unused = pq_getmsgint(buf, sizeof(int16));
|
||||
|
||||
CheckDim(dim);
|
||||
CheckExpectedDim(typmod, dim);
|
||||
|
||||
if (unused != 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATA_EXCEPTION),
|
||||
errmsg("expected unused to be 0, not %d", unused)));
|
||||
|
||||
result = InitMiniVector(dim);
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
result->x[i] = pq_getmsgint(buf, sizeof(uint8));
|
||||
CheckElement(result->x[i]);
|
||||
}
|
||||
|
||||
PG_RETURN_POINTER(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert internal representation to the external binary representation
|
||||
*/
|
||||
FUNCTION_PREFIX PG_FUNCTION_INFO_V1(minivec_send);
|
||||
Datum
|
||||
minivec_send(PG_FUNCTION_ARGS)
|
||||
{
|
||||
MiniVector *vec = PG_GETARG_MINIVEC_P(0);
|
||||
StringInfoData buf;
|
||||
|
||||
pq_begintypsend(&buf);
|
||||
pq_sendint(&buf, vec->dim, sizeof(int16));
|
||||
pq_sendint(&buf, vec->unused, sizeof(int16));
|
||||
for (int i = 0; i < vec->dim; i++)
|
||||
pq_sendint8(&buf, vec->x[i]);
|
||||
|
||||
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
||||
}
|
||||
126
src/minivec.h
Normal file
126
src/minivec.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#ifndef MINIVEC_H
|
||||
#define MINIVEC_H
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#define MINIVEC_MAX_DIM 16000
|
||||
|
||||
#define fp8 uint8
|
||||
|
||||
#define MINIVEC_SIZE(_dim) (offsetof(MiniVector, x) + sizeof(fp8)*(_dim))
|
||||
#define DatumGetMiniVector(x) ((MiniVector *) PG_DETOAST_DATUM(x))
|
||||
#define PG_GETARG_MINIVEC_P(x) DatumGetMiniVector(PG_GETARG_DATUM(x))
|
||||
#define PG_RETURN_MINIVEC_P(x) PG_RETURN_POINTER(x)
|
||||
|
||||
typedef struct MiniVector
|
||||
{
|
||||
int32 vl_len_; /* varlena header (do not touch directly!) */
|
||||
int16 dim; /* number of dimensions */
|
||||
int16 unused; /* reserved for future use, always zero */
|
||||
fp8 x[FLEXIBLE_ARRAY_MEMBER];
|
||||
} MiniVector;
|
||||
|
||||
MiniVector *InitMiniVector(int dim);
|
||||
|
||||
/*
|
||||
* Check if fp8 is NaN
|
||||
*/
|
||||
static inline bool
|
||||
Fp8IsNan(fp8 num)
|
||||
{
|
||||
return (num & 0x7F) == 0x7F;
|
||||
}
|
||||
|
||||
float lookup[128] = {0, 0.00195312, 0.00390625, 0.00585938, 0.0078125, 0.00976562, 0.0117188, 0.0136719, 0.015625, 0.0175781, 0.0195312, 0.0214844, 0.0234375, 0.0253906, 0.0273438, 0.0292969, 0.03125, 0.0351562, 0.0390625, 0.0429688, 0.046875, 0.0507812, 0.0546875, 0.0585938, 0.0625, 0.0703125, 0.078125, 0.0859375, 0.09375, 0.101562, 0.109375, 0.117188, 0.125, 0.140625, 0.15625, 0.171875, 0.1875, 0.203125, 0.21875, 0.234375, 0.25, 0.28125, 0.3125, 0.34375, 0.375, 0.40625, 0.4375, 0.46875, 0.5, 0.5625, 0.625, 0.6875, 0.75, 0.8125, 0.875, 0.9375, 1, 1.125, 1.25, 1.375, 1.5, 1.625, 1.75, 1.875, 2, 2.25, 2.5, 2.75, 3, 3.25, 3.5, 3.75, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 88, 96, 104, 112, 120, 128, 144, 160, 176, 192, 208, 224, 240, 256, 288, 320, 352, 384, 416, 448, NAN};
|
||||
|
||||
/*
|
||||
* Convert a fp8 to a float4
|
||||
*/
|
||||
static inline float
|
||||
Fp8ToFloat4(fp8 num)
|
||||
{
|
||||
float v = lookup[num & 0x7F];
|
||||
|
||||
return (num & 0x80) == 0x80 ? -v : v;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a float4 to a fp8
|
||||
*/
|
||||
static inline fp8
|
||||
Float4ToFp8Unchecked(float num)
|
||||
{
|
||||
union
|
||||
{
|
||||
float f;
|
||||
uint32 i;
|
||||
} swapfloat;
|
||||
|
||||
uint32 bin;
|
||||
int exponent;
|
||||
int mantissa;
|
||||
uint8 result;
|
||||
|
||||
swapfloat.f = num;
|
||||
bin = swapfloat.i;
|
||||
exponent = (bin & 0x7F800000) >> 23;
|
||||
mantissa = bin & 0x007FFFFF;
|
||||
|
||||
/* Sign */
|
||||
result = (bin & 0x80000000) >> 24;
|
||||
|
||||
if (isinf(num) || isnan(num))
|
||||
{
|
||||
/* NaN */
|
||||
result |= 0x7F;
|
||||
}
|
||||
else if (exponent > 116)
|
||||
{
|
||||
int m;
|
||||
int gr;
|
||||
int s;
|
||||
|
||||
exponent -= 127;
|
||||
s = mantissa & 0x000FFFFF;
|
||||
|
||||
/* Subnormal */
|
||||
if (exponent < -6)
|
||||
{
|
||||
int diff = -exponent - 6;
|
||||
|
||||
mantissa >>= diff;
|
||||
mantissa += 1 << (23 - diff);
|
||||
s |= mantissa & 0x000FFFFF;
|
||||
}
|
||||
|
||||
m = mantissa >> 20;
|
||||
|
||||
/* Round */
|
||||
gr = (mantissa >> 19) % 4;
|
||||
if (gr == 3 || (gr == 1 && s != 0))
|
||||
m += 1;
|
||||
|
||||
if (m == 8)
|
||||
{
|
||||
m = 0;
|
||||
exponent += 1;
|
||||
}
|
||||
|
||||
if (exponent > 8)
|
||||
{
|
||||
/* Infinite, which is NaN */
|
||||
result |= 0x7F;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exponent >= -7)
|
||||
result |= (exponent + 7) << 3;
|
||||
|
||||
result |= m;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -30,6 +30,15 @@ SELECT * FROM t2 ORDER BY val;
|
||||
|
||||
(4 rows)
|
||||
|
||||
DROP TABLE t;
|
||||
DROP TABLE t2;
|
||||
-- minivec
|
||||
CREATE TABLE t (val minivec(3));
|
||||
INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL);
|
||||
CREATE TABLE t2 (val minivec(3));
|
||||
\copy t TO 'results/minivec.bin' WITH (FORMAT binary)
|
||||
\copy t2 FROM 'results/minivec.bin' WITH (FORMAT binary)
|
||||
--SELECT * FROM t2 ORDER BY val;
|
||||
DROP TABLE t;
|
||||
DROP TABLE t2;
|
||||
-- sparsevec
|
||||
|
||||
170
test/expected/minivec.out
Normal file
170
test/expected/minivec.out
Normal file
@@ -0,0 +1,170 @@
|
||||
SELECT '[1,2,3]'::minivec;
|
||||
minivec
|
||||
---------
|
||||
[1,2,3]
|
||||
(1 row)
|
||||
|
||||
SELECT '[-1,-2,-3]'::minivec;
|
||||
minivec
|
||||
------------
|
||||
[-1,-2,-3]
|
||||
(1 row)
|
||||
|
||||
SELECT '[1.,2.,3.]'::minivec;
|
||||
minivec
|
||||
---------
|
||||
[1,2,3]
|
||||
(1 row)
|
||||
|
||||
SELECT ' [ 1, 2 , 3 ] '::minivec;
|
||||
minivec
|
||||
---------
|
||||
[1,2,3]
|
||||
(1 row)
|
||||
|
||||
SELECT '[1.23456]'::minivec;
|
||||
minivec
|
||||
---------
|
||||
[1.25]
|
||||
(1 row)
|
||||
|
||||
SELECT '[hello,1]'::minivec;
|
||||
ERROR: invalid input syntax for type minivec: "[hello,1]"
|
||||
LINE 1: SELECT '[hello,1]'::minivec;
|
||||
^
|
||||
SELECT '[NaN,1]'::minivec;
|
||||
ERROR: NaN not allowed in minivec
|
||||
LINE 1: SELECT '[NaN,1]'::minivec;
|
||||
^
|
||||
SELECT '[Infinity,1]'::minivec;
|
||||
ERROR: "Infinity" is out of range for type minivec
|
||||
LINE 1: SELECT '[Infinity,1]'::minivec;
|
||||
^
|
||||
SELECT '[-Infinity,1]'::minivec;
|
||||
ERROR: "-Infinity" is out of range for type minivec
|
||||
LINE 1: SELECT '[-Infinity,1]'::minivec;
|
||||
^
|
||||
SELECT '[65519,-65519]'::minivec;
|
||||
ERROR: "65519" is out of range for type minivec
|
||||
LINE 1: SELECT '[65519,-65519]'::minivec;
|
||||
^
|
||||
SELECT '[65520,-65520]'::minivec;
|
||||
ERROR: "65520" is out of range for type minivec
|
||||
LINE 1: SELECT '[65520,-65520]'::minivec;
|
||||
^
|
||||
SELECT '[1e-8,-1e-8]'::minivec;
|
||||
minivec
|
||||
---------
|
||||
[0,-0]
|
||||
(1 row)
|
||||
|
||||
SELECT '[4e38,1]'::minivec;
|
||||
ERROR: "4e38" is out of range for type minivec
|
||||
LINE 1: SELECT '[4e38,1]'::minivec;
|
||||
^
|
||||
SELECT '[1e-46,1]'::minivec;
|
||||
minivec
|
||||
---------
|
||||
[0,1]
|
||||
(1 row)
|
||||
|
||||
SELECT '[1,2,3'::minivec;
|
||||
ERROR: invalid input syntax for type minivec: "[1,2,3"
|
||||
LINE 1: SELECT '[1,2,3'::minivec;
|
||||
^
|
||||
SELECT '[1,2,3]9'::minivec;
|
||||
ERROR: invalid input syntax for type minivec: "[1,2,3]9"
|
||||
LINE 1: SELECT '[1,2,3]9'::minivec;
|
||||
^
|
||||
DETAIL: Junk after closing right brace.
|
||||
SELECT '1,2,3'::minivec;
|
||||
ERROR: invalid input syntax for type minivec: "1,2,3"
|
||||
LINE 1: SELECT '1,2,3'::minivec;
|
||||
^
|
||||
DETAIL: Vector contents must start with "[".
|
||||
SELECT ''::minivec;
|
||||
ERROR: invalid input syntax for type minivec: ""
|
||||
LINE 1: SELECT ''::minivec;
|
||||
^
|
||||
DETAIL: Vector contents must start with "[".
|
||||
SELECT '['::minivec;
|
||||
ERROR: invalid input syntax for type minivec: "["
|
||||
LINE 1: SELECT '['::minivec;
|
||||
^
|
||||
SELECT '[ '::minivec;
|
||||
ERROR: invalid input syntax for type minivec: "[ "
|
||||
LINE 1: SELECT '[ '::minivec;
|
||||
^
|
||||
SELECT '[,'::minivec;
|
||||
ERROR: invalid input syntax for type minivec: "[,"
|
||||
LINE 1: SELECT '[,'::minivec;
|
||||
^
|
||||
SELECT '[]'::minivec;
|
||||
ERROR: minivec must have at least 1 dimension
|
||||
LINE 1: SELECT '[]'::minivec;
|
||||
^
|
||||
SELECT '[ ]'::minivec;
|
||||
ERROR: minivec must have at least 1 dimension
|
||||
LINE 1: SELECT '[ ]'::minivec;
|
||||
^
|
||||
SELECT '[,]'::minivec;
|
||||
ERROR: invalid input syntax for type minivec: "[,]"
|
||||
LINE 1: SELECT '[,]'::minivec;
|
||||
^
|
||||
SELECT '[1,]'::minivec;
|
||||
ERROR: invalid input syntax for type minivec: "[1,]"
|
||||
LINE 1: SELECT '[1,]'::minivec;
|
||||
^
|
||||
SELECT '[1a]'::minivec;
|
||||
ERROR: invalid input syntax for type minivec: "[1a]"
|
||||
LINE 1: SELECT '[1a]'::minivec;
|
||||
^
|
||||
SELECT '[1,,3]'::minivec;
|
||||
ERROR: invalid input syntax for type minivec: "[1,,3]"
|
||||
LINE 1: SELECT '[1,,3]'::minivec;
|
||||
^
|
||||
SELECT '[1, ,3]'::minivec;
|
||||
ERROR: invalid input syntax for type minivec: "[1, ,3]"
|
||||
LINE 1: SELECT '[1, ,3]'::minivec;
|
||||
^
|
||||
SELECT '[1,2,3]'::minivec(3);
|
||||
minivec
|
||||
---------
|
||||
[1,2,3]
|
||||
(1 row)
|
||||
|
||||
SELECT '[1,2,3]'::minivec(2);
|
||||
minivec
|
||||
---------
|
||||
[1,2,3]
|
||||
(1 row)
|
||||
|
||||
SELECT '[1,2,3]'::minivec(3, 2);
|
||||
ERROR: invalid type modifier
|
||||
LINE 1: SELECT '[1,2,3]'::minivec(3, 2);
|
||||
^
|
||||
SELECT '[1,2,3]'::minivec('a');
|
||||
ERROR: invalid input syntax for type integer: "a"
|
||||
LINE 1: SELECT '[1,2,3]'::minivec('a');
|
||||
^
|
||||
SELECT '[1,2,3]'::minivec(0);
|
||||
ERROR: dimensions for type minivec must be at least 1
|
||||
LINE 1: SELECT '[1,2,3]'::minivec(0);
|
||||
^
|
||||
SELECT '[1,2,3]'::minivec(16001);
|
||||
ERROR: dimensions for type minivec cannot exceed 16000
|
||||
LINE 1: SELECT '[1,2,3]'::minivec(16001);
|
||||
^
|
||||
SELECT unnest('{"[1,2,3]", "[4,5,6]"}'::minivec[]);
|
||||
unnest
|
||||
---------
|
||||
[1,2,3]
|
||||
[4,5,6]
|
||||
(2 rows)
|
||||
|
||||
SELECT '{"[1,2,3]"}'::minivec(2)[];
|
||||
minivec
|
||||
-------------
|
||||
{"[1,2,3]"}
|
||||
(1 row)
|
||||
|
||||
@@ -28,6 +28,21 @@ SELECT * FROM t2 ORDER BY val;
|
||||
DROP TABLE t;
|
||||
DROP TABLE t2;
|
||||
|
||||
-- minivec
|
||||
|
||||
CREATE TABLE t (val minivec(3));
|
||||
INSERT INTO t (val) VALUES ('[0,0,0]'), ('[1,2,3]'), ('[1,1,1]'), (NULL);
|
||||
|
||||
CREATE TABLE t2 (val minivec(3));
|
||||
|
||||
\copy t TO 'results/minivec.bin' WITH (FORMAT binary)
|
||||
\copy t2 FROM 'results/minivec.bin' WITH (FORMAT binary)
|
||||
|
||||
--SELECT * FROM t2 ORDER BY val;
|
||||
|
||||
DROP TABLE t;
|
||||
DROP TABLE t2;
|
||||
|
||||
-- sparsevec
|
||||
|
||||
CREATE TABLE t (val sparsevec(3));
|
||||
|
||||
38
test/sql/minivec.sql
Normal file
38
test/sql/minivec.sql
Normal file
@@ -0,0 +1,38 @@
|
||||
SELECT '[1,2,3]'::minivec;
|
||||
SELECT '[-1,-2,-3]'::minivec;
|
||||
SELECT '[1.,2.,3.]'::minivec;
|
||||
SELECT ' [ 1, 2 , 3 ] '::minivec;
|
||||
SELECT '[1.23456]'::minivec;
|
||||
SELECT '[hello,1]'::minivec;
|
||||
SELECT '[NaN,1]'::minivec;
|
||||
SELECT '[Infinity,1]'::minivec;
|
||||
SELECT '[-Infinity,1]'::minivec;
|
||||
SELECT '[65519,-65519]'::minivec;
|
||||
SELECT '[65520,-65520]'::minivec;
|
||||
SELECT '[1e-8,-1e-8]'::minivec;
|
||||
SELECT '[4e38,1]'::minivec;
|
||||
SELECT '[1e-46,1]'::minivec;
|
||||
SELECT '[1,2,3'::minivec;
|
||||
SELECT '[1,2,3]9'::minivec;
|
||||
SELECT '1,2,3'::minivec;
|
||||
SELECT ''::minivec;
|
||||
SELECT '['::minivec;
|
||||
SELECT '[ '::minivec;
|
||||
SELECT '[,'::minivec;
|
||||
SELECT '[]'::minivec;
|
||||
SELECT '[ ]'::minivec;
|
||||
SELECT '[,]'::minivec;
|
||||
SELECT '[1,]'::minivec;
|
||||
SELECT '[1a]'::minivec;
|
||||
SELECT '[1,,3]'::minivec;
|
||||
SELECT '[1, ,3]'::minivec;
|
||||
|
||||
SELECT '[1,2,3]'::minivec(3);
|
||||
SELECT '[1,2,3]'::minivec(2);
|
||||
SELECT '[1,2,3]'::minivec(3, 2);
|
||||
SELECT '[1,2,3]'::minivec('a');
|
||||
SELECT '[1,2,3]'::minivec(0);
|
||||
SELECT '[1,2,3]'::minivec(16001);
|
||||
|
||||
SELECT unnest('{"[1,2,3]", "[4,5,6]"}'::minivec[]);
|
||||
SELECT '{"[1,2,3]"}'::minivec(2)[];
|
||||
Reference in New Issue
Block a user