使用OCI向Oracle插入Geometry数据

    使用C/C++操作Oracle数据库,使用OCI可谓是最强大,当然也是最难的方式。Oracle是一个功能复杂而强大的数据库,它可以很好的支持空间数据(Oracle spatial)。如何使用OCI向Oracle数据库中插入空间数据(SDO_GEOMETRY字段)呢,本文将给出代码。

    首先,给出OCI连接数据库的代码:(ph开头的变量均是OCI句柄)

 1 //以指定的模式创建环境句柄
 2      OCIEnvCreate(&phEnv,connMode,(dvoid *)0,0,0,0,(size_t)0,(dvoid **)0);
 3      //分配服务器句柄,注意不要少了取值符号&
 4      OCIHandleAlloc((dvoid *)phEnv,(dvoid **)&phServer,OCI_HTYPE_SERVER,0,(dvoid **)0);
 5      //分配错误句柄
 6      OCIHandleAlloc((dvoid *)phEnv,(dvoid **)&phErr,OCI_HTYPE_ERROR,0,(dvoid **)0);
 7      //创建服务器上下文句柄,c_str()函数将C++类型的string字符串转化为C串 char*
 8      if(OCIServerAttach(phServer,phErr,(text *)DBname.c_str(),strlen(DBname.c_str()),OCI_DEFAULT) ==OCI_SUCCESS)
 9          cout<<"DB "+DBname+" is connected successfully!"<<endl;
10      else
11      {
12           cout<<"DB "+DBname+" is fail to connect,Please check whether you type a right DB name!"<<endl;
13      }
14      //分配上下文句柄
15       OCIHandleAlloc((dvoid *)phEnv,(dvoid **)&phSvcCtx,OCI_HTYPE_SVCCTX,0,(dvoid **)0);
16       //设置服务器上下文句柄的服务器句柄属性
17       OCIAttrSet((dvoid *)phSvcCtx,OCI_HTYPE_SVCCTX,(dvoid *)phServer,(ub4)0,OCI_ATTR_SERVER,phErr);
18       //分配用户会话句柄
19        OCIHandleAlloc((dvoid *)phEnv,(dvoid **)&phSession,OCI_HTYPE_SESSION,0,(dvoid **)0);
20        //为用户会话句柄设置用户名和密码属性
21        OCIAttrSet((dvoid *)phSession,OCI_HTYPE_SESSION,(dvoid *)username.c_str(),(ub4)strlen(username.c_str()),OCI_ATTR_USERNAME,phErr);
22        OCIAttrSet((dvoid *)phSession,OCI_HTYPE_SESSION,(dvoid *)password.c_str(),(ub4)strlen(password.c_str()),OCI_ATTR_PASSWORD,phErr);
23        //申请描述句柄
24        OCIHandleAlloc((dvoid*)phEnv,(dvoid**)&phdsc,OCI_HTYPE_DESCRIBE,0,(void**)0);
25        if (OCISessionBegin(phSvcCtx,phErr,phSession,OCI_CRED_RDBMS,OCI_DEFAULT)==OCI_SUCCESS)
26        {
27            cout<<"user session is created successfully!"<<endl;
28        } 
29        else
30        {
31            cout<<"user session is fail to create! "<<endl;
32        }
33        //在服务器上下文环境中设置用户会话属性
34        OCIAttrSet((dvoid *)phSvcCtx, OCI_HTYPE_SVCCTX,(dvoid *)phSession,(ub4) 0,OCI_ATTR_SESSION,phErr);

接下来进行数据插入:

//HYARRAYT型指针
 OCIType * ordinates_tdo =NULL;
//HYARRAYT的类型映射OCIARRAY
OCIArray * hyarray_Point =NULL;
//HYARRAYT的类型映射OCIARRAY
OCIArray * hyarray_MBR =NULL;
OCINumber oci_number;
//声明绑定
OCIBind* bndhp1 = NULL;
OCIBind* bndhp2 = NULL;
//创建用于描述SDO_ORDINATE_ARRAY类型的描述符
ordinates_tdo = get_tdo(SDO_ORDINATE_ARRAY);
//分配语句句柄
CheckErr(phErr,OCIHandleAlloc(phEnv,(void **)&phStmt,OCI_HTYPE_STMT,0,0));
string sql_str ="";
sql_str = "INSERT INTO "+table+" VALUES(:1,SDO_GEOMETRY(2002,NULL,NULL,SDO_ELEM_INFO_ARRAY( 1,2,1),:ordinates))"
text * insert = (text*)sql_str.c_str();
//准备SQL语句
    CheckErr(phErr,OCIStmtPrepare(phStmt,phErr,insert,strlen((char *)insert),OCI_NTV_SYNTAX,OCI_DEFAULT));

//变长数组类型的初始化,初始化SDO_ORDINATE_ARRAY
CheckErr(phErr,OCIObjectNew(phEnv,phErr,phSvcCtx,OCI_TYPECODE_VARRAY,ordinates_tdo,(dvoid*)NULL,OCI_DURATION_SESSION,FALSE,(dvoid**)&hyarray_Point));
vector<trackpoint> pointSet = track.getPointSet();
//输入坐标值 (linestring)
for (int i=0;i<pointSet.size();i++)
    {
        CheckErr(phErr,OCINumberFromReal(phErr,(dvoid*)&pointSet[i].lon,(uword)sizeof(double),&oci_number));
        CheckErr(phErr,OCICollAppend(phEnv,phErr,(dvoid*)&oci_number,(dvoid*)0,(OCIColl*)hyarray_Point));
        CheckErr(phErr,OCINumberFromReal(phErr,(dvoid*)&pointSet[i].lat,(uword)sizeof(double),&oci_number));
        CheckErr(phErr,OCICollAppend(phEnv,phErr,(dvoid*)&oci_number,(dvoid*)0,(OCIColl*)hyarray_Point));
    }
//绑定变量
CheckErr(phErr,OCIBindByPos(phStmt,&bndhp1,phErr,1,&nid,sizeof(int),SQLT_FLT,0,0,0,0,0,OCI_DEFAULT));
//变量绑定,此处为坐标
CheckErr(phErr,OCIBindByName(phStmt,&bndhp1,phErr,(text*)":ordinates",(sb4)-1,(dvoid*)0,(sb4)0,SQLT_NTY,(dvoid*)0,(ub2*)0,(ub2*)0,(ub4)0,(ub4*)0,(ub4)OCI_DEFAULT));
CheckErr(phErr,OCIBindObject(bndhp1,phErr,ordinates_tdo,(dvoid**)&hyarray_Point,(ub4*)0,(dvoid**)0,(ub4*)0));
//执行SQL语句
CheckErr(phErr,OCIStmtExecute(phSvcCtx,phStmt,phErr,1,0,NULL,NULL,OCI_DEFAULT));
OCITransCommit(phSvcCtx,phErr,(ub4)0);

应该注意的是Oracle spatial的SDO_GEOMETRY字段,它的构建方式为:

SDO_GEOMETRY(

      2002  --表示集合类型,此处为线串

      NULL  --表示坐标系

      NULL  -- 表示点的类型

      SDO_ELEM_INFO_ARRAY(1,2,1) --表示几何的属性

      SDO_ORDINATE_ARRAY   --表示几何类型的坐标

      (

            x1,x2,

            x3,x4,

            .....

            xn,xn+1

      )

)

以上具体可查看Oracle官方文档。

原文地址:https://www.cnblogs.com/WonderHow/p/4049925.html