Browse Source

first commit

GTong 11 months ago
commit
09a27d619f

+ 3 - 0
go.mod

@@ -0,0 +1,3 @@
+module xg_data_generate
+
+go 1.22.2

+ 93 - 0
internal/dbBase/select.go

@@ -0,0 +1,93 @@
+package dbBase
+
+import (
+	"database/sql"
+	"fmt"
+	"log"
+	_ "xg_data_generate/pkg/go-driver-xugusql"
+)
+
+type TableInfo struct {
+	filedName []string
+	filedType []string
+	filedLen  []int
+	filedDec  []int
+}
+
+func GetDbLink(ip string, port string, dbBase string, user string, pwd string) *sql.DB {
+	var db *sql.DB
+	var err error
+	dbLink := fmt.Sprintf("IP=%s;DB=%s;User=%s;"+"PWD=%s;Port=%s;AUTO_COMMIT=on;CHAR_SET=UTF8", ip, dbBase, user, pwd, port)
+	db, err = sql.Open("xugusql", dbLink)
+	if err != nil {
+		log.Fatal("db open fail")
+	}
+	err = db.Ping()
+	if err != nil {
+		log.Fatal("db Ping fail")
+	} else {
+		log.Printf("db Ping ok")
+	}
+	return db
+}
+
+func GetAllTables(db *sql.DB, sql string) ([]string, error) {
+
+}
+
+func QueryFieldType(db *sql.DB, sql string) error {
+	tableInfo := []TableInfo{}
+	rows, err := db.Query(sql)
+	if err != nil {
+		log.Fatal(err)
+	}
+	var cols []string
+	cols, err = rows.Columns()
+	if err != nil {
+		log.Fatal(err)
+	}
+	colsType, err := rows.ColumnTypes()
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println("cols Name:", cols)
+	// 打印每个列的信息
+	for _, col := range colsType {
+		// 获取列的扫描类型
+		/*ScanType() reflect.Type
+		返回 Go 语言中的类型,用于扫描数据库值到该列。用于确定该列的数据应被扫描到什么类型的 Go 变量。*/
+		scanType := col.ScanType()
+		fmt.Println("Scan Type:", scanType)
+
+		tableInfo = append(tableInfo, TableInfo{
+			filedName: []string{col.Name()},
+			filedType: []string{col.DatabaseTypeName()},
+		})
+	}
+
+	fmt.Println("tableInfo:", tableInfo)
+
+	// var sqlResult string
+	// pvals := make([]interface{}, len(cols))
+	// for key, _ := range pvals {
+	// 	dest := make([]byte, 216)
+	// 	pvals[key] = &dest
+	// } /* end for */
+
+	// for rows.Next() {
+	// 	err = rows.Scan(pvals...)
+	// 	if err != nil {
+	// 		log.Fatal(err)
+	// 	}
+	// 	for _, v := range pvals {
+
+	// 		//	fmt.Printf("%s | ", string(*(v.(*[]byte))))
+	// 		sqlResult += fmt.Sprintf("%s", string(*(v.(*[]byte))))
+
+	// 	}
+
+	// }
+
+	rows.Close()
+	return nil
+}

+ 10 - 0
main.go

@@ -0,0 +1,10 @@
+package main
+
+import "xg_data_generate/internal/dbBase"
+
+func main() {
+	db := dbBase.GetDbLink("127.0.0.1", "5138", "system", "SYSDBA", "SYSDBA")
+	dbBase.QueryFieldType(db, "select * from sys_tables")
+	defer db.Close()
+
+}

BIN
pkg/go-driver-xugusql/lib/win/xugusql.dll


+ 48 - 0
pkg/go-driver-xugusql/xugusql.go

@@ -0,0 +1,48 @@
+package xugusql
+
+import (
+	"context"
+	"database/sql"
+	"database/sql/driver"
+	"time"
+)
+
+// XuguDriver is exported to make the driver directly accessible
+type XuguDriver struct{}
+
+/* Register Driver */
+func init() {
+
+	/* Register makes a database driver available by the provided name.
+	 * If Register is called twice with the same name or if driver is nil,
+	 * it panics.
+	 */
+	sql.Register("xugusql", &XuguDriver{})
+	timezone, _ := time.LoadLocation("Asia/Shanghai")
+	time.Local = timezone
+}
+
+// Open opens a database specified by its database driver name and a
+// driver-specific data source name, usually consisting of at least a
+// database name and connection information.
+//
+// Most users will open a database via a driver-specific connection
+// helper function that returns a *DB. No database drivers are included
+// in the Go standard library. See https://golang.org/s/sqldrivers for
+// a list of third-party drivers.
+//
+// Open may just validate its arguments without creating a connection
+// to the database. To verify that the data source name is valid, call
+// Ping.
+// The returned DB is safe for concurrent use by multiple goroutines
+// and maintains its own pool of idle connections. Thus, the Open
+// function should be called just once. It is rarely necessary to
+// close a DB.
+func (db XuguDriver) Open(dsn string) (driver.Conn, error) {
+	conn := &connector{dsn: dsn}
+	return conn.Connect(context.Background())
+}
+
+func (db XuguDriver) OpenConnector(dsn string) (driver.Connector, error) {
+	return &connector{dsn: dsn}, nil
+}

+ 401 - 0
pkg/go-driver-xugusql/xugusql.h

@@ -0,0 +1,401 @@
+
+#ifndef _XG_DRIVERAPI_H_ 
+#define _XG_DRIVERAPI_H_ 
+
+#ifdef WIN32 
+#define XG_API __cdecl
+#else
+//linuxs about
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <grp.h>
+#include <arpa/inet.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#define XG_API
+#endif
+typedef long long int64;
+
+#ifdef __cplusplus
+extern "C"{
+#endif 
+
+#define XGC_ATTR_SERVER_VERSION   1 
+#define XGC_ATTR_DBNAME           2 
+#define XGC_ATTR_ISO_LEVEL        3
+#define XGC_ATTR_SERVER_CHARSET   4
+#define XGC_ATTR_CLIENT_CHARSET   5
+
+#define XGC_ATTR_USESSL           6
+#define XGC_ATTR_SRV_TURN_IPS      7
+#define XGC_ATTR_TIMEZONE          8
+#define XGC_ATTR_LOB_DESCRIBER     9
+#define XGC_ATTR_AUTOCOMMIT       11
+#define XGC_ATTR_STMT_SERVER_CURSOR   12
+
+#define XGC_ATTR_USE_CURSOR        0
+#define XGC_ATTR_NOTUSE_CURSOR     1
+#define XGC_ATTR_USE_CURSORDEFAULT 0
+
+typedef enum tagPARAMINOUT_TYPE {
+		PARAM_INPUT = 1,
+		PARAM_OUTPUT = 2,
+		PARAM_INPUTOUTPUT = 3,
+		PARAM_RETURNVALUE = 6,
+}PARAMINOUT_TYPE;
+#define XGC_ATTR_COL_COUNT  61
+#define XGC_ATTR_ROW_COUNT  62
+#define XGC_ATTR_EFFECT_NUM 63
+#define XGC_ATTR_RESULT_TYPE 64
+#define XGC_ATTR_SQL_TYPE 65
+#define XGC_ATTR_IS_MUTIRESULT  66
+
+#define   XGC_ISO_READONLY    1
+#define   XGC_ISO_READCOMMIT  2
+#define   XGC_ISO_READREPEAT  3
+#define   XGC_ISO_SERIAL      4
+#define   XGC_CHARSET_GBK     1
+#define   XGC_CHARSET_GB2312  2
+#define   XGC_CHARSET_UTF8    3
+
+
+#define  XG_C_NULL                    0
+#define  XG_C_BOOL                    1
+#define  XG_C_CHAR                    2
+#define  XG_C_TINYINT                 3
+#define  XG_C_SHORT                   4
+#define  XG_C_INTEGER                 5
+#define  XG_C_BIGINT                  6
+#define  XG_C_FLOAT                   7
+#define  XG_C_DOUBLE                  8
+#define  XG_C_NUMERIC                 9
+#define  XG_C_DATE	                  10
+#define  XG_C_TIME			          11
+#define  XG_C_TIME_TZ                 12
+#define  XG_C_DATETIME                13
+#define  XG_C_DATETIME_TZ             14
+#define  XG_C_BINARY                  15
+
+
+#define DATETIME_ASLONG 23 
+#define  XG_C_NVARBINARY        18 
+#define  XG_C_REFCUR       58
+#define  XG_C_CHARN1  63
+
+#define  XG_C_NCHAR                   62   /* only for c# wchar use */ 
+
+#define  XG_C_INTERVAL                21
+#define  XG_C_INTERVAL_YEAR_TO_MONTH  28
+#define  XG_C_INTERVAL_DAY_TO_SECOND  31
+
+#define  XG_C_TIMESTAMP     XG_C_DATETIME
+#define  XG_C_LOB                     40
+#define  XG_C_CLOB                    41
+#define  XG_C_BLOB                    42
+
+#define XG_SUCCESS              0
+#define XG_NO_DATA              100  
+
+#define XG_ERROR               -1
+#define XG_NET_ERROR           -4
+#define XG_INVALID_ARG         -3
+#define XG_SOCKET_ERROR        -8 
+#define XG_LOGIN_ERROR         -9 
+
+#define XG_NULL_DATA           -11
+#define XG_TRUNCATED_DATA      -12
+#define XG_DATATYPE_ERROR      -13      /* Data type cannot be converted */  
+#define XG_FLOW_DATA           -14      /* Data type out of bounds */
+#define XG_COL_SEQ_ERR         -15      /* Data serial number out of bounds */
+#define XG_COL_EXCEPT_DATAOFF  -18      /* Data offset out of bounds */ 
+
+#define XG_COL_DATA_OVERFLOW    98   
+
+
+
+
+
+int XG_API  SetConnStr(char* str, void** p_conn);
+int XG_API  GetConnStr(char* str, void** p_conn);
+ 
+/* return :
+ *   2 : Successful connection
+ *  -1 : Connection string incoming error
+ *  -8 : Failed to create sock
+ *  -9 : Login database failed
+ *  */
+int XG_API XGC_OpenConn(char* Conn_str,void** p_conn);
+
+/* return :
+ *   0 : Success
+ *  -1 : Fail
+ * */
+int XG_API XGC_CloseConn(void** p_conn);
+
+/* return :
+ *   2 : Successful connection
+ *  -3 : Parameter error 
+ *  -8 : Failed to create sock
+ *  -9 : Login database failed
+ *  */
+int XG_API XGC_OpenConn_Ips(char* Conn_str,int ntimes,void** turnIP_attrs,void** p_conn);
+
+
+/* Explicitly create parameters 
+ * return :
+ *   0 : Success
+ *  -3 : Parameter error
+ * */
+int XG_API XGC_CreateParams(void** p_params);
+
+
+/* Reset parameters in connection 
+ * Note: explicitly created parameters will not be processed
+ * */
+int XG_API XGC_ResetParams(void** p_conn);
+
+
+/* Bind explicitly created parameters to the connection */
+/* X//将显式创建的参数绑定到连接上
+* 配合 XGC_CreateParams 使用
+* p_conn 连接指针
+* p_params 显式创建的参数结构指针
+*返回值  成功返回0 参数错误 传入类型不匹配 返回 -3 ;
+*/
+int XG_API XGC_BindParams2Conn(void** p_conn,void** p_params);
+
+
+int XG_API XGC_BindParamByName(void** p_conn, char* param_name, int param_type, 
+           int datatype, void*  value, int param_size,  int* rt_code,  int* rlen_val);
+
+/* 参数 按名进行批量绑定
+* p_conn 连接句柄 或显式申明的参数句柄
+* param_name 参数在sql中的名
+* param_num sql中 按名绑定参数的个数
+* param_type 参数输入输出型  1 输入 2 输出 3输入输出  6 返回值 ,
+* datatype 参数C类型
+* array_size 参数数组长度-参数的批量的个数
+* array_value 参数数组 首地址
+* param_size  参数固定长度, 变长的填入总体长度( 内部 长度值 长度值 这样)
+* rlen_val  int型 数组  存放参数数组中 数组内每个元素的实际长度 按组元序号对应
+返回值:正确返回 0 错误返回 -1 ,参数传入错误返回-3  ,参数名错误 -53 ;
+*/
+int XG_API XGC_BindParamArrayByName(void** p_conn, char* param_name,int param_num, 
+     int param_type,int datatype, int array_size, void* array_value, 
+           int param_size, int * rlen_val);
+//按序号绑定 2 种用法
+/*=====================================
+* p_conn     连接句柄 (隐式参数句柄)   2 p_conn  参数句柄(显式创建参数句柄)
+* param_no   参数号: 从1开始
+* param_type 参数输入输出型 1236
+* datatype   参数数据类型
+* value      参数值
+* param_size 单个参数的空间大小 buffer
+* rlen_val   具体的每个参数 的对应实际大小
+返回值 正确返回 0  ;传入指针参数错误  返回 -3 ;参数序号超界 -51; 参数输入输出型错:-52 ;参数号小于1 -54 ;参数跳跃未按序 -55; 尚未实现功能 -8;
+======================================*/
+int XG_API XGC_BindParamByPos(void** p_conn, int param_no,int param_type, 
+                int datatype, void* value, int param_size, int * rlen_val);
+/*批量按序号绑定
+* p_conn 连接句柄 或显式申明的参数句柄
+* param_no 参数号 从1 开始
+* param_num sql中 按名绑定参数的个数
+* param_type 参数输入输出型  1 输入 2 输出 3输入输出  6 返回值 ,
+* datatype 参数C类型
+* array_size 参数数组长度-参数的批量的个数
+* array_value 参数数组 首地址
+* param_size  参数固定长度, 变长的填入总体长度( 内部 长度值 长度值 这样)
+* rlen_val  int型 数组  存放参数数组中 数组内每个元素的实际长度 按组元序号对应
+* 返回值:正确返回 0;传入指针参数错误  返回 -3 ;参数序号超界 -51; 参数输入输出型错:-52 ;参数号小于1 -54 ;  尚未实现功能 -8;
+*/
+int XG_API XGC_BindParamArrayByPos(void** p_conn, int param_no, int param_num, 
+     int param_type,int datatype, int array_size, void* array_value, int param_size, int * rlen_val); 
+ 
+
+/* SQL execution without result set return */
+
+/* 无结果集返回的sql执行 --支持DDL ,insert update ,delete等执行
+* p_conn 连接指针 ,cmd_sql sql语句 ,如sql里面有参数 请提前在 p_conn连接句柄里面绑定
+*返回值:  update 和delete时 返回影响的行数 ,insert 返回插入行数, 其他成功返回0 ,一般错误返回-1 ; 网络错 -4;
+无结果集返回的执行,最多支持影响的行数 rowid 这些
+*/
+int XG_API XGC_Execute_no_query(void** p_conn,char* cmd_sql); 
+
+/* 查询 返回首行首列
+*查询简便化封装,返回结果集的首行首列 --
+根据type 来解析re_val 数据为数值的是定长 数据是变长的 re_val 为长度(4字节int)+指向数据的指针 (或者是数组)
+* p_conn 连接指针 ,cmd_sql sql语句 常为 select count(*) 等
+* re_val  存放值的buffer缓存区, 一般为字符串返回。
+* type 空值 时返回 0 ,,如果值为101 说明buff空间不足返回的是指向值的指针
+返回值 :成功 返回 0  网络错 -4;一般错误 -1; ,insert返回1 ,update 返回2 ;delete  返回3 ;
+*/
+int XG_API XGC_Execute_query_with_one(void** p_conn ,char* cmd_sql,void* re_val,int* type);
+
+/* usage: prepare name can be given a specific name or NULL
+ *  (1) If the SQL statement is a query, the prepare_name parameter can 
+ *      be given a specific value.
+ *  (2) If the SQL statement is not a query, the prepare_name parameter 
+ *      must be NULL 
+ * */
+int XG_API XGC_Prepare2(void** p_conn,char* cmd_sql,char* prepare_name); 
+
+/* usage: 
+ *  (1) If the SQL statement is a query, when both prepare_name and servercursor_name 
+ *      are given as NULL, it means that the server cursor is not used.
+ *  (2) If the SQL statement is a query, when prepare_name and servercursor_name are 
+ *      given specific values, it means that the server cursor is used.
+ *  
+ *  notice:
+ *     If the 'prepare_name' parameter in the 'XGC_Prepare2' phase is NULL, 
+ *     then the 'prepare_name' in 'XGC_Execute2' must also be NULL. 
+ * */
+int XG_API XGC_Execute2(void** p_conn, char* prepare_name, char* servercursor_name,void** pres);
+int XG_API XGC_ExecBatch(void**  p_conn,char* cmd_sql, int ArrayCount);
+
+int XG_API XGC_UnPrepare(void** p_conn,char* prepare_name);
+
+/* 关闭服务器端游标
+*p_conn 连接指针, * cursor_name 游标名 ,游标释放应 在unprepare之前调用
+* 返回值 成功返回0 失败返回-1 ;网络错 返回-4 ;
+*/
+int XG_API XGC_CloseCursor(void** p_conn,char* cursor_name);
+/*带返回结果集的 查询语句执行 生成reader
+* *p_conn 连接指针,* cmd_sql 查询sql语句 ,
+* * p_res 返回的结果集指针 ,
+* 输出型参数 field_num 结果集的列数 ,   rowcount 结果集的行数   effected_num:  update delete 影响的行数 ,无则不填,
+*返回值 成功返回0   ;网络错返回-4 ;失败返回-1 ;
+*/
+int XG_API XGC_ExecwithDataReader(void** p_conn ,char* cmd_sql,void** p_res,
+                int* field_num,int64* rowcount,int* effected_num);
+
+/* 
+ * Get result set from server cursor
+ * int XG_API XGC_FetchServerCursorRowset(void** p_conn ,char* cmd_sql,void** p_res);
+ *
+ * */
+int XG_API XGC_FetchServerCursorRowset(void** p_conn ,char* servercursor_name,void** p_res);
+
+int XG_API XGC_FetchServerCursorRowset_V2(void** p_conn, char* sql_cmd, void** p_res);
+
+/* Fetching data from the server cursor header (extra)*/
+int XG_API XGC_FetchRefCursorHead(void** p_conn ,char* Cursor_name ,void** p_res,
+                int* field_num,int64* rowcount,int* cached);
+
+/* 服务器游标获取数据   XGC_Prepare2+XGC_Execute2 (冗余项)
+*  *p_conn 连接指针,* cmd_sql  需要游标执行的 select 查询sql语句
+* Cursor_name 服务器端游标名 由用户自行命名后传入
+* * p_res 返回的结果集指针 ,输出型参数 field_num 结果集的列数 ,   rowcount 结果集的行数   effected_num:  update delete 影响的行数
+* 正常返回0 失败返回-1
+*/
+int XG_API XGC_ExecwithServerCursorReader(void** p_conn ,char* cmd_sql, 
+    char* Cursor_name ,void** p_res,int* field_num,int64* rowcount,int* effected_num);
+
+/*
+ * Execution of stored procedures and functions, 
+ * involving input and output of parameters
+ * */
+int XG_API XGC_Execute_procesure(void** p_conn , char*  cmd_sql,void* para); 
+
+/*
+ *  RESULT
+ *
+ * */
+int XG_API  XGC_GetData(void** pTr_Result,int col_no,int TarCtype, 
+           void* TarValuePtr,int BuffLen,int* lenPtr);
+
+int XG_API  XGC_getResultcolType(void**  pTr_Result,int col_no,int* col_type) ;
+int XG_API  XGC_getResultcolname(void**  pTr_Result,int col_no,char* col_name) ;
+int XG_API  XGC_getResultcolseq(void**  pTr_Result,char* col_name);
+/* 返回结果集的列个数
+  输出参数 field_num 返回结果集列个数
+  正常返回 0 ,输入结果集类型异常返回 -3
+*/
+int XG_API  XGC_getResultColumnsnum(void**  pTr_Result,int* field_num);
+/* 返回结果集 行数
+**  pTr_Result 结果集指针
+*  输出参数 record_num 返回结果集 行数
+*  正常返回 0 ,输入结果集类型异常返回 -3
+*/
+int XG_API  XGC_getResultRecordnum(void**  pTr_Result,int* record_num);
+int XG_API  XGC_getResultcolmodi(void**  pTr_Result, int col_no, int* modi);//add 202-02-19
+
+int XG_API  XGC_getResultColInfo(void**  pTr_Result,int col_no, 
+    char* col_Tabname, char* col_name, char* col_alias, int* datatype,
+         int* col_modi,int* col_flag);
+
+/* Result set cursor moves to the next result set */
+int XG_API XGC_ReadNext(void** p_res);
+
+/* Release result set */
+int XG_API XGC_FreeRowset(void** p_res);
+
+/*
+ * Get the next result set, suitable for multiple result sets
+ * */
+int XG_API XGC_NextResult(void** p_res);
+
+/* Attribute */
+int XG_API XGC_GetAttr(void** hd_ptr, int attrtype, void * ValuePtr, 
+                int  BuffLen, int* ret_attr_type, int* re_len);
+int XG_API XGC_SetAttr(void** hd_ptr, int attrtype, const void * ValuePtr, int  BuffLen);
+
+/*
+ * BLOB\CLOB
+ * */
+int XG_API XGC_Create_Lob(void** Lob_ptr);
+int XG_API XGC_Put_Lob_data(void** Lob_ptr, void* data, int len );
+int XG_API XGC_Get_Lob_data(void** Lob_ptr, void* data, int len);
+int XG_API XGC_Distroy_Lob(void** Lob_ptr);
+int XG_API XGC_LobWrite_SetPos(void** Lob_ptr,int setpos);
+int XG_API XGC_LobRead_SetPos(void** Lob_ptr,int setpos);
+int XG_API XGC_Reset_Lob(void** Lob_ptr);
+
+/* 
+ * ERROR INFO
+ * */
+int  XG_API XGC_GetError(void** hd_ptr, char* err_text,int* rlen);
+int  XG_API XGC_GetErrorInfo(void** p_handptr, char* ccode, char* errmessage, int* rlen); 
+int  XG_API XGC_GetErrorInfoOption(void** p_handptr, char* ccode, int * ret_code, 
+                char* errmessage, int max_message_len, int* rlen);
+
+/*
+ *  OTHER
+ *
+ * */
+void XG_API XGC_FreePtr(void**Ptr);
+/* 释放对象资源  --可用对象有 连接, 结果集 ,显式参数结构指针 ,大对象
+* *Ptr_obj 对象指针地址传入
+*/
+void XG_API XGC_Drop(void**Ptr_obj);
+int  XG_API dt2dtm_Api(long long  t,char * p_dt);
+int  XG_API Release_IpsAttrs(void** pconn_IpsAttr);//ips= 
+int  XG_API fun_sql_type(char* sql);
+/* 重置对象资源 -包括连接中显式参数结构和大对象
+* 不包括结果集
+* Ptr_obj 对象指针地址
+*/
+int  XG_API XGC_Reset(void**Ptr_obj); 
+/*/
+获取结果集类型,并根据结果集的类型 type 不同: 返回 结果集的行,列数,  update delete 影响的行数 ,insert 返回的 rowid值
+// insert_rowid 为 char(24)的字符串
+* 返回值  成功返回0 ,参数错误 返回-3;
+*/
+int  XG_API  XGC_getResultRet(void**  pTr_Result,int * type, 
+       int* field_num,int * rowcount, int *effected_num ,char* insert_rowid);
+
+/* Get the rowid of the last insert operation */
+int  XG_API XGC_GetLastInsertId(void** p_conn, char* insert_rowid);
+int  XG_API XGC_GetFunReturnType(void** p_conn, int * type);
+#ifdef __cplusplus
+
+}
+#endif 
+
+#endif

+ 323 - 0
pkg/go-driver-xugusql/xugusql_auxi.go

@@ -0,0 +1,323 @@
+package xugusql
+
+import (
+	"C"
+	"database/sql/driver"
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+	"unsafe"
+)
+
+// Auxiliary Struct
+type __Value struct {
+	// Boolean value, if the value is true, it means that the data
+	// type of the current field is a large object data type
+	islob bool
+
+	// A pointer of * C.char data type, usually
+	// pointing to the address of the parameter value to be bound
+	value *C.char
+	plob  unsafe.Pointer
+
+	// length usually specifies the true length of the parameter
+	// data to be bound
+	length C.int
+
+	// buff usually specifies the memory buffer
+	// size of the parameter data to be bound
+	buff C.int
+
+	// When parameter binding, specify the data type of the field in the table
+	types int
+
+	// Return code
+	rcode C.int
+}
+
+type parse struct {
+	// bind_type is used to identify the type of parameter binding.
+	// Parameter binding types include binding by parameter name
+	// and binding by parameter placeholder
+	bind_type int
+
+	// param_count is used to specify the number
+	// of parameters that need to be bound in the SQL statement
+	param_count int
+
+	// When the parameter binding type is binding
+	// by parameter name, param_names is a collection of parameter names
+	param_names []*C.char
+
+	Val []__Value
+
+	// When the parameter binding type is binding
+	// by parameter placeholder, position identifies the parameter position
+	position int
+}
+
+type ParseParam interface {
+	// Conversion parameter data type
+	assertParamType(driver.Value, int) error
+	// Number of parsing parameters
+	assertParamCount(string) int
+
+	// Parse parameter binding type (binding type by parameter name
+	// and binding type by parameter position)
+	assertBindType(string) int
+
+	// Parse parameter name
+	assertParamName(string) error
+}
+
+func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
+	__Par := make([]driver.Value, len(named))
+
+	for pos, Param := range named {
+		if len(Param.Name) > 0 {
+			return nil, errors.New("Driver does not support the use of Named Parameters")
+		}
+		__Par[pos] = Param.Value
+	}
+
+	return __Par, nil
+}
+
+func (self *parse) assertParamType(dV driver.Value, pos int) error {
+
+	var dest __Value
+	switch dV.(type) {
+
+	case int64:
+		srcv, ok := dV.(int64)
+		if !ok {
+			news := errorNews("int64")
+			return errors.New(news)
+		}
+
+		S := strconv.FormatInt(srcv, 10)
+		dest.value = C.CString(S)
+		dest.length = C.int(strings.Count(S, "") - 1)
+		dest.buff = dest.length + 1
+		dest.islob = false
+		dest.types = SQL_XG_C_CHAR
+
+	case float32:
+		srcv, ok := dV.(float64)
+		if !ok {
+			news := errorNews("float32")
+			return errors.New(news)
+		}
+
+		S := strconv.FormatFloat(srcv, 'f', 6, 64)
+		dest.value = C.CString(S)
+		dest.length = C.int(strings.Count(S, "") - 1)
+		dest.buff = dest.length + 1
+		dest.islob = false
+		dest.types = SQL_XG_C_CHAR
+
+	case float64:
+		srcv, ok := dV.(float64)
+		if !ok {
+			news := errorNews("float64")
+			return errors.New(news)
+		}
+
+		S := strconv.FormatFloat(srcv, 'f', 15, 64)
+		dest.value = C.CString(S)
+		dest.length = C.int(strings.Count(S, "") - 1)
+		dest.buff = dest.length + 1
+		dest.islob = false
+		dest.types = SQL_XG_C_CHAR
+
+	case bool:
+		srcv, ok := dV.(bool)
+		if !ok {
+			news := errorNews("bool")
+			return errors.New(news)
+		}
+
+		S := strconv.FormatBool(srcv)
+		dest.value = C.CString(S)
+		dest.length = C.int(strings.Count(S, "") - 1)
+		dest.buff = dest.length + 1
+		dest.islob = false
+		dest.types = SQL_XG_C_CHAR
+
+	case string:
+		srcv, ok := dV.(string)
+		if !ok {
+			news := errorNews("string")
+			return errors.New(news)
+		}
+
+		dest.value = C.CString(srcv)
+		dest.length = C.int(strings.Count(srcv, "") - 1)
+		dest.buff = dest.length + 1
+		dest.islob = false
+		dest.types = SQL_XG_C_CHAR
+
+		if dest.length == 0 {
+			dest.length = 1
+		}
+
+	case time.Time:
+		srcv, ok := dV.(time.Time)
+		if !ok {
+			news := errorNews("time.Time")
+			return errors.New(news)
+		}
+
+		tm := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d",
+			srcv.Year(), int(srcv.Month()), srcv.Day(),
+			srcv.Hour(), srcv.Minute(), srcv.Second())
+
+		dest.value = C.CString(tm)
+		dest.length = C.int(strings.Count(tm, "") - 1)
+		dest.buff = dest.length + 1
+		dest.islob = false
+		dest.types = SQL_XG_C_CHAR
+
+	case []byte:
+
+		re := cgo_xgc_new_lob(&dest.plob)
+		if re < 0 {
+			return errors.New("Cannot create new large object")
+		}
+
+		srcv, ok := dV.([]byte)
+		if !ok {
+
+			news := errorNews("[]byte")
+			return errors.New(news)
+		}
+
+		cgo_xgc_put_lob_data(
+			&dest.plob,
+			unsafe.Pointer((*C.char)(unsafe.Pointer(&srcv[0]))),
+			len(srcv))
+		cgo_xgc_put_lob_data(&dest.plob, nil, -1)
+
+		dest.value = nil
+		dest.length = C.int(8)
+		dest.buff = C.int(8)
+		dest.islob = true
+		dest.types = SQL_XG_C_BLOB
+
+	case nil:
+		dest.value = C.CString("xugusql")
+		dest.length = 0
+		dest.buff = C.int(strings.Count("xugusql", ""))
+		dest.islob = false
+		dest.types = SQL_XG_C_CHAR
+
+	default:
+		/* OTHER DATA TYPE */
+		return errors.New("Unknown data type")
+	}
+
+	self.position = pos
+	self.Val = append(self.Val, dest)
+
+	return nil
+}
+
+func errorNews(str string) string {
+	return fmt.Sprintf("[%s] asserting data type failed.", str)
+}
+
+func (self *parse) assertParamCount(query string) int {
+
+	if self.bind_type == 0 {
+		self.bind_type = self.assertBindType(query)
+	}
+
+	switch self.bind_type {
+	case BIND_PARAM_BY_POS:
+		self.param_count = strings.Count(query, "?")
+	case BIND_PARAM_BY_NAME:
+
+		self.param_count = 0
+		pos := 0
+		phead := -1
+
+		for true {
+			pos = strings.IndexByte(query[phead+1:], ':')
+			if pos == -1 {
+				break
+			}
+
+			pos += phead + 1
+			tmp := pos
+			for tmp > phead {
+				tmp--
+				if query[tmp] == ' ' {
+					continue
+				}
+
+				if query[tmp] == ',' || query[tmp] == '(' {
+					self.param_count++
+				}
+				break
+			}
+			phead = pos
+		}
+	}
+
+	return self.param_count
+}
+
+func (self *parse) assertBindType(query string) int {
+
+	self.bind_type = strings.IndexByte(query, '?')
+	if self.bind_type != -1 {
+		return BIND_PARAM_BY_POS
+	}
+
+	return BIND_PARAM_BY_NAME
+}
+
+func (self *parse) assertParamName(query string) error {
+
+	if self.param_count <= 0 {
+		self.assertParamCount(query)
+	}
+
+	pos := 0
+	phead := -1
+
+	for true {
+		pos = strings.IndexByte(query[phead+1:], ':')
+		if pos == -1 {
+			break
+		}
+
+		pos += phead + 1
+		tmp := pos
+		for tmp > phead {
+			tmp--
+			if query[tmp] == ' ' {
+				continue
+			}
+
+			// Parse parameter positions bound by parameter name
+			if query[tmp] == ',' || query[tmp] == '(' {
+				parg := pos
+				for true {
+					parg++
+					if query[parg] == ',' || query[parg] == ')' || query[parg] == ' ' {
+						self.param_names = append(self.param_names, C.CString(query[pos+1:parg]))
+						break
+					}
+				}
+			}
+			break
+		}
+
+		phead = pos
+	}
+
+	return nil
+}

+ 219 - 0
pkg/go-driver-xugusql/xugusql_cgo.go

@@ -0,0 +1,219 @@
+package xugusql
+
+import (
+	"unsafe"
+)
+
+/*
+#cgo CFLAGS : -I/usr/include
+#cgo LDFLAGS : -L/lib/win -lxugusql
+
+#include <stdlib.h>
+#include <string.h>
+#include "xugusql.h"
+*/
+import "C"
+
+var IPS_COUNTER int = 0
+var IPS_BODY unsafe.Pointer
+
+/* Collect error information from the database server */
+func cgo_xgc_error(__pConn *unsafe.Pointer, pLog *C.char, act *C.int) int {
+	return int(C.XGC_GetError(__pConn, pLog, act))
+}
+
+/*
+ * 'C.XGC_OpenConn' is used to establish a new connection session with XGDB,
+ * return value:
+ *      (int) 2 : Success               (int)-1 : Failure
+ *      (int)-8 : TCP/IP socket error.  (int)-9 : Login xgdb failure.
+ */
+func cgo_xgc_connect(pdsn *C.char, __pConn *unsafe.Pointer) int {
+	return int(C.XGC_OpenConn(pdsn, __pConn))
+}
+
+/* 'C.XGC_OpenConn_Ips' is used to establish a new connection session with XGDB,
+ * it is different from'C.XGC_OpenConn' in that'C.XGC_OpenConn_Ips' can achieve
+ * connection load balancing between distributed database nodes.
+ */
+func cgo_xgc_connect_ips(pdsn *C.char, __pConn *unsafe.Pointer) int {
+	return int(C.XGC_OpenConn_Ips(pdsn, C.int(IPS_COUNTER), &IPS_BODY, __pConn))
+}
+
+/*
+ * The cgo-level call,
+ * to realize the user's memory allocation application.
+ */
+func cgo_c_calloc(Size uint) *C.char {
+	return (*C.char)(C.calloc(C.ulonglong(1), C.ulonglong(Size)))
+}
+
+/*
+ * The cgo-level call,
+ * to cleans up the data in the memory requested by cgo_c_calloc.
+ */
+func cgo_c_memset(pointer *C.char, length uint) {
+	C.memset(unsafe.Pointer(pointer), 0x0, C.ulonglong(length))
+}
+
+/*
+ * The cgo-level call,
+ * releases the memory requested by cgo_c_calloc.
+ */
+func cgo_c_free(__Pr unsafe.Pointer) {
+	C.free(__Pr)
+}
+
+// Execute SQL statements without result set return, including DDL and DML
+func cgo_xgc_execnoquery(__pConn *unsafe.Pointer, query *C.char) int {
+	return int(C.XGC_Execute_no_query(__pConn, query))
+}
+
+/*
+ * Return the type of the SQL statement,
+ * confirm it is DDL, DML and DQL.
+ */
+func cgo_xgc_sql_type(sql *C.char) int {
+	return int(C.fun_sql_type(sql))
+}
+
+/*
+ * Binding parameters,
+ * the binding method uses the form of placeholders.
+ */
+func cgo_xgc_bindparambypos(__pConn *unsafe.Pointer, seq int, ArgType int,
+	Type int, Valu unsafe.Pointer, Buff C.int, act *C.int) int {
+	return int(C.XGC_BindParamByPos(__pConn, C.int(seq), C.int(ArgType),
+		C.int(Type), Valu, Buff, act))
+}
+
+/*
+ * Binding parameters,
+ * the binding method uses the form of the parameter name.
+ */
+func cgo_xgc_bindparambyname(__pConn *unsafe.Pointer, Name *C.char, ArgType int,
+	Type int, Valu unsafe.Pointer, Buff C.int, Rcode *C.int, act *C.int) int {
+	return int(C.XGC_BindParamByName(__pConn, Name, C.int(ArgType), C.int(Type),
+		Valu, Buff, Rcode, act))
+}
+
+/*
+ * Disconnect the database session connection established
+ * by'C.XGC_OpenConn_Ips'.
+ */
+func cgo_xgc_disconnect(__pConn *unsafe.Pointer) int {
+	return int(C.XGC_CloseConn(__pConn))
+}
+
+// Prepare the executed SQL statement.
+func cgo_xgc_prepare(__pConn *unsafe.Pointer, query *C.char, prename *C.char) int {
+	return int(C.XGC_Prepare2(__pConn, query, prename))
+}
+
+// Execute the SQL statement prepared by'C.XGC_Prepare2'.
+func cgo_xgc_execute(__pConn *unsafe.Pointer, prename *C.char,
+	curname *C.char, res *unsafe.Pointer) int {
+	return int(C.XGC_Execute2(__pConn, prename, curname, res))
+}
+
+// Cancel the SQL statement prepared by'C.XGC_Prepare2'.
+func cgo_xgc_unprepare(__pConn *unsafe.Pointer, prename *C.char) int {
+	return int(C.XGC_UnPrepare(__pConn, prename))
+}
+
+// Close server cursor.
+func cgo_xgc_close_cursor(__pConn *unsafe.Pointer, curname *C.char) int {
+	return int(C.XGC_CloseCursor(__pConn, curname))
+}
+
+// Receive the result set from the database server.
+func cgo_xgc_get_result_set(__pConn *unsafe.Pointer, pCT *C.int, pCC *C.int,
+	pRC *C.int, pEC *C.int, pID *C.char) int {
+	return int(C.XGC_getResultRet(__pConn, pCT, pCC, pRC, pEC, pID))
+}
+
+// Release result set.
+func cgo_xgc_free_rowset(__pRes *unsafe.Pointer) int {
+	return int(C.XGC_FreeRowset(__pRes))
+}
+
+// Get data in the form of a cursor.
+func cgo_xgc_fetch_with_cursor(__pConn *unsafe.Pointer,
+	curname *C.char, __pRes *unsafe.Pointer) int {
+	return int(C.XGC_FetchServerCursorRowset(__pConn, curname, __pRes))
+}
+
+// Get the column name of the specified column.
+func cgo_xgc_get_column_name(__pRes *unsafe.Pointer, Seq int, cname *C.char) int {
+	return int(C.XGC_getResultcolname(__pRes, C.int(Seq), cname))
+}
+
+// Get the number of fields in the current query.
+func cgo_xgc_get_fields_count(__pRes *unsafe.Pointer, CCnt *C.int) int {
+	return int(C.XGC_getResultColumnsnum(__pRes, CCnt))
+}
+
+// Get the next row of result set data.
+func cgo_xgc_read_next(__pRes *unsafe.Pointer) int {
+	return int(C.XGC_ReadNext(__pRes))
+}
+
+// Get the number of rows in the result set.
+func cgo_xgc_get_rows_count(__pRes *unsafe.Pointer, Rows *C.int) int {
+	return int(C.XGC_getResultRecordnum(__pRes, Rows))
+}
+
+// Get the next result set.
+func cgo_xgc_next_result(__pRes *unsafe.Pointer) int {
+	return int(C.XGC_NextResult(__pRes))
+}
+
+func cgo_xgc_exec_with_cursor(__pConn *unsafe.Pointer, query *C.char,
+	curname *C.char, __pRes *unsafe.Pointer, fields *C.int, rows *C.longlong, effects *C.int) int {
+	return int(C.XGC_ExecwithServerCursorReader(__pConn, query, curname, __pRes, fields, rows, effects))
+}
+
+// Get the column data type of the specified column.
+func cgo_xgc_get_column_type(__pRes *unsafe.Pointer, Seq int, ColuType *C.int) int {
+	return int(C.XGC_getResultcolType(__pRes, C.int(Seq), ColuType))
+}
+
+// Get the data of the specified column.
+func cgo_xgc_get_data(__pRes *unsafe.Pointer, Seq int, tartype int,
+	pVal *C.char, Buff uint, act *C.int) int {
+	return int(C.XGC_GetData(__pRes, C.int(Seq), C.int(tartype), unsafe.Pointer(pVal), C.int(Buff), act))
+}
+
+// Obtain large object data.
+func cgo_xgc_get_lob(__pRes *unsafe.Pointer, Seq int, tartype int,
+	__pLob *unsafe.Pointer, Buff uint, act *C.int) int {
+	return int(C.XGC_GetData(__pRes, C.int(Seq), C.int(tartype), unsafe.Pointer(__pLob), C.int(Buff), act))
+}
+
+// Create a large object data box.
+func cgo_xgc_new_lob(__pLob *unsafe.Pointer) int {
+	return int(C.XGC_Create_Lob(__pLob))
+}
+
+// Obtain large object data.
+func cgo_xgc_get_lob_data(__pLob *unsafe.Pointer, pVal unsafe.Pointer, act C.int) int {
+	return int(C.XGC_Get_Lob_data(__pLob, pVal, act))
+}
+
+// Obtain large object data.
+func cgo_xgc_put_lob_data(__pLob *unsafe.Pointer, pVal unsafe.Pointer, act int) int {
+	return int(C.XGC_Put_Lob_data(__pLob, pVal, C.int(act)))
+}
+
+// Release large object data resources.
+func cgo_xgc_lob_distroy(__pLob *unsafe.Pointer) int {
+	return int(C.XGC_Distroy_Lob(__pLob))
+}
+
+// Receive data from the database server.
+func cgo_xgc_exec_with_reader(__pConn *unsafe.Pointer, Sql *C.char,
+	__pRes *unsafe.Pointer, fieldCount *C.int, rowCount *C.longlong, effectCount *C.int) int {
+	return int(C.XGC_ExecwithDataReader(__pConn, Sql, __pRes, fieldCount, rowCount, effectCount))
+}
+
+/* }}*/

+ 77 - 0
pkg/go-driver-xugusql/xugusql_connector.go

@@ -0,0 +1,77 @@
+package xugusql
+
+import (
+	"C"
+	"context"
+	"database/sql/driver"
+	"strings"
+	"unsafe"
+)
+
+const (
+	ERROR_BUFF_SIZE        uint = 1024
+	PREPARE_NAME_BUFF_SIZE uint = 128
+	CURSOR_NAME_BUFF_SIZE  uint = 128
+	ROWID_BUFF_SIZE        uint = 256
+	COLUMN_NAME_BUFF_SIZE  uint = 256
+
+	FIELD_BUFF_SIZE uint = 4096
+	LOB_BUFF_SIZE   uint = 8
+	RET_NO_DATA     int  = 100
+
+	SQL_UNKNOWN   int = 0
+	SQL_SELECT    int = 4
+	SQL_CREATE    int = 5
+	SQL_PROCEDURE int = 10
+
+	SQL_PARAM_INPUT       int = 1
+	SQL_PARAM_OUTPUT      int = 2
+	SQL_PARAM_INPUTOUTPUT int = 3
+	SQL_PARAM_RETURNVALUE int = 6
+
+	SQL_XG_C_CHAR int = 2
+	SQL_XG_C_CLOB int = 41
+	SQL_XG_C_BLOB int = 42
+	SQL_XG_C_NULL int = -11
+
+	BIND_PARAM_BY_NAME int = 62
+	BIND_PARAM_BY_POS  int = 63
+)
+
+type connector struct {
+	dsn string
+}
+
+// Connect implements driver.Connector interface.
+// Connect returns a connection to the database.
+func (self *connector) Connect(ctx context.Context) (driver.Conn, error) {
+
+	obj := &xugusqlConn{conn: nil}
+	connKeyValue := C.CString(self.dsn)
+
+	defer func() {
+		cgo_c_free(unsafe.Pointer(connKeyValue))
+	}()
+
+	pos := strings.Index(strings.ToUpper(self.dsn), "IPS=")
+	if pos != -1 {
+		IPS_COUNTER++
+		re := cgo_xgc_connect_ips(connKeyValue, &obj.conn)
+		if re < 0 {
+			return nil, obj.get_error()
+		}
+	} else {
+		re := cgo_xgc_connect(connKeyValue, &obj.conn)
+		if re < 0 {
+			return nil, obj.get_error()
+		}
+	}
+
+	return obj, nil
+}
+
+// Driver implements driver.Connector interface.
+// Driver returns &XuguDriver{}
+func (self *connector) Driver() driver.Driver {
+	return &XuguDriver{}
+}

+ 163 - 0
pkg/go-driver-xugusql/xugusql_fields.go

@@ -0,0 +1,163 @@
+/*PACK NAME*/
+package xugusql
+
+import (
+	"database/sql"
+	"reflect"
+	"time"
+)
+
+type NullTime struct {
+	Time  time.Time
+	Valid bool // Valid is true if Time is not NULL
+}
+
+type xugusqlField struct {
+	tableName string
+
+	/*
+	 * Store the name of the column
+	 * name of the current field
+	 * */
+	name   string
+	length int
+
+	/*
+	 * Store the data type information
+	 * of the current field column
+	 * */
+	fieldType fieldType
+}
+
+type fieldType byte
+
+const (
+	fieldTypeBool fieldType = iota + 0x01
+	fieldTypeChar
+	fieldTypeTinyint
+	fieldTypeShort
+	fieldTypeInteger
+	fieldTypeBigint
+	fieldTypeFloat
+	fieldTypeDouble
+	fieldTypeNumeric
+	fieldTypeDate
+	fieldTypeTime
+	fieldTypeTimeTZ
+	fieldTypeDatetime   fieldType = 23
+	fieldTypeDatetimeTZ fieldType = 14
+	fieldTypeBinary     fieldType = 15
+
+	fieldTypeInterval    fieldType = 21
+	fieldTypeIntervalY2M fieldType = 28
+	fieldTypeIntervalD2S fieldType = 31
+	fieldTypeLob         fieldType = 40
+	fieldTypeClob        fieldType = 41
+	fieldTypeBlob        fieldType = 42
+)
+
+/* {{ */
+func (self *xugusqlField) typeDatabaseName() string {
+	switch self.fieldType {
+	case fieldTypeBool:
+		return "BOOLEAN"
+	case fieldTypeChar:
+		return "CHAR"
+	case fieldTypeTinyint:
+		return "TINYINT"
+	case fieldTypeShort:
+		return "SHORT"
+	case fieldTypeInteger:
+		return "INTEGER"
+	case fieldTypeBigint:
+		return "BIGINT"
+	case fieldTypeFloat:
+		return "FLOAT"
+	case fieldTypeDouble:
+		return "DOUBLE"
+	case fieldTypeNumeric:
+		return "NUMERIC"
+	case fieldTypeDate:
+		return "DATE"
+	case fieldTypeTime:
+		return "TIME"
+	case fieldTypeTimeTZ:
+		return "TIMEZONE"
+	case fieldTypeDatetime:
+		return "DATETIME"
+	case fieldTypeDatetimeTZ:
+		return "DATETIME TIMEZONE"
+	case fieldTypeBinary:
+		return "BINARY"
+	case fieldTypeInterval:
+		return "INTERVAL"
+	case fieldTypeIntervalY2M:
+		return "INTERVAL YEAR TO MONTH"
+	case fieldTypeIntervalD2S:
+		return "INTERVAL DAY TO SECOND"
+	case fieldTypeClob:
+		return "CLOB"
+	case fieldTypeBlob:
+		return "BLOB"
+	default:
+		return ""
+	}
+}
+
+/* {{ */
+func (self *xugusqlField) scanType() reflect.Type {
+	switch self.fieldType {
+	case fieldTypeBool:
+		return scanTypeBool
+	case fieldTypeTinyint:
+		return scanTypeInt8
+	case fieldTypeShort:
+		return scanTypeInt16
+	case fieldTypeInteger:
+		return scanTypeInt32
+	case fieldTypeBigint:
+		return scanTypeInt64
+	case fieldTypeFloat:
+		return scanTypeFloat32
+	case fieldTypeDouble:
+		return scanTypeFloat64
+	case fieldTypeDate,
+		fieldTypeTime,
+		fieldTypeDatetime:
+		return scanTypeNullTime
+	case fieldTypeTimeTZ,
+		fieldTypeDatetimeTZ,
+		fieldTypeChar,
+		fieldTypeBinary,
+		fieldTypeInterval,
+		fieldTypeNumeric,
+		fieldTypeIntervalY2M,
+		fieldTypeIntervalD2S,
+		fieldTypeLob,
+		fieldTypeClob,
+		fieldTypeBlob:
+		return scanTypeRawBytes
+	default:
+		return scanTypeUnknown
+
+	}
+}
+
+var (
+	scanTypeFloat32   = reflect.TypeOf(float32(0))
+	scanTypeFloat64   = reflect.TypeOf(float64(0))
+	scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})
+	scanTypeNullInt   = reflect.TypeOf(sql.NullInt64{})
+	scanTypeNullTime  = reflect.TypeOf(time.Time{})
+	scanTypeInt8      = reflect.TypeOf(int8(0))
+	scanTypeInt16     = reflect.TypeOf(int16(0))
+	scanTypeInt32     = reflect.TypeOf(int32(0))
+	scanTypeInt64     = reflect.TypeOf(int64(0))
+	scanTypeUnknown   = reflect.TypeOf(new(interface{}))
+	scanTypeRawBytes  = reflect.TypeOf(sql.RawBytes{})
+	scanTypeUint8     = reflect.TypeOf(uint8(0))
+	scanTypeUint16    = reflect.TypeOf(uint16(0))
+	scanTypeUint32    = reflect.TypeOf(uint32(0))
+	scanTypeUint64    = reflect.TypeOf(uint64(0))
+	scanTypeBool      = reflect.TypeOf(bool(false))
+)

+ 346 - 0
pkg/go-driver-xugusql/xugusql_pconn.go

@@ -0,0 +1,346 @@
+package xugusql
+
+import (
+	"C"
+	"context"
+	"database/sql/driver"
+	"errors"
+	"unsafe"
+)
+
+type xugusqlConn struct {
+	conn unsafe.Pointer
+
+	/* xugusqlResult */
+	affectedRows int
+	insertId     int
+}
+
+func (self *xugusqlConn) get_error() error {
+
+	message := cgo_c_calloc(ERROR_BUFF_SIZE)
+	defer func() {
+		cgo_c_free(unsafe.Pointer(message))
+	}()
+
+	var length C.int
+	cgo_xgc_error(&self.conn, message, &length)
+	return errors.New(C.GoString(message))
+}
+
+func (self *xugusqlConn) Begin() (driver.Tx, error) {
+
+	err := self.exec("set auto_commit off;")
+	if err != nil {
+		return nil, self.get_error()
+	}
+
+	return &xugusqlTx{tconn: self}, nil
+}
+
+func (self *xugusqlConn) Close() error {
+	re := cgo_xgc_disconnect(&self.conn)
+	if re < 0 {
+		return self.get_error()
+	}
+	return nil
+}
+
+func (self *xugusqlConn) Prepare(query string) (driver.Stmt, error) {
+
+	sql := C.CString(query)
+	defer func() {
+		cgo_c_free(unsafe.Pointer(sql))
+	}()
+
+	switch cgo_xgc_sql_type(sql) {
+	case SQL_PROCEDURE:
+		return nil, errors.New("Prepare does not support stored procedures")
+	case SQL_UNKNOWN:
+		return nil, errors.New("Unknown SQL statement type")
+	case SQL_CREATE:
+		return nil, errors.New("Prepare does not support DDL.")
+	}
+
+	stmt := &xugusqlStmt{
+		stmt_conn:   self.conn,
+		prepared:    false,
+		prename:     nil,
+		curopend:    false,
+		curname:     nil,
+		param_count: 0,
+		result:      nil,
+		mysql:       query,
+	}
+
+	if stmt.prename == nil {
+		stmt.prename = cgo_c_calloc(PREPARE_NAME_BUFF_SIZE)
+	}
+
+	re := cgo_xgc_prepare(&self.conn, sql, stmt.prename)
+	if re < 0 {
+		return nil, self.get_error()
+	}
+
+	stmt.prepared = true
+
+	return stmt, nil
+}
+
+func (self *xugusqlConn) Query(query string,
+	args []driver.Value) (driver.Rows, error) {
+	sql := C.CString(query)
+	defer func() {
+		cgo_c_free(unsafe.Pointer(sql))
+	}()
+
+	parser := &parse{
+		bind_type:   0,
+		param_count: 0,
+		position:    0,
+	}
+
+	if len(args) != 0 {
+
+		for pos, param := range args {
+
+			err := parser.assertParamType(param, pos)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		if len(parser.Val) != parser.assertParamCount(query) {
+			return nil, errors.New("The number of parameters does not match")
+		}
+
+		switch parser.assertBindType(query) {
+
+		case BIND_PARAM_BY_POS:
+			for pos, param := range parser.Val {
+
+				if !param.islob {
+					re := cgo_xgc_bindparambypos(&self.conn, pos+1, SQL_PARAM_INPUT,
+						param.types, unsafe.Pointer(param.value), param.buff, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				} else {
+
+					re := cgo_xgc_bindparambypos(&self.conn, pos+1, SQL_PARAM_INPUT,
+						param.types, unsafe.Pointer(&param.plob), param.buff, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				}
+
+			}
+
+		case BIND_PARAM_BY_NAME:
+			parser.assertParamName(query)
+
+			for pos, param := range parser.Val {
+
+				if !param.islob {
+					re := cgo_xgc_bindparambyname(&self.conn, parser.param_names[pos], SQL_PARAM_INPUT,
+						param.types, unsafe.Pointer(param.value), param.buff, &param.rcode, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				} else {
+
+					re := cgo_xgc_bindparambyname(&self.conn, parser.param_names[pos], SQL_PARAM_INPUT,
+						param.types, unsafe.Pointer(&param.plob), param.buff, &param.rcode, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				}
+			}
+
+		}
+	}
+
+	defer func() {
+		for pos, param := range parser.Val {
+			if parser.bind_type == BIND_PARAM_BY_NAME {
+				cgo_c_free(unsafe.Pointer(parser.param_names[pos]))
+			}
+
+			if !param.islob {
+				cgo_c_free(unsafe.Pointer(param.value))
+			} else {
+				cgo_xgc_lob_distroy(&param.plob)
+			}
+		}
+	}()
+
+	rows := &xugusqlRows{
+		rows_conn:   self.conn,
+		result:      nil,
+		lastRowRelt: int(0),
+		lastRelt:    int(0),
+		prepared:    false,
+	}
+
+	var fieldCount, effectCount C.int
+	var rowCount C.longlong
+
+	re := cgo_xgc_exec_with_reader(&self.conn, sql, &rows.result,
+		&fieldCount, &rowCount, &effectCount)
+	if re < 0 {
+		return nil, self.get_error()
+	}
+
+	return rows, nil
+}
+
+func (self *xugusqlConn) Exec(query string,
+	args []driver.Value) (driver.Result, error) {
+
+	sql := C.CString(query)
+	switch cgo_xgc_sql_type(sql) {
+	case SQL_SELECT:
+		return nil, errors.New("Exec does not support queries")
+	case SQL_UNKNOWN:
+		return nil, errors.New("Unknown SQL statement type")
+	}
+
+	parser := &parse{
+		bind_type:   0,
+		param_count: 0,
+		position:    0,
+	}
+
+	if len(args) != 0 {
+		for pos, param := range args {
+			err := parser.assertParamType(param, pos)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		if len(parser.Val) != parser.assertParamCount(query) {
+			return nil, errors.New("The number of parameters does not match")
+		}
+
+		switch parser.assertBindType(query) {
+
+		case BIND_PARAM_BY_POS:
+
+			for pos, param := range parser.Val {
+				if !param.islob {
+					re := cgo_xgc_bindparambypos(&self.conn, pos+1, SQL_PARAM_INPUT,
+						param.types, unsafe.Pointer(param.value), param.buff, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				} else {
+
+					re := cgo_xgc_bindparambypos(&self.conn, pos+1, SQL_PARAM_INPUT,
+						param.types, unsafe.Pointer(&param.plob), param.buff, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				}
+
+			}
+
+		case BIND_PARAM_BY_NAME:
+			parser.assertParamName(query)
+
+			for pos, param := range parser.Val {
+
+				if !param.islob {
+					re := cgo_xgc_bindparambyname(&self.conn, parser.param_names[pos], SQL_PARAM_INPUT,
+						param.types, unsafe.Pointer(param.value), param.buff, &param.rcode, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				} else {
+
+					re := cgo_xgc_bindparambyname(&self.conn, parser.param_names[pos], SQL_PARAM_INPUT,
+						param.types, unsafe.Pointer(&param.plob), param.buff, &param.rcode, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				}
+			}
+
+		}
+	}
+
+	defer func() {
+		cgo_c_free(unsafe.Pointer(sql))
+
+		for pos, param := range parser.Val {
+			if parser.bind_type == BIND_PARAM_BY_NAME {
+				cgo_c_free(unsafe.Pointer(parser.param_names[pos]))
+			}
+
+			if !param.islob {
+				cgo_c_free(unsafe.Pointer(param.value))
+			} else {
+				cgo_xgc_lob_distroy(&param.plob)
+			}
+		}
+	}()
+
+	self.affectedRows = 0
+	self.insertId = 0
+
+	err := self.exec(query)
+	if err == nil {
+		return &xugusqlResult{
+			affectedRows: int64(self.affectedRows),
+			insertId:     int64(self.insertId),
+		}, nil
+	}
+
+	return nil, err
+}
+
+func (self *xugusqlConn) exec(query string) error {
+
+	sql := C.CString(query)
+	defer func() {
+		cgo_c_free(unsafe.Pointer(sql))
+	}()
+
+	self.affectedRows = cgo_xgc_execnoquery(&self.conn, sql)
+	if self.affectedRows < 0 {
+		return self.get_error()
+	}
+
+	return nil
+}
+
+func (self *xugusqlConn) ExecContext(ctx context.Context,
+	query string, args []driver.NamedValue) (driver.Result, error) {
+
+	Value, err := namedValueToValue(args)
+	if err != nil {
+		return nil, err
+	}
+
+	return self.Exec(query, Value)
+}
+
+func (self *xugusqlConn) Ping(ctx context.Context) error {
+
+	sql := C.CString("select count(*) from dual;")
+	defer func() {
+		cgo_c_free(unsafe.Pointer(sql))
+	}()
+
+	var fieldCount, effectCount C.int
+	var rowCount C.longlong
+	var result unsafe.Pointer
+
+	re := cgo_xgc_exec_with_reader(&self.conn, sql, &result,
+		&fieldCount, &rowCount, &effectCount)
+	if re < 0 {
+		return self.get_error()
+	}
+
+	return nil
+}

+ 28 - 0
pkg/go-driver-xugusql/xugusql_result.go

@@ -0,0 +1,28 @@
+package xugusql
+
+type xugusqlResult struct {
+
+	// Returns the number of rows affected
+	// by update, delete and other related operations
+	affectedRows int64
+
+	// Returns the GUID number of
+	// the insert operation (not supported)
+	insertId int64
+}
+
+// LastInsertId returns the integer generated by the database
+// in response to a command. Typically this will be from an
+// "auto increment" column when inserting a new row. Not all
+// databases support this feature, and the syntax of such
+// statements varies.
+func (self *xugusqlResult) LastInsertId() (int64, error) {
+	return self.insertId, nil
+}
+
+// RowsAffected returns the number of rows affected by an
+// update, insert, or delete. Not every database or database
+// driver may support this.
+func (self *xugusqlResult) RowsAffected() (int64, error) {
+	return self.affectedRows, nil
+}

+ 336 - 0
pkg/go-driver-xugusql/xugusql_rows.go

@@ -0,0 +1,336 @@
+package xugusql
+
+import (
+	"C"
+	"database/sql/driver"
+	"errors"
+	"io"
+	"reflect"
+	"time"
+	"unsafe"
+)
+
+type Row struct {
+	// Data information storage carrier of each column in the result set
+	columns []xugusqlField
+	// The name of each column in the result set of the current query
+	names []string
+	done  bool
+}
+
+type xugusqlRows struct {
+	// A context handle pointer, which can be used to obtain
+	// information about the result set
+	result unsafe.Pointer
+	// The return value of the function cgo_xgc_read_next()
+	lastRowRelt int
+
+	// The return value of the function cgo_xgc_next_result()
+	lastRelt int
+	// Boolean value, used to identify whether the executed
+	// SQL statement has been prepared
+	prepared bool
+
+	// Context connection handle pointer
+	rows_conn unsafe.Pointer
+	rowset    Row
+}
+
+func (self *xugusqlRows) get_error() error {
+
+	conn := self.rows_conn
+	message := cgo_c_calloc(ERROR_BUFF_SIZE)
+	defer func() {
+		cgo_c_free(unsafe.Pointer(message))
+	}()
+
+	var length C.int
+	cgo_xgc_error(&conn, message, &length)
+	return errors.New(C.GoString(message))
+}
+
+/*
+ * Columns returns the column names.
+ * Columns returns an error if the rows are closed.
+ */
+func (self *xugusqlRows) Columns() []string {
+
+	var FieldCount C.int
+
+	result := self.result
+	if self.rowset.names != nil {
+		return self.rowset.names
+	}
+
+	re := cgo_xgc_get_fields_count(&result, &FieldCount)
+	if re < 0 {
+		return self.rowset.names
+	}
+
+	column_name := cgo_c_calloc(COLUMN_NAME_BUFF_SIZE)
+	defer func() {
+		cgo_c_free(unsafe.Pointer(column_name))
+	}()
+
+	columns := make([]string, int(FieldCount))
+	fields := make([]xugusqlField, int(FieldCount))
+
+	for j := range columns {
+		cgo_c_memset(column_name, COLUMN_NAME_BUFF_SIZE)
+		re = cgo_xgc_get_column_name(&result, j+1, column_name)
+		if re < 0 {
+			return columns
+		}
+		columns[j] = C.GoString(column_name)
+		fields[j].name = C.GoString(column_name)
+
+		var dtype C.int
+		re = cgo_xgc_get_column_type(&result, j+1, &dtype)
+		if re < 0 {
+			return columns
+		}
+		fields[j].fieldType = fieldType(dtype)
+	}
+
+	self.rowset.columns = fields
+	self.rowset.names = columns
+
+	return columns
+}
+
+func (self *xugusqlRows) Close() error {
+
+	result := self.result
+
+	self.rowset.columns = nil
+	self.rowset.names = nil
+
+	if result != nil {
+		re := cgo_xgc_free_rowset(&result)
+		if re < 0 {
+			return self.get_error()
+		}
+		self.result = nil
+	}
+
+	return nil
+}
+
+// TODO(bradfitz): for now we need to defensively clone all
+// []byte that the driver returned (not permitting
+// *RawBytes in Rows.Scan), since we're about to close
+// the Rows in our defer, when we return from this function.
+// the contract with the driver.Next(...) interface is that it
+// can return slices into read-only temporary memory that's
+// only valid until the next Scan/Close. But the TODO is that
+// for a lot of drivers, this copy will be unnecessary. We
+// should provide an optional interface for drivers to
+// implement to say, "don't worry, the []bytes that I return
+// from Next will not be modified again." (for instance, if
+// they were obtained from the network anyway) But for now we
+// don't care.
+func (self *xugusqlRows) Next(dest []driver.Value) error {
+
+	if self.result == nil {
+		return errors.New("The result set has been released")
+	}
+
+	result := self.result
+	self.lastRowRelt = cgo_xgc_read_next(&result)
+	if self.lastRowRelt < 0 {
+		return self.get_error()
+	}
+
+	if self.lastRowRelt == RET_NO_DATA {
+		return io.EOF
+	}
+
+	pVal := cgo_c_calloc(FIELD_BUFF_SIZE)
+	defer func() {
+		cgo_c_free(unsafe.Pointer(pVal))
+	}()
+
+	var FieldCount = len(self.rowset.names)
+	var length C.int
+
+	for j := 0; j < FieldCount; j++ {
+
+		coluType := self.rowset.columns[j].fieldType
+		switch coluType {
+
+		case fieldTypeBinary, fieldTypeLob,
+			fieldTypeClob, fieldTypeBlob:
+
+			var pLob unsafe.Pointer
+			cgo_xgc_new_lob(&pLob)
+
+			re := cgo_xgc_get_lob(&result, j+1, int(coluType), &pLob, LOB_BUFF_SIZE, &length)
+			if re < 0 && re != SQL_XG_C_NULL {
+				return self.get_error()
+			}
+
+			dest[j] = make([]byte, int(length)+1)
+
+			if re == SQL_XG_C_NULL {
+				dest[j] = nil
+			} else {
+				data := make([]byte, int(length))
+				cgo_xgc_get_lob_data(&pLob, unsafe.Pointer(&data[0]), length)
+				dest[j] = data
+			}
+
+			cgo_xgc_lob_distroy(&pLob)
+
+		case fieldTypeDate:
+			cgo_c_memset(pVal, FIELD_BUFF_SIZE)
+			re := cgo_xgc_get_data(&result, j+1, int(fieldTypeChar), pVal, FIELD_BUFF_SIZE, &length)
+			if re < 0 && re != SQL_XG_C_NULL {
+				return self.get_error()
+			}
+
+			if re == SQL_XG_C_NULL {
+				dest[j] = nil
+			} else {
+				//tzone, _ := time.LoadLocation("Asia/Shanghai")
+				//tv, _ := time.ParseInLocation("2006-01-02", C.GoString(pVal), tzone)
+				tv, _ := time.Parse("2006-01-02", C.GoString(pVal))
+				dest[j] = tv
+			}
+
+		case fieldTypeTime,
+			fieldTypeTimeTZ:
+			cgo_c_memset(pVal, FIELD_BUFF_SIZE)
+			re := cgo_xgc_get_data(&result, j+1, int(fieldTypeChar), pVal, FIELD_BUFF_SIZE, &length)
+			if re < 0 && re != SQL_XG_C_NULL {
+				return self.get_error()
+			}
+
+			if re == SQL_XG_C_NULL {
+				dest[j] = nil
+			} else {
+				//tzone, _ := time.LoadLocation("Asia/Shanghai")
+				//tv, _ := time.ParseInLocation("15:04:05", C.GoString(pVal), tzone)
+				tv, _ := time.Parse("15:04:05", C.GoString(pVal))
+				dest[j] = tv
+			}
+
+		case fieldTypeDatetime,
+			fieldTypeDatetimeTZ:
+
+			cgo_c_memset(pVal, FIELD_BUFF_SIZE)
+			re := cgo_xgc_get_data(&result, j+1, int(fieldTypeChar), pVal, FIELD_BUFF_SIZE, &length)
+			if re < 0 && re != SQL_XG_C_NULL {
+				return self.get_error()
+			}
+
+			if re == SQL_XG_C_NULL {
+				dest[j] = nil
+			} else {
+				//tzone, _ := time.LoadLocation("Asia/Shanghai")
+				//tv, _ := time.ParseInLocation("2006-01-02 15:04:05", C.GoString(pVal), tzone)
+				tv, _ := time.Parse("2006-01-02 15:04:05", C.GoString(pVal))
+				dest[j] = tv
+			}
+
+		default:
+			cgo_c_memset(pVal, FIELD_BUFF_SIZE)
+			re := cgo_xgc_get_data(&result, j+1, int(fieldTypeChar), pVal, FIELD_BUFF_SIZE, &length)
+			if re < 0 && re != SQL_XG_C_NULL {
+				return self.get_error()
+			}
+
+			dest[j] = make([]byte, int(length)+1)
+			if re == SQL_XG_C_NULL {
+				dest[j] = nil
+			} else {
+				dest[j] = []byte(C.GoString(pVal))
+			}
+		}
+	}
+
+	return nil
+}
+
+// The driver is at the end of the current result set.
+// Test to see if there is another result set after the current one.
+// Only close Rows if there is no further result sets to read.
+func (self *xugusqlRows) HasNextResultSet() bool {
+
+	result := self.result
+	if self.prepared {
+		return false
+	}
+
+	if self.lastRowRelt == RET_NO_DATA {
+		self.lastRelt = cgo_xgc_next_result(&result)
+		if self.lastRelt == RET_NO_DATA {
+			return false
+		}
+
+		self.rowset.columns = nil
+		self.rowset.names = nil
+		self.result = result
+		return true
+	}
+
+	return false
+}
+
+// NextResultSet prepares the next result set for reading. It reports whether
+// there is further result sets, or false if there is no further result set
+// or if there is an error advancing to it. The Err method should be consulted
+// to distinguish between the two cases.
+//
+// After calling NextResultSet, the Next method should always be called before
+// scanning. If there are further result sets they may not have rows in the result
+// set.
+func (self *xugusqlRows) NextResultSet() error {
+
+	if self.result == nil {
+		return errors.New("The result set has been released")
+	}
+
+	result := self.result
+	if self.prepared {
+		return io.EOF
+	}
+
+	if self.lastRelt == RET_NO_DATA {
+		return io.EOF
+	}
+
+	self.result = result
+	return nil
+}
+
+/* {{ */
+/* {{ type ColumnTypeScanType interface }} */
+func (self *xugusqlRows) ColumnTypeScanType(index int) reflect.Type {
+	return self.rowset.columns[index].scanType()
+}
+
+/* {{ */
+/* {{ RowsColumnTypeDatabaseTypeName }} */
+func (self *xugusqlRows) ColumnTypeDatabaseTypeName(index int) string {
+	return self.rowset.columns[index].typeDatabaseName()
+}
+
+/* {{ */
+/* {{ RowsColumnTypeLength }} */
+func (self *xugusqlRows) ColumnTypeLength(index int) (int64, bool) {
+	return 0, false
+}
+
+/* {{ */
+/* {{ RowsColumnTypeNullable */
+func (self *xugusqlRows) ColumnTypeNullable(index int) (nullable, ok bool) {
+	/* not support */
+	return false, false
+}
+
+/* {{ */
+/* {{ RowsColumnTypePrecisionScale */
+func (self *xugusqlRows) ColumnTypePrecisionScale(index int) (int64, int64, bool) {
+	/* not support */
+	return 0, 0, false
+}

+ 316 - 0
pkg/go-driver-xugusql/xugusql_stmt.go

@@ -0,0 +1,316 @@
+package xugusql
+
+import (
+	"C"
+	"database/sql/driver"
+	"errors"
+	"unsafe"
+)
+
+type xugusqlStmt struct {
+
+	// Context connection handle pointer
+	stmt_conn unsafe.Pointer
+
+	// Boolean value, used to identify whether
+	// the executed SQL statement has been prepared
+	prepared bool
+	// Accept the prepared code for
+	// the prepared SQL statement
+	prename *C.char
+	// Boolean value used to identify
+	// whether the cursor is enabled
+	curopend bool
+	// Cursor name
+	curname *C.char
+	//  The number of parameters
+	// in the executed SQL statement
+	param_count int
+	mysql       string
+	// Context result set handle pointer
+	result unsafe.Pointer
+}
+
+/* Collect error information from the database server */
+func (self *xugusqlStmt) get_error() error {
+	message := cgo_c_calloc(ERROR_BUFF_SIZE)
+	defer func() {
+		cgo_c_free(unsafe.Pointer(message))
+	}()
+
+	var length C.int
+	cgo_xgc_error(&self.stmt_conn, message, &length)
+	return errors.New(C.GoString(message))
+}
+
+/* {{ */
+func (self *xugusqlStmt) Close() error {
+
+	if self.curopend {
+		re := cgo_xgc_close_cursor(&self.stmt_conn, self.curname)
+		if re < 0 {
+			return self.get_error()
+		}
+
+		cgo_c_free(unsafe.Pointer(self.curname))
+		self.curname = nil
+		self.curopend = false
+	}
+
+	if self.prepared {
+		re := cgo_xgc_unprepare(&self.stmt_conn, self.prename)
+		if re < 0 {
+			return self.get_error()
+		}
+
+		cgo_c_free(unsafe.Pointer(self.prename))
+		self.prename = nil
+		self.prepared = false
+	}
+
+	return nil
+}
+
+/* {{ */
+func (self *xugusqlStmt) NumInput() int {
+
+	parser := &parse{
+		bind_type:   0,
+		param_count: 0,
+		position:    0,
+	}
+
+	return parser.assertParamCount(self.mysql)
+}
+
+// Exec executes a prepared statement with the given arguments and
+// returns a Result summarizing the effect of the statement.
+func (self *xugusqlStmt) Exec(args []driver.Value) (driver.Result, error) {
+
+	sql := C.CString(self.mysql)
+	switch cgo_xgc_sql_type(sql) {
+	case SQL_SELECT:
+		return nil, errors.New("Exec does not support queries")
+	}
+
+	if !self.prepared {
+		return nil, errors.New("SQL statement is not Prepared")
+	}
+
+	parser := &parse{
+		bind_type:   0,
+		param_count: 0,
+		position:    0,
+	}
+
+	if len(args) != 0 {
+
+		for pos, param := range args {
+			err := parser.assertParamType(param, pos)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		if len(parser.Val) != parser.assertParamCount(self.mysql) {
+			return nil, errors.New("The number of parameters does not match")
+		}
+
+		switch parser.assertBindType(self.mysql) {
+		case BIND_PARAM_BY_POS:
+			for pos, param := range parser.Val {
+				if !param.islob {
+					re := cgo_xgc_bindparambypos(&self.stmt_conn, pos+1,
+						SQL_PARAM_INPUT, param.types,
+						unsafe.Pointer(param.value), param.buff, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				} else {
+					re := cgo_xgc_bindparambypos(&self.stmt_conn, pos+1,
+						SQL_PARAM_INPUT, param.types,
+						unsafe.Pointer(&param.plob), param.buff, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				}
+			}
+
+		case BIND_PARAM_BY_NAME:
+			parser.assertParamName(self.mysql)
+			for pos, param := range parser.Val {
+				if !param.islob {
+					re := cgo_xgc_bindparambyname(&self.stmt_conn, parser.param_names[pos],
+						SQL_PARAM_INPUT, param.types, unsafe.Pointer(param.value),
+						param.buff, &param.rcode, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				} else {
+					re := cgo_xgc_bindparambyname(&self.stmt_conn, parser.param_names[pos],
+						SQL_PARAM_INPUT, param.types, unsafe.Pointer(&param.plob),
+						param.buff, &param.rcode, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				}
+			}
+		}
+	}
+
+	defer func() {
+		cgo_c_free(unsafe.Pointer(sql))
+		for pos, param := range parser.Val {
+			if parser.bind_type == BIND_PARAM_BY_NAME {
+				cgo_c_free(unsafe.Pointer(parser.param_names[pos]))
+			}
+
+			if !param.islob {
+				cgo_c_free(unsafe.Pointer(param.value))
+			} else {
+				cgo_xgc_lob_distroy(&param.plob)
+			}
+		}
+
+	}()
+
+	result := &xugusqlResult{
+		affectedRows: 0,
+		insertId:     0,
+	}
+
+	re := cgo_xgc_execute(&self.stmt_conn, self.prename, self.curname, &self.result)
+	if re < 0 {
+		return nil, self.get_error()
+	}
+
+	var pCT, pCC, pRC, pEC C.int
+	var pID = cgo_c_calloc(ROWID_BUFF_SIZE)
+
+	re = cgo_xgc_get_result_set(&self.result, &pCT, &pCC, &pRC, &pEC, pID)
+	if re < 0 {
+		return nil, self.get_error()
+	}
+
+	cgo_c_free(unsafe.Pointer(pID))
+	result.affectedRows = int64(pEC)
+
+	return result, nil
+}
+
+// QueryContext executes a prepared query statement with the given arguments
+// and returns the query results as a *Rows.
+func (self *xugusqlStmt) Query(args []driver.Value) (driver.Rows, error) {
+
+	sql := C.CString(self.mysql)
+	if cgo_xgc_sql_type(sql) != SQL_SELECT {
+		return nil, errors.New("The executed SQL statement is not a SELECT")
+	}
+
+	if !self.prepared {
+		return nil, errors.New("SQL statement is not Prepared")
+	}
+
+	parser := &parse{
+		bind_type:   0,
+		param_count: 0,
+		position:    0,
+	}
+
+	if len(args) != 0 {
+
+		for pos, param := range args {
+			err := parser.assertParamType(param, pos)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		if len(parser.Val) != parser.assertParamCount(self.mysql) {
+			return nil, errors.New("The number of parameters does not match")
+		}
+
+		switch parser.assertBindType(self.mysql) {
+		case BIND_PARAM_BY_POS:
+			for pos, param := range parser.Val {
+				if !param.islob {
+					re := cgo_xgc_bindparambypos(&self.stmt_conn, pos+1,
+						SQL_PARAM_INPUT, param.types,
+						unsafe.Pointer(param.value), param.buff, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				} else {
+
+					re := cgo_xgc_bindparambypos(&self.stmt_conn, pos+1,
+						SQL_PARAM_INPUT, param.types,
+						unsafe.Pointer(&param.plob), param.buff, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				}
+			}
+
+		case BIND_PARAM_BY_NAME:
+			parser.assertParamName(self.mysql)
+			for pos, param := range parser.Val {
+				if !param.islob {
+					re := cgo_xgc_bindparambyname(&self.stmt_conn,
+						parser.param_names[pos],
+						SQL_PARAM_INPUT, param.types, unsafe.Pointer(param.value),
+						param.buff, &param.rcode, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				} else {
+
+					re := cgo_xgc_bindparambyname(&self.stmt_conn,
+						parser.param_names[pos],
+						SQL_PARAM_INPUT, param.types, unsafe.Pointer(&param.plob),
+						param.buff, &param.rcode, &param.length)
+					if re < 0 {
+						return nil, self.get_error()
+					}
+				}
+			}
+		}
+	}
+
+	defer func() {
+		cgo_c_free(unsafe.Pointer(sql))
+		for pos, param := range parser.Val {
+			if parser.bind_type == BIND_PARAM_BY_NAME {
+				cgo_c_free(unsafe.Pointer(parser.param_names[pos]))
+			}
+
+			if !param.islob {
+				cgo_c_free(unsafe.Pointer(param.value))
+			} else {
+				cgo_xgc_lob_distroy(&param.plob)
+			}
+		}
+
+	}()
+
+	//if self.curname == nil {
+	//	self.curname = cgo_c_calloc(CURSOR_NAME_BUFF_SIZE)
+	//}
+
+	re := cgo_xgc_execute(&self.stmt_conn, self.prename, self.curname, &self.result)
+	if re < 0 {
+		return nil, self.get_error()
+	}
+
+	//re = cgo_xgc_fetch_with_cursor(&self.stmt_conn, self.curname, &self.result)
+	//if re < 0 {
+	//	return nil, self.get_error()
+	//}
+
+	//self.curopend = true
+	return &xugusqlRows{
+		result:    self.result,
+		prepared:  self.prepared,
+		rows_conn: self.stmt_conn,
+	}, nil
+
+}

+ 35 - 0
pkg/go-driver-xugusql/xugusql_tranx.go

@@ -0,0 +1,35 @@
+package xugusql
+
+import (
+	"errors"
+)
+
+type xugusqlTx struct {
+	tconn *xugusqlConn
+}
+
+func (self *xugusqlTx) Commit() error {
+	if self.tconn == nil {
+		return errors.New("Invalid connection")
+	}
+	err := self.tconn.exec("commit;")
+	if err != nil {
+		return err
+	}
+
+	return self.tconn.exec("set auto_commit on;")
+}
+
+func (self *xugusqlTx) Rollback() error {
+
+	if self.tconn == nil {
+		return errors.New("Invalid connection")
+	}
+	err := self.tconn.exec("rollback;")
+	if err != nil {
+		return err
+	}
+
+	return self.tconn.exec("set auto_commit on;")
+
+}

BIN
xugusql.dll