Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 关于setDataBuffer(OCCI)包装器的实践_C++_Oracle_Wrapper - Fatal编程技术网

C++ 关于setDataBuffer(OCCI)包装器的实践

C++ 关于setDataBuffer(OCCI)包装器的实践,c++,oracle,wrapper,C++,Oracle,Wrapper,我有一个OracleConnection类,它使用OCCI Oracle API访问数据库。我现在需要从数据库中获取多行记录,这是通过API的ResultSet::getDataBuffer(…)函数完成的。此函数接受一系列参数,其中一个参数是定义可以包含的数据类型的大型枚举 显然,我不想用oracleapi类型来扩展我的应用程序代码,所以其他API可以与这个API互换。所以我的问题是如何在函数包装器中最好地使用这个类型参数?我应该创建一个枚举并只使用我需要的类型,还是模板可以帮助我在这里映射到

我有一个OracleConnection类,它使用OCCI Oracle API访问数据库。我现在需要从数据库中获取多行记录,这是通过API的ResultSet::getDataBuffer(…)函数完成的。此函数接受一系列参数,其中一个参数是定义可以包含的数据类型的大型枚举

显然,我不想用oracleapi类型来扩展我的应用程序代码,所以其他API可以与这个API互换。所以我的问题是如何在函数包装器中最好地使用这个类型参数?我应该创建一个枚举并只使用我需要的类型,还是模板可以帮助我在这里映射到OracleConnection类中OCCI的枚举

Occi功能:

void setDataBuffer(
   unsigned int colIndex,
   void *buffer,
   Type type,
   sb4 size = 0,
   ub2 *length = NULL,
   sb2 *ind = NULL,
   ub2 *rc = NULL);
Type
下面是一个如下所示的枚举:

enum Type
{
 OCCI_SQLT_CHR=SQLT_CHR,
 OCCI_SQLT_NUM=SQLT_NUM,
 OCCIINT = SQLT_INT,
 OCCIFLOAT = SQLT_FLT,
 OCCIBFLOAT = SQLT_BFLOAT,
 OCCIBDOUBLE = SQLT_BDOUBLE,
 OCCIIBFLOAT = SQLT_IBFLOAT,
 OCCIIBDOUBLE = SQLT_IBDOUBLE,
 OCCI_SQLT_STR=SQLT_STR,
 OCCI_SQLT_VNU=SQLT_VNU,
 OCCI_SQLT_PDN=SQLT_PDN,
 OCCI_SQLT_LNG=SQLT_LNG,
 OCCI_SQLT_VCS=SQLT_VCS,
.... (about 2x as many to go)
template <typename T>
struct oracle_type_traits;


template <> // create a specialization for each relevant type
struct oracle_type_traits<double> {
    static const value = OCCIBDOUBLE // its value member should be the value you want to map to
};
我的包装器如下所示:

void setDataBuffer(unsigned int colIndex, void * buffer, unsigned long size = 0, int type /*use int or template or redefine own Type Enum?*/,  unsigned short * length = NULL, signed short * ind = NULL, unsigned short * rc = NULL)

我建议使用enum选项。使用它作为模板意味着您的API用户应该了解之前可能有点困难的所有类型。使用它作为枚举还可以让它们作为引用枚举的选项,并决定哪些SQL类型符合要求。

我建议使用枚举选项。使用它作为模板意味着您的API用户应该了解之前可能有点困难的所有类型。使用它作为枚举还可以让它们作为引用枚举的选项,并决定哪些SQL类型符合要求。

一个选项可以是将函数设置为模板,然后使用traits类将模板类型转换为表示各种Oracle类型的值

traits类可以如下所示:

enum Type
{
 OCCI_SQLT_CHR=SQLT_CHR,
 OCCI_SQLT_NUM=SQLT_NUM,
 OCCIINT = SQLT_INT,
 OCCIFLOAT = SQLT_FLT,
 OCCIBFLOAT = SQLT_BFLOAT,
 OCCIBDOUBLE = SQLT_BDOUBLE,
 OCCIIBFLOAT = SQLT_IBFLOAT,
 OCCIIBDOUBLE = SQLT_IBDOUBLE,
 OCCI_SQLT_STR=SQLT_STR,
 OCCI_SQLT_VNU=SQLT_VNU,
 OCCI_SQLT_PDN=SQLT_PDN,
 OCCI_SQLT_LNG=SQLT_LNG,
 OCCI_SQLT_VCS=SQLT_VCS,
.... (about 2x as many to go)
template <typename T>
struct oracle_type_traits;


template <> // create a specialization for each relevant type
struct oracle_type_traits<double> {
    static const value = OCCIBDOUBLE // its value member should be the value you want to map to
};

setDataBuffer(…)
中,只需选中
oracle\u type\u traits::value
即可获得相应的oracle类型ID。

一个选项是将函数设置为模板,然后使用traits类将模板类型转换为表示各种oracle类型的值

traits类可以如下所示:

enum Type
{
 OCCI_SQLT_CHR=SQLT_CHR,
 OCCI_SQLT_NUM=SQLT_NUM,
 OCCIINT = SQLT_INT,
 OCCIFLOAT = SQLT_FLT,
 OCCIBFLOAT = SQLT_BFLOAT,
 OCCIBDOUBLE = SQLT_BDOUBLE,
 OCCIIBFLOAT = SQLT_IBFLOAT,
 OCCIIBDOUBLE = SQLT_IBDOUBLE,
 OCCI_SQLT_STR=SQLT_STR,
 OCCI_SQLT_VNU=SQLT_VNU,
 OCCI_SQLT_PDN=SQLT_PDN,
 OCCI_SQLT_LNG=SQLT_LNG,
 OCCI_SQLT_VCS=SQLT_VCS,
.... (about 2x as many to go)
template <typename T>
struct oracle_type_traits;


template <> // create a specialization for each relevant type
struct oracle_type_traits<double> {
    static const value = OCCIBDOUBLE // its value member should be the value you want to map to
};

setDataBuffer(…)
内部,您只需检查
oracle\u type\u traits::value
即可获得相应的oracle类型ID。

从包装器用户的POV中,最好是他们调用重载函数或函数(成员)他们将对象传递给适当类型的模板,然后该模板将神奇地为该类型做正确的事情。也就是说,对于您的类(或Oracle API)支持的任何类型,最好都有一个函数
getData(unsigned int colIndex,T&)
,该函数将找出必要的缓冲区大小,分配缓冲区,确定正确的枚举,并调用Oracle API函数。
我相信您可以解决大部分细节,可能除了如何将类型映射到
枚举
,所以这就是我将尝试解决的问题

基本上,我认为这有两种可能,其中一种(使用编译时列表)更适合支持大量类型,而另一种(使用特征)则需要使用,前提是有更多特定于此的类型,而不仅仅是将一个类型映射到
枚举

traits方法使用起来非常简单,但如果您有许多类型,那么它会非常乏味:

template<typename T>
struct get_data_buffer_traits;

template<>
struct get_data_buffer_traits<int> {
  Type type OCCIINT;
};

template<>
struct get_data_buffer_traits<float> {
  Type type OCCIBFLOAT;
};
但是,如果是这种情况,您还可以创建一个编译时映射,将两者映射在一起,并(在编译时)搜索右侧的
enum
值。如果您手头没有提供此功能的模板元库,以下是如何自己实现此功能的概要:

// Beware, brain-compiled code ahead!

struct nil {};

template< typename HType
        , Type HEnum
        , class T >
struct set_data_buffer_type_map_node {
  typedef HType      head_type
  enum             { head_enum = HEnum };
  typedef T          tail_type;
};

typedef 
  set_data_buffer_type_map_node< int , OCCIINT
  set_data_buffer_type_map_node< float, OCCIBFLOAT
  ...
  nil
  > > // either count or keep adding these until compiler accepts :)
  set_data_buffer_type_map;

template< typename T, class Map >
struct getter {
  // recurse towards tail
  Type get_enum() { return getter<T,typename Map::tail_type>::get_enum(); }
};

template< typename T, Type HEnum, class Tail >
struct getter< T, set_data_buffer_type_map<T,HEnum,Tail> > {
  // current node has T as HType
  Type get_enum() { return set_data_buffer_type_map<T,HEnum,Tail>::head_enum; }
};

 template< typename T, typename HType, Type HEnum, >
struct getter< T, set_data_buffer_type_map<T,HEnum,nil> > {
  // no function here, so compile-time error
};

template< typename T>
Type get_type_enum()
{
   return getter<T, set_data_buffer_type_map>::get_enum();
}
//当心,brain提前编译了代码!
结构nil{};
模板
结构集\数据\缓冲区\类型\映射\节点{
typedef HType head_type
枚举{head_enum=HEnum};
类型def T tail_类型;
};
类型定义
设置数据缓冲区类型映射节点>//计算或继续添加这些,直到编译器接受:)
设置数据缓冲区类型映射;
模板
结构吸气剂{
//向尾部递归
键入get_enum(){return getter::get_enum();}
};
模板
struct getter{
//当前节点具有作为HType的T
类型get_enum(){return set_data_buffer_Type_map::head_enum;}
};
模板
struct getter{
//这里没有函数,所以编译时出错
};
模板
类型get_类型_枚举()
{
返回getter::get_enum();
}

(注意:这只是一个大纲。我甚至没有试图编译它。)

从包装器用户的角度来看,最好是他们调用重载函数或函数(成员)模板,将适当类型的对象传递给该模板,然后该模板将神奇地为该类型做正确的事情。也就是说,对于您的类(或Oracle API)支持的任何类型,最好都有一个函数
getData(unsigned int colIndex,T&)
,该函数将找出必要的缓冲区大小,分配缓冲区,确定正确的枚举,并调用Oracle API函数。
我相信您可以解决大部分细节,可能除了如何将类型映射到
枚举
,所以这就是我将尝试解决的问题

基本上,我认为这有两种可能,其中一种(使用编译时列表)更适合支持大量类型,而另一种(使用特征)则需要使用,前提是有更多特定于此的类型,而不仅仅是将一个类型映射到
枚举

traits方法使用起来非常简单,但如果您有许多类型,那么它会非常乏味:

template<typename T>
struct get_data_buffer_traits;

template<>
struct get_data_buffer_traits<int> {
  Type type OCCIINT;
};

template<>
struct get_data_buffer_traits<float> {
  Type type OCCIBFLOAT;
};
但是,如果是这种情况,您还可以创建一个编译时映射,将两者映射在一起,并(在编译时)搜索右侧的
enum
值。如果你没有模板