/* ----------------------------------------------------------------------- *//** * * @file TypeTraits_impl.hpp * *//* ----------------------------------------------------------------------- */ #ifndef MADLIB_POSTGRES_TYPETRAITS_IMPL_HPP #define MADLIB_POSTGRES_TYPETRAITS_IMPL_HPP namespace madlib { namespace dbconnector { namespace postgres { template class convertTo { public: convertTo(const T& inOrig) : mOrig(inOrig) { } operator U() { if (std::numeric_limits::is_signed && !std::numeric_limits::is_signed && utils::isNegative(mOrig)) { std::stringstream errorMsg; errorMsg << "Invalid value conversion. Expected unsigned value but " "got " << mOrig << "."; throw std::invalid_argument(errorMsg.str()); } else if ( (std::numeric_limits::digits > std::numeric_limits::digits || (!std::numeric_limits::is_signed && std::numeric_limits::is_signed)) && mOrig > static_cast(std::numeric_limits::max())) { std::stringstream errorMsg; errorMsg << "Invalid value conversion. Cannot represent " << mOrig << "in target type (" << typeid(T).name() << ")."; throw std::invalid_argument(errorMsg.str()); } return static_cast(mOrig); } private: const T& mOrig; }; #define WITH_OID(_oid) enum { oid = _oid } /* * The type OID (_oid) can be set to InvalidOid if it should not be used for * type verification. This is the case for types that are not built-in and for * which no fixed OID is known at compile time. */ #define WITHOUT_OID enum { oid = InvalidOid } #define WITH_TYPE_CLASS(_typeClass) enum { typeClass = _typeClass } #define WITH_TYPE_NAME(_type_name) \ static inline const char* typeName() { \ return _type_name; \ } /* The type name (_type_name) can be NULL if it should not be used for type * verification. This is the case for built-in types, for which only the type * OID should be verified, but not the type name. */ #define WITHOUT_TYPE_NAME \ static const char* typeName() { \ return NULL; \ } /* * Mutable means in this context that the value of a variable can be changed and * that it would change the value for the backend */ #define WITH_MUTABILITY(_isMutable) \ enum { isMutable = _isMutable } #define WITHOUT_SYSINFO \ static SystemInformation* toSysInfo(const value_type&) { \ return NULL; \ } #define WITH_DEFAULT_EXTENDED_TRAITS \ WITHOUT_TYPE_NAME \ WITHOUT_SYSINFO #define WITH_SYS_INFO_CONVERSION(_convertToSysInfo) \ static SystemInformation* toSysInfo(const value_type& value) { \ (void) value; \ return _convertToSysInfo; \ } #define WITH_TO_PG_CONVERSION(_convertToPG) \ static Datum toDatum(const value_type& value) { \ return _convertToPG; \ } #define WITH_TO_CXX_CONVERSION(_convertToCXX) \ static value_type toCXXType(Datum value, bool needMutableClone, \ SystemInformation* sysInfo) { \ \ (void) value; \ (void) needMutableClone; \ (void) sysInfo; \ return _convertToCXX; \ } #define WITH_BIND_TO_STREAM(_bindToStream) \ template \ static void bindToStream(dbal::ByteStream& stream, \ reference_type& ref) { \ \ _bindToStream; \ } template struct TypeTraitsBase { enum { oid = InvalidOid }; enum { alignment = MAXIMUM_ALIGNOF }; enum { isMutable = dbal::Immutable }; enum { typeClass = dbal::SimpleType }; typedef T value_type; static const char* typeName() { return NULL; } static SystemInformation* toSysInfo(const value_type&) { return NULL; } }; template <> struct TypeTraits : public TypeTraitsBase { enum { oid = FLOAT8OID }; enum { alignment = ALIGNOF_DOUBLE }; WITH_TO_PG_CONVERSION( Float8GetDatum(value) ); WITH_TO_CXX_CONVERSION( DatumGetFloat8(value) ); }; template <> struct TypeTraits{ typedef float value_type; WITH_OID( FLOAT4OID ); WITH_TYPE_CLASS( dbal::SimpleType ); WITH_MUTABILITY( dbal::Immutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( Float4GetDatum(value) ); WITH_TO_CXX_CONVERSION( DatumGetFloat4(value) ); }; template <> struct TypeTraits : public TypeTraitsBase { enum { oid = INT8OID }; enum { alignment = ALIGNOF_LONG }; WITH_TO_PG_CONVERSION( Int64GetDatum(value) ); WITH_TO_CXX_CONVERSION( DatumGetInt64(value) ); }; template <> struct TypeTraits : public TypeTraitsBase { enum { oid = INT8OID }; enum { alignment = ALIGNOF_LONG }; WITH_TO_PG_CONVERSION( Int64GetDatum((convertTo(value))) ); WITH_TO_CXX_CONVERSION( (convertTo(DatumGetInt64(value))) ); }; template <> struct TypeTraits : public TypeTraitsBase { enum { oid = INT4OID }; enum { alignment = ALIGNOF_INT }; WITH_TO_PG_CONVERSION( Int32GetDatum(value) ); WITH_TO_CXX_CONVERSION( DatumGetInt32(value) ); }; template <> struct TypeTraits : public TypeTraitsBase { enum { oid = INT4OID }; enum { alignment = ALIGNOF_INT }; WITH_TO_PG_CONVERSION( Int32GetDatum((convertTo(value))) ); WITH_TO_CXX_CONVERSION( (convertTo(DatumGetInt32(value))) ); }; template <> struct TypeTraits : public TypeTraitsBase { enum { oid = INT2OID }; enum { alignment = ALIGNOF_SHORT }; WITH_TO_PG_CONVERSION( Int16GetDatum(value) ); WITH_TO_CXX_CONVERSION( DatumGetInt16(value) ); }; template <> struct TypeTraits : public TypeTraitsBase { enum { oid = INT2OID }; enum { alignment = ALIGNOF_SHORT }; WITH_TO_PG_CONVERSION( Int16GetDatum((convertTo(value))) ); WITH_TO_CXX_CONVERSION( (convertTo(DatumGetInt16(value))) ); }; template <> struct TypeTraits : public TypeTraitsBase { enum { oid = BOOLOID }; enum { alignment = 1 }; WITH_TO_PG_CONVERSION( BoolGetDatum(value) ); WITH_TO_CXX_CONVERSION( DatumGetBool(value) ); }; template <> struct TypeTraits { typedef char* value_type; WITH_OID( TEXTOID ); WITH_TYPE_CLASS( dbal::SimpleType ); WITH_MUTABILITY( dbal::Immutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION(PointerGetDatum(cstring_to_text(value))); WITH_TO_CXX_CONVERSION(text_to_cstring(DatumGetTextPP(value))); }; template <> struct TypeTraits { typedef std::string value_type; WITH_OID( TEXTOID ); WITH_TYPE_CLASS( dbal::SimpleType ); WITH_MUTABILITY( dbal::Immutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION(PointerGetDatum( cstring_to_text_with_len(value.data(), static_cast(value.size())))); WITH_TO_CXX_CONVERSION(std::string(VARDATA_ANY(value), VARSIZE_ANY(value) - VARHDRSZ)); }; template <> struct TypeTraits : public TypeTraitsBase { enum { alignment = MAXIMUM_ALIGNOF }; WITH_TYPE_NAME("bytea8"); WITH_TO_PG_CONVERSION( PointerGetDatum(value.byteString()) ); WITH_TO_CXX_CONVERSION( madlib_DatumGetByteaP(value) ); }; template <> struct TypeTraits : public TypeTraitsBase { enum { alignment = MAXIMUM_ALIGNOF }; WITH_MUTABILITY( dbal::Mutable ); WITH_TYPE_NAME("bytea8"); WITH_TO_PG_CONVERSION( PointerGetDatum(value.byteString()) ); WITH_TO_CXX_CONVERSION( needMutableClone ? madlib_DatumGetByteaPCopy(value) : madlib_DatumGetByteaP(value) ); }; template <> struct TypeTraits { typedef FunctionHandle value_type; WITH_OID( REGPROCOID ); WITH_TYPE_CLASS( dbal::SimpleType ); WITH_MUTABILITY( dbal::Immutable ); WITHOUT_TYPE_NAME; WITH_SYS_INFO_CONVERSION( value.getSysInfo() ); WITH_TO_PG_CONVERSION( ObjectIdGetDatum(value.funcID()) ); WITH_TO_CXX_CONVERSION( FunctionHandle(sysInfo, DatumGetObjectId(value)) ); }; template <> struct TypeTraits > : public TypeTraitsBase > { enum { oid = INT4ARRAYOID }; enum { isMutable = dbal::Immutable }; enum { typeClass = dbal::ArrayType }; WITH_TO_PG_CONVERSION( PointerGetDatum(value.array()) ); WITH_TO_CXX_CONVERSION( madlib_DatumGetArrayTypeP(value) ); }; template <> struct TypeTraits > : public TypeTraitsBase > { enum { oid = INT4ARRAYOID }; enum { isMutable = dbal::Mutable }; enum { typeClass = dbal::ArrayType }; WITH_TO_PG_CONVERSION( PointerGetDatum(value.array()) ); WITH_TO_CXX_CONVERSION( needMutableClone ? madlib_DatumGetArrayTypePCopy(value) : madlib_DatumGetArrayTypeP(value) ); }; template <> struct TypeTraits > : public TypeTraitsBase > { enum { oid = INT8ARRAYOID }; enum { isMutable = dbal::Immutable }; enum { typeClass = dbal::ArrayType }; WITH_TO_PG_CONVERSION( PointerGetDatum(value.array()) ); WITH_TO_CXX_CONVERSION( madlib_DatumGetArrayTypeP(value) ); }; template <> struct TypeTraits > : public TypeTraitsBase > { enum { oid = INT8ARRAYOID }; enum { isMutable = dbal::Mutable }; enum { typeClass = dbal::ArrayType }; WITH_TO_PG_CONVERSION( PointerGetDatum(value.array()) ); WITH_TO_CXX_CONVERSION( needMutableClone ? madlib_DatumGetArrayTypePCopy(value) : madlib_DatumGetArrayTypeP(value) ); }; template <> struct TypeTraits > { typedef ArrayHandle value_type; WITH_OID( FLOAT8ARRAYOID ); WITH_TYPE_CLASS( dbal::ArrayType ); WITH_MUTABILITY( dbal::Immutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( PointerGetDatum(value.array()) ); WITH_TO_CXX_CONVERSION( madlib_DatumGetArrayTypeP(value) ); }; template <> struct TypeTraits > { typedef ArrayHandle value_type; WITH_OID(TEXTARRAYOID); WITH_TYPE_CLASS( dbal::ArrayType ); WITH_MUTABILITY( dbal::Immutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( PointerGetDatum(value.array()) ); WITH_TO_CXX_CONVERSION( reinterpret_cast(madlib_DatumGetArrayTypeP(value)) ); }; // Note: See the comment for PG_FREE_IF_COPY in fmgr.h. Essentially, when // writing UDFs, we do not have to worry about deallocating copies of immutable // arrays. They will simply be garbage collected. template <> struct TypeTraits > { typedef MutableArrayHandle value_type; WITH_OID( FLOAT8ARRAYOID ); WITH_TYPE_CLASS( dbal::ArrayType ); WITH_MUTABILITY( dbal::Mutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( PointerGetDatum(value.array()) ); WITH_TO_CXX_CONVERSION( needMutableClone ? madlib_DatumGetArrayTypePCopy(value) : madlib_DatumGetArrayTypeP(value) ); }; // NativeColumnVector template <> struct TypeTraits< dbal::eigen_integration::HandleMap< const dbal::eigen_integration::ColumnVector, ArrayHandle > > { typedef dbal::eigen_integration::HandleMap< const dbal::eigen_integration::ColumnVector, ArrayHandle > value_type; WITH_OID( FLOAT8ARRAYOID ); WITH_TYPE_CLASS( dbal::ArrayType ); WITH_MUTABILITY( dbal::Immutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( PointerGetDatum(value.memoryHandle().array()) ); WITH_TO_CXX_CONVERSION( ArrayHandle(reinterpret_cast( madlib_DatumGetArrayTypeP(value))) ); }; // MutableNativeColumnVector template <> struct TypeTraits< dbal::eigen_integration::HandleMap< dbal::eigen_integration::ColumnVector, MutableArrayHandle > > { typedef dbal::eigen_integration::HandleMap< dbal::eigen_integration::ColumnVector, MutableArrayHandle > value_type; WITH_OID( FLOAT8ARRAYOID ); WITH_TYPE_CLASS( dbal::ArrayType ); WITH_MUTABILITY( dbal::Mutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( PointerGetDatum(value.memoryHandle().array()) ); WITH_TO_CXX_CONVERSION( MutableArrayHandle(reinterpret_cast( needMutableClone ? madlib_DatumGetArrayTypePCopy(value) : madlib_DatumGetArrayTypeP(value) )) ); }; // NativeIntegerVector template <> struct TypeTraits< dbal::eigen_integration::HandleMap< const dbal::eigen_integration::IntegerVector, ArrayHandle > > { typedef dbal::eigen_integration::HandleMap< const dbal::eigen_integration::IntegerVector, ArrayHandle > value_type; WITH_OID( INT4ARRAYOID ); WITH_TYPE_CLASS( dbal::ArrayType ); WITH_MUTABILITY( dbal::Immutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( PointerGetDatum(value.memoryHandle().array()) ); WITH_TO_CXX_CONVERSION( ArrayHandle(reinterpret_cast( madlib_DatumGetArrayTypeP(value))) ); }; // MutableNativeIntegerVector template <> struct TypeTraits< dbal::eigen_integration::HandleMap< dbal::eigen_integration::IntegerVector, MutableArrayHandle > > { typedef dbal::eigen_integration::HandleMap< dbal::eigen_integration::IntegerVector, MutableArrayHandle > value_type; WITH_OID( INT4ARRAYOID ); WITH_TYPE_CLASS( dbal::ArrayType ); WITH_MUTABILITY( dbal::Mutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( PointerGetDatum(value.memoryHandle().array()) ); WITH_TO_CXX_CONVERSION( MutableArrayHandle(reinterpret_cast( needMutableClone ? madlib_DatumGetArrayTypePCopy(value) : madlib_DatumGetArrayTypeP(value) )) ); }; // NativeMatrix template <> struct TypeTraits< dbal::eigen_integration::HandleMap< const dbal::eigen_integration::Matrix, ArrayHandle > > { typedef dbal::eigen_integration::HandleMap< const dbal::eigen_integration::Matrix, ArrayHandle > value_type; WITH_OID( FLOAT8ARRAYOID ); WITH_TYPE_CLASS( dbal::ArrayType ); WITH_MUTABILITY( dbal::Immutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( PointerGetDatum(value.memoryHandle().array()) ); WITH_TO_CXX_CONVERSION( ArrayHandle( reinterpret_cast(madlib_DatumGetArrayTypeP(value)) ) ); }; // MutableNativeMatrix template <> struct TypeTraits< dbal::eigen_integration::HandleMap< dbal::eigen_integration::Matrix, MutableArrayHandle > > { typedef dbal::eigen_integration::HandleMap< dbal::eigen_integration::Matrix, MutableArrayHandle > value_type; WITH_OID( FLOAT8ARRAYOID ); WITH_TYPE_CLASS( dbal::ArrayType ); WITH_MUTABILITY( dbal::Mutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( PointerGetDatum(value.memoryHandle().array()) ); WITH_TO_CXX_CONVERSION( MutableArrayHandle( reinterpret_cast(needMutableClone ? madlib_DatumGetArrayTypePCopy(value) : madlib_DatumGetArrayTypeP(value) )) ); }; // MappedColumnVector and MutableMappedColumnVector // FIXME: This looks gross. We want to express this without hurting our eyes. template struct TypeTraits< dbal::eigen_integration::HandleMap< typename boost::mpl::if_c::type, TransparentHandle > > : public TypeTraitsBase::type, TransparentHandle > > { typedef TypeTraitsBase::type, TransparentHandle > > Base; typedef typename Base::value_type value_type; enum { oid = FLOAT8ARRAYOID }; enum { alignment = MAXIMUM_ALIGNOF }; enum { isMutable = IsMutable }; enum { typeClass = dbal::ArrayType }; WITH_TO_PG_CONVERSION( PointerGetDatum(VectorToNativeArray(value)) ) WITH_TO_CXX_CONVERSION(( NativeArrayToMappedVector(value, needMutableClone) )); }; // MappedIntegerVector and MutableMappedIntegerVector template struct TypeTraits< dbal::eigen_integration::HandleMap< typename boost::mpl::if_c::type, TransparentHandle > > : public TypeTraitsBase::type, TransparentHandle > > { typedef TypeTraitsBase::type, TransparentHandle > > Base; typedef typename Base::value_type value_type; enum { oid = INT4ARRAYOID }; enum { alignment = MAXIMUM_ALIGNOF }; enum { isMutable = IsMutable }; enum { typeClass = dbal::ArrayType }; WITH_TO_PG_CONVERSION( PointerGetDatum(VectorToNativeArray(value)) ) WITH_TO_CXX_CONVERSION(( NativeArrayToMappedVector(value, needMutableClone) )); }; // MappedMatrix and MutableMappedMatrix template struct TypeTraits< dbal::eigen_integration::HandleMap< typename boost::mpl::if_c::type, TransparentHandle > > : public TypeTraitsBase::type, TransparentHandle > > { typedef TypeTraitsBase::type, TransparentHandle > > Base; typedef typename Base::value_type value_type; enum { oid = FLOAT8ARRAYOID }; enum { alignment = MAXIMUM_ALIGNOF }; enum { isMutable = IsMutable }; enum { typeClass = dbal::ArrayType }; WITH_TO_PG_CONVERSION( PointerGetDatum(MatrixToNativeArray(value)) ) WITH_TO_CXX_CONVERSION(( NativeArrayToMappedMatrix(value, needMutableClone) )) }; // MappedVectorXcd and MutableMappedVectorXcd template struct TypeTraits< dbal::eigen_integration::HandleMap< typename boost::mpl::if_c::type, TransparentHandle, IsMutable> > > : public TypeTraitsBase::type, TransparentHandle, IsMutable> > > { typedef TypeTraitsBase::type, TransparentHandle, IsMutable> > > Base; typedef typename Base::value_type value_type; enum { oid = FLOAT8ARRAYOID }; enum { alignment = MAXIMUM_ALIGNOF }; enum { isMutable = IsMutable }; enum { typeClass = dbal::ArrayType }; WITH_TO_PG_CONVERSION( PointerGetDatum(VectorXcdToNativeArray(value)) ) WITH_TO_CXX_CONVERSION(( NativeArrayToMappedVectorXcd(value, needMutableClone) )) }; // ------------------------------------------------------------------------ // locally allocated structures require copying // ------------------------------------------------------------------------ template <> struct TypeTraits : public TypeTraitsBase { typedef dbal::eigen_integration::ColumnVector value_type; enum { oid = FLOAT8ARRAYOID }; enum { isMutable = dbal::Immutable }; enum { typeClass = dbal::ArrayType }; WITH_TO_PG_CONVERSION( PointerGetDatum(VectorToNativeArray(value)) ); // No need to support retrieving this type from the backend. Use // MappedColumnVector instead. }; template <> struct TypeTraits : public TypeTraitsBase { typedef dbal::eigen_integration::IntegerVector value_type; enum { oid = INT4ARRAYOID }; enum { isMutable = dbal::Immutable }; enum { typeClass = dbal::ArrayType }; WITH_TO_PG_CONVERSION( PointerGetDatum(VectorToNativeArray(value)) ); // No need to support retrieving this type from the backend. Use // MappedIntegerVector instead. }; template <> struct TypeTraits : public TypeTraitsBase { typedef dbal::eigen_integration::Matrix value_type; enum { oid = FLOAT8ARRAYOID }; enum { isMutable = dbal::Immutable }; enum { typeClass = dbal::ArrayType }; WITH_TO_PG_CONVERSION( PointerGetDatum(MatrixToNativeArray(value)) ); // No need to support retrieving this type from the backend. Use // MappedMatrix instead. }; template struct TypeTraits > { typedef Eigen::MatrixBase value_type; WITH_OID( FLOAT8ARRAYOID ); WITH_TYPE_CLASS( dbal::ArrayType ); WITH_MUTABILITY( dbal::Immutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( PointerGetDatum( Derived::RowsAtCompileTime == 1 || Derived::ColsAtCompileTime == 1 ? VectorToNativeArray(value) : MatrixToNativeArray(value) ) ); // No need to support retrieving this type from the backend. Use // MappedColumnVector or MappedMatrix instead. }; template struct TypeTraits< Eigen::Block > { typedef Eigen::Block value_type; WITH_OID( FLOAT8ARRAYOID ); WITH_TYPE_CLASS( dbal::ArrayType ); WITH_MUTABILITY( dbal::Immutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( PointerGetDatum(MatrixToNativeArray(value)) ); // No need to support retrieving this type from the backend. Use // MappedMatrix instead. }; template struct TypeTraits< Eigen::Block > { typedef Eigen::Block value_type; WITH_OID( FLOAT8ARRAYOID ); WITH_TYPE_CLASS( dbal::ArrayType ); WITH_MUTABILITY( dbal::Immutable ); WITH_DEFAULT_EXTENDED_TRAITS; WITH_TO_PG_CONVERSION( PointerGetDatum(VectorToNativeArray(value)) ); // No need to support retrieving this type from the backend. Use // MappedColumnVector instead. }; template <> struct TypeTraits { typedef dbal::eigen_integration::SparseColumnVector value_type; WITHOUT_OID; WITH_TYPE_NAME("svec"); WITH_TYPE_CLASS( dbal::SimpleType ); WITH_MUTABILITY( dbal::Immutable ); WITHOUT_SYSINFO; WITH_TO_PG_CONVERSION( PointerGetDatum(SparseColumnVectorToLegacySparseVector(value)) ); WITH_TO_CXX_CONVERSION( LegacySparseVectorToSparseColumnVector(reinterpret_cast(value)) ); }; // Special cases template <> struct TypeTraits : public TypeTraitsBase { enum { alignment = MAXIMUM_ALIGNOF }; }; #undef WITH_OID #undef WITHOUT_OID #undef WITH_TYPE_CLASS #undef WITH_TYPE_NAME #undef WITHOUT_TYPE_NAME #undef WITH_MUTABILITY #undef WITHOUT_SYSINFO #undef WITH_DEFAULT_EXTENDED_TRAITS #undef WITH_SYS_INFO_CONVERSION #undef WITH_TO_PG_CONVERSION #undef WITH_TO_CXX_CONVERSION } // namespace postgres } // namespace dbconnector } // namespace madlib #endif // defined(MADLIB_POSTGRES_TYPETRAITS_IMPL_HPP)