blob: 75fce15e83cf6557ae72730f2dc338ecac908f40 [file] [log] [blame]
/* ----------------------------------------------------------------------- *//**
*
* @file AnyType_proto.hpp
*
*//* ----------------------------------------------------------------------- */
#ifndef MADLIB_POSTGRES_ANYTYPE_PROTO_HPP
#define MADLIB_POSTGRES_ANYTYPE_PROTO_HPP
namespace madlib {
namespace dbconnector {
namespace postgres {
struct SystemInformation;
/**
* @brief Proxy for PostgreSQL objects
*
* AnyType objects are used by user-defined code to both retrieve and return
* values from the backend.
*
* The content of an AnyType object is specified by mContent. It can be:
* - Null
* - A scalar value, which is just a PostgreSQL Datum
* - A function composite value, which is a virtual composite value consisting
* of all function arguments
* - A native composite value, which is a PostgreSQL HeapTupleHeader
* - A return composite value, which is a vector of AnyType objects
*/
class AnyType {
public:
AnyType();
template <typename T> AnyType(const T& inValue,
bool inForceLazyConversionToDatum = false);
template <typename T> T getAs() const;
AnyType operator[](uint16_t inID) const;
uint16_t numFields() const;
bool isNull() const;
bool isComposite() const;
AnyType& operator<<(const AnyType& inValue);
// FIXME: A temporary workaround for UDF to get/set user_fctx, a better
// solution is desired which complies with the design principles of DB
// abstraction layer.
// For some analytic algorithms (e.g. LDA), a stateful function would be
// very useful which allows to carry some states accross invocations within
// a query. Alternatively, one can achieve similar functionaltiy using a
// windowed aggregator, but this may suffer from severe performance
// degradation.
void * getUserFuncContext();
void setUserFuncContext(void * user_fctx);
MemoryContext getCacheMemoryContext();
protected:
/**
* @brief RAII class to temporarily change \c sLazyConversionToDatum
*/
class LazyConversionToDatumOverride {
public:
LazyConversionToDatumOverride(bool inLazyConversionToDatum);
~LazyConversionToDatumOverride();
protected:
bool mOriginalValue;
};
static bool sLazyConversionToDatum;
static bool lazyConversionToDatum();
// UDF and FunctionHandle access getAsDatum(), which is not part of the
// public API
friend class UDF;
friend class FunctionHandle;
/**
* @brief Type of the value of the current AnyType object
*/
enum ContentType {
Null,
Scalar,
FunctionComposite,
NativeComposite,
ReturnComposite
};
AnyType(FunctionCallInfo inFnCallInfo);
AnyType(SystemInformation* inSysInfo, HeapTupleHeader inTuple,
Datum inDatum, Oid inTypeID);
AnyType(SystemInformation* inSysInfo, Datum inDatum, Oid inTypeID,
bool inIsMutable);
void consistencyCheck() const;
Datum getAsDatum(FunctionCallInfo inFCInfo,
Oid inTargetTypeID = InvalidOid) const;
class Placeholder;
ContentType mContentType;
boost::any mContent;
std::function<Datum()> mToDatumFn;
Datum mDatum;
FunctionCallInfo fcinfo;
SystemInformation* mSysInfo;
HeapTupleHeader mTupleHeader;
std::vector<AnyType> mChildren;
Oid mTypeID;
const char* mTypeName;
bool mIsMutable;
};
AnyType Null();
/**
* @brief Cast that extract the proper type from AnyType but leaves other types
* unaffected
*
* Sometimes it is desirable to write generic code that works on both an
* \c AnyType object as well as a value with a concrete type. For instance, a
* \c FunctionHandle always returns an \c AnyType object. In generatic code,
* however, a \c FunctionHandle might as well be replaced by just call a
* "normal" functor or a C++ function pointer, both of which typically return
* concrete types (e.g., double).
*
* In generic code, we could write <tt>AnyType_cast<double>(func())</tt> so that
* if the template parameter \c Function is \c AnyType, we have an explicit
* conversion to \c double, and if \c Function is just a function pointer, the
* return value of <tt>func()</tt> passes unchanged.
*/
template <class T>
inline
T
AnyType_cast(const AnyType& inValue) {
return inValue.getAs<T>();
}
template <class T>
inline
const T&
AnyType_cast(const T& inValue) {
return inValue;
}
template <class T>
inline
T&
AnyType_cast(T& inValue) {
return inValue;
}
} // namespace postgres
} // namespace dbconnector
} // namespace madlib
#endif // defined(MADLIB_POSTGRES_ANYTYPE_PROTO_HPP)