Browse Source

first commit

GTong 1 year ago
commit
3886ff0902

+ 123 - 0
cmd/cmd.go

@@ -0,0 +1,123 @@
+package cmd
+
+import (
+	"database/sql"
+	"fmt"
+	"os"
+	"strings"
+	"xg_once_query/dbBase"
+	"xg_once_query/setting"
+)
+
+func CmdInit(db *sql.DB) {
+	args := os.Args[1:]
+	if len(args) == 0 {
+		fmt.Println("没有参数")
+		//view(db)
+		return
+	}
+
+	first := args[0]
+	switch first {
+	case "--":
+		var sql string
+		if len(args[1:]) == 0 {
+			fmt.Println("“-”缺少映射指令")
+			return
+		}
+		//setting.PrintSqlMap()
+		//println("args[1]", args[1])
+		if setting.SqlMaps[args[1]] == nil {
+			fmt.Println("不存在的映射指令")
+			return
+		} else {
+			sql = setting.SqlMaps[args[1]].(string)
+		}
+		sql = strings.TrimSpace(sql)
+		//%s替换
+		countArguments(&sql, args)
+		//Limit添加
+		if setting.SInfo.Limit != "0" {
+
+			if sql[len(sql)-1] == ';' {
+				index := len(sql) - 2
+				sql := sql[:index+1] + " limit " + setting.SInfo.Limit
+				fmt.Println("sql: ", sql)
+				dbBase.DbQuery(db, sql)
+				break
+			}
+			sql = fmt.Sprintf(sql+" limit %s", setting.SInfo.Limit)
+			fmt.Println("sql: ", sql)
+		}
+		fmt.Println("sql: ", sql)
+		dbBase.DbQuery(db, sql)
+
+	case "-":
+		sql := args[1]
+		if sql == "" {
+			fmt.Println("指令为空")
+			break
+		}
+		fmt.Println("sql: ", sql)
+		dbBase.DbQuery(db, sql)
+
+	default:
+		//fmt.Println("cmd  = default")
+		sql := args[0]
+		if sql == "" {
+			fmt.Println("指令为空")
+			break
+		}
+
+	}
+}
+
+func countArguments(sql *string, args []string) {
+	// 计算 %s 的出现次数
+	count := strings.Count(*sql, "%s")
+	switch count {
+	case 0:
+		break
+	case 1:
+		if len(args) < 3 {
+			fmt.Println("缺少参数")
+			return
+		}
+		*sql = strings.Replace(*sql, "%s", args[2], 1)
+
+	case 2:
+		if len(args) < 4 {
+			fmt.Println("缺少参数")
+			return
+		} else {
+			*sql = strings.Replace(*sql, "%s", args[2], 1)
+			*sql = strings.Replace(*sql, "%s", args[3], 1)
+
+		}
+	case 3:
+		if len(args) < 5 {
+			fmt.Println("缺少参数")
+			return
+		} else {
+			*sql = strings.Replace(*sql, "%s", args[2], 1)
+			*sql = strings.Replace(*sql, "%s", args[3], 1)
+			*sql = strings.Replace(*sql, "%s", args[4], 1)
+
+		}
+	case 4:
+		if len(args) < 6 {
+			fmt.Println("缺少参数")
+			return
+		} else {
+			*sql = strings.Replace(*sql, "%s", args[2], 1)
+			*sql = strings.Replace(*sql, "%s", args[3], 1)
+			*sql = strings.Replace(*sql, "%s", args[4], 1)
+			*sql = strings.Replace(*sql, "%s", args[5], 1)
+
+		}
+
+	default:
+		fmt.Println("缺少参数")
+		return
+	}
+}

+ 54 - 0
cmd/view.go

@@ -0,0 +1,54 @@
+package cmd
+
+import (
+	"bufio"
+	"database/sql"
+	"fmt"
+	"os"
+	"strings"
+	"xg_once_query/dbBase"
+)
+
+func view(db *sql.DB) {
+	// 创建一个新的读取器
+	reader := bufio.NewReader(os.Stdin)
+
+	for {
+
+		fmt.Print("SQL> ")
+		input, _ := reader.ReadString(';')
+		input = strings.TrimLeft(input, " ")
+		fmt.Printf("SQL =%s, end \n ", input)
+		firstSpaceIndex := strings.Index(input, " ")
+		if firstSpaceIndex != -1 {
+			firstWord := input[:firstSpaceIndex]
+			if strings.HasPrefix(strings.ToLower(firstWord), "select") {
+				dbBase.DbQuery(db, input)
+			} else {
+				dbBase.DbExec(db, input)
+			}
+
+		}
+
+	}
+
+	// go io.Copy(os.Stdout, waiter.Reader)
+	// go io.Copy(os.Stderr, waiter.Reader)
+
+	// // "golang.org/x/crypto/ssh/terminal"
+	// //此处是关键,需要将标准输入转成标准终端输入
+	// fd := os.Stdin.Fd()
+	// if terminal.IsTerminal(int(fd)) {
+	// 	oldState, err := terminal.MakeRaw(int(fd))
+	// 	if err != nil {
+	// 		zap.S().Fatalln(err)
+	// 	}
+	// 	defer terminal.Restore(int(fd), oldState)
+	// }
+
+	// go io.Copy(waiter.Conn, os.Stdin)
+	// if err != nil {
+	// 	panic(err)
+	// }
+
+}

+ 66 - 0
config.toml

@@ -0,0 +1,66 @@
+[database]
+Db = "xugusql"
+DbHost = "10.28.20.101"
+DbPort = "5190"
+DbName = "SYSTEM"
+DbUser = "SYSDBA"
+DbPassWord = "SYSDBA"
+
+[setting] 
+limit = "0" #会在sql语句后面拼接 limit语句 ,为 0 则不拼接 limit 语句。只在 (-)参数下起效。
+colLimit = "13" #限制命令行打印表格列数
+
+[sql]
+gstores =  "SELECT * FROM sys_gstores WHERE GSTO_NO = %s"
+stores = "SELECT * FROM sys_all_stores WHERE  GSTO_NO = %s"
+tablespaces = "SELECT * FROM sys_tablespaces;"
+
+tablenames = "select table_name from sys_tables;"
+tableid = "select table_id from sys_tables"
+tables = "select * from sys_tables"
+t1 = "select %s from %s;"
+
+# 查询权限 
+qx = """SELECT 'GRANT SELECT ON ' || D.SCHEMA_NAME || '.' || B.OBJ_NAME || ' TO ' || C.USER_NAME ||';'
+     FROM ALL_ACLS A,ALL_OBJECTS B,ALL_USERS C,ALL_SCHEMAS D WHERE C.USER_ID=A.GRANTEE_ID 
+     AND A.OBJECT_ID = B.OBJ_ID AND B.SCHEMA_ID=D.SCHEMA_ID AND D.SCHEMA_NAME='USR_SOD' 
+     AND B.OBJ_NAME ='SURF_WEA_GLB_MUL_HOR_TAB' AND BIT_AND(AUTHORITY,5) = 1"""
+
+
+#查看线程状态
+thd =" SELECT STATE,COUNT(*) FROM SYS_ALL_THD_STATUS WHERE STATE>0 GROUP BY STATE ; "
+
+#查看事务信息
+transid ="""select * from sys_all_thd_session
+ where curr_tid in (select r_transid from ( select *, bit_and(tranid,16777215) lockid 
+ from sys_all_trans where lockid in (SELECT WAIT_OBJ 
+ FROM SYS_all_THD_STATUS  WHERE STATE=8 GROUP BY WAIT_OBJ)));"""
+
+#查看表大小 按TB (db_name='%s' and t.table_name='%s')
+"tablesize" = """select d.db_name,sn.schema_name,t.table_name,count(*)*8/1024/1024||'T' 
+ as cnt from sys_schemas@sys sn,sys_tables@sys t,sys_gstores@sys s,sys_databases@sys d
+  where s.obj_id=t.table_id and sn.schema_id=t.schema_id and sn.db_id=t.db_id and s.db_id=d.db_id and sn.db_id=t.db_id 
+  and db_name='%s' and t.table_name='%s' group by t.table_name,sn.schema_name,d.db_name;""" 
+
+clusters = "show clusters"
+
+
+"daka" = """SELECT 
+NULL AS '加班强度'
+,ROUND(NVL(当月加班次数/当月应出勤次数,0),4) AS '加班频率'
+,NVL(ROUND(当月加班时长总和/当月加班次数,2),0)  AS '加班时长(平均)/分钟' 
+,NVL(当月加班时长总和,0) AS '当月加班时长总和(分钟)'
+,当月加班次数
+,当月实际出勤次数+当月出差次数 AS '当月实际出勤次数(公司+外勤)'
+,当月应出勤次数
+,当月实际出勤次数
+,当月出差次数
+,round((当月实际出勤次数+当月出差次数)/当月应出勤次数,4) AS '出勤频率(公司+外勤)'
+,round(当月出差次数/当月应出勤次数,4) AS '出差频率'
+,年月,部门,姓名 
+FROM xugu.KQ_VIEW  
+WHERE 考勤日期 >= '2023-12-01'
+GROUP BY ROUND(NVL(当月加班次数/当月应出勤次数,0),4),NVL(ROUND(当月加班时长总和/当月加班次数,2),0)
+,NVL(当月加班时长总和,0),当月加班次数,当月实际出勤次数+当月出差次数,当月应出勤次数,当月实际出勤次数,当月出差次数
+,round((当月实际出勤次数+当月出差次数)/当月应出勤次数,4),年月,部门,姓名;
+"""

+ 82 - 0
dbBase/db.go

@@ -0,0 +1,82 @@
+package dbBase
+
+import (
+	"database/sql"
+	"fmt"
+	"time"
+
+	_ "xg_once_query/go-driver-xugusql"
+	"xg_once_query/setting"
+
+	log "github.com/sirupsen/logrus"
+)
+
+func DbInit() *sql.DB {
+	db := setting.DbInfo.Db
+	ip := setting.DbInfo.DbHost
+	port := setting.DbInfo.DbPort
+	dbName := setting.DbInfo.DbName
+	user := setting.DbInfo.DbUser
+	pwd := setting.DbInfo.DbPassWord
+
+	fmt.Println(db, ip, port, dbName, user, pwd)
+	dataSourceNameL := fmt.Sprintf("IP=%s;DB=%s;User=%s;PWD=%s;Port=%s;AUTO_COMMIT=on;CHAR_SET=UTF8", ip, dbName, user, pwd, port)
+	dBase, err := sql.Open(db, dataSourceNameL)
+	if err != nil {
+		log.Println("数据库连接失败:", err)
+	}
+	return dBase
+}
+
+func DbQuery(db *sql.DB, sql string) {
+	log.Println("sql:", sql)
+	if len(sql) < 4 {
+		return
+	}
+	if sql[0:4] == "show" || len(sql) < 6 || sql[0:6] == "select" || sql[0:6] == "SELECT" {
+		rows, err := db.Query(sql)
+		if err != nil {
+			log.Println("数据库查询失败:", err)
+			return
+		}
+
+		//获取表列名
+		colHeads, err := rows.Columns()
+		if err != nil {
+			log.Println("DbQuery:获取表列名失败", err)
+			return
+		}
+
+		//表数据空间生成
+		pvals := make([]interface{}, len(colHeads))
+		for key := range pvals {
+			dest := make([]byte, 216)
+			pvals[key] = &dest
+		}
+		if len(colHeads) < 9 {
+			TablePrint(rows, colHeads, pvals)
+		} else {
+			TablePrints(rows, colHeads, pvals)
+		}
+	} else {
+		fmt.Println("非查询语句")
+		return
+	}
+
+}
+
+func DbExec(db *sql.DB, sql string) {
+	startTime := time.Now()
+	result, err := db.Exec(sql)
+	if err != nil {
+		log.Println(err)
+		return
+	}
+	lastInsertID, _ := result.LastInsertId()
+	rowsAffected, _ := result.RowsAffected()
+
+	duration := time.Since(startTime) // 计算执行时间
+	fmt.Printf("SQL 执行耗时: %s\n", duration)
+	fmt.Printf("Last Insert ID: %d\n", lastInsertID)
+	fmt.Printf("Rows Affected: %d\n", rowsAffected)
+}

+ 24 - 0
dbBase/db_test.go

@@ -0,0 +1,24 @@
+package dbBase
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestA(t *testing.T) {
+	db := DbInit()
+	defer db.Close()
+	err := db.Ping()
+	if err != nil {
+		fmt.Printf("connect xugu dbms ... failed\n")
+		return
+	} else {
+		fmt.Printf("connect xugu dbms ... ok\n")
+	}
+
+	DbQuery(db, "select * from sys_tables ")
+}
+
+func TestIns(t1 *testing.T) {
+	
+}

+ 114 - 0
dbBase/tablePrint.go

@@ -0,0 +1,114 @@
+package dbBase
+
+import (
+	"database/sql"
+	"fmt"
+	"log"
+	"strconv"
+	"xg_once_query/setting"
+
+	"github.com/jedib0t/go-pretty/v6/table"
+)
+
+func TablePrint(rows *sql.Rows, colHeads []string, pvals []interface{}) {
+	//log.Println("TablePrint")
+	// 表列名
+	t := table.NewWriter()
+	var header table.Row
+	for _, v := range colHeads {
+		header = append(header, v)
+	}
+	t.AppendHeader(header)
+
+	for rows.Next() {
+		err := rows.Scan(pvals...)
+		if err != nil {
+			//log.Fatal(err)
+			log.Println(err)
+			break
+		}
+		var row table.Row
+
+		for v := range pvals {
+			row = append(row, string(*(pvals[v].(*[]byte))))
+			// log.Println("len row : ", len(row))
+			// log.Println("row", row)
+		}
+		t.AppendRow(row)
+	}
+
+	//输出命令行表格
+	fmt.Println(t.Render())
+}
+
+func TablePrints(rows *sql.Rows, colHeads []string, pvals []interface{}) {
+
+	//输出表列名参数
+	//n group组 = colHeads / cplLimit 49 ... / 5 = 9 余4 cols[n group组:cplLimit]
+	colLimit, _ := strconv.Atoi(setting.SInfo.ColLimit)
+	if len(colHeads) < colLimit {
+		colLimit = len(colHeads)
+	}
+
+	group := len(colHeads) / colLimit
+	remainder := len(colHeads) % colLimit
+	colLimitTmp := colLimit
+	colStart := 0
+
+	//输出表数据
+	var pv2 [][]string
+
+	for rows.Next() {
+
+		err := rows.Scan(pvals...)
+		if err != nil {
+			//log.Fatal(err)
+			log.Println(err)
+		}
+		copiedSlice := make([]string, len(pvals))
+
+		for i, val := range pvals {
+			// 使用 interface{} 类型进行深拷贝,并将结果存储到 copiedSlice 中
+			copiedSlice[i] = string(*val.(*[]byte))
+		}
+
+		pv2 = append(pv2, copiedSlice)
+
+	}
+
+	for i := 0; i < group+1; i++ {
+		colSTmp := colStart
+		colLTmp := colLimitTmp
+		//表列名
+		t := table.NewWriter()
+		var header table.Row
+
+		colTmp := colHeads[colStart:colLimitTmp]
+		for _, v := range colTmp {
+			header = append(header, v)
+		}
+		t.AppendHeader(header)
+		//表数据
+
+		for v := range pv2 {
+			var row table.Row
+			abc := pv2[v][colSTmp:colLTmp]
+
+			for v2 := range abc {
+				row = append(row, abc[v2])
+			}
+			t.AppendRow(row)
+		}
+
+		colStart = colLimitTmp
+		if colLimitTmp < len(colHeads)-remainder {
+			colLimitTmp += colLimit
+		} else {
+			colLimitTmp = len(colHeads)
+		}
+
+		//输出命令行表格
+		fmt.Println(t.Render())
+	}
+
+}

BIN
go-driver-xugusql/lib/arm/libxugusql.so


+ 48 - 0
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
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
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
+}

+ 220 - 0
go-driver-xugusql/xugusql_cgo.go

@@ -0,0 +1,220 @@
+package xugusql
+
+import (
+	"unsafe"
+)
+
+/*
+#cgo CFLAGS : -I/usr/include
+#cgo LDFLAGS : -L/usr/lib64 -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.ulong(1), C.ulong(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.ulong(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
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
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
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
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
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
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
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;")
+
+}

+ 3 - 0
go.mod

@@ -0,0 +1,3 @@
+module xg_once_query
+
+go 1.21.4

+ 31 - 0
main.go

@@ -0,0 +1,31 @@
+package main
+
+import (
+	"fmt"
+	"xg_once_query/cmd"
+	dbBase "xg_once_query/dbBase"
+	_ "xg_once_query/go-driver-xugusql"
+
+	log "github.com/sirupsen/logrus"
+)
+
+func main() {
+	log.SetLevel(log.TraceLevel)
+	//	log.SetReportCaller(true)
+	log.SetFormatter(&log.TextFormatter{
+		FullTimestamp:   true,
+		TimestampFormat: "2006-01-02 15:04:05",
+	})
+
+	db := dbBase.DbInit()
+	defer db.Close()
+	err := db.Ping()
+	if err != nil {
+		fmt.Printf("数据库连接失败 connect xugu dbms ... failed\n")
+		return
+	} else {
+		fmt.Printf("数据库连接成功 connect xugu dbms ... ok\n")
+	}
+	cmd.CmdInit(db)
+
+}

+ 76 - 0
setting/setting.go

@@ -0,0 +1,76 @@
+package setting
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+
+	"github.com/spf13/viper"
+)
+
+type DataBaseInfo struct {
+	Db         string `toml:"Db" `
+	DbHost     string `toml:"DbHost" `
+	DbPort     string `toml:"DbPort" `
+	DbName     string `toml:"DbName" `
+	DbUser     string `toml:"DbUser" `
+	DbPassWord string `toml:"DbPassWord" `
+}
+
+type SettingInfo struct {
+	Limit    string `toml:"Limit" `
+	ColLimit string `toml:"ColLimit" `
+}
+
+var SqlMaps map[string]any
+var DbInfo DataBaseInfo
+var SInfo SettingInfo
+
+func init() {
+	v := viper.New()
+	//v.SetConfigFile("/home/gtong/GO/xgx/XGX/config.toml")
+	executablePath, err := os.Executable()
+	if err != nil {
+		// 处理错误
+	}
+
+	configFilePath := filepath.Join(filepath.Dir(executablePath), "config.toml")
+	//fmt.Println("configFilePath", configFilePath)
+
+	v.AddConfigPath(".")
+
+	v.SetConfigFile(configFilePath)
+	v.SetConfigFile("./config.toml")
+	if err := v.ReadInConfig(); err != nil {
+		if _, ok := err.(viper.ConfigFileNotFoundError); ok {
+			fmt.Printf("配置文件不存在:%v\n", err)
+		} else {
+
+			fmt.Printf("配置文件存在,解析失败:%v\n", err)
+		}
+	}
+
+	//获取数据库连接信息
+	database := v.Sub("database")
+	err = database.Unmarshal(&DbInfo)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	//获取基本设置
+	setting := v.Sub("setting")
+	err = setting.Unmarshal(&SInfo)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	//获取sql
+	SqlMaps = v.GetStringMap("sql")
+
+}
+
+func PrintSqlMap() {
+	for k := range SqlMaps {
+		fmt.Printf("%s ----> %s\n", k, SqlMaps[k])
+	}
+}

+ 40 - 0
setting/setting_test.go

@@ -0,0 +1,40 @@
+package setting
+
+import (
+	"log"
+	"testing"
+
+	"github.com/spf13/viper"
+)
+
+type ConfigTest struct {
+	HttpAddr  string ` toml:"http_addr"`
+	GrpcAddr  string `json:"grpc_addr" toml:"grpcaddr" yaml:"grpc_addr"`
+	JaegerUrl string `json:"jaeger_url" toml:"jaeger_url" yaml:"jaeger_url" mapstructure:"jaeger_url"`
+	Tracing   bool   `toml:"tracing"  json:"tracing" yaml:"tracing" ` // opentelemetry tracing
+}
+
+type ConfigTest2 struct {
+	Host     string ` toml:"Host"`
+	Port     string `json:"Port" toml:"Port" yaml:"Port"`
+	Name     string `json:"Name" toml:"Name" yaml:"Name" mapstructure:"Name"`
+	Username string `toml:"Username"  json:"Username" yaml:"Username" ` // opentelemetry tracing
+}
+type C1 struct {
+	Abc ConfigTest2 `mapstructure:"database"`
+}
+
+// jaeger 加载配置文件
+func TestSourceFile_Unmarshal(t *testing.T) {
+	filePath := "config.toml"
+	viper.SetConfigFile(filePath)
+	if err := viper.ReadInConfig(); err != nil {
+		t.Error(err)
+	}
+
+	c := &C1{}
+	if err := viper.Unmarshal(&c); err != nil {
+		t.Error(err)
+	}
+	log.Println("Unmarshal file sucess", "v", c)
+}