Browse Source

first commit

GTong 10 months ago
commit
c4b989071c
16 changed files with 1925 additions and 0 deletions
  1. 15 0
      .vscode/launch.json
  2. 3 0
      go.mod
  3. 55 0
      main.go
  4. 80 0
      xugu/xugu_buffer.go
  5. 231 0
      xugu/xugu_conn.go
  6. 66 0
      xugu/xugu_connector.go
  7. 30 0
      xugu/xugu_define.go
  8. 53 0
      xugu/xugu_driver.go
  9. 231 0
      xugu/xugu_fields.go
  10. 82 0
      xugu/xugu_model.go
  11. 510 0
      xugu/xugu_parse.go
  12. 32 0
      xugu/xugu_result.go
  13. 102 0
      xugu/xugu_rows.go
  14. 163 0
      xugu/xugu_sock.go
  15. 100 0
      xugu/xugu_stmt.go
  16. 172 0
      xugu/xugu_utils.go

+ 15 - 0
.vscode/launch.json

@@ -0,0 +1,15 @@
+{
+    // 使用 IntelliSense 了解相关属性。 
+    // 悬停以查看现有属性的描述。
+    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "Launch Package",
+            "type": "go",
+            "request": "launch",
+            "mode": "auto",
+            "program": "${workspaceFolder}/main.go"
+        }
+    ]
+}

+ 3 - 0
go.mod

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

+ 55 - 0
main.go

@@ -0,0 +1,55 @@
+package main
+
+import (
+	"database/sql"
+	"log"
+	_ "xugu_go_driver/xugu"
+)
+
+func main() {
+	db, err := sql.Open("xugusql", "IP=127.0.0.1;DB=SYSTEM;User=SYSDBA;PWD=SYSDBA;Port=5138;AUTO_COMMIT=on;CHAR_SET=UTF8")
+	if err != nil {
+		log.Fatal("err ", err)
+	}
+	// if err := db.Ping(); err != nil {
+	// 	log.Fatal("err ping ", err)
+	// }
+	//db.Query("select * from dual")
+
+	// rows, err := db.Query("select * from test1 where id = ?;", 2)
+	// if err != nil {
+	// 	log.Fatal(err)
+	// }
+
+	// var cols []string
+	// cols, err = rows.Columns()
+	// if err != nil {
+	// 	log.Fatal(err)
+	// }
+
+	// 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\t", string(*(v.(*[]byte))))
+	// 	}
+	// 	fmt.Printf("\n")
+	// }
+
+	// rows.Close()
+
+	stmt, err := db.Prepare("select * from dual where id = ?")
+	if err != nil {
+		log.Fatal(err)
+	}
+	stmt.Exec("2")
+}

+ 80 - 0
xugu/xugu_buffer.go

@@ -0,0 +1,80 @@
+package xugu
+
+import (
+	"errors"
+	"fmt"
+	"net"
+	"time"
+)
+
+var (
+	ErrBusyBuffer = errors.New("busy buffer")
+)
+
+type buffer struct {
+	buf     []byte // buf 是一个字节缓冲区,长度和容量相等。
+	conn    net.Conn
+	idx     int
+	length  int
+	timeout time.Duration
+}
+
+// newBuffer 分配并返回一个新的缓冲区。
+func newBuffer(nc net.Conn) buffer {
+	return buffer{
+		buf:  make([]byte, 2048),
+		conn: nc,
+	}
+}
+
+// store 存储 buf,这是一个更新的缓冲区,如果合适的话。
+func (b *buffer) store(buf []byte) error {
+	if len(buf) > cap(b.buf) {
+		fmt.Println("大于缓冲区: len(buf) > cap(b.buf)")
+		return ErrBusyBuffer
+	}
+	b.buf = buf[:cap(buf)]
+
+	return nil
+}
+
+func (b *buffer) peekChar() byte {
+	ret := b.buf[b.idx]
+	//	fmt.Println("peekChar内部的: ", b.buf[b.idx:])
+	return ret
+}
+func (b *buffer) reset() {
+	b.idx = 0
+	b.buf = make([]byte, 2048)
+}
+
+// 返回指定字节的切片
+func (b *buffer) readNext(need int, reverse bool) []byte {
+	//长度不够返回
+	if len(b.buf[b.idx:]) < need {
+		//调用一次接收服务器消息
+		b.conn.Read(b.buf[b.idx:])
+		offset := b.idx
+		b.idx += need
+
+		return b.buf[offset:b.idx]
+	}
+
+	offset := b.idx
+	b.idx += need
+
+	//fmt.Println("readNext: ", b.buf[offset:b.idx])
+	if reverse {
+		//	tmp2 := b.buf[offset:b.idx]
+		//fmt.Println("readNext: 转换小端前", tmp2, " - ", string(tmp2))
+		tmp := reverseBytes(b.buf[offset:b.idx])
+		//	fmt.Println("readNext: 转换小端后", tmp, " - ", string(tmp))
+
+		return tmp
+	} else {
+		//	fmt.Println("readNext: 没有转换:", b.buf[offset:b.idx])
+		//	fmt.Println("readNext: 没有转换:", string(b.buf[offset:b.idx]))
+		return b.buf[offset:b.idx]
+	}
+
+}

+ 231 - 0
xugu/xugu_conn.go

@@ -0,0 +1,231 @@
+package xugu
+
+import (
+	"bytes"
+	"context"
+	"database/sql/driver"
+	"errors"
+	"fmt"
+	"net"
+	"sync"
+)
+
+type xuguConn struct {
+	dsnConfig
+	conn        net.Conn
+	mu          sync.Mutex
+	useSSL      bool // 是否使用加密
+	havePrepare int  //default 0
+
+	prepareNo   int
+	prepareName string
+	//presPrepareCata *Result
+
+	errStr []byte
+
+	sendBuff bytes.Buffer
+	readBuff buffer
+}
+
+type dsnConfig struct {
+	IP             string
+	Port           string
+	Database       string
+	User           string
+	Password       string
+	Encryptor      string //加密库的解密口令
+	CharSet        string //客户端使用的字符集名
+	TimeZone       string
+	IsoLevel       string //事务隔离级别
+	LockTimeout    string //加锁超时
+	AutoCommit     string
+	StrictCommit   string
+	Result         string
+	ReturnSchema   string
+	ReturnCursorID string
+	LobRet         string
+	ReturnRowid    string
+	Version        string
+}
+
+func (xgConn *xuguConn) Begin() (driver.Tx, error) {
+	gt("xuguConn.Begin")
+	defer gt("xuguConn.Begin end")
+	return nil, nil
+
+}
+
+func (xgConn *xuguConn) Close() error {
+	gt("xuguConn.Close")
+	defer gt("xuguConn.Close end")
+	xgConn.mu.Lock()
+	defer xgConn.mu.Unlock()
+	err := xgConn.conn.Close()
+	if err != nil {
+		fmt.Println("Close connection error")
+		xgConn.mu.Unlock()
+		return err
+	}
+
+	return nil
+}
+
+func (xgConn *xuguConn) Exec(sql string,
+	args []driver.Value) (driver.Result, error) {
+	gt("xuguConn.Exec")
+	defer gt("xuguConn.Exec end")
+
+	return nil, nil
+}
+
+func (xgConn *xuguConn) Query(sql string,
+	args []driver.Value) (driver.Rows, error) {
+	gt("xuguConn.Query")
+	defer gt("xuguConn.Query end")
+
+	xgConn.mu.Lock()
+	defer xgConn.mu.Unlock()
+	// 检测sql语句不是查询则报错
+	if switchSQLType(sql) != SQL_SELECT {
+		return nil, errors.New("The executed SQL statement is not a SELECT")
+	}
+
+	// 有传进来的参数
+	if len(args) != 0 {
+		values := []xuguValue{}
+		//判断类型
+		for _, param := range args {
+			err := assertParamType(param, &values)
+			if err != nil {
+				return nil, err
+			}
+		}
+		//send msg
+		if err := sockSendPutStatement(xgConn, []byte(sql), &values, len(args)); err != nil {
+			return nil, err
+		}
+
+		if err := sockSendExecute(xgConn); err != nil {
+			return nil, err
+		}
+
+	} else {
+
+		//send msg
+		if err := sockSendPutStatement(xgConn, []byte(sql), nil, len(args)); err != nil {
+			return nil, err
+		}
+
+		if err := sockSendExecute(xgConn); err != nil {
+			return nil, err
+		}
+
+	}
+	//recv msg
+	aR, err := xuguSockRecvMsg(xgConn)
+	if err != nil {
+		return nil, err
+	}
+
+	switch aR.rt {
+	case selectResult:
+		rows := &xuguRows{
+			rows_conn: xgConn,
+			results:   aR.s,
+			colIdx:    0,
+			prepared:  false,
+		}
+
+		return rows, nil
+	case errInfo:
+
+		return nil, errors.New(string(aR.e.ErrStr))
+	case warnInfo:
+
+		return nil, errors.New(string(aR.w.WarnStr))
+	default:
+	}
+
+	return nil, errors.New("xugu Query error")
+}
+
+func (xgConn *xuguConn) Ping(ctx context.Context) error {
+	gt("xuguConn.Ping")
+	defer gt("xuguConn.Ping end")
+
+	//send
+	xgConn.mu.Lock()
+	sockSendPutStatement(xgConn, []byte("select count(*) from dual;"), nil, 0)
+	sockSendExecute(xgConn)
+
+	_, err := xuguSockRecvMsg(xgConn)
+	if err != nil {
+		fmt.Println("Ping err : ", err.Error())
+		return err
+	}
+	xgConn.readBuff.reset()
+	xgConn.mu.Unlock()
+	return nil
+}
+
+func (xgConn *xuguConn) Prepare(sql string) (driver.Stmt, error) {
+	gt("xuguConn.Prepare")
+	defer gt("xuguConn.Prepare end")
+
+	xgConn.mu.Lock()
+	defer xgConn.mu.Unlock()
+
+	//判断sql类型
+	switch switchSQLType(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.")
+	}
+	//发送创建prepare
+	prepareName := "GTONG"
+
+	err := xuguPrepare(xgConn, sql, prepareName)
+	if err != nil {
+		return nil, err
+	}
+	count := assertParamCount(sql)
+	stmt := &xuguStmt{
+		stmt_conn:  xgConn,
+		prepared:   true,
+		prename:    make([]byte, 128),
+		curopend:   false,
+		curname:    make([]byte, 128),
+		paramCount: count,
+		mysql:      sql,
+	}
+	stmt.prename = []byte(xgConn.prepareName)
+	return stmt, nil
+}
+
+func xuguPrepare(pConn *xuguConn, cmd_sql string, prepareName string) error {
+
+	fmt.Println("\n ---xuguPrepare")
+	prepareName = fmt.Sprintf("%s%d", prepareName, pConn.prepareNo)
+	sqlRet := fmt.Sprintf("PREPARE %s AS %s", prepareName, cmd_sql)
+	pConn.prepareName = prepareName
+	pConn.prepareNo++
+	//send msg
+	sockSendPutStatement(pConn, []byte(sqlRet), nil, 0)
+	sockSendExecute(pConn)
+	//recv msg
+	_, err := xuguSockRecvMsg(pConn)
+	if err != nil {
+		fmt.Println("xuguPrepare parseMsg(&pConn.readBuff, pConn)")
+		return err
+	}
+
+	fmt.Println("Message from server:", pConn.readBuff.buf[pConn.readBuff.idx:])
+	fmt.Println("Message from server:", string(pConn.readBuff.buf[pConn.readBuff.idx:]))
+
+	fmt.Println("\n ---xuguPrepare end")
+
+	return nil
+}

+ 66 - 0
xugu/xugu_connector.go

@@ -0,0 +1,66 @@
+package xugu
+
+import (
+	"context"
+	"database/sql/driver"
+	"fmt"
+	"net"
+	"time"
+)
+
+type connector struct {
+	dsn string
+}
+
+// Driver implements driver.Connector interface.
+// Driver returns &XuguDriver{}
+func (conntor *connector) Driver() driver.Driver {
+	fmt.Println(">>>>>(conntor *connector) Driver()")
+	return &XuguDriver{}
+}
+
+// Connect implements driver.Connector interface.
+// Connect returns a connection to the database.
+/*
+dsn解析
+创建连接
+设置为 tcp 长连接(
+创建连接缓冲区
+设置连接超时配置
+接收来自服务端的握手请求
+*/
+func (conntor *connector) Connect(ctx context.Context) (driver.Conn, error) {
+	gt("(conntor *connector) Connect(ctx context.Context) run ")
+	defer gt("(conntor *connector) Connect(ctx context.Context) end")
+	dsnConfig := parseDSN(conntor.dsn)
+
+	xgConn := &xuguConn{conn: nil}
+	xgConn.dsnConfig = dsnConfig
+
+	nd := net.Dialer{Timeout: 5 * time.Second}
+	netConn, err := nd.DialContext(ctx, "tcp", fmt.Sprintf("%s:%s", xgConn.IP, xgConn.Port))
+	if err != nil {
+		fmt.Println("tcp Connect error: ", err)
+		return nil, err
+	}
+
+	// 启用 TCP 保活
+	if tc, ok := netConn.(*net.TCPConn); ok {
+		if err := tc.SetKeepAlive(true); err != nil {
+			//c.cfg.Logger.Print(err) // 如果设置保活失败,记录错误但不终止
+			fmt.Println("SetKeepAlive error", err)
+			return nil, err
+		}
+	}
+
+	xgConn.conn = netConn
+	xgConn.mu.Lock()
+	xgConn.readBuff = newBuffer(xgConn.conn)
+	fmt.Println("连接串为: ", conntor.dsn)
+	err = xgSockOpenConn(ctx, xgConn)
+	if err != nil {
+		return nil, err
+	}
+	xgConn.mu.Unlock()
+	return xgConn, nil
+}

+ 30 - 0
xugu/xugu_define.go

@@ -0,0 +1,30 @@
+package xugu
+
+//协议消息类型
+type msgType byte
+
+const (
+	selectResult msgType = iota + 0x00
+	insertResult
+	updateResult
+	deleteResult
+	procRet
+	outParamRet
+	errInfo
+	warnInfo
+	message
+	formArgDescri
+)
+
+// SQL类型常量
+const (
+	SQL_UNKNOWN = iota
+	SQL_SELECT
+	SQL_INSERT
+	SQL_UPDATE
+	SQL_DELETE
+	SQL_CREATE
+	SQL_ALTER
+	SQL_PROCEDURE
+	SQL_OTHER
+)

+ 53 - 0
xugu/xugu_driver.go

@@ -0,0 +1,53 @@
+package xugu
+
+import (
+	"context"
+	"database/sql"
+	"database/sql/driver"
+	"time"
+)
+
+// XuguDriver is exported to make the driver directly accessible
+type XuguDriver struct{}
+
+/* Register Driver */
+func init() {
+	gt("init()")
+	defer gt("init() end")
+	/* 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) {
+	gt("Open")
+	defer gt("Open end")
+	conn := &connector{dsn: dsn}
+	return conn.Connect(context.Background())
+}
+
+func (db XuguDriver) OpenConnector(dsn string) (driver.Connector, error) {
+	gt("OpenConnector")
+	defer gt("OpenConnector end")
+	return &connector{dsn: dsn}, nil
+}

+ 231 - 0
xugu/xugu_fields.go

@@ -0,0 +1,231 @@
+package xugu
+
+import (
+	"database/sql"
+	"database/sql/driver"
+	"fmt"
+	"reflect"
+	"time"
+)
+
+type FieldDescri struct {
+	FieldNameLen    int
+	FieldName       string
+	FieldType       fieldType
+	FieldPreciScale fieldPreciScaleInfo
+	FieldFlag       uint32
+}
+
+type fieldPreciScaleInfo struct {
+	scale    uint16
+	accuracy uint16
+}
+
+type fieldType uint16
+
+const (
+	fieldType_EMPTY fieldType = iota + 0x00
+	fieldType_NULL
+	fieldType_BOOL
+	fieldType_I1
+	fieldType_I2
+	fieldType_I4
+	fieldType_I8
+	fieldType_NUM
+	fieldType_R4
+	fieldType_R8
+
+	fieldType_DATE
+	fieldType_TIME
+	fieldType_TIME_TZ
+	fieldType_DATETIME
+	fieldType_DATETIME_TZ
+
+	fieldType_INTERVAL_Y
+	fieldType_INTERVAL_Y2M
+	fieldType_INTERVAL_M
+
+	fieldType_INTERVAL_D
+	fieldType_INTERVAL_D2H
+	fieldType_INTERVAL_H
+	fieldType_INTERVAL_D2M
+	fieldType_INTERVAL_H2M
+	fieldType_INTERVAL_MI
+	fieldType_INTERVAL_D2S
+	fieldType_INTERVAL_H2S
+	fieldType_INTERVAL_M2S
+	fieldType_INTERVAL_S
+
+	fieldType_ROWVER
+	fieldType_GUID
+	fieldType_CHAR
+	fieldType_NCHAR
+	fieldType_CLOB
+
+	fieldType_BINARY
+	fieldType_BLOB
+
+	fieldType_GEOM
+	fieldType_POINT
+	fieldType_BOX
+	fieldType_POLYLINE
+	fieldType_POLYGON
+
+	fieldType_BLOB_I
+	fieldType_BLOB_S
+	fieldType_BLOB_M
+	fieldType_BLOB_OM
+	fieldType_STREAM
+	fieldType_ROWID
+	fieldType_SIBLING
+	fieldType_MAX_SYS fieldType = 47
+
+	fieldType_BLADE_BEGIN fieldType = 101
+	fieldType_BLADE_END   fieldType = 1000
+
+	fieldType_OBJECT fieldType = 1001 // object type
+	fieldType_REFROW
+	fieldType_RECORD  // record type
+	fieldType_VARRAY  // array type
+	fieldType_TABLE   // table type
+	fieldType_ITABLE  // Idxby table
+	fieldType_CURSOR  // involved ref-record type (cannot change)
+	fieldType_REFCUR  // REF_CURSOR type
+	fieldType_ROWTYPE // ref row type
+	fieldType_COLTYPE // ref column type
+	fieldType_CUR_REC
+	fieldType_PARAM
+)
+
+/* {{ */
+func (self *FieldDescri) typeDatabaseName() string {
+	switch self.FieldType {
+	case fieldType_BOOL:
+		return "BOOLEAN"
+	case fieldType_CHAR, fieldType_NCHAR:
+		return "CHAR"
+	case fieldType_I1:
+		return "TINYINT"
+	case fieldType_I2:
+		return "SHORT"
+	case fieldType_I4:
+		return "INTEGER"
+	case fieldType_I8:
+		return "BIGINT"
+	case fieldType_R4:
+		return "FLOAT"
+	case fieldType_R8:
+		return "DOUBLE"
+	case fieldType_NUM:
+		return "NUMERIC"
+	case fieldType_DATE:
+		return "DATE"
+	case fieldType_TIME:
+		return "TIME"
+	case fieldType_TIME_TZ:
+		return "TIMEZONE"
+	case fieldType_DATETIME:
+		return "DATETIME"
+	case fieldType_DATETIME_TZ:
+		return "DATETIME TIMEZONE"
+	case fieldType_BINARY:
+		return "BINARY"
+	case fieldType_INTERVAL_Y:
+		return "INTERVAL YEAR"
+	case fieldType_INTERVAL_Y2M:
+		return "INTERVAL YEAR TO MONTH"
+	case fieldType_INTERVAL_D2S:
+		return "INTERVAL DAY TO SECOND"
+	case fieldType_CLOB:
+		return "CLOB"
+	case fieldType_BLOB:
+		return "BLOB"
+	default:
+		return ""
+	}
+}
+
+/* {{ */
+func (self *FieldDescri) scanType() reflect.Type {
+
+	switch self.FieldType {
+
+	case fieldType_BOOL:
+		return scanTypeBool
+	case fieldType_I1:
+		return scanTypeInt8
+	case fieldType_I2:
+		return scanTypeInt16
+	case fieldType_I4:
+		return scanTypeInt32
+	case fieldType_I8:
+		return scanTypeInt64
+	case fieldType_R4:
+		return scanTypeFloat32
+	case fieldType_R8:
+		return scanTypeFloat64
+	case fieldType_DATE,
+		fieldType_TIME,
+		fieldType_DATETIME:
+		return scanTypeNullTime
+	case fieldType_TIME_TZ,
+		fieldType_DATETIME_TZ,
+		fieldType_CHAR,
+		fieldType_NCHAR,
+		fieldType_BINARY,
+		//fieldTypeInterval,
+		fieldType_NUM,
+		fieldType_INTERVAL_Y2M,
+		fieldType_INTERVAL_D2S,
+		//fieldTypeLob,
+		fieldType_CLOB,
+		fieldType_BLOB:
+		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))
+)
+
+func processValue(value driver.Value) {
+	switch v := value.(type) {
+	case nil:
+		fmt.Println("Value is nil")
+	case int64:
+		fmt.Printf("Value is int64: %d\n", v)
+	case float64:
+		fmt.Printf("Value is float64: %f\n", v)
+	case bool:
+		fmt.Printf("Value is bool: %t\n", v)
+	case []byte:
+		fmt.Printf("Value is []byte: %x\n", v)
+	case string:
+		fmt.Printf("Value is string: %s\n", v)
+	case time.Time:
+		fmt.Printf("Value is time.Time: %s\n", v)
+	case driver.Rows:
+		fmt.Println("Value is driver.Rows")
+		// You can further process the rows here
+	default:
+		fmt.Println("Unknown type")
+	}
+}

+ 82 - 0
xugu/xugu_model.go

@@ -0,0 +1,82 @@
+package xugu
+
+type SelectResult struct {
+	Field_Num uint32
+	Fields    []FieldDescri
+	Values    [][]FieldValue //[字段][字段所有值]
+	rowIdx    int
+	fad       *FormArgDescri
+}
+
+type FieldValue struct {
+	Col_len  uint32
+	Col_Data []byte
+}
+
+type InsertResult struct {
+	RowidLen  uint32
+	RowidData []byte
+}
+
+type UpdateResult struct {
+	UpdateNum uint32
+}
+
+type DeleteResult struct {
+	DeleteNum uint32
+}
+
+type ProcRet struct {
+	RetDType   uint32
+	RetDataLen uint32
+	RetData    []byte
+}
+
+type OutParamRet struct {
+	OutParamNo    uint32
+	OutParamDType uint32
+	OutParamLen   uint32
+	OutParamData  []byte
+}
+
+type ErrInfo struct {
+	ErrStrLen uint32
+	ErrStr    []byte
+}
+
+type WarnInfo struct {
+	WarnStrLen uint32
+	WarnStr    []byte
+}
+
+type Message struct {
+	MsgStrLen uint32
+	MsgStr    []byte
+}
+
+type FormArgDescri struct {
+	ArgNum uint32
+	Args   []ArgDescri
+}
+
+type ArgDescri struct {
+	ArgNameLen    uint32
+	ArgName       []byte
+	ArgNo         uint32
+	ArgDType      uint32
+	ArgPreciScale uint32
+}
+
+type allResult struct {
+	rt msgType
+	s  *SelectResult
+	i  *InsertResult
+	u  *UpdateResult
+	d  *DeleteResult
+	p  *ProcRet
+	o  *OutParamRet
+	e  *ErrInfo
+	w  *WarnInfo
+	m  *Message
+	f  *FormArgDescri
+}

+ 510 - 0
xugu/xugu_parse.go

@@ -0,0 +1,510 @@
+package xugu
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type xuguValue struct {
+	// 布尔值,如果值为 true,表示当前字段的数据类型是大对象数据类型
+	islob bool
+	//字段名
+	paramName []byte
+	//paramNameLength [2]byte
+	// 字段的实际值
+	value []byte
+	// 值的长度
+	valueLength int
+	// 字段的类型
+	types fieldType
+}
+
+// 判断参数个数
+func assertParamCount(query string) int {
+	fmt.Println("----assertParamCount func 判断参数个数")
+
+	paramCount := strings.Count(query, "?")
+	fmt.Println("Parse.param_count = ", paramCount)
+
+	return paramCount
+}
+func assertParamType(dV driver.Value, values *[]xuguValue) error {
+	var dest xuguValue
+	switch srcv := dV.(type) {
+	case int64:
+		S := strconv.FormatInt(srcv, 10)
+		dest.value = []byte(S)
+		dest.valueLength = strings.Count(S, "") - 1
+		dest.islob = false
+		dest.types = fieldType_I8
+
+	case float32:
+		S := strconv.FormatFloat(float64(srcv), 'f', 6, 64)
+		dest.value = []byte(S)
+		dest.valueLength = strings.Count(S, "") - 1
+		dest.islob = false
+		dest.types = fieldType_R4
+
+	case float64:
+		S := strconv.FormatFloat(srcv, 'f', 15, 64)
+		dest.value = []byte(S)
+		dest.valueLength = strings.Count(S, "") - 1
+		dest.islob = false
+		dest.types = fieldType_R8
+
+	case bool:
+		S := strconv.FormatBool(srcv)
+		dest.value = []byte(S)
+		dest.valueLength = strings.Count(S, "") - 1
+		dest.islob = false
+		dest.types = fieldType_BOOL
+
+	case string:
+		dest.value = []byte(srcv)
+		dest.valueLength = strings.Count(srcv, "") - 1
+		dest.islob = false
+		dest.types = fieldType_CHAR
+
+	case time.Time:
+		tm := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d",
+			srcv.Year(), int(srcv.Month()), srcv.Day(),
+			srcv.Hour(), srcv.Minute(), srcv.Second())
+		dest.value = []byte(tm)
+		dest.valueLength = strings.Count(tm, "") - 1
+		dest.islob = false
+		dest.types = fieldType_TIME
+
+	case []byte:
+		dest.value = srcv
+		dest.valueLength = len(srcv)
+		dest.islob = true
+		dest.types = fieldType_BLOB
+
+	case nil:
+		dest.value = []byte("xugusql")
+		dest.valueLength = 0
+		dest.islob = false
+		dest.types = fieldType_CHAR
+
+	default:
+		return errors.New("unknown data type")
+	}
+
+	*values = append(*values, dest)
+	return nil
+}
+
+func parseMsg(readBuf *buffer, pConn *xuguConn) (*allResult, error) {
+	var err error
+	aR := allResult{}
+	for {
+		char := readBuf.peekChar()
+		fmt.Println("parseMsg 内的 peekChar: ", char, "-", string(char))
+		switch char {
+
+		case 'K':
+			fmt.Println("消息类型为K")
+			readBuf.reset()
+			return &aR, nil
+
+		case '$':
+			readBuf.idx++
+			fmt.Println("消息类型为$")
+			if aR.f, err = parseFormArgDescri(readBuf); err != nil {
+				return nil, err
+			}
+			aR.rt = formArgDescri
+			return &aR, err
+		case 'A':
+			readBuf.idx++
+			fmt.Println("消息类型为A")
+			if aR.s, err = parseSelectResult(readBuf); err != nil {
+				return nil, err
+			}
+			aR.rt = selectResult
+			return &aR, err
+
+		case 'I':
+			readBuf.idx++
+			fmt.Println("消息类型为I")
+			if aR.i, err = parseInsertResult(readBuf); err != nil {
+				return nil, err
+			}
+			aR.rt = insertResult
+			return &aR, err
+
+		case 'U':
+			fmt.Println("消息类型为U")
+			readBuf.idx++
+			if aR.u, err = parseUpdateResult(readBuf); err != nil {
+				return nil, err
+			}
+			aR.rt = updateResult
+			return &aR, err
+
+		case 'D':
+			fmt.Println("消息类型为D")
+			readBuf.idx++
+			readBuf.idx++
+			if aR.d, err = parseDeleteResult(readBuf); err != nil {
+				return nil, err
+			}
+			aR.rt = deleteResult
+			return &aR, err
+
+		case 'E':
+			fmt.Println("消息类型为E")
+			readBuf.idx++
+
+			if aR.e, err = parseErrInfo(readBuf); err != nil {
+				return nil, err
+			}
+			pConn.errStr = aR.e.ErrStr
+			aR.rt = errInfo
+			return &aR, err
+
+		case 'W':
+			fmt.Println("消息类型为W")
+			readBuf.idx++
+			if aR.w, err = parseWarnInfo(readBuf); err != nil {
+				return nil, err
+			}
+			aR.rt = warnInfo
+			return &aR, err
+
+		case 'M':
+			fmt.Println("消息类型为M")
+			readBuf.idx++
+			if aR.m, err = parseMessage(readBuf); err != nil {
+				return nil, err
+			}
+			aR.rt = message
+			return &aR, err
+
+		default:
+			fmt.Println("消息类型为其他")
+			return nil, errors.New("parseMsg: unknown message type")
+		}
+
+	}
+}
+func parseSelectResult(readBuf *buffer) (*SelectResult, error) {
+	fmt.Println("调用 parseSelectResult")
+	data := &SelectResult{}
+
+	char := readBuf.peekChar()
+	fmt.Println("--=char: ", string(char), char)
+
+	//Field_Num
+	Field_Num := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+	data.Field_Num = Field_Num
+	data.rowIdx = 0
+	fmt.Println("Field_Num: ", data.Field_Num)
+
+	//获取字段信息
+	for i := 0; i < int(Field_Num); i++ {
+
+		field := FieldDescri{}
+
+		//Field_Name_Len
+		field.FieldNameLen = int(binary.LittleEndian.Uint32(readBuf.readNext(4, true)))
+		fmt.Println("field.FieldNameLen: ", field.FieldNameLen)
+		//Field_Name:
+		field.FieldName = string(readBuf.readNext(field.FieldNameLen, false))
+		fmt.Println("field.Field_Name: ", field.FieldName)
+		//Field_DType:
+		field.FieldType = fieldType(binary.LittleEndian.Uint32(readBuf.readNext(4, true)))
+		fmt.Println("field.FieldType: ", field.FieldType)
+		//Field_Preci_Scale:
+		fieldPreciScale := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+		if int32(fieldPreciScale) <= 0 {
+			field.FieldPreciScale = fieldPreciScaleInfo{
+				scale:    0,
+				accuracy: 0,
+			}
+		} else {
+			field.FieldPreciScale = fieldPreciScaleInfo{
+				scale:    uint16(fieldPreciScale >> 16),
+				accuracy: uint16(fieldPreciScale & 0xFFFF),
+			}
+		}
+		fmt.Println("field.FieldPreciScale: ", field.FieldPreciScale)
+		//Field_Flag:
+		field.FieldFlag = binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+		fmt.Println("field.FieldFlag: ", field.FieldFlag)
+		data.Fields = append(data.Fields, field)
+	}
+
+	data.Values = make([][]FieldValue, data.Field_Num)
+
+	//获取字段的行值,并判断类型
+	// 使用 Peek 方法检查下一个字节是否为'R'或'K'
+	fmt.Println("\n\n=========开始获取行数据=================================")
+	defer func() {
+		fmt.Println("\n\n=========获取行数据结束=================================")
+	}()
+
+	char = readBuf.peekChar()
+	fmt.Println("  --char: ", string(char))
+	readBuf.idx++
+	if char == 'K' {
+		return data, nil
+	} else if char == 'R' {
+		colIdx := 0
+		//typeIdx := 0
+		fmt.Println("开始循环 ")
+
+		for {
+			col := FieldValue{}
+			//获取数据的大小
+			col.Col_len = binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+			fmt.Println("数据大小为: ", col.Col_len)
+
+			col.Col_Data = readBuf.readNext(int(col.Col_len), false)
+			fmt.Println("fieldTypeVarChar data: ", col.Col_Data, string(col.Col_Data))
+			data.Values[colIdx] = append(data.Values[colIdx], col)
+			colIdx++
+			fmt.Println("从查询返回 解析出的值 :", col.Col_Data, string(col.Col_Data))
+			char := readBuf.peekChar()
+			//既不是R 也不是K 代表该行还有其他字段内容没有读取完成
+			if char == 'R' {
+				readBuf.idx++
+				colIdx = 0
+				continue
+			} else if char == 'K' {
+				return data, nil
+				//break
+			}
+
+		} //for end
+
+	} else if char == '$' {
+		fmt.Println("  查询返回 $ ")
+		fad, err := parseFormArgDescri(readBuf)
+		if err != nil {
+			return nil, err
+		}
+
+		char := readBuf.peekChar()
+		//既不是R 也不是K 代表该行还有其他字段内容没有读取完成
+		if char == 'K' {
+			data.fad = fad
+			return data, nil
+			//break
+		}
+
+		return nil, errors.New("select to $ 解析失败")
+	} else {
+		return nil, errors.New("解析失败")
+	}
+
+}
+
+// func parseSelectResult2(readBuf *buffer) (*SelectResult, error) {
+
+// 	data := &SelectResult{}
+// 	char := readBuf.peekChar()
+// 	if char == 'K' {
+// 		return nil, errors.New("parseSelectResult error char is K")
+// 	}
+
+// 	fmt.Println("--=char: ", string(char))
+// 	//Field_Num
+// 	Field_Num := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+// 	data.Field_Num = Field_Num
+// 	//data.rowIdx = 0
+// 	fmt.Println("Field_Num: ", data.Field_Num)
+
+// 	//获取字段信息
+// 	for i := 0; i < int(Field_Num); i++ {
+
+// 		field := FieldDescri{}
+
+// 		//Field_Name_Len
+// 		field.FieldNameLen = int(binary.LittleEndian.Uint32(readBuf.readNext(4, true)))
+// 		fmt.Println("field.FieldNameLen: ", field.FieldNameLen)
+// 		//Field_Name:
+// 		field.FieldName = string(readBuf.readNext(field.FieldNameLen, false))
+// 		fmt.Println("field.Field_Name: ", field.FieldName)
+// 		//Field_DType:
+// 		field.FieldType = fieldType(binary.LittleEndian.Uint32(readBuf.readNext(4, true)))
+// 		fmt.Println("field.FieldType: ", field.FieldType)
+// 		//Field_Preci_Scale:
+// 		fieldPreciScale := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+// 		if int32(fieldPreciScale) <= 0 {
+// 			field.FieldPreciScale = fieldPreciScaleInfo{
+// 				scale:    0,
+// 				accuracy: 0,
+// 			}
+// 		} else {
+// 			field.FieldPreciScale = fieldPreciScaleInfo{
+// 				scale:    uint16(fieldPreciScale >> 16),
+// 				accuracy: uint16(fieldPreciScale & 0xFFFF),
+// 			}
+// 		}
+// 		fmt.Println("field.FieldPreciScale: ", field.FieldPreciScale)
+// 		//Field_Flag:
+// 		field.FieldFlag = binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+// 		fmt.Println("field.FieldFlag: ", field.FieldFlag)
+// 		data.Fields = append(data.Fields, field)
+// 	}
+
+// 	//获取字段的行值,并判断类型
+// 	// 使用 Peek 方法检查下一个字节是否为'R'或'K'
+// 	fmt.Println("\n\n=========开始获取行数据=================================")
+// 	defer func() {
+// 		fmt.Println("\n\n=========获取行数据结束=================================")
+// 	}()
+
+// 	//data.Values = make([][]FieldValue, 0)
+// 	data.Values = [][]FieldValue
+// 	colIdx := 0
+// 	char = readBuf.peekChar()
+// 	fmt.Println("  --char: ", string(char))
+// 	readBuf.idx++
+// 	if char == 'K' {
+// 		return data, nil
+// 	} else if char == 'R' {
+// 		for {
+// 			col := FieldValue{}
+// 			//获取数据的大小
+// 			col.Col_len = binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+// 			fmt.Println("数据大小为: ", col.Col_len)
+
+// 			col.Col_Data = readBuf.readNext(int(col.Col_len), false)
+// 			fmt.Println("fieldTypeVarChar data: ", col.Col_Data, string(col.Col_Data))
+// 			data.Values[colIdx] = append(data.Values[colIdx], col)
+// 			colIdx++
+// 			fmt.Println("从查询返回 解析出的值 :", col.Col_Data, string(col.Col_Data))
+
+// 			char := readBuf.peekChar()
+// 			//next for
+// 			if char == 'R' {
+// 				readBuf.idx++
+// 				continue
+
+// 				//end parse
+// 			} else if char == 'K' {
+// 				return data, nil
+
+// 			}
+// 			//swich end
+// 			fmt.Println("循环结束")
+// 			fmt.Printf("解析请求 data:%#v\n", data.Fields)
+// 			return data, nil
+// 		} //for end
+// 	} else {
+// 		return data, errors.New("select parse error")
+// 	}
+
+// }
+
+func parseInsertResult(readBuf *buffer) (*InsertResult, error) {
+
+	//Rowid_Len
+	Rowid_Len := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+	//Rowid_Data
+	encoded := readBuf.readNext(int(Rowid_Len), false)
+
+	//检测是否结束
+	char := readBuf.peekChar()
+
+	if char == 'K' {
+		return &InsertResult{
+			RowidLen:  Rowid_Len,
+			RowidData: encoded,
+		}, nil
+	}
+	return nil, errors.New("parseInsertResult error")
+}
+
+func parseUpdateResult(readBuf *buffer) (*UpdateResult, error) {
+	updateNum := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+
+	return &UpdateResult{UpdateNum: updateNum}, nil
+}
+
+func parseDeleteResult(readBuf *buffer) (*DeleteResult, error) {
+	deleteNum := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+
+	return &DeleteResult{DeleteNum: deleteNum}, nil
+}
+
+func parseProcRet(readBuf *buffer) (*ProcRet, error) {
+	retDType := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+
+	retDataLen := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+	retData := readBuf.readNext(int(retDataLen), false)
+
+	return &ProcRet{RetDType: retDType, RetDataLen: retDataLen, RetData: retData}, nil
+}
+
+func parseOutParamRet(readBuf *buffer) (*OutParamRet, error) {
+	outParamNo := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+
+	outParamDType := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+
+	outParamLen := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+
+	outParamData := readBuf.readNext(int(outParamLen), false)
+
+	return &OutParamRet{
+		OutParamNo:    outParamNo,
+		OutParamDType: outParamDType,
+		OutParamLen:   outParamLen,
+		OutParamData:  outParamData,
+	}, nil
+}
+
+func parseErrInfo(readBuf *buffer) (*ErrInfo, error) {
+	errStrLen := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+
+	errStr := readBuf.readNext(int(errStrLen), false)
+
+	return &ErrInfo{ErrStrLen: errStrLen, ErrStr: errStr}, nil
+
+}
+
+func parseWarnInfo(readBuf *buffer) (*WarnInfo, error) {
+	warnStrLen := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+
+	warnStr := readBuf.readNext(int(warnStrLen), false)
+
+	return &WarnInfo{WarnStrLen: warnStrLen, WarnStr: warnStr}, nil
+}
+
+func parseMessage(readBuf *buffer) (*Message, error) {
+	msgStrLen := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+
+	msgStr := readBuf.readNext(int(msgStrLen), false)
+
+	return &Message{MsgStrLen: msgStrLen, MsgStr: msgStr}, nil
+}
+
+func parseFormArgDescri(readBuf *buffer) (*FormArgDescri, error) {
+	//	FormArgDescri:   '$' Arg_Num { Arg_Name_Len Arg_Name Arg_No Arg_DType Arg_Preci_Scale }+
+	Arg_Num := binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+	formArgDescri := &FormArgDescri{ArgNum: Arg_Num}
+	fmt.Println("-- parseFormArgDescri Arg_Num:", Arg_Num)
+	for i := 0; i < int(Arg_Num); i++ {
+		arg := ArgDescri{}
+		//Arg_Name_Len
+		arg.ArgNameLen = binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+		//Arg_Name
+		arg.ArgName = readBuf.readNext(int(arg.ArgNameLen), false)
+		//Arg_No
+		arg.ArgNo = binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+		//Argg_DType
+		arg.ArgDType = binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+		//Arg_Preci_Scale
+		arg.ArgPreciScale = binary.LittleEndian.Uint32(readBuf.readNext(4, true))
+		formArgDescri.Args = append(formArgDescri.Args, arg)
+	}
+	fmt.Printf("formArgDescri %#v \n", formArgDescri)
+	return formArgDescri, nil
+}

+ 32 - 0
xugu/xugu_result.go

@@ -0,0 +1,32 @@
+package xugu
+
+import "fmt"
+
+type xuguResult 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 *xuguResult) LastInsertId() (int64, error) {
+	fmt.Println(">>>>>(self *xugusqlResult) LastInsertId()")
+	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 *xuguResult) RowsAffected() (int64, error) {
+	fmt.Println(">>>>>(self *xugusqlResult) RowsAffected()")
+	return self.affectedRows, nil
+}

+ 102 - 0
xugu/xugu_rows.go

@@ -0,0 +1,102 @@
+package xugu
+
+import (
+	"database/sql/driver"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"reflect"
+	"time"
+)
+
+type xuguRows struct {
+	rows_conn *xuguConn
+
+	results  *SelectResult
+	colIdx   int
+	prepared bool
+}
+
+func (row *xuguRows) Next(dest []driver.Value) error {
+	gt("Next()")
+	defer gt("Next() end")
+
+	fmt.Println("rowIdx", row.results.rowIdx, len(row.results.Values[0]))
+	if row.results.rowIdx >= len(row.results.Values[0]) {
+		return errors.New("The result set has been released")
+	}
+	//	fmt.Println(" -- int(row.results.Field_Num)", int(row.results.Field_Num))
+	fmt.Printf("这个 %#v", row.results.Values)
+	for j := 0; j < int(row.results.Field_Num); j++ {
+
+		coluType := row.results.Fields[j].FieldType
+		//fmt.Println("  --coluType: ", coluType, row.results.Fields[j].typeDatabaseName())
+
+		switch coluType {
+
+		case fieldType_DATE:
+
+		case fieldType_BINARY,
+			fieldType_CLOB,
+			fieldType_BLOB:
+			dest[j] = row.results.Values[j][row.results.rowIdx].Col_Data
+
+		case fieldType_TIME,
+			fieldType_TIME_TZ:
+			tv, _ := time.Parse("15:04:05", string(row.results.Values[j][row.results.rowIdx].Col_Data))
+			dest[j] = tv
+
+		case fieldType_DATETIME,
+			fieldType_DATETIME_TZ:
+			tv, _ := time.Parse("2006-01-02 15:04:05", string(row.results.Values[j][row.results.rowIdx].Col_Data))
+			dest[j] = tv
+
+		case fieldType_I1:
+			dest[j] = int8(row.results.Values[j][row.results.rowIdx].Col_Data[0])
+		case fieldType_I4:
+
+			dest[j] = binary.LittleEndian.Uint32(reverseBytes(row.results.Values[j][row.results.rowIdx].Col_Data))
+		case fieldType_CHAR:
+			dest[j] = row.results.Values[j][row.results.rowIdx].Col_Data
+		default:
+
+			//填入一行的数据
+			//TODO这里长度改为一行长度
+			dest[j] = make([]byte, len(row.results.Values))
+			// Values[字段][0]
+			dest[j] = row.results.Values[j][row.results.rowIdx].Col_Data
+
+		}
+	}
+	row.results.rowIdx++
+
+	return nil
+}
+
+// Columns返回列的名字集,它的个数是从slice的长度中推断出来的。
+// 如果不知道特定的列名,应该为该条目返回一个空的字符串
+func (row *xuguRows) Columns() []string {
+	gt("Columns()")
+	defer gt("Columns() end")
+
+	var columns []string
+
+	for i, v := range row.results.Fields {
+		columns = append(columns, v.FieldName)
+		fmt.Printf("append(columns, v.FieldName) 个数%d ,v: %s\n", i+1, columns[i])
+	}
+
+	return columns
+}
+
+func (row *xuguRows) ColumnTypeScanType(index int) reflect.Type {
+	fmt.Println(">>>>>ColumnTypeScanType ")
+	fmt.Printf("  -- row.results.Fields %#v \n", row.results.Fields[index].FieldType)
+	fmt.Printf("  -- row.results.Fields %#v \n", row.results.Fields[index].scanType())
+	return row.results.Fields[index].scanType()
+}
+
+func (self *xuguRows) Close() error {
+	fmt.Println(">>>>>((self *xuguRows) Close() ")
+	return nil
+}

+ 163 - 0
xugu/xugu_sock.go

@@ -0,0 +1,163 @@
+package xugu
+
+import (
+	"bytes"
+	"context"
+	"encoding/binary"
+	"errors"
+	"fmt"
+)
+
+func xgSockOpenConn(ctx context.Context, pConn *xuguConn) error {
+	fmt.Println("   ---xgSockOpenConn(ctx context.Context, pConn *xuguConn)")
+	//发送
+	//fmt.Printf("login   database = '%s' user = '%s'  password = '%s' version='201' ", pConn.Database, pConn.User, pConn.Password)
+	//	message := "login   database = 'SYSTEM' user = 'SYSDBA'  password = 'SYSDBA' version='201' "
+	dsnMessage := generateLoginString(pConn.dsnConfig)
+	_, err := pConn.conn.Write([]byte(dsnMessage))
+	if err != nil {
+		return errors.New("向数据库发起连接失败")
+	}
+	fmt.Println("数据已发送:", dsnMessage)
+
+	buffer := make([]byte, 1)
+	n, err := pConn.conn.Read(buffer)
+	if err != nil {
+		return errors.New("接收数据库连接失败:")
+	}
+
+	fmt.Println("读取数据库服务返回:", string(buffer[:n]))
+	if !bytes.Equal(buffer[:n], []byte("K")) {
+		return errors.New("数据库连接失败")
+	} else {
+		return nil
+	}
+
+}
+
+func sockSendPutStatement(pConn *xuguConn, sql []byte, values *[]xuguValue, paramCount int) error {
+	if pConn.sendBuff.Len() > 0 {
+		//将缓冲区重置为空
+		pConn.sendBuff.Reset()
+	}
+	// ?
+	pConn.sendBuff.Write([]byte("?"))
+	fmt.Println("?", pConn.sendBuff.Bytes())
+	// Comand_Len
+	sqlLength := uint32(len(sql))
+	var networkBytes [4]byte
+	binary.BigEndian.PutUint32(networkBytes[:], sqlLength)
+	pConn.sendBuff.Write(networkBytes[:])
+	fmt.Println("Comand_Len", pConn.sendBuff.Bytes())
+	//  Comand_str
+	pConn.sendBuff.Write(sql)
+	//'0' end
+	binary.BigEndian.PutUint32(networkBytes[:], 0)
+	pConn.sendBuff.Write([]byte{0})
+
+	fmt.Println("Comand_str + 0", pConn.sendBuff.Bytes())
+	// Param_num
+	if paramCount <= 0 {
+		var Param_num [4]byte
+		binary.BigEndian.PutUint32(Param_num[:], 0)
+		pConn.sendBuff.Write(Param_num[:])
+	} else {
+		fmt.Println("paramCount> 0: ", paramCount)
+		var networkBytes [2]byte
+		binary.BigEndian.PutUint16(networkBytes[:], uint16(paramCount))
+		pConn.sendBuff.Write(networkBytes[:])
+		fmt.Println("Param_num", pConn.sendBuff.Bytes())
+
+	}
+	fmt.Println("Param_num ", pConn.sendBuff.Bytes())
+
+	if values != nil {
+		//当缓冲区大于8190字节时,直接发送
+		if pConn.sendBuff.Len() > 8190 {
+			_, err := pConn.conn.Write(pConn.sendBuff.Bytes())
+			if err != nil {
+				fmt.Println("sockSend Write failed: ", err)
+				return err
+			}
+		}
+
+		fmt.Println(" sendBuff ", pConn.sendBuff.Bytes())
+
+		//发送后续参数
+		//	Param_num   { Param_name_len Param_name Param_INOUT Param_DType Param_Data_Len Param_Data }
+		for _, value := range *values {
+			//Param_name_len
+			if value.paramName == nil {
+				var Param_name_len [2]byte
+				pConn.sendBuff.Write(Param_name_len[:])
+				fmt.Println("Param_name_len sendBuff ", pConn.sendBuff.Bytes())
+				//Param_name
+				// var Param_name []byte
+				// pConn.sendBuff.Write(Param_name)
+				fmt.Println("Param_name_data sendBuff ", pConn.sendBuff.Bytes())
+			} else {
+				var Param_name_len [2]byte
+				fmt.Println("paramName ", value.paramName)
+				binary.BigEndian.PutUint16(Param_name_len[:], uint16(len(value.paramName)))
+				pConn.sendBuff.Write(Param_name_len[:])
+				fmt.Println("Param_name_len sendBuff ", pConn.sendBuff.Bytes())
+				//Param_name
+				pConn.sendBuff.Write(value.paramName[:])
+				fmt.Println("Param_name_data sendBuff ", pConn.sendBuff.Bytes())
+			}
+
+			//Param_INOUT
+			Param_INOUT := [2]byte{0x1}
+			pConn.sendBuff.Write(reverseBytes(Param_INOUT[:]))
+			fmt.Println("Param_INOUT sendBuff ", pConn.sendBuff.Bytes())
+			//Param_DType
+			var Param_DType [2]byte
+			binary.BigEndian.PutUint16(Param_DType[:], uint16(value.types))
+			pConn.sendBuff.Write(Param_DType[:])
+			fmt.Println("Param_DType sendBuff ", pConn.sendBuff.Bytes())
+			//Param_Data_Len 根据DType 修改长度
+			//if value.types
+			var Param_Data_Len [4]byte
+			binary.BigEndian.PutUint32(Param_Data_Len[:], uint32(8))
+			pConn.sendBuff.Write(Param_Data_Len[:])
+			fmt.Println("Param_Data_Len sendBuff ", pConn.sendBuff.Bytes())
+			//Param_Data 根据DType 修改长度
+			var Param_Data [7]byte
+
+			pConn.sendBuff.Write([]byte(Param_Data[:]))
+			pConn.sendBuff.Write([]byte(value.value))
+			//binary.BigEndian.PutUint32(networkBytes[:], 0)
+			// pConn.sendBuff.Write([]byte{0})
+			// fmt.Println("Param_Data sendBuff ", pConn.sendBuff.Bytes())
+
+		}
+
+	}
+	fmt.Println("SockSendPutStatement msg: ", pConn.sendBuff.String())
+	fmt.Println("SockSendPutStatement msg: ", pConn.sendBuff.Bytes())
+	return nil
+}
+
+func sockSendExecute(pConn *xuguConn) error {
+	fmt.Println("\n ---sockSendExecute")
+	fmt.Println("SockSendExecute msg: ", pConn.sendBuff.String())
+	_, err := pConn.conn.Write(pConn.sendBuff.Bytes())
+	if err != nil {
+		return err
+	}
+	fmt.Println("\n ---sockSendExecute end")
+	return nil
+}
+
+func xuguSockRecvMsg(pConn *xuguConn) (*allResult, error) {
+	pConn.conn.Read(pConn.readBuff.buf)
+	fmt.Println("pConn.readBuff.buf ::", pConn.readBuff.buf, string(pConn.readBuff.buf))
+
+	rs, err := parseMsg(&pConn.readBuff, pConn)
+	if err != nil {
+		fmt.Println("xuguPrepare parseMsg(&pConn.readBuff, pConn)")
+		return nil, err
+	}
+	pConn.readBuff.reset()
+	return rs, nil
+}

+ 100 - 0
xugu/xugu_stmt.go

@@ -0,0 +1,100 @@
+package xugu
+
+import (
+	"database/sql/driver"
+	"errors"
+	"fmt"
+)
+
+type xuguStmt struct {
+
+	// 上下文连接句柄指针
+	stmt_conn *xuguConn
+
+	// 布尔值,用于标识执行的 SQL 语句是否已准备好
+	prepared bool
+
+	// 接受准备好的 SQL 语句的代码
+	prename []byte
+
+	// 布尔值,用于标识游标是否启用
+	curopend bool
+
+	// 游标名称
+	curname []byte
+
+	// 执行的 SQL 语句中的参数数量
+	paramCount int
+	mysql      string
+
+	//需替换的参数字段信息
+	//parser *xuguParse
+}
+
+func (stmt *xuguStmt) Close() error {
+	fmt.Println("\n>>>>>> (stmt *xuguStmt) Close method called")
+	return nil
+}
+
+func (stmt *xuguStmt) NumInput() int {
+	fmt.Println("\n>>>>>(stmt *xuguStmt) NumInput()")
+
+	// parser := &xuguParse{
+	// 	bind_type:   0,
+	// 	param_count: 0,
+	// }
+
+	fmt.Println("stmt.mysql: ", stmt.mysql)
+	return assertParamCount(stmt.mysql)
+	//return 0
+}
+
+func (stmt *xuguStmt) Exec(args []driver.Value) (driver.Result, error) {
+	gt("stmt Exec")
+	defer gt("stmt Exec end")
+
+	stmt.stmt_conn.mu.Lock()
+	defer stmt.stmt_conn.mu.Unlock()
+	//send msg
+	//如果有参数
+	if stmt.paramCount > 0 && len(args) > 0 {
+		values := []xuguValue{}
+		for _, param := range args {
+			assertParamType(param, &values)
+			//fmt.Printf("Field Name: %s, Field Type: %s, Field Value: %v\n", v1, v1, v1)
+		}
+		sockSendPutStatement(stmt.stmt_conn, stmt.prename, &values, stmt.paramCount)
+		sockSendExecute(stmt.stmt_conn)
+		//没有参数
+	} else {
+		sockSendPutStatement(stmt.stmt_conn, []byte(stmt.mysql), nil, 0)
+		sockSendExecute(stmt.stmt_conn)
+	}
+
+	//recv msg
+	aR, err := xuguSockRecvMsg(stmt.stmt_conn)
+	if err != nil {
+		return nil, err
+	}
+	switch aR.rt {
+	case selectResult:
+
+		return nil, errors.New("select result type is error")
+	case errInfo:
+
+		return nil, errors.New(string(aR.e.ErrStr))
+	case warnInfo:
+
+		return nil, errors.New(string(aR.w.WarnStr))
+	default:
+		return &xuguResult{
+			affectedRows: int64(0),
+			insertId:     int64(0),
+		}, nil
+	}
+
+}
+
+func (stmt *xuguStmt) Query(args []driver.Value) (driver.Rows, error) {
+	return nil, nil
+}

+ 172 - 0
xugu/xugu_utils.go

@@ -0,0 +1,172 @@
+package xugu
+
+import (
+	"fmt"
+	"strings"
+)
+
+func parseDSN(dsn string) dsnConfig {
+	// Initialize a dsnConfig struct
+	var config dsnConfig
+
+	// Split the string by semicolons
+	pairs := strings.Split(dsn, ";")
+
+	// Iterate over the pairs and map them to the struct fields
+	for _, pair := range pairs {
+		// Split each pair by the equals sign
+		kv := strings.SplitN(pair, "=", 2)
+		if len(kv) != 2 {
+			continue
+		}
+		key, value := strings.TrimSpace(kv[0]), strings.Trim(strings.TrimSpace(kv[1]), "'")
+		keyL := strings.ToLower(key)
+
+		// Map the key to the appropriate struct field
+		switch keyL {
+		case "ip":
+			config.IP = value
+		case "port":
+			config.Port = value
+		case "db":
+			config.Database = value
+		case "user":
+			config.User = value
+		case "pwd":
+			config.Password = value
+		case "encryptor":
+			config.Encryptor = value
+		case "char_set":
+			config.CharSet = value
+		case "time_zone":
+			config.TimeZone = value
+		case "iso_level":
+			config.IsoLevel = value
+		case "lock_timeout":
+			config.LockTimeout = value
+		case "auto_commit":
+			config.AutoCommit = value
+		case "strict_commit":
+			config.StrictCommit = value
+		case "result":
+			config.Result = value
+		case "return_schema":
+			config.ReturnSchema = value
+		case "return_cursor_id":
+			config.ReturnCursorID = value
+		case "lob_ret":
+			config.LobRet = value
+		case "return_rowid":
+			config.ReturnRowid = value
+		case "version":
+			config.Version = value
+		}
+	}
+
+	return config
+}
+
+func generateLoginString(config dsnConfig) string {
+	baseString := "login   database = '%s' user = '%s'  password = '%s' "
+	additionalParams := ""
+
+	if config.Encryptor != "" {
+		additionalParams += fmt.Sprintf(" encryptor='%s'", config.Encryptor)
+	}
+	if config.CharSet != "" {
+		additionalParams += fmt.Sprintf(" char_set='%s'", config.CharSet)
+	}
+	if config.TimeZone != "" {
+		additionalParams += fmt.Sprintf(" time_zone='%s'", config.TimeZone)
+	}
+	if config.IsoLevel != "" {
+		additionalParams += fmt.Sprintf(" iso_level='%s'", config.IsoLevel)
+	}
+	if config.LockTimeout != "" {
+		additionalParams += fmt.Sprintf(" lock_timeout='%s'", config.LockTimeout)
+	}
+	if config.AutoCommit != "" {
+		additionalParams += fmt.Sprintf(" auto_commit='%s'", config.AutoCommit)
+	}
+	if config.StrictCommit != "" {
+		additionalParams += fmt.Sprintf(" strict_commit='%s'", config.StrictCommit)
+	}
+	if config.Result != "" {
+		additionalParams += fmt.Sprintf(" result='%s'", config.Result)
+	}
+	if config.ReturnSchema != "" {
+		additionalParams += fmt.Sprintf(" return_schema='%s'", config.ReturnSchema)
+	}
+	if config.ReturnCursorID != "" {
+		additionalParams += fmt.Sprintf(" return_cursor_id='%s'", config.ReturnCursorID)
+	}
+	if config.LobRet != "" {
+		additionalParams += fmt.Sprintf(" lob_ret='%s'", config.LobRet)
+	}
+	if config.ReturnRowid != "" {
+		additionalParams += fmt.Sprintf(" return_rowid='%s'", config.ReturnRowid)
+	}
+	if config.Version != "" {
+		additionalParams += fmt.Sprintf(" version='%s'", config.Version)
+	} else {
+		additionalParams += " version='201'"
+	}
+
+	finalString := fmt.Sprintf(baseString, config.Database, config.User, config.Password)
+	if additionalParams != "" {
+		finalString += additionalParams
+	}
+	//finalString += " version='201'"
+	return finalString
+}
+
+// reverseBytes 反转 byte slice 的顺序
+func reverseBytes(b []byte) []byte {
+	reversed := make([]byte, len(b))
+	for i := range b {
+		reversed[i] = b[len(b)-1-i]
+	}
+	return reversed
+}
+
+func gt(name string) {
+	fmt.Printf("\n=============%s================\n", name)
+}
+
+func switchSQLType(sql string) int {
+	// 去掉首尾的空格、换行符和回车符
+	sql = strings.TrimSpace(sql)
+	if len(sql) < 6 {
+		return SQL_OTHER
+	}
+
+	// 取前6个字符并转为大写
+	kstr := strings.ToUpper(sql[:6])
+
+	// 根据SQL语句前缀判断类型
+	switch {
+	case strings.HasPrefix(kstr, "SELECT"):
+		if strings.Contains(sql, ";") && len(sql[strings.Index(sql, ";"):]) > 5 {
+			return SQL_OTHER // 多结果集
+		}
+		return SQL_SELECT
+	case strings.HasPrefix(kstr, "INSERT"):
+		return SQL_INSERT
+	case strings.HasPrefix(kstr, "UPDATE"):
+		return SQL_UPDATE
+	case strings.HasPrefix(kstr, "DELETE"):
+		return SQL_DELETE
+	case strings.HasPrefix(kstr, "CREATE"):
+		return SQL_CREATE
+	case strings.HasPrefix(kstr, "ALTER "):
+		return SQL_ALTER
+	case strings.HasPrefix(kstr, "EXEC "):
+		return SQL_PROCEDURE
+	case strings.HasPrefix(kstr, "EXECUT"):
+		return SQL_PROCEDURE
+	case strings.HasPrefix(kstr, "STC"):
+		return SQL_SELECT
+	default:
+		return SQL_OTHER
+	}
+}