blob: 1aa486ee02566897126e688ec905b94123a7ee57 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "postgres.h"
#include "catalog/pg_type.h"
#include "utils/builtins.h"
#include "vadt.h"
/* the maximum length of numeric */
#define MAX_NUM_LEN 32
/* Get the size of vectorized data */
#define FUNCTION_VTYPESIZE(type) \
size_t v##type##Size(vheader *vh) \
{\
size_t len = offsetof(vheader,isnull);\
return len + vh->dim * sizeof(bool) + vh->dim * sizeof(type) + sizeof(Datum);\
}
/* Build the vectorized data */
#define FUNCTION_BUILD(type, typeoid) \
vheader* buildv##type(int n) \
{ \
vheader* result; \
result = (vheader*) palloc0(offsetof(v##type,values) + n * sizeof(type) + sizeof(Datum)) ; \
result->dim = n; \
result->elemtype = typeoid; \
result->isnull = palloc0(sizeof(bool) * n); \
SET_VARSIZE(result,v##type##Size(result)); \
return result; \
}
/* Destroy the vectorized data */
#define FUNCTION_DESTORY(type, typeoid) \
void destroyv##type(vheader **header) \
{ \
v##type** ptr = (v##type**) header; \
pfree((*header)->isnull); \
pfree(*ptr); \
*ptr = NULL; \
}
/*
* Serialize functions and deserialize functions for the abstract data types
*/
#define FUNCTION_SERIALIZATION(type,typeoid) \
size_t v##type##serialization(vheader* vh,unsigned char *buf) \
{ \
size_t len = 0; \
v##type *vt = (v##type *)vh; \
\
memcpy(buf + len,vt,offsetof(vheader,isnull)); \
len += offsetof(vheader,isnull); \
\
memcpy(buf + len,vh->isnull,sizeof(bool) * vh->dim); \
len += sizeof(bool) * vh->dim; \
\
memcpy(buf + len,vt->values,sizeof(type) * vh->dim); \
len += sizeof(type) * vh->dim; \
\
return len; \
} \
\
\
Datum v##type##deserialization(unsigned char* buf,size_t* len) \
{\
vheader* vh = (vheader *) buf;\
*len = 0;\
\
v##type* vt = palloc(sizeof(v##type) + sizeof(type) * vh->dim);\
memcpy(vt,buf,offsetof(vheader,isnull));\
*len += offsetof(vheader,isnull);\
\
vt->header.isnull = palloc(vh->dim * sizeof(bool));\
memcpy(vt->header.isnull, buf + *len,vh->dim * sizeof(bool));\
*len += vh->dim * sizeof(bool);\
\
memcpy(vt->values,buf + *len,vh->dim * sizeof(type)); \
*len += vh->dim * sizeof(type); \
\
return PointerGetDatum(vt); \
}
/*
* IN function for the abstract data types
* e.g. Datum vint2in(PG_FUNCTION_ARGS)
*/
#define FUNCTION_IN(type, typeoid, MACRO_DATUM) \
PG_FUNCTION_INFO_V1(v##type##in); \
Datum \
v##type##in(PG_FUNCTION_ARGS) \
{ \
char *intString = PG_GETARG_CSTRING(0); \
v##type *res = NULL; \
char tempstr[MAX_NUM_LEN] = {0}; \
int n = 0; \
res = palloc0(offsetof(v##type, values) + (MAX_VECTOR_SIZE) * sizeof(type)); \
for (n = 0; *intString && n < MAX_VECTOR_SIZE; n++) \
{ \
char *start = NULL;\
while (*intString && isspace((unsigned char) *intString)) \
intString++; \
if (*intString == '\0') \
break; \
start = intString; \
while ((*intString && !isspace((unsigned char) *intString)) && *intString != '\0') \
intString++; \
Assert(intString - start < MAX_NUM_LEN); \
strncpy(tempstr, start, intString - start); \
tempstr[intString - start] = 0; \
res->values[n] = MACRO_DATUM(DirectFunctionCall1(type##in, CStringGetDatum(tempstr))); \
while (*intString && !isspace((unsigned char) *intString)) \
intString++; \
} \
while (*intString && isspace((unsigned char) *intString)) \
intString++; \
if (*intString) \
ereport(ERROR, \
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), \
errmsg("int2vector has too many elements"))); \
SET_VARSIZE(res, (offsetof(v##type, values) + n * sizeof(type))); \
res->header.elemtype = typeoid; \
res->header.dim = n; \
res->header.isnull = palloc0(sizeof(bool) * n); \
PG_RETURN_POINTER(res); \
}
/*
* OUT function for the abstract data types
* e.g. Datum vint2out(PG_FUNCTION_ARGS)
*/
#define FUNCTION_OUT(type, typeoid, MACRO_DATUM) \
PG_FUNCTION_INFO_V1(v##type##out); \
Datum \
v##type##out(PG_FUNCTION_ARGS) \
{ \
v##type * arg1 = (v##type *) PG_GETARG_POINTER(0); \
int len = arg1->header.dim; \
int i = 0; \
char *rp; \
char *result; \
rp = result = (char *) palloc0(len * MAX_NUM_LEN + 1); \
for (i = 0; i < len; i++) \
{ \
if (i != 0) \
*rp++ = ' '; \
strcat(rp, DatumGetCString(DirectFunctionCall1(type##out, MACRO_DATUM(arg1->values[i]))));\
while (*++rp != '\0'); \
} \
*rp = '\0'; \
PG_RETURN_CSTRING(result); \
}
/*
* Operator function for the abstract data types, this MACRO is used for the
* V-types OP V-types.
* e.g. extern Datum vint2vint2pl(PG_FUNCTION_ARGS);
*/
#define __FUNCTION_OP(type1, type2, opsym, opstr) \
PG_FUNCTION_INFO_V1(v##type1##v##type2##opstr); \
Datum \
v##type1##v##type2##opstr(PG_FUNCTION_ARGS) \
{ \
int size = 0; \
int i = 0; \
v##type1 *arg1 = PG_GETARG_POINTER(0); \
v##type2 *arg2 = PG_GETARG_POINTER(1); \
Assert((arg1)->header.dim == (arg2)->header.dim); \
size = (arg1)->header.dim; \
if(sizeof(type1) > sizeof(type2)) \
{ \
v##type1 *res = NULL; \
res = (v##type1 *)buildv##type1(size); \
while(i < size) \
{ \
res->header.isnull[i] = \
arg1->header.isnull[i] || arg2->header.isnull[i]; \
if(!res->header.isnull[i]) \
res->values[i] = arg1->values[i] opsym arg2->values[i]; \
i++; \
} \
PG_RETURN_POINTER(res); \
} \
else \
{ \
v##type2 *res = NULL; \
res = (v##type2 *)buildv##type2(size); \
while(i < size) \
{ \
res->header.isnull[i] = \
arg1->header.isnull[i] || arg2->header.isnull[i]; \
if(!res->header.isnull[i]) \
res->values[i] = arg1->values[i] opsym arg2->values[i]; \
i++; \
} \
PG_RETURN_POINTER(res); \
} \
}
/*
* Operator function for the abstract data types, this MACRO is used for the
* V-types OP Consts.
* e.g. extern Datum vint2int2pl(PG_FUNCTION_ARGS);
*/
#define __FUNCTION_OP_RCONST(type, const_type, CONST_ARG_MACRO, opsym, opstr) \
PG_FUNCTION_INFO_V1(v##type##const_type##opstr); \
Datum \
v##type##const_type##opstr(PG_FUNCTION_ARGS) \
{ \
int size = 0; \
int i = 0; \
v##type *arg1 = PG_GETARG_POINTER(0); \
const_type arg2 = CONST_ARG_MACRO(1); \
v##type *res = NULL; \
size = (arg1)->header.dim; \
res = (v##type *)buildv##type(size); \
while(i < size) \
{ \
res->header.isnull[i] = (arg1)->header.isnull[i]; \
if(!res->header.isnull[i]) \
res->values[i] = arg1->values[i] opsym arg2; \
i ++ ;\
} \
PG_RETURN_POINTER(res); \
}
/*
* Comparision function for the abstract data types, this MACRO is used for the
* V-types OP V-types.
* e.g. extern Datum vint2vint2eq(PG_FUNCTION_ARGS);
*/
#define __FUNCTION_CMP(type1, type2, cmpsym, cmpstr) \
PG_FUNCTION_INFO_V1(v##type1##v##type2##cmpstr); \
Datum \
v##type1##v##type2##cmpstr(PG_FUNCTION_ARGS) \
{ \
int size = 0; \
int i = 0; \
v##type1 *arg1 = PG_GETARG_POINTER(0); \
v##type2 *arg2 = PG_GETARG_POINTER(1); \
vbool *res = NULL; \
size = (arg1)->header.dim; \
res = (vbool*)buildvbool(size); \
while(i < size) \
{ \
res->header.isnull[i] = \
arg1->header.isnull[i] || arg2->header.isnull[i]; \
if(!res->header.isnull[i]) \
res->values[i] = arg1->values[i] cmpsym arg2->values[i]; \
i++; \
} \
PG_RETURN_POINTER(res); \
}
/*
* Comparision function for the abstract data types, this MACRO is used for the
* V-types OP Consts.
* e.g. extern Datum vint2int2eq(PG_FUNCTION_ARGS);
*/
#define __FUNCTION_CMP_RCONST(type, const_type, CONST_ARG_MACRO, cmpsym, cmpstr) \
PG_FUNCTION_INFO_V1(v##type##const_type##cmpstr); \
Datum \
v##type##const_type##cmpstr(PG_FUNCTION_ARGS) \
{ \
int size = 0; \
int i = 0; \
v##type *arg1 = PG_GETARG_POINTER(0); \
const_type arg2 = CONST_ARG_MACRO(1); \
vbool *res = NULL; \
size = (arg1)->header.dim; \
res = (vbool*)buildvbool(size); \
while(i < size) \
{ \
res->header.isnull[i] = (arg1)->header.isnull[i]; \
if(!res->header.isnull[i]) \
res->values[i] = arg1->values[i] cmpsym arg2; \
i++; \
} \
PG_RETURN_POINTER(res); \
}
/* Implement the functions for the all data types by the upper BASE MARCO.*/
#define _FUNCTION_OP(type1, type2) \
__FUNCTION_OP(type1, type2, +, pl) \
__FUNCTION_OP(type1, type2, -, mi) \
__FUNCTION_OP(type1, type2, *, mul) \
__FUNCTION_OP(type1, type2, /, div)
#define FUNCTION_OP(type) \
_FUNCTION_OP(type, int2) \
_FUNCTION_OP(type, int4) \
_FUNCTION_OP(type, int8) \
_FUNCTION_OP(type, float4) \
_FUNCTION_OP(type, float8)
#define _FUNCTION_OP_RCONST(type, const_type, CONST_ARG_MACRO) \
__FUNCTION_OP_RCONST(type, const_type, CONST_ARG_MACRO, +, pl) \
__FUNCTION_OP_RCONST(type, const_type, CONST_ARG_MACRO, -, mi) \
__FUNCTION_OP_RCONST(type, const_type, CONST_ARG_MACRO, *, mul) \
__FUNCTION_OP_RCONST(type, const_type, CONST_ARG_MACRO, /, div)
#define FUNCTION_OP_RCONST(type) \
_FUNCTION_OP_RCONST(type, int2, PG_GETARG_INT16) \
_FUNCTION_OP_RCONST(type, int4, PG_GETARG_INT32) \
_FUNCTION_OP_RCONST(type, int8, PG_GETARG_INT64) \
_FUNCTION_OP_RCONST(type, float4, PG_GETARG_FLOAT4) \
_FUNCTION_OP_RCONST(type, float8, PG_GETARG_FLOAT8)
#define _FUNCTION_CMP(type1, type2) \
__FUNCTION_CMP(type1, type2, ==, eq) \
__FUNCTION_CMP(type1, type2, !=, ne) \
__FUNCTION_CMP(type1, type2, >, gt) \
__FUNCTION_CMP(type1, type2, >=, ge) \
__FUNCTION_CMP(type1, type2, <, lt) \
__FUNCTION_CMP(type1, type2, <=, le)
#define FUNCTION_CMP(type1) \
_FUNCTION_CMP(type1, int2) \
_FUNCTION_CMP(type1, int4) \
_FUNCTION_CMP(type1, int8) \
_FUNCTION_CMP(type1, float4) \
_FUNCTION_CMP(type1, float8)
#define _FUNCTION_CMP_RCONST(type, const_type, CONST_ARG_MACRO) \
__FUNCTION_CMP_RCONST(type, const_type, CONST_ARG_MACRO, ==, eq) \
__FUNCTION_CMP_RCONST(type, const_type, CONST_ARG_MACRO, !=, ne) \
__FUNCTION_CMP_RCONST(type, const_type, CONST_ARG_MACRO, >, gt) \
__FUNCTION_CMP_RCONST(type, const_type, CONST_ARG_MACRO, >=, ge) \
__FUNCTION_CMP_RCONST(type, const_type, CONST_ARG_MACRO, <, lt) \
__FUNCTION_CMP_RCONST(type, const_type, CONST_ARG_MACRO, <=, le) \
#define FUNCTION_CMP_RCONST(type) \
_FUNCTION_CMP_RCONST(type, int2, PG_GETARG_INT16) \
_FUNCTION_CMP_RCONST(type, int4, PG_GETARG_INT32) \
_FUNCTION_CMP_RCONST(type, int8, PG_GETARG_INT64) \
_FUNCTION_CMP_RCONST(type, float4, PG_GETARG_FLOAT4) \
_FUNCTION_CMP_RCONST(type, float8, PG_GETARG_FLOAT8)
#define FUNCTION_OP_ALL(type) \
FUNCTION_OP(type) \
FUNCTION_OP_RCONST(type) \
FUNCTION_CMP(type) \
FUNCTION_CMP_RCONST(type)
#define FUNCTION_GETPTR(type) \
type* getptrv##type(vheader *header,int n) \
{\
if(n < 0 || n > header->dim) return NULL; \
v##type* ptr = (v##type *) header; \
return ptr->values + n; \
}
#define FUNCTION_GETVALUE(type) \
void getvaluev##type(vheader *header,int n,Datum *ptr) \
{ \
if(n < 0 || n > header->dim) return;\
*ptr = ((v##type*)header)->values[n];\
}
#define TYPE_DEFINE(type, typeoid) \
FUNCTION_VTYPESIZE(type) \
FUNCTION_OP_ALL(type) \
FUNCTION_BUILD(type, typeoid) \
FUNCTION_DESTORY(type, typeoid) \
FUNCTION_GETPTR(type) \
FUNCTION_GETVALUE(type) \
FUNCTION_SERIALIZATION(type,typeoid) \
/* These MACRO will be expanded when the code is compiled. */
TYPE_DEFINE(int2, INT2OID)
TYPE_DEFINE(int4, INT4OID)
TYPE_DEFINE(int8, INT8OID)
TYPE_DEFINE(float4, FLOAT4OID)
TYPE_DEFINE(float8, FLOAT8OID)
TYPE_DEFINE(bool, BOOLOID)
FUNCTION_IN(int2, INT2OID, DatumGetInt16)
FUNCTION_IN(int4, INT4OID, DatumGetInt32)
FUNCTION_IN(int8, INT8OID, DatumGetInt64)
FUNCTION_IN(float4, FLOAT4OID, DatumGetFloat4)
FUNCTION_IN(float8, FLOAT8OID, DatumGetFloat8)
FUNCTION_IN(bool, BOOLOID, DatumGetBool)
FUNCTION_OUT(int2, INT2OID, Int16GetDatum)
FUNCTION_OUT(int4, INT4OID, Int32GetDatum)
FUNCTION_OUT(int8, INT8OID, Int64GetDatum)
FUNCTION_OUT(float4, FLOAT4OID, Float4GetDatum)
FUNCTION_OUT(float8, FLOAT8OID, Float8GetDatum)
FUNCTION_OUT(bool, BOOLOID, BoolGetDatum)