Browse Source

适配时间类型

GTong 9 months ago
parent
commit
dd4f9f3454

+ 62 - 1
main.go

@@ -9,7 +9,7 @@ import (
 	_ "xugu_go_driver/xugu"
 )
 
-func main() {
+func main3() {
 	db, err := sql.Open("xugusql", "IP=192.168.2.216;DB=SYSTEM;User=SYSDBA;PWD=SYSDBA;Port=15138;AUTO_COMMIT=on;CHAR_SET=UTF8")
 	if err != nil {
 		log.Fatal("err ", err)
@@ -187,3 +187,64 @@ func processQuery(db *sql.DB, id int, logger *log.Logger) {
 	logger.Println("goroutine %d 完成\n", id)
 	fmt.Printf("goroutine %d 完成\n", id)
 }
+
+func main() {
+	db, err := sql.Open("xugusql", "IP=10.28.20.101;DB=SYSTEM;User=SYSDBA;PWD=SYSDBA;Port=5190;AUTO_COMMIT=on;CHAR_SET=UTF8")
+	if err != nil {
+		log.Fatal("err ", err)
+	}
+	lp := LicenseProcess{
+		Creator:         "Alice",
+		ApplyDate:       "2023-01-01",
+		RelatedProject:  "Project A",
+		SalesPerson:     "Bob",
+		SalesEmail:      "bob@example.com",
+		TechSupport:     "Charlie",
+		TechEmail:       "charlie@example.com",
+		ProductName:     "Product X",
+		Version:         "1.0",
+		Processor:       "Intel",
+		OperatingSystem: "Linux",
+		IP:              "192.168.1.1",
+		MAC:             "00:1A:2B:3C:4D:5E",
+	}
+	var Ins2 = `
+	INSERT INTO LicenseProcess (
+		Creator, ApplyDate, RelatedProject, SalesPerson, SalesEmail, TechSupport, TechEmail,
+		ProductName, Version, Processor, OperatingSystem, IP, MAC
+	) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+	`
+	_, err = db.Exec(Ins2,
+		lp.Creator, lp.ApplyDate, lp.RelatedProject, lp.SalesPerson, lp.SalesEmail, lp.TechSupport, lp.TechEmail,
+		lp.ProductName, lp.Version, lp.Processor, lp.OperatingSystem, lp.IP, lp.MAC,
+	)
+	if err != nil {
+
+		fmt.Printf("[ERROR] %s\n", err.Error())
+		return
+	}
+
+	fmt.Printf("%s ... ok\n", Ins2)
+
+	err = db.Close()
+	if err != nil {
+
+		fmt.Printf("[ERROR] %s\n", err.Error())
+	}
+}
+
+type LicenseProcess struct {
+	Creator         string // 创建人
+	ApplyDate       string // 申请日期
+	RelatedProject  string // 关联项目
+	SalesPerson     string // 销售人员
+	SalesEmail      string // 销售邮箱
+	TechSupport     string // 技术人员
+	TechEmail       string // 技术邮箱
+	ProductName     string // 产品名称
+	Version         string // 版本
+	Processor       string // 处理器
+	OperatingSystem string // 操作系统
+	IP              string // IP
+	MAC             string // MAC
+}

+ 88 - 0
test/Stability_test.go

@@ -0,0 +1,88 @@
+package test
+
+import (
+	"database/sql"
+	"log"
+	"os"
+	"testing"
+
+	"time"
+)
+
+func setupDB() (*sql.DB, error) {
+	db, err := sql.Open("xugusql", "IP=10.28.20.101;"+
+		"DB=GODB;User=SYSDBA;PWD=SYSDBA;"+
+		"Port= 5190;AUTO_COMMIT=on;CHAR_SET=UTF8")
+	if err != nil {
+		return nil, err
+	}
+	return db, nil
+}
+
+// TestStability 测试数据库的稳定性
+func TestStability(t *testing.T) {
+	db, err := setupDB()
+	if err != nil {
+		t.Fatalf("Failed to connect to database: %v", err)
+	}
+	defer db.Close()
+
+	duration := 1 * time.Hour // 测试运行时间
+	endTime := time.Now().Add(duration)
+	// 创建日志文件
+	logFile, err := os.OpenFile("stability_test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
+	if err != nil {
+		log.Fatalf("Failed to open log file: %v", err)
+	}
+	defer logFile.Close()
+
+	// 设置日志输出到文件
+	log.SetOutput(logFile)
+	for time.Now().Before(endTime) {
+		// 执行插入操作
+		stmt, err := db.Prepare("INSERT INTO users(name) VALUES(?)")
+		if err != nil {
+			t.Fatalf("Failed to prepare insert statement: %v", err)
+			log.Fatalf("Failed to prepare insert statement: %v", err)
+		}
+		_, err = stmt.Exec("TestUser")
+		stmt.Close()
+		if err != nil {
+			t.Fatalf("Failed to execute insert statement: %v", err)
+			log.Fatalf("Failed to execute insert statement: %v", err)
+
+		}
+
+		// 执行查询操作
+		stmt, err = db.Prepare("SELECT name FROM users WHERE name = ?")
+		if err != nil {
+			t.Fatalf("Failed to prepare select statement: %v", err)
+			log.Fatalf("Failed to prepare select statement: %v", err)
+		}
+		var name string
+		err = stmt.QueryRow("TestUser").Scan(&name)
+		stmt.Close()
+		if err != nil {
+			t.Fatalf("Failed to query row: %v", err)
+			log.Fatalf("Failed to prepare select statement: %v", err)
+		}
+
+		if name != "TestUser" {
+			t.Errorf("Expected name 'TestUser', but got '%s'", name)
+			log.Fatalf("Failed to prepare select statement: %v", err)
+		}
+
+		// 执行删除操作
+		stmt, err = db.Prepare("DELETE FROM users WHERE name = ?")
+		if err != nil {
+			t.Fatalf("Failed to prepare delete statement: %v", err)
+			log.Fatalf("Failed to prepare select statement: %v", err)
+		}
+		_, err = stmt.Exec("TestUser")
+		stmt.Close()
+		if err != nil {
+			t.Fatalf("Failed to execute delete statement: %v", err)
+			log.Fatalf("Failed to prepare select statement: %v", err)
+		}
+	}
+}

+ 3 - 3
test/create_table_test.go

@@ -15,9 +15,9 @@ var db *sql.DB
 
 func init() {
 	var err error
-	db, err = sql.Open("xugusql", "IP=192.168.2.216;"+
-		"DB=SYSTEM;User=SYSDBA;PWD=SYSDBA;"+
-		"Port= 15138;AUTO_COMMIT=on;CHAR_SET=UTF8")
+	db, err = sql.Open("xugusql", "IP=10.28.20.101;"+
+		"DB=GOdb;User=SYSDBA;PWD=SYSDBA;"+
+		"Port= 5190;AUTO_COMMIT=on;CHAR_SET=UTF8")
 	if err != nil {
 		fmt.Printf("[ERROR] %s\n", err.Error())
 	}

+ 59 - 0
test/dbexec_test.go

@@ -13,6 +13,13 @@ var INS = []string{
 	"INSERT INTO gotab2 VALUES(1, 'XuguSQL', '2020-01-01 00:00:00');",
 	"INSERT INTO gotab2 VALUES(1, '', NULL);"}
 
+var Ins2 = `
+INSERT INTO LicenseProcess (
+    Creator, ApplyDate, RelatedProject, SalesPerson, SalesEmail, TechSupport, TechEmail,
+    ProductName, Version, Processor, OperatingSystem, IP, MAC
+) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+`
+
 func TestDbexec(t *testing.T) {
 
 	for _, sql := range INS {
@@ -33,3 +40,55 @@ func TestDbexec(t *testing.T) {
 		fmt.Printf("[ERROR] %s\n", err.Error())
 	}
 }
+
+type LicenseProcess struct {
+	Creator         string // 创建人
+	ApplyDate       string // 申请日期
+	RelatedProject  string // 关联项目
+	SalesPerson     string // 销售人员
+	SalesEmail      string // 销售邮箱
+	TechSupport     string // 技术人员
+	TechEmail       string // 技术邮箱
+	ProductName     string // 产品名称
+	Version         string // 版本
+	Processor       string // 处理器
+	OperatingSystem string // 操作系统
+	IP              string // IP
+	MAC             string // MAC
+}
+
+func TestDbexec2(t *testing.T) {
+	lp := LicenseProcess{
+		Creator:         "Alice",
+		ApplyDate:       "2023-01-01",
+		RelatedProject:  "Project A",
+		SalesPerson:     "Bob",
+		SalesEmail:      "bob@example.com",
+		TechSupport:     "Charlie",
+		TechEmail:       "charlie@example.com",
+		ProductName:     "Product X",
+		Version:         "1.0",
+		Processor:       "Intel",
+		OperatingSystem: "Linux",
+		IP:              "192.168.1.1",
+		MAC:             "00:1A:2B:3C:4D:5E",
+	}
+
+	_, err := db.Exec(Ins2,
+		lp.Creator, lp.ApplyDate, lp.RelatedProject, lp.SalesPerson, lp.SalesEmail, lp.TechSupport, lp.TechEmail,
+		lp.ProductName, lp.Version, lp.Processor, lp.OperatingSystem, lp.IP, lp.MAC,
+	)
+	if err != nil {
+
+		fmt.Printf("[ERROR] %s\n", err.Error())
+		return
+	}
+
+	fmt.Printf("%s ... ok\n", Ins2)
+
+	err = db.Close()
+	if err != nil {
+
+		fmt.Printf("[ERROR] %s\n", err.Error())
+	}
+}

+ 56 - 2
test/lob_test.go

@@ -7,9 +7,15 @@ import (
 	"testing"
 )
 
+func TestCreateLob(t *testing.T) {
+	_, err := db.Exec("CREATE TABLE gotab4 (image BLOB);")
+	if err != nil {
+		fmt.Printf("[ERROR] %s\n", err.Error())
+	}
+}
 func TestInsertLob(t *testing.T) {
 	// 打开文件
-	file, err := os.Open("A.jpg")
+	file, err := os.Open("C0077.MP4")
 	if err != nil {
 		fmt.Println("Error opening file:", err)
 		return
@@ -23,7 +29,7 @@ func TestInsertLob(t *testing.T) {
 		return
 	}
 
-	_, err = db.Exec("INSERT INTO gotab3 VALUES(?,NULL,?,NULL);", 3, fileContent)
+	_, err = db.Exec("INSERT INTO gotab4 VALUES(?);", fileContent)
 	if err != nil {
 		fmt.Printf("[ERROR] %s\n", err.Error())
 	}
@@ -59,3 +65,51 @@ func TestSelecttLob(t *testing.T) {
 	rows.Close()
 	db.Close()
 }
+
+func TestSelecttLobToSave(t *testing.T) {
+	rows, err := db.Query("select * from gotab4;")
+	if err != nil {
+		fmt.Printf("[ERROR] %s\n", err.Error())
+		return
+	}
+
+	column, err := rows.Columns()
+	if err != nil {
+		fmt.Printf("[ERROR] %s\n", err.Error())
+		return
+	}
+	rows_value := make([]interface{}, len(column))
+	for key, _ := range rows_value {
+		dest := make([]byte, 1000000)
+		rows_value[key] = &dest
+	}
+
+	for rows.Next() {
+		rows.Scan(rows_value...)
+
+		for _, v := range rows_value {
+			//fmt.Printf("结果: %s\t", string(*(v.(*[]byte))))
+			SaveToFile(*(v.(*[]byte)), "Ct.MP4")
+		}
+		fmt.Printf("\n")
+	}
+
+	rows.Close()
+	db.Close()
+}
+
+// SaveToFile 将字节切片保存到文件中
+func SaveToFile(data []byte, filename string) error {
+	file, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer file.Close()
+
+	_, err = file.Write(data)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}

+ 272 - 0
test/typeAll_test.go

@@ -0,0 +1,272 @@
+package test
+
+import (
+	"encoding/binary"
+	"fmt"
+	"log"
+	"math"
+	"testing"
+)
+
+var TypeAllCreate = `CREATE TABLE typeALL_table (
+    char_field CHAR(255),                      -- 固定长度为n的字符串
+    varchar_field VARCHAR(255),                -- 可变长度字符串
+    binary_field BINARY(255),                  -- 固定长度为n的二进制数据
+    tinyint_field TINYINT,                     -- 精度为3,标度为0的有符号精确数值
+    smallint_field SMALLINT,                   -- 精度为5,标度为0的有符号精确数值
+    integer_field INTEGER,                     -- 精度为10,标度为0的有符号精确数值
+    bigint_field BIGINT,                       -- 精度为19,标度为0的有符号精确数值
+    float_field FLOAT,                         -- 单精度浮点数
+    double_field DOUBLE,                       -- 双精度浮点数
+    bool_field BOOL,                           -- 布尔类型
+    numeric_field NUMERIC(20, 2)              -- 精度为p,标度为s的有符号精确数值
+);`
+
+func TestTypeAllCreate(t *testing.T) {
+	_, err := db.Exec(TypeAllCreate)
+
+	if err != nil {
+
+		fmt.Printf("[ERROR] %s\n", err.Error())
+
+	} else {
+		fmt.Printf("%s ... ok\n", TypeAllCreate)
+	}
+
+}
+
+var insSql1 = `INSERT INTO typeALL_table (
+    char_field,
+    varchar_field,
+    binary_field,
+    tinyint_field,
+    smallint_field,
+    integer_field,
+    bigint_field,
+    float_field,
+    double_field,
+    bool_field,
+    numeric_field
+) VALUES (
+    'A',                                       -- char_field: 固定长度为255的字符串,只插入一个字符,剩余填充空格
+    'This is a varchar',                       -- varchar_field: 可变长度字符串
+    0x010203,                                  -- binary_field: 固定长度为255的二进制数据,这里插入一个3字节的示例
+    127,                                       -- tinyint_field: 范围在 -128 到 127 之间
+    32767,                                     -- smallint_field: 范围在 -32768 到 32767 之间
+    2147483647,                                -- integer_field: 范围在 -2147483648 到 2147483647 之间
+    9223372036854775807,                       -- bigint_field: 范围在 -9223372036854775808 到 9223372036854775807 之间
+    3.14,                                      -- float_field: 单精度浮点数
+    2.718281828459045,                         -- double_field: 双精度浮点数
+    true,                                      -- bool_field: 布尔类型,true 表示1,false 表示0
+    123456789012345670.12                    -- numeric_field: 精度为20,标度为2的有符号精确数值
+);`
+
+func TestTypeAllInsert(t *testing.T) {
+
+	_, err := db.Exec(insSql1)
+	if err != nil {
+
+		fmt.Printf("[ERROR] %s\n", err.Error())
+		return
+	}
+
+	fmt.Printf("%s ... ok\n", Ins2)
+
+	err = db.Close()
+	if err != nil {
+
+		fmt.Printf("[ERROR] %s\n", err.Error())
+	}
+}
+
+type TypeAll struct {
+	CharField     string
+	VarcharField  string
+	BinaryField   []byte
+	TinyintField  int8
+	SmallintField int16
+	IntegerField  int32
+	BigintField   int64
+	FloatField    float32
+	DoubleField   float64
+	BoolField     bool
+	NumericField  float64
+}
+
+func TestTypeAllSelect(t *testing.T) {
+
+	rows, err := db.Query("SELECT char_field, varchar_field, binary_field, tinyint_field, smallint_field, integer_field, bigint_field, float_field, double_field, bool_field, numeric_field FROM typeALL_table")
+	if err != nil {
+		log.Fatalf("Failed to query database: %v", err)
+	}
+	defer rows.Close()
+
+	for rows.Next() {
+		var record TypeAll
+		err := rows.Scan(&record.CharField, &record.VarcharField, &record.BinaryField, &record.TinyintField, &record.SmallintField, &record.IntegerField, &record.BigintField, &record.FloatField, &record.DoubleField, &record.BoolField, &record.NumericField)
+		if err != nil {
+			log.Fatalf("Failed to scan row: %v", err)
+		}
+
+		f := 2.718281828459045
+		bits := math.Float64bits(f)             // 将 float64 转换为 uint64
+		bytes := make([]byte, 8)                // 创建一个长度为 8 的字节切片
+		binary.BigEndian.PutUint64(bytes, bits) // 将 uint64 转换为 []byte 并存储在 bytes 中
+
+		var bb byte
+		bb = byte(104)
+		bytes[7] = bb
+		fmt.Println("B", bytes)
+		fl := math.Float64frombits(binary.BigEndian.Uint64(bytes))
+		fmt.Println("fl", fl)
+		fmt.Println("F", f)
+		fmt.Printf("CharField: %s\n", record.CharField)
+		fmt.Printf("VarcharField: %s\n", record.VarcharField)
+		fmt.Printf("BinaryField: %v\n", record.BinaryField)
+		fmt.Printf("TinyintField: %d\n", record.TinyintField)
+		fmt.Printf("SmallintField: %d\n", record.SmallintField)
+		fmt.Printf("IntegerField: %d\n", record.IntegerField)
+		fmt.Printf("BigintField: %d\n", record.BigintField)
+		fmt.Printf("FloatField: %f\n", record.FloatField)
+		fmt.Printf("DoubleField: %g\n", record.DoubleField)
+
+		fmt.Printf("BoolField: %t\n", record.BoolField)
+		fmt.Printf("NumericField: %f\n", record.NumericField)
+		fmt.Println("----------")
+	}
+
+	if err = rows.Err(); err != nil {
+		log.Fatalf("Error occurred during row iteration: %v", err)
+	}
+
+	err = db.Close()
+	if err != nil {
+
+		fmt.Printf("[ERROR] %s\n", err.Error())
+	}
+}
+
+// -----------------------stmt------------------------------
+var insSql2 = `INSERT INTO typeALL_table (
+    char_field,
+    varchar_field,
+    binary_field,
+    tinyint_field,
+    smallint_field,
+    integer_field,
+    bigint_field,
+    float_field,
+    double_field,
+    bool_field,
+    numeric_field
+) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
+
+func TestTypeAllInsertStmt(t *testing.T) {
+
+	stmt, err := db.Prepare(insSql2)
+	if err != nil {
+		t.Fatalf("Failed to prepare statement: %v", err)
+	}
+	defer stmt.Close()
+
+	_, err = stmt.Exec(
+		"A",                            // char_field: 固定长度为255的字符串,只插入一个字符,剩余填充空格
+		"This is a varchar",            // varchar_field: 可变长度字符串
+		[]byte{0x01, 0x02, 0x03},       // binary_field: 固定长度为255的二进制数据,这里插入一个3字节的示例
+		int8(127),                      // tinyint_field: 范围在 -128 到 127 之间
+		int16(32767),                   // smallint_field: 范围在 -32768 到 32767 之间
+		int32(2147483647),              // integer_field: 范围在 -2147483648 到 2147483647 之间
+		int64(9223372036854775807),     // bigint_field: 范围在 -9223372036854775808 到 9223372036854775807 之间
+		float32(3.14),                  // float_field: 单精度浮点数
+		float64(2.718281828459045),     // double_field: 双精度浮点数
+		true,                           // bool_field: 布尔类型,true 表示1,false 表示0
+		float64(123456789012345670.12), // numeric_field: 精度为20,标度为2的有符号精确数值
+	)
+	if err != nil {
+		t.Fatalf("Failed to execute statement: %v", err)
+	}
+
+	err = db.Close()
+	if err != nil {
+
+		fmt.Printf("[ERROR] %s\n", err.Error())
+	}
+}
+
+func TestTypeAllQueryStmt(t *testing.T) {
+	querySql := `SELECT 
+	char_field, 
+	varchar_field, 
+	binary_field, 
+	tinyint_field, 
+	smallint_field, 
+	integer_field, 
+	bigint_field, 
+	float_field, 
+	double_field, 
+	bool_field, 
+	numeric_field 
+FROM typeALL_table`
+
+	stmt, err := db.Prepare(querySql)
+	if err != nil {
+		t.Fatalf("Failed to prepare statement: %v", err)
+	}
+	defer stmt.Close()
+
+	rows, err := stmt.Query()
+	if err != nil {
+		t.Fatalf("Failed to execute query: %v", err)
+	}
+	defer rows.Close()
+
+	for rows.Next() {
+		var record TypeAll
+		//var smallintBytes, floatBytes []byte
+
+		err := rows.Scan(
+			&record.CharField,
+			&record.VarcharField,
+			&record.BinaryField,
+			&record.TinyintField,
+			&record.SmallintField,
+			&record.IntegerField,
+			&record.BigintField,
+			&record.FloatField,
+			&record.DoubleField,
+			&record.BoolField,
+			&record.NumericField,
+		)
+		if err != nil {
+			t.Fatalf("Failed to scan row: %v", err)
+		}
+
+		// 将 smallintBytes 转换为 int16
+		// if len(smallintBytes) == 2 {
+		// 	record.SmallintField = int16(binary.BigEndian.Uint16(smallintBytes))
+		// }
+
+		// //将 floatBytes 转换为 float32
+		// if len(floatBytes) == 4 {
+		// 	bits := binary.BigEndian.Uint32(floatBytes)
+		// 	record.FloatField = math.Float32frombits(bits)
+		// }
+
+		fmt.Printf("CharField: %s\n", record.CharField)
+		fmt.Printf("VarcharField: %s\n", record.VarcharField)
+		fmt.Printf("BinaryField: %v\n", record.BinaryField)
+		fmt.Printf("TinyintField: %d\n", record.TinyintField)
+		fmt.Printf("SmallintField: %d\n", record.SmallintField)
+		fmt.Printf("IntegerField: %d\n", record.IntegerField)
+		fmt.Printf("BigintField: %d\n", record.BigintField)
+		fmt.Printf("FloatField: %f\n", record.FloatField)
+		fmt.Printf("DoubleField: %f\n", record.DoubleField)
+		fmt.Printf("BoolField: %t\n", record.BoolField)
+		fmt.Printf("NumericField: %f\n", record.NumericField)
+		fmt.Println("----------")
+	}
+
+	if err = rows.Err(); err != nil {
+		t.Fatalf("Error occurred during row iteration: %v", err)
+	}
+}

+ 187 - 0
test/typeTime_test.go

@@ -0,0 +1,187 @@
+package test
+
+import (
+	"fmt"
+	"log"
+	"testing"
+	"time"
+)
+
+var timeCreate = `CREATE TABLE example_table (
+    time_field TIME,                           -- 时间数据类型,时分秒字段
+    datetime_field DATETIME,                   -- 时间戳数据类型,年月日时分秒字段
+    date_field DATE,                           -- 日期数据类型,年月日字段
+    time_with_zone_field TIME WITH TIME ZONE,  -- 时间数据类型,时分秒,时区字段
+    datetime_with_zone_field TIMESTAMP WITH TIME ZONE, -- 时间戳数据类型,年月日时分秒,时区字段
+    interval_year_field INTERVAL YEAR,         -- 年间隔
+    interval_month_field INTERVAL MONTH,       -- 月间隔
+    interval_day_field INTERVAL DAY,           -- 日间隔
+    interval_hour_field INTERVAL HOUR,         -- 小时间隔
+    interval_minute_field INTERVAL MINUTE,     -- 分钟间隔
+    interval_second_field INTERVAL SECOND,     -- 秒间隔
+    interval_day_to_hour_field INTERVAL DAY TO HOUR,    -- 日时间隔
+    interval_day_to_minute_field INTERVAL DAY TO MINUTE, -- 日时分间隔
+    interval_day_to_second_field INTERVAL DAY TO SECOND, -- 日时分秒间隔
+    interval_hour_to_minute_field INTERVAL HOUR TO MINUTE, -- 时分间隔
+    interval_hour_to_second_field INTERVAL HOUR TO SECOND, -- 时分秒间隔
+    interval_minute_to_second_field INTERVAL MINUTE TO SECOND -- 分秒间隔
+);
+`
+
+func TestTypeTimeCreate(t *testing.T) {
+	_, err := db.Exec(TypeAllCreate)
+
+	if err != nil {
+
+		fmt.Printf("[ERROR] %s\n", err.Error())
+
+	} else {
+		fmt.Printf("%s ... ok\n", TypeAllCreate)
+	}
+
+}
+
+var TypeTimeInsert = `INSERT INTO example_table (
+	time_field,
+	datetime_field,
+	date_field,
+	time_with_zone_field,
+	datetime_with_zone_field,
+	interval_year_field,
+	interval_month_field,
+	interval_day_field,
+	interval_hour_field,
+	interval_minute_field,
+	interval_second_field,
+	interval_day_to_hour_field,
+	interval_day_to_minute_field,
+	interval_day_to_second_field,
+	interval_hour_to_minute_field,
+	interval_hour_to_second_field,
+	interval_minute_to_second_field
+) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
+
+func TestTypeTimeInsert(t *testing.T) {
+	stmt, err := db.Prepare(TypeTimeInsert)
+	if err != nil {
+		log.Fatalf("Failed to prepare statement: %v", err)
+	}
+	defer stmt.Close()
+	// 创建一个 time.Duration 表示 90 分钟
+	ninetyMinutes := time.Duration(90) * time.Minute
+	fmt.Println("Ninety Minutes:", ninetyMinutes)
+	currentTime := time.Now()
+	fmt.Println("Current Time:", currentTime)
+
+	_, err = stmt.Exec(
+		"12:34:56",            // time_field: 时分秒
+		"2024-07-30 14:32:59", // datetime_field: 年月日时分秒
+		"2024-07-30",          // date_field: 年月日
+		"12:34:56+02:00",      // time_with_zone_field: 时分秒,时区字段
+		currentTime,           // datetime_with_zone_field: 年月日时分秒,时区字段 //"2024-07-30 14:32:59+02:00"
+		1,                     // interval_year_field: 年间隔
+		2,                     // interval_month_field: 月间隔
+		3,                     // interval_day_field: 日间隔
+		ninetyMinutes,         // interval_hour_field: 小时间隔
+		5,                     // interval_minute_field: 分钟间隔
+		6,                     // interval_second_field: 秒间隔
+		"3 4",                 // interval_day_to_hour_field: 日时间隔
+		"3 4:5",               // interval_day_to_minute_field: 日时分间隔
+		"4:5:6",               // interval_day_to_second_field: 日时分秒间隔
+		"4:5",                 // interval_hour_to_minute_field: 时分间隔
+		"4:5:6",               // interval_hour_to_second_field: 时分秒间隔
+		"5:6",                 // interval_minute_to_second_field: 分秒间隔
+	)
+	if err != nil {
+		log.Fatalf("Failed to execute statement: %v", err)
+	}
+
+	fmt.Println("Data inserted successfully")
+
+}
+
+type ExampleRecord struct {
+	TimeField                   time.Time
+	DatetimeField               time.Time
+	DateField                   time.Time
+	TimeWithZoneField           time.Time
+	DatetimeWithZoneField       time.Time
+	IntervalYearField           string
+	IntervalMonthField          string
+	IntervalDayField            string
+	IntervalHourField           string
+	IntervalMinuteField         string
+	IntervalSecondField         string
+	IntervalDayToHourField      string
+	IntervalDayToMinuteField    string
+	IntervalDayToSecondField    string
+	IntervalHourToMinuteField   string
+	IntervalHourToSecondField   string
+	IntervalMinuteToSecondField string
+}
+
+func TestTypeTimeQuery(t *testing.T) {
+	query := `SELECT 
+	time_field, 
+	datetime_field, 
+	date_field, 
+	time_with_zone_field, 
+	datetime_with_zone_field,
+	interval_year_field,
+	interval_month_field,
+	interval_day_field,
+	interval_hour_field,
+	interval_minute_field,
+	interval_second_field,
+	interval_day_to_hour_field,
+	interval_day_to_minute_field,
+	interval_day_to_second_field,
+	interval_hour_to_minute_field,
+	interval_hour_to_second_field,
+	interval_minute_to_second_field
+FROM example_table`
+
+	stmt, err := db.Prepare(query)
+	if err != nil {
+		log.Fatalf("Failed to prepare statement: %v", err)
+	}
+	defer stmt.Close()
+
+	rows, err := stmt.Query()
+	if err != nil {
+		log.Fatalf("Failed to execute query: %v", err)
+	}
+	defer rows.Close()
+
+	for rows.Next() {
+		var record ExampleRecord
+		err := rows.Scan(
+			&record.TimeField,
+			&record.DatetimeField,
+			&record.DateField,
+			&record.TimeWithZoneField,
+			&record.DatetimeWithZoneField,
+			&record.IntervalYearField,
+			&record.IntervalMonthField,
+			&record.IntervalDayField,
+			&record.IntervalHourField,
+			&record.IntervalMinuteField,
+			&record.IntervalSecondField,
+			&record.IntervalDayToHourField,
+			&record.IntervalDayToMinuteField,
+			&record.IntervalDayToSecondField,
+			&record.IntervalHourToMinuteField,
+			&record.IntervalHourToSecondField,
+			&record.IntervalMinuteToSecondField,
+		)
+		if err != nil {
+			log.Fatalf("Failed to scan row: %v", err)
+		}
+
+		fmt.Printf("%+v\n", record)
+	}
+
+	if err = rows.Err(); err != nil {
+		log.Fatalf("Error occurred during row iteration: %v", err)
+	}
+}

+ 3 - 12
xugu/xugu_buffer.go

@@ -27,17 +27,6 @@ func newBuffer(nc net.Conn) buffer {
 	}
 }
 
-// store 存储 buf,这是一个更新的缓冲区,如果合适的话。
-func (b *buffer) store(buf []byte) error {
-	if 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:])
@@ -85,7 +74,9 @@ func (b *buffer) readNext(need int, reverse bool) ([]byte, error) {
 
 	offset := b.idx
 	b.idx += int64(need)
-
+	if GlobalIsBig {
+		reverse = false
+	}
 	if reverse {
 		//	tmp2 := b.buf[offset:b.idx]
 		//fmt.Println("readNext: 转换小端前", tmp2, " - ", string(tmp2))

+ 47 - 2
xugu/xugu_conn.go

@@ -184,6 +184,7 @@ func (xgConn *xuguConn) Prepare(sql string) (driver.Stmt, error) {
 	prepareName := "GTONG"
 
 	err := xuguPrepare(xgConn, sql, prepareName)
+	fmt.Println("xuguPrepare err : ", err)
 	if err != nil {
 		return nil, err
 	}
@@ -213,18 +214,62 @@ func xuguPrepare(pConn *xuguConn, cmd_sql string, prepareName string) error {
 	sockSendPutStatement(pConn, []byte(sqlRet), nil, 0)
 	sockSendExecute(pConn)
 	//recv msg
-	_, err := xuguSockRecvMsg(pConn)
+	aR, err := xuguSockRecvMsg(pConn)
+	switch aR.rt {
+
+	case errInfo:
+
+		return errors.New(string(aR.e.ErrStr))
+	case warnInfo:
+
+		return errors.New(string(aR.w.WarnStr))
+	default:
+	}
+
 	if err != nil {
 		fmt.Println("xuguPrepare parseMsg(&pConn.readBuff, pConn)")
 		return err
 	}
 
-
 	fmt.Println("\n ---xuguPrepare end")
 
 	return nil
 }
 
+func xuguUnPrepare(pConn *xuguConn, prepareName string) error {
+
+	fmt.Println("\n ---xuguUnPrepare")
+	sqlRet := fmt.Sprintf("DEALLOCATE %s ", prepareName)
+	fmt.Println("sqlRet : ", sqlRet)
+	fmt.Println("prepareName : ", prepareName)
+	//send msg
+	sockSendPutStatement(pConn, []byte(sqlRet), nil, 0)
+	sockSendExecute(pConn)
+	//recv msg
+	aR, err := xuguSockRecvMsg(pConn)
+	switch aR.rt {
+
+	case 'K':
+		return nil
+	case errInfo:
+
+		return errors.New(string(aR.e.ErrStr))
+	case warnInfo:
+
+		return errors.New(string(aR.w.WarnStr))
+	default:
+	}
+
+	if err != nil {
+		fmt.Println("xuguUnPrepare parseMsg(&pConn.readBuff, pConn)")
+		return err
+	}
+
+	fmt.Println("\n ---xuguUnPrepare end")
+
+	return nil
+}
+
 func (xgConn *xuguConn) Exec(sql string,
 	args []driver.Value) (driver.Result, error) {
 	gt("xuguConn.Exec")

+ 2 - 0
xugu/xugu_connector.go

@@ -32,6 +32,8 @@ dsn解析
 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")
+	GlobalIsBig = CheckEndian()
+
 	dsnConfig := parseDSN(conntor.dsn)
 
 	xgConn := &xuguConn{conn: nil}

+ 3 - 1
xugu/xugu_define.go

@@ -1,6 +1,8 @@
 package xugu
 
-//协议消息类型
+var GlobalIsBig bool
+
+// 协议消息类型
 type msgType byte
 
 const (

+ 28 - 18
xugu/xugu_parse.go

@@ -36,6 +36,7 @@ func assertParamCount(query string) int {
 func assertParamType(dV driver.Value, values *[]xuguValue) error {
 	var dest xuguValue
 	switch srcv := dV.(type) {
+
 	case int64:
 		buf := make([]byte, 8)
 		binary.BigEndian.PutUint64(buf, uint64(srcv))
@@ -44,53 +45,62 @@ func assertParamType(dV driver.Value, values *[]xuguValue) error {
 		dest.islob = false
 		dest.types = fieldType_I8
 
-	case float32:
-		S := strconv.FormatFloat(float64(srcv), 'f', 6, 64)
-		dest.value = []byte(S)
-		dest.valueLength = 4
-		dest.islob = false
-		dest.types = fieldType_R4
-
 	case float64:
 		S := strconv.FormatFloat(srcv, 'f', 15, 64)
 		dest.value = []byte(S)
-		dest.valueLength = 8
+		dest.valueLength = len(S)
 		dest.islob = false
-		dest.types = fieldType_R8
+		dest.types = fieldType_CHAR
 
 	case bool:
-		S := strconv.FormatBool(srcv)
-		dest.value = []byte(S)
+		//S := strconv.FormatBool(srcv)
+		var tmp []byte
+		if srcv {
+			tmp = []byte{1}
+		} else {
+			tmp = []byte{0}
+		}
+
+		dest.value = []byte(tmp)
 		dest.valueLength = 1
 		dest.islob = false
 		dest.types = fieldType_BOOL
 
 	case string:
 		dest.value = []byte(srcv)
-		dest.valueLength = strings.Count(srcv, "") - 1
+		dest.valueLength = len(srcv)
 		dest.islob = false
 		dest.types = fieldType_CHAR
+		if dest.valueLength == 0 {
+			dest.valueLength = 1
+			dest.value = []byte{0}
+		}
 
 	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.valueLength = strings.Count(tm, "") - 1
+		dest.valueLength = len(tm)
 		dest.islob = false
-		dest.types = fieldType_TIME
-
+		//dest.types = fieldType_TIME
+		dest.types = fieldType_CHAR
 	case []byte:
 		dest.value = srcv
 		dest.valueLength = len(srcv)
 		dest.islob = true
 		dest.types = fieldType_BLOB
+		if dest.valueLength == 0 {
+			dest.valueLength = 1
+			dest.value = []byte{0}
+		}
 
 	case nil:
-		dest.value = []byte("xugusql")
+		dest.value = []byte{0}
 		dest.valueLength = 0
 		dest.islob = false
-		dest.types = fieldType_CHAR
+		dest.types = fieldType_NULL
 
 	default:
 		return errors.New("unknown data type")
@@ -304,7 +314,7 @@ func parseSelectResult(readBuf *buffer) (*SelectResult, error) {
 			if err != nil {
 				return nil, err
 			}
-
+			fmt.Println("col.Col_Data: ", col.Col_Data)
 			data.Values[colIdx] = append(data.Values[colIdx], col)
 			colIdx++
 			// if col.Col_len > 8000 {

+ 19 - 3
xugu/xugu_rows.go

@@ -5,6 +5,7 @@ import (
 	"encoding/binary"
 	"fmt"
 	"io"
+	"math"
 	"reflect"
 	"time"
 )
@@ -34,15 +35,18 @@ func (row *xuguRows) Next(dest []driver.Value) error {
 
 		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_INTERVAL_Y, fieldType_INTERVAL_M, fieldType_INTERVAL_D, 
+		fieldType_INTERVAL_H,fieldType_INTERVAL_S, 
+			fieldType_INTERVAL_MI:
+			dest[j] = binary.BigEndian.Uint32(row.results.Values[j][row.results.rowIdx].Col_Data)
+
 		case fieldType_TIME,
-			fieldType_TIME_TZ:
+			fieldType_TIME_TZ, fieldType_DATE:
 			tv, _ := time.Parse("15:04:05", string(row.results.Values[j][row.results.rowIdx].Col_Data))
 			dest[j] = tv
 
@@ -61,13 +65,25 @@ func (row *xuguRows) Next(dest []driver.Value) error {
 				dest[j] = utcTime
 			}
 
+		case fieldType_R4:
+			dest[j] = math.Float32frombits(binary.BigEndian.Uint32(row.results.Values[j][row.results.rowIdx].Col_Data))
+			fmt.Println("float ", dest[j])
+		case fieldType_R8:
+
+			dest[j] = math.Float64frombits(binary.BigEndian.Uint64(row.results.Values[j][row.results.rowIdx].Col_Data))
+			fmt.Println("	dest[j]  r8", dest[j])
+		case fieldType_NUM:
+			dest[j] = row.results.Values[j][row.results.rowIdx].Col_Data
 		case fieldType_I1:
 			dest[j] = int8(row.results.Values[j][row.results.rowIdx].Col_Data[0])
+		case fieldType_I2:
+			dest[j] = int16(binary.BigEndian.Uint16(row.results.Values[j][row.results.rowIdx].Col_Data))
 		case fieldType_I4:
 			dest[j] = binary.BigEndian.Uint32(row.results.Values[j][row.results.rowIdx].Col_Data)
 		case fieldType_I8:
 			dest[j] = int64(binary.BigEndian.Uint64(row.results.Values[j][row.results.rowIdx].Col_Data))
 			//dest[j] = row.results.Values[j][row.results.rowIdx].Col_Data
+
 		case fieldType_CHAR, fieldType_NCHAR:
 			dest[j] = string(row.results.Values[j][row.results.rowIdx].Col_Data)
 		default:

+ 17 - 14
xugu/xugu_sock.go

@@ -46,36 +46,39 @@ func sockSendPutStatement(pConn *xuguConn, sql []byte, values *[]xuguValue, para
 	var networkBytes [4]byte
 	binary.BigEndian.PutUint32(networkBytes[:], sqlLength)
 	pConn.sendBuff.Write(networkBytes[:])
+	fmt.Println("sqlLength", sqlLength)
 	//  Comand_str
 	pConn.sendBuff.Write(sql)
+	fmt.Println("Comand_str", sql, string(sql))
 	//'0' end
 	binary.BigEndian.PutUint32(networkBytes[:], 0)
 	pConn.sendBuff.Write([]byte{0})
-
+	fmt.Println("0", 0)
 	// Param_num
 
 	var Param_num [4]byte
 	binary.BigEndian.PutUint32(Param_num[:], uint32(paramCount))
 	pConn.sendBuff.Write(Param_num[:])
-
+	fmt.Println("Param_num", paramCount)
 	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
-			}
-		}
+		// if pConn.sendBuff.Len() > 8190 {
+		// 	_, err := pConn.conn.Write(pConn.sendBuff.Bytes())
+		// 	if err != nil {
+		// 		fmt.Println("sockSend Write failed: ", err)
+		// 		return err
+		// 	}
+		// }
 
 		//发送后续参数
 		//	Param_num   { Param_name_len Param_name Param_INOUT Param_DType Param_Data_Len Param_Data }
-		for _, value := range *values {
+		for i, value := range *values {
+			fmt.Println("循环 ", i)
 			//Param_name_len
 			if value.paramName == nil {
 				var Param_name_len [2]byte
 				pConn.sendBuff.Write(Param_name_len[:])
-
+				fmt.Println("Param_name_len", Param_name_len)
 				//Param_name
 				// var Param_name []byte
 				// pConn.sendBuff.Write(Param_name)
@@ -99,16 +102,16 @@ func sockSendPutStatement(pConn *xuguConn, sql []byte, values *[]xuguValue, para
 			var Param_DType [2]byte
 			binary.BigEndian.PutUint16(Param_DType[:], uint16(value.types))
 			pConn.sendBuff.Write(Param_DType[:])
-
+			fmt.Println("Param_DType: ", Param_DType)
 			//Param_Data_Len 根据DType 修改长度
 			Param_Data_Len := make([]byte, 4)
 			binary.BigEndian.PutUint32(Param_Data_Len[:], uint32(value.valueLength))
 			pConn.sendBuff.Write(Param_Data_Len[:])
-
+			fmt.Println("Param_Data_Len: ", Param_Data_Len)
 			//Param_Data 根据DType 修改长度
 			//Param_Data := make([]byte, value.valueLength)
 			pConn.sendBuff.Write([]byte(value.value))
-
+			fmt.Println("Param_Data: ", []byte(value.value))
 		}
 
 	}

+ 7 - 2
xugu/xugu_stmt.go

@@ -33,7 +33,12 @@ type xuguStmt struct {
 
 func (stmt *xuguStmt) Close() error {
 	fmt.Println("\n>>>>>> (stmt *xuguStmt) Close method called")
-	return nil
+	//关闭 prepare
+	fmt.Println("stmt.stmt_conn.prepareName", stmt.stmt_conn.prepareName)
+	err := xuguUnPrepare(stmt.stmt_conn, stmt.stmt_conn.prepareName)
+	//释放资源
+
+	return err
 }
 
 func (stmt *xuguStmt) NumInput() int {
@@ -126,7 +131,7 @@ func (stmt *xuguStmt) Query(args []driver.Value) (driver.Rows, error) {
 
 	switch aR.rt {
 	case selectResult:
-		
+
 		rows := &xuguRows{
 			rows_conn: stmt.stmt_conn,
 			results:   aR.s,

+ 17 - 0
xugu/xugu_utils.go

@@ -1,6 +1,7 @@
 package xugu
 
 import (
+	"encoding/binary"
 	"fmt"
 	"strings"
 )
@@ -170,3 +171,19 @@ func switchSQLType(sql string) int {
 		return SQL_OTHER
 	}
 }
+
+// CheckEndian 判断机器的字节序
+func CheckEndian() bool {
+	var i int32 = 0x01020304
+	b := [4]byte{}
+
+	// 将整数值写入字节切片
+	binary.BigEndian.PutUint32(b[:], uint32(i))
+
+	// 判断字节序
+	if b[0] == 0x01 {
+		return false // 大端字节序
+	} else {
+		return true // 小端字节序
+	}
+}

+ 313 - 0
协议.ini

@@ -0,0 +1,313 @@
+http://gitlab2.xugu.com/cyj/xugusql
+
+1.连接:
+     1.1 客户端主动发起连接,创建socket后,向服务端发出连接字符串: 
+	login   database = '数据库名' user = '用户名'  password = '口令' [ encryptor = '加密库的解密口令' ]  
+		[ char_set = '客户端使用的字符集名'] [ time_zone='时区']  [iso_level='事务隔离级别']
+		[ lock_timeout='加锁超时' ] [ auto_commit='on或off']  [ strict_commit='on或off'] 
+		[ result='char']   [ return_schema='on或off ] [ return_cursor_id='on或off ]
+		[ lob_ret='descriptor']  [ return_rowid = true] version='客户端协议版本号'
+		
+	解释:	
+		连接串中除了login database=数据库名 user = '用户名'  password = '口令' 外,其余为可选项,若未指定那些项,则系统为连接设置默认值
+		
+		数据解密口令:用于启动加密数据库,若库未加密,则可不要,但带上此参数不会影响连接
+		
+		客户端使用的字符集名: 'GB2312' ,'GBK','BIG5' 等,默认为GBK
+		
+		时区:	'GMT +08:00'
+		
+		事务隔离级别:
+			'READ COMMITED':读已提交
+			'REPEATIABLE READ':可重复读 
+			'SERIALIZABLE':序列化
+		
+		加锁超时:
+			毫秒数,表示本连接中的事务在争用锁时,最多等候的时间,若在此时间内加锁不成功,则回滚事务并报错
+		
+		auto_commit:
+			on:表示自动提交,即每个命令都作为一个事务,命令完成立即提交
+			off:非自动提交,需要 commit命令才提交
+		
+		strict_commit: 是否该连接中执行的事务使用严格提交(即须记实了事务日志才向客户端返回'K')
+		
+		result='char': 当设置了该项后,则float,integer等不以字串方式返回的结果皆强制使用字符串方式返回(此项对于odbc,jdbc等标准驱动皆不使用)
+		
+		return_schema: 是否在返回字段名信息时加上模式名,若设置为'on',则返回的字段名形式为: 模式名.表名.字段名 '%' 别名,否则返回的字段名形式为:表名.字段名 '%' 别名
+		
+		return_cursor_id: 若该项设置为'on',则存贮过程的ref_cursor的返回值为cursor的ID号,此时,客户端若要使用ref_currsor的结果,则应使用fetch命令,cursor的名为: 'CurN' + 游标号的16进制字串,
+				若该项设置为off或没有该项,则将在返回结果中直接嵌入ref_cursor的结果集 
+		
+		lob_ret='descriptor': 该项目前服务器版本中没有,拟新加入,若有该项,则在返回大对象时不以数据形式返回,代之以描述符,当真正需要大对象数据时,使用 GET LOB 大对象描述符;命令从服务器取回数据
+		
+		version:
+			客户端协议版本,目前都应是:'201'
+
+ 
+    1.2 服务器端: 发回字节'K'表示成功,否则,发回错误信息(见错误信息格式)并立即关闭连接
+
+
+2.所有DML及DDL访问:
+
+    2.1 客户端发出访问: 
+	
+        QryStream:  '?'  Comand_Len   Comand_str   Param_num   { Param_name_len Param_name Param_INOUT Param_DType Param_Data_Len Param_Data }*
+		?  5 ? STC 1 0 1   type_int 4 1
+		
+	解释:
+		Command_len: 	命令长度(网络序32位整数,计算命令长度时不包括结束符0x0)
+		Command_str: 	命令字串(发送时应包括结束符0x0)	  
+		Param_num:	参数个数(网络序16位整数,若没有参数则此值为0)
+		
+		Param_name_len: 参数名字长度(网络序短整数,若参数无名,则此值为0)
+		Param_name:	参数名(该部分字节数应与Param_name_Len一致)
+		Param_INOUT: 参数输出输入类型(网络序16位整数)
+		Param_DType:	参数数据类型号(网络序16位整数)
+		Param_Data_Len:	参数长度(网络序32位整数)
+		Param_Data:	参数数据(该部分字节数应与Param_Data_Len一致)
+		
+		{}*:		表示参数部分可有0至多个参数,其重复的次数取决于Param_num,若Param_num为0,则没有参数需要发送
+ 
+ 		
+
+    2.2 服务器返回:  服务器可返回一组或多组信息,并以字节'K'标识所有信息已传送完毕
+	
+	SrvResponse:     { FormArgDescri | SelectResult | InsertResult | UpdateResult | DeleteResult | ProcRet | OutParamRet | ErrInfo | WarnInfo | Message }*  'K'
+	
+	FormArgDescri:   '$' Arg_Num { Arg_Name_Len Arg_Name Arg_No Arg_DType Arg_Preci_Scale }+ 
+	
+	SelectResult:    'A' Field_Num { Field_Name_Len Field_Name Field_DType Field_Preci_Scale Field_Flag }+  { 'R' Col_len1 Col_Data1 ... }*
+	
+	InsertResult:	 'I' Rowid_Len  Rowid_Data
+	
+	UpdateResult:	 'U' Update_Num	
+
+	DeleteResult:	 'D' Delete_Num
+
+	ProcRet:	 'O' Ret_DType  Ret_Data_Len  Ret_Data
+
+	OutParamRet:	 'P' Out_Param_No   Out_Param_DType  Out_Param_Len  Out_Param_Data
+
+	ErrInfo:	 'E' Err_Str_Len  Err_Str
+	
+	WarnInfo:	 'W' Warn_Str_Len Warn_Str
+
+	Message:	 'M' Msg_Str_Len  Msg_Str
+
+
+	解释:
+		FormArgDescri:   形式参数描述,执行prepare语句后,通常返回此部分信息
+		Arg_Num:	 形参个数(网络序32位整数)
+		Arg_Name_Len:	 形参名长度(网络序32位整数)
+		Arg_Name:	 形参名(字节数与Arg_Name_Len一致)
+		Ar_No:		 形参的序号(网络序32位整数,若prepare语句中使用?号表示参数,则服务器按?号的顺序从1开始为其设定序号)
+		Argg_DType:	 形参的数据类型ID(网络序32位整数)
+		Arg_Preci_Scale: 形参的精度标度(网络序32位整数
+
+		SelectResult:	 查询结果集,包含一组结果集字段描述 以及0至多个行数据
+		Field_Num:	 结果集字段数
+		Field_Name_Len:  字段名长度(网络序32位整数)
+		Field_Name:	 字段名(字节数与Field_Name_Len一致)
+		Field_DType:	 字段数据类型ID(网络序32位整数)
+		Field_Preci_Scale:字段的精度标度(网络序32位整数,若为-1或0表示没有精度标度信息,否则高16位为精度低16位为标度)
+		Field_Flag:	字段的其它属性标志(网络序32位整数),其中每一个位表征字段的某一个特性,各位对应的特性如下
+				FIELD_BASE_TAB=1,	/* 表示字段是实际的表的字段(否则,表示字段实际上是表达式) */
+				FIELD_NOT_NULL=2,	/* 表示字段具有非空约束 */
+				FIELD_IS_PRIMARY=4, 	/* 表示字段是主键 */
+				FIELD_IS_SERIAL=8,	/* 表示字段是序列值 */
+				FIELD_IS_TIMESTAMP=16,	/* 表示字段是timestamp */
+				FIELD_IS_LOB=32,	/* 表示字段是大对象类型 */
+				FIELD_IS_UNIQUE=64,	/* 表示字段是唯一值类型 */
+				FIELD_IS_ROWID=128,	/* 表示字段是rowid */
+				FIELD_IS_DUMMY=256, 	/* 表示字段不应输出 */
+				FIELD_IS_HIDE=512,	/* 表示字段是隐藏字段 */				 
+
+		Col_len:	 列数据长度(网络序32位整数)
+		Col_Data:	 列数据(字节数与Col_Len一致)
+		
+		注:  返回结果中,记录数据由 'R'开头,后跟若干个列的长度及数据,每个'R'后的列数据个数为Field_Num个		
+
+
+		InsertResult:	插入语句的返回结果
+		Rowid_Len:	插入语句返回的新行的ROWID数据的长度
+		Rowid_Data:	插入语句返回的新行的ROWID数据(为base64编码)
+
+
+		UpdateResult:	更改语句返回的结果
+		Update_Num:	更改语句影响的行数(网络序32位整数)
+		
+		DeleteResult:	删除语句的返回结果
+		Delete_Num:	删除的行数
+		
+		ProcRet:	存贮函数调用的返回值
+		Ret_DType:	返回值数据类型(网络序32位整数)
+		Ret_Data_Len:	返回值数据长度(网络序32位整数)
+		Ret_Data:	返回值数据	
+
+		OutParamRet:	返回型参数
+		Out_Param_No:	返回型参数的参数号
+		Out_Param_DType:返回参数的数据类型(网络序32位整数)
+		Out_Param_Len:	返回参数的数据长度(网络序32位整数)
+		Out_Param_Date:	返回参数的数据	
+
+		ErrInfo:	错误信息(通常在返回数据的最后出现,即出现在 'K'字符前)
+		Err_Str_Len:	错误信息长度(网络序32位整数)
+		Err_Str:	错误信息(字节数与Err_Str_Len一致)
+	
+		WarnInfo:	警告信息(通常在返回数据的最后出现,即出现在 'K'字符前)
+		Warn_Str_Len:	警告信息长度(网络序32位整数)
+		Warn_Str:	警告信息(字节数与Warn_Str_Len一致)
+
+		Message:	通知信息(出现的位置没有一定的规定)
+		Msg_Str_Len:	通知信息长度(网络序32位整数)
+		Msg_Str:	通知信息(字节数与Msg_Str_Len一致)
+
+		注: {}* 中各种返回信息是并列的关系,可能一次返回中含有0个至多个返回信息,不能假定改到其中其种返回信息就认为没有其它种类的返回信息,
+			有些类型的返回信息甚至可能重重出现,如:一次发多条select 语句就会造成返回信息中包含多个查询结果集.
+
+	2.3 关于新版本中将增加的大对象数据返回形式的说明
+		
+		a) 当在连接中未加入了 lob_ret='descriptor'子串时,使用原来的方式返回大对象数据
+
+		b) 当在连接中加入了 lob_ret='descriptor'子串时,应该将大对象对应的列返回值视作描述符,描述符分两种:一种为内嵌在行内的大对象数据的描述符,一种为非内嵌大对象描述符
+			内嵌大对象描述符:   
+				BLOB类型:'b' + 大对象数据  即:大对象数据仍直接返回,只是前面加了一个 'b'字符,因此大对象数据的长度实际为列数据长度-1
+				CLOB类型:'c' + 大对象数据  即:大对象数据仍直接返回,只是前面加了一个 'c'字符,因此大对象数据的长度实际为列数据长度-1
+
+			非内嵌大对象描述符:
+				BLOB类型: 'B' + 大对象描述符字串 ,该字符串由两部分组成:前面为descriptor的base64编码,后面为大对象的数据长度(10进制数值串),
+					   中间由空格分开;整个串的长度为列数据长度-1;
+				CLOB类型: 'C' + 大对象描述符字串,其余与BLOB相同 
+		
+		c) 当大对象字段返回的字段长度为0时,仍表示该字段为空值,不能再去取该字段的数据作为描述符用
+
+		d) 对于内嵌大对象,驱动应保存其数据,而不能从服务器另取数据
+
+		e) 对于非内嵌大对象,驱动在向应用程序返回数据时使用: 
+			GET LOB '大对象描述符' offset 偏移量 limit 读取长度; 命令来读取大对象数据. (注意:大对象描述符串包括前面的‘B’或‘C’,
+				但不包含后面的大对象长度字串,描述前后有'号)  
+			服务端以单行单列结果集的形式返回数据:
+				对于BLOB,返回的字段名为:BLOBDATA,返回记录的数据长度为实际读取长度(通常就是limit,若已读到尾,则小于limit),
+				对于CLOB,返回的字段名为:CLOBDATA,若不存在库字符集与客户端字符集的差异,则返回记录的数据长度为实际读取长度,
+				否则,返回的数据长度为字符集转换后的长度,当然,内容也就为转换后的内容。
+
+				
+	
+3.数据类型ID的取值:以下取值未写明数值的按有数值的依次向下增1
+	
+	TYPE_EMPTY = 0,
+	TYPE_NULL,
+	TYPE_BOOL,
+	TYPE_I1,
+	TYPE_UI1,
+	TYPE_I2,
+	TYPE_UI2,
+	TYPE_I4,
+	TYPE_UI4,
+	TYPE_I8,
+	TYPE_UI8,
+	TYPE_R4,
+	TYPE_R8,
+	TYPE_DATE,
+	TYPE_TIME,
+	TYPE_DATETIME,
+	TYPE_TIMESTAMP,
+	TYPE_INTERVAL_D2S,
+	TYPE_SMALLTIME,
+	TYPE_TIME_TZ,
+	TYPE_DATETIME_TZ,
+	TYPE_INTERVAL_Y2M,
+
+	TYPE_DECIMAL,
+	TYPE_NUMERIC,
+	TYPE_CY, 
+	TYPE_STR,
+	TYPE_CHAR,
+	TYPE_VARCHAR,
+	TYPE_CLOB,
+	TYPE_BINARY,
+	TYPE_BLOB,
+	TYPE_IMAGE,
+	TYPE_BLOB_INROW,
+	TYPE_BLOB_S,
+	TYPE_BLOB_M,
+	TYPE_BLOB_OM,
+	TYPE_STREAM,
+	TYPE_AUDIO,
+	TYPE_VIDEO,
+	TYPE_ROWVER,
+
+	TYPE_INTERVAL_Y,
+	TYPE_INTERVAL_M,
+	TYPE_INTERVAL_D,
+	TYPE_INTERVAL_H,
+	TYPE_INTERVAL_MI,
+	TYPE_INTERVAL_S,
+	TYPE_INTERVAL_D2H,
+	TYPE_INTERVAL_D2M,
+	TYPE_INTERVAL_H2M,
+	TYPE_INTERVAL_H2S,
+	TYPE_INTERVAL_M2S,
+	TYPE_GUID,
+
+	TYPE_GEOMETRY=60,
+	TYPE_POINT,
+	TYPE_BOX,
+	TYPE_POLYLINE,
+	TYPE_POLYGON,
+	
+
+	TYPE_MAX_SYS=100,
+
+	TYPE_BLADE_BEGIN=101,
+	TYPE_BLADE_END=1000,
+	
+	TYPE_OBJECT=1001,		/* 对象类型 */
+	TYPE_RECORD,			/* 记录类型 */
+	TYPE_VARRAY,			/* 数组类型 */
+	TYPE_TABLE,			/* 表类型 */
+	TYPE_IDXBY_TAB,			/* index by 表类型 */
+	TYPE_ROWTYPE,			/* 引用行类型 */
+	TYPE_COLTYPE,			/* 引用列类型 */
+	TYPE_ROW,			/* 行类型  */
+	TYPE_CUR_REC,			/* 引用记录类型(不能更改字段) */
+	TYPE_CURSOR,			/* 游标类型 */
+	TYPE_REFCUR,			/* REF_CURSOR类型 */
+	TYPE_PARAM,
+
+	TYPE_UDT_BEGIN=1100,	
+
+
+4.数据类型返回格式
+	2.1.若连接时连接串中有 result='char',则各类型数据的返回值皆转换成字符串的形式进行返回,
+	    
+	    	数值型(integer,float,numeric等),返回的字符串变由数字与小数点组成
+	    	日期型格式:‘2011-3-3’
+		时间型格式 ‘12:03:40’或 ‘12:03:40.999'
+		日期时间型格式:‘2011-3-3 12:34:23' 或 ‘2011-3-3 12:34:23.999'
+		带时区的日期时间格式:‘2011-3-3 12:34:23+08:00' 或‘2011-3-3 12:34:23-08:00'
+		带时区的时间格式:‘12:34:23+08:00' 或‘12:34:23-08:00'
+
+	2.2若连接串中不含 result='char',则各类型数据的返回值通常以二进制方式返回
+		
+		char、varchar、clob、numeric等类型以字符串形式返回
+		数值型(integer等除numeric外)返回格式,就是其二进制格式,只是转换成了网络序
+		date: 32位网络序整数,为从1970-1-1起流失的天数(负数表示在1970-1-1之前)
+		time: 32位网络序整数,为一天内从0:0:0开始流失的毫秒数
+		datetime:64位网络序整数,为从1970-1-1起流失的毫秒数(负数表示在1970-1-1之前)
+		time with time zone:6字节,前4字节为32位网络序时间值,后2字节为16位网络序时区值,时间值与time的处理方式一样,
+			时区值为时区相对于格林威治天文台的时差,单位为分钟,有正负之分。
+		datetime with time zone:10字节,前8字节为64位网络序日期时间值,后2字节为16位网络序时区值,日期时间值与datetime的处理方式一样,
+			时区值为时区相对于格林威治天文台的时差,单位为分钟,有正负之分。
+
+		interval year:	32位网络序整数,单位为年
+		interval month:	32位网络序整数,单位为月
+		interval day:	32位网络序整数,单位为天
+
+		interval hour:	32位网络序整数,单位为小时
+		interval minute:32位网络序整数,单位为分钟
+		interval second:64位网络序整数,单位为毫秒(微秒  CYJ)
+
+		注:interval XX to YY(如interval day to second)其返回的值的格式与 interval YY相同,
+		即:interval day to second 返回格式与interval second相同,余类推
+