Browse Source

first commit

GTong 1 year ago
commit
3653b1f79c
37 changed files with 3368 additions and 0 deletions
  1. 36 0
      file/test copy.txt
  2. 28 0
      file/test.txt
  3. 9 0
      go.mod
  4. 136 0
      go.sum
  5. 84 0
      internal/auto/auto.go
  6. 48 0
      internal/config/config_test.go
  7. 156 0
      internal/config/readFile.go
  8. 163 0
      internal/dbBase/db.go
  9. 59 0
      internal/dbBase/db_test.go
  10. 89 0
      internal/logs/logs.go
  11. 101 0
      internal/produce/image.go
  12. 47 0
      internal/utils/print_Fmt.go
  13. 38 0
      internal/utils/utils.go
  14. 7 0
      logs/xuguALL_2024-03-25 11.07.24txt
  15. 6 0
      logs/xuguALL_2024-03-25 11.14.24txt
  16. 4 0
      logs/xuguALL_2024-03-25 11.15.24txt
  17. 12 0
      logs/xuguALL_2024-03-25 11.16.24txt
  18. 0 0
      logs/xuguALL_2024-03-25 11.22.24txt
  19. 6 0
      logs/xuguALL_2024-03-25 11.27.24txt
  20. 6 0
      logs/xuguALL_2024-03-25 11.48.24txt
  21. 6 0
      logs/xuguALL_2024-03-25 11.50.24txt
  22. 6 0
      logs/xuguALL_2024-03-25 11.53.24txt
  23. 6 0
      logs/xuguALL_2024-03-25 11.54.24txt
  24. 6 0
      logs/xuguALL_2024-03-25 11.57.24txt
  25. 16 0
      main.go
  26. BIN
      pkg/go-driver-xugusql/lib/arm/libxugusql.so
  27. 48 0
      pkg/go-driver-xugusql/xugusql.go
  28. 401 0
      pkg/go-driver-xugusql/xugusql.h
  29. 323 0
      pkg/go-driver-xugusql/xugusql_auxi.go
  30. 220 0
      pkg/go-driver-xugusql/xugusql_cgo.go
  31. 77 0
      pkg/go-driver-xugusql/xugusql_connector.go
  32. 163 0
      pkg/go-driver-xugusql/xugusql_fields.go
  33. 346 0
      pkg/go-driver-xugusql/xugusql_pconn.go
  34. 28 0
      pkg/go-driver-xugusql/xugusql_result.go
  35. 336 0
      pkg/go-driver-xugusql/xugusql_rows.go
  36. 316 0
      pkg/go-driver-xugusql/xugusql_stmt.go
  37. 35 0
      pkg/go-driver-xugusql/xugusql_tranx.go

+ 36 - 0
file/test copy.txt

@@ -0,0 +1,36 @@
+[xugu]
+ip = 10.28.20.101
+port = 5190
+database = system
+user_password = sysdba:sysdba
+
+[sql]
+用例名称 = 基础数据类型
+测试要求 = "基础数据类型应符合下列条款;支持数值类型;支持字符类型;支持二进制类型;支持日期类型;支持布尔类型;支持大文本类型支持大对象类型;"
+测试步骤 = """
+--支持二进制类型;
+create table IF NOT EXISTS t3(a blob,b binary);
+insert into t3 values(?,'a'); <# /home/gtong/xugu_work/xgtest/file/test_pic_1.png
+select * from t3;
+"""
+
+
+--支持数值类型;
+create table t1(a int,b bigint,c float,d double,e tinyint,f smallint,g numeric(5,2));
+insert into t1 values(1,100,123456,123456,12,123,123.12);
+select * from t1;
+--支持字符类型;
+create table t2(a char(20),b varchar,c clob);
+insert into t2 values('a','ab','abc');
+select * from t2;
+
+
+
+用例名称 = 12321数据类型
+测试要求 = "据类型大苏打萨达萨达是;支持数值类型;支持字符类型;支持二进制类型;支持日期类型;支持布尔类型;支持大文本类型支持大对象类型;"
+测试步骤 = """
+--支持二进制类型;
+create table IF NOT EXISTS t4(a blob,b binary);
+insert into t4 values(?,'a'); <# /home/gtong/xugu_work/xgtest/file/test_pic_1.png
+select * from t4;
+"""

+ 28 - 0
file/test.txt

@@ -0,0 +1,28 @@
+[xugu]
+ip = 10.28.20.101
+port = 5190
+database = system
+user_password = sysdba:sysdba
+
+[sql]
+用例名称 = 基础数据类型
+测试要求 = "基础数据类型应符合下列条款;支持数值类型;支持字符类型;支持二进制类型;支持日期类型;支持布尔类型;支持大文本类型支持大对象类型;"
+测试步骤 = """
+--支持数值类型;
+create table  IF NOT EXISTS  t1(a int,b bigint,c float,d double,e tinyint,f smallint,g numeric(5,2));
+insert into t1 values(1,100,123456,123456,12,123,123.12);
+select * from t1;
+--支持字符类型;
+create table  IF NOT EXISTS  t2(a char(20),b varchar,c clob);
+insert into t2 values('a','ab','abc');
+select * from t2;
+"""
+
+用例名称 = 12321数据类型
+测试要求 = "据类型大苏打萨达萨达是;支持数值类型;支持字符类型;支持二进制类型;支持日期类型;支持布尔类型;支持大文本类型支持大对象类型;"
+测试步骤 = """
+--支持二进制类型;
+create table IF NOT EXISTS t4(a blob,b binary);
+insert into t4 values(?,'a'); <# /home/gtong/xugu_work/xgtest/file/test_pic_1.png
+select * from t4;
+"""

+ 9 - 0
go.mod

@@ -0,0 +1,9 @@
+module xgAutoTest
+
+go 1.21.4
+
+require (
+	github.com/go-xorm/xorm v0.7.9 // indirect
+	xorm.io/builder v0.3.6 // indirect
+	xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb // indirect
+)

+ 136 - 0
go.sum

@@ -0,0 +1,136 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
+github.com/go-xorm/xorm v0.7.9 h1:LZze6n1UvRmM5gpL9/U9Gucwqo6aWlFVlfcHKH10qA0=
+github.com/go-xorm/xorm v0.7.9/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ=
+github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
+github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
+go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
+xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=
+xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb h1:msX3zG3BPl8Ti+LDzP33/9K7BzO/WqFXk610K1kYKfo=
+xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=

+ 84 - 0
internal/auto/auto.go

@@ -0,0 +1,84 @@
+package auto
+
+import (
+	"bufio"
+	"database/sql"
+	"fmt"
+	"strings"
+	"xgAutoTest/internal/config"
+	"xgAutoTest/internal/dbBase"
+	"xgAutoTest/internal/utils"
+)
+
+func AutoRun() {
+	db := dbBase.GetDb()
+	//defer db.Close()
+	config := config.ConfigInfo{}
+	config.GetConfigInfo("./file/test.txt")
+
+	for _, Part := range config.CommandSql.Part {
+		//fmt.Println("[sql] Part: ", Part)
+		//[].part 键值
+		partMap := config.ParseGroupCase(Part)
+		//fmt.Println("[sql] partMap: ", partMap)
+		//[].partMap[测试步骤],sql运行
+		partTestStepScanner := bufio.NewScanner(strings.NewReader(partMap["测试步骤"]))
+		for partTestStepScanner.Scan() {
+			partLine := partTestStepScanner.Text()
+			switch {
+
+			case strings.HasPrefix(partLine, "--"):
+				strings.TrimSpace(strings.TrimPrefix(partLine, "--"))
+				//fmt.Printf("带有--key: %s\n", key)
+
+			case strings.Contains(partLine, ";"):
+				//fmt.Printf("不带有--sql: %s\n", partLine)
+				sql := strings.TrimSpace(partLine[:strings.Index(partLine, ";")+1])
+				//fmt.Printf("sql TrimSpace: %s\n", sql)
+				isQueryOrInsert(db, sql)
+
+			}
+		}
+		if err := partTestStepScanner.Err(); err != nil {
+			fmt.Println("partTestStepScanner.Error reading input:", err)
+		}
+
+	}
+}
+
+func isQueryOrInsert(db *sql.DB, sql string) {
+	switch {
+	//执行查询语句
+	case strings.HasPrefix(sql, "select"):
+		{
+			fmt.Printf("\nsql is select: %s\n", sql)
+			dbBase.QueryString(db, sql)
+		}
+	//执行大对象插入语句
+	case isBlob(sql):
+		{
+			fmt.Printf("\nsql is 大对象插入: %s\n", sql)
+		}
+	//其他语句调用exec函数
+	default:
+		{
+			//不是大对象插入语句的处理
+			fmt.Printf("\nsql is 不是大对象插入语句的处理: %s\n", sql)
+			dbBase.ExecString(db, sql)
+		}
+	}
+}
+
+func isBlob(sql string) bool {
+	utils.ContainsKeyword(sql, "values")
+	questionMarksCount := utils.IsInsertBlob(sql)
+	switch {
+	case questionMarksCount > 0:
+		{
+			return true
+		}
+	default:
+		return false
+	}
+
+}

+ 48 - 0
internal/config/config_test.go

@@ -0,0 +1,48 @@
+package config
+
+import (
+	"fmt"
+	"path"
+	"runtime"
+	"testing"
+)
+
+func getCurrentPath() string {
+	_, filename, _, _ := runtime.Caller(1)
+
+	return path.Dir(filename)
+}
+func TestGetConfigInfo(t1 *testing.T) {
+	var config ConfigInfo
+	config.GetConfigInfo("../../file/test.txt")
+	fmt.Println(config)
+}
+func TestReadFile(t1 *testing.T) {
+	fmt.Println(getCurrentPath())
+	var config ConfigInfo
+	//config.GetConfigInfo("../../file/test.txt")
+	configRet := config.ReadCofing("../../file/test.txt")
+	fmt.Println(configRet)
+	fmt.Println("-------------------ParseConfigSql------------------------")
+	retXugu := config.ParseConfigSql(configRet["xugu"])
+	retSql := config.ParseConfigSql(configRet["sql"])
+	for _, v := range retXugu {
+		fmt.Println("retXugu", v)
+	}
+	for _, v := range retSql {
+		fmt.Println("retSql", v)
+	}
+	fmt.Println("------------------ParseGroupCase---------------------------")
+	var a map[string]string
+	for _, v := range retXugu {
+		a = config.ParseGroupCase(v)
+		fmt.Println("ParseSqlCase:", a)
+	}
+	fmt.Println("a", a["port"])
+
+	var b map[string]string
+	for _, v := range retSql {
+		b = config.ParseGroupCase(v)
+		fmt.Println("ParseSqlCase:", b)
+	}
+}

+ 156 - 0
internal/config/readFile.go

@@ -0,0 +1,156 @@
+package config
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"strings"
+)
+
+type ConfigInfo struct {
+	DbInfo     DbInfo
+	CommandSql CommandSql
+}
+
+type DbInfo struct {
+	Ip       string
+	Prot     string
+	Database string
+	User     string
+	PassWord string
+}
+
+type CommandSql struct {
+	Part []string
+}
+
+func (config *ConfigInfo) GetConfigInfo(fileLocal string) {
+	configRet := config.ReadCofing(fileLocal)
+	xuguRet := config.ParseConfigSql(configRet["xugu"])
+	xuguMap := config.ParseGroupCase(xuguRet[0])
+	dbInfo := DbInfo{
+		Ip:       xuguMap["ip"],
+		Prot:     xuguMap["port"],
+		Database: xuguMap["database"],
+		User:     xuguMap["user"],
+		PassWord: xuguMap["password"],
+	}
+	config.DbInfo = dbInfo
+	sqlRet := config.ParseConfigSql(configRet["sql"])
+	commandSql := CommandSql{
+		Part: sqlRet,
+	}
+	config.CommandSql = commandSql
+
+}
+
+func (config *ConfigInfo) ReadCofing(fileName string) map[string]string {
+	// 打开配置文件
+	file, err := os.Open(fileName)
+	if err != nil {
+		fmt.Println("打开文件错误:", err)
+		return nil
+	}
+	defer file.Close()
+
+	ret := config.ParseConfigFile(file)
+	return ret
+
+}
+
+// 读取配置文件,并解析每组,返回 键为组,值为文件原格式(包含空格换行)的map[string]string
+func (config *ConfigInfo) ParseConfigFile(file *os.File) map[string]string {
+	result := make(map[string]string)
+	var currentKey string
+	var lines []string
+
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		line := scanner.Text()
+
+		// 处理注释部分
+		// if strings.Contains(line, "#") {
+		// 	line = strings.SplitN(line, "#", 2)[0]
+		// }
+
+		if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
+			if currentKey != "" {
+				result[currentKey] = strings.Join(lines, "\n")
+				lines = nil
+			}
+			currentKey = line[1 : len(line)-1]
+		} else {
+			lines = append(lines, line)
+		}
+	}
+	if currentKey != "" {
+		result[currentKey] = strings.Join(lines, "\n")
+	}
+
+	if err := scanner.Err(); err != nil {
+		fmt.Println("Error scanning file:", err)
+		return nil
+	}
+	return result
+}
+
+// 将[ ]组下的单个片段中,以=号前为键,=号后为值,解析为map[string]string ,
+func (*ConfigInfo) ParseGroupCase(input string) map[string]string {
+	sqlMap := make(map[string]string)
+	scanner := bufio.NewScanner(strings.NewReader(input))
+	for scanner.Scan() {
+		line := scanner.Text()
+		parts := strings.SplitN(line, "=", 2)
+		if len(parts) != 2 {
+			continue
+		}
+		key := strings.TrimSpace(parts[0])
+		value := strings.TrimSpace(parts[1])
+		if strings.HasPrefix(value, `"""`) {
+			// Value continues on next lines until closing """
+			var multiLineValue strings.Builder
+			multiLineValue.WriteString(strings.TrimPrefix(value, `"""`))
+			for scanner.Scan() {
+				nextLine := scanner.Text()
+				if strings.Contains(nextLine, `"""`) {
+					multiLineValue.WriteString("\n")
+					multiLineValue.WriteString(strings.TrimSuffix(nextLine, `"""`))
+					break
+				} else {
+					multiLineValue.WriteString("\n")
+					multiLineValue.WriteString(nextLine)
+				}
+			}
+			//fmt.Printf("Key: %s, Value: %s\n", key, multiLineValue.String())
+			sqlMap[key] = multiLineValue.String()
+		} else {
+			//fmt.Printf("Key: %s, Value: %s\n", key, value)
+			sqlMap[key] = value
+		}
+	}
+	if err := scanner.Err(); err != nil {
+		fmt.Println("Error reading input:", err)
+		os.Exit(1)
+	}
+	return sqlMap
+}
+
+// 解析[sql]组下的片段,一个用例名称到下一个用列名称前为一个片段
+func (*ConfigInfo) ParseConfigSql(input string) []string {
+	lines := strings.Split(input, "\n")
+	var testCases []string
+	var currentTestCase strings.Builder
+
+	for _, line := range lines {
+		if strings.HasPrefix(line, "用例名称") && currentTestCase.Len() > 0 {
+			testCases = append(testCases, currentTestCase.String())
+			currentTestCase.Reset()
+		}
+		currentTestCase.WriteString(line + "\n")
+	}
+	if currentTestCase.Len() > 0 {
+		testCases = append(testCases, currentTestCase.String())
+	}
+
+	return testCases
+}

+ 163 - 0
internal/dbBase/db.go

@@ -0,0 +1,163 @@
+package dbBase
+
+import (
+	"C"
+	"database/sql"
+	"fmt"
+	"log"
+	"os"
+	"strings"
+	"xgAutoTest/internal/logs"
+	_ "xgAutoTest/pkg/go-driver-xugusql"
+)
+import "time"
+
+var db *sql.DB
+
+func InitDb(ip string, port string, dbBase string, user string, pwd string) {
+	var err error
+	dbLink := fmt.Sprintf("IP=%s;DB=%s;User=%s;"+"PWD=%s;Port=%s;AUTO_COMMIT=on;CHAR_SET=UTF8", ip, dbBase, user, pwd, port)
+	db, err = sql.Open("xugusql", dbLink)
+	if err != nil {
+		log.Fatal("db open fail")
+	}
+	err = db.Ping()
+	if err != nil {
+		log.Fatal("db Ping fail")
+	} else {
+		log.Printf("db Ping ok")
+	}
+}
+
+func GetDb() *sql.DB {
+	return db
+}
+
+func QueryString(db *sql.DB, sql string) string {
+	//fmt.Printf("\nQueryString().sql: \n", sql)
+	logs.Log.Printf("QueryString().sql: %s\n", sql)
+	// 记录开始时间
+	start := time.Now()
+	rows, err := db.Query(sql)
+	if err != nil {
+		log.Fatal(err)
+	}
+	var cols []string
+	cols, err = rows.Columns()
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	var sqlResult string
+	sqlResult += fmt.Sprintf("SQL> %s", sql+"\n\n")
+	pvals := make([]interface{}, len(cols))
+	for key, _ := range pvals {
+		dest := make([]byte, 216)
+		pvals[key] = &dest
+	} /* end for */
+	for _, v := range cols {
+		//fmt.Printf("%s | ", v)
+		sqlResult += fmt.Sprintf("%s | ", v)
+	}
+	sqlResult += "\n------------------------------------------------------------------------------\n"
+	records := 0
+	for rows.Next() {
+		err = rows.Scan(pvals...)
+		if err != nil {
+			log.Fatal(err)
+		}
+		for _, v := range pvals {
+			if string(*(v.(*[]byte))) == "" {
+				//	fmt.Printf("%s| ", "<NULL>")
+				sqlResult += fmt.Sprintf("%s | ", "<NULL>")
+			} else {
+				//	fmt.Printf("%s | ", string(*(v.(*[]byte))))
+				sqlResult += fmt.Sprintf("%s | ", string(*(v.(*[]byte))))
+			}
+
+		}
+		records++
+		//fmt.Printf("\n")
+		sqlResult += "\n"
+	}
+
+	//fmt.Println("--------------------------------")
+	// 记录结束时间
+	end := time.Now()
+
+	// 计算操作耗时
+	duration := end.Sub(start)
+	rows.Close()
+
+	sqlResult += fmt.Sprintf("\nTotal %d records.\n", records)
+
+	sqlResult += fmt.Sprintf("\nUse time:%s ms.", strings.Replace(duration.String(), "µs", "", -1))
+	fmt.Println("sqlResult:", sqlResult)
+	return sqlResult
+}
+
+func ExecString(db *sql.DB, sql string) string {
+	var sqlResult string
+	start := time.Now()
+	result, err := db.Exec(sql)
+	if err != nil {
+		log.Fatal(err)
+	}
+	// 记录结束时间
+	end := time.Now()
+
+	// 计算操作耗时
+	duration := end.Sub(start)
+	sqlResult += fmt.Sprintf("SQL> %s", sql+"\n\n")
+	// 获取影响的行数
+	rowsAffected, err := result.RowsAffected()
+	if err != nil {
+		log.Fatal(err)
+	}
+	//fmt.Printf("Rows affected: %d\n", rowsAffected)
+
+	sqlResult += fmt.Sprintf("Total %d records effected.", rowsAffected)
+	sqlResult += fmt.Sprintf("\nUse time:%s ms.", strings.Replace(duration.String(), "µs", "", -1))
+	fmt.Println("sqlResult", sqlResult)
+
+	return sqlResult
+}
+
+func ExecPrepareString(db1 *sql.DB, sql string, fileLocal []string) {
+
+	//var sqlResult string
+	fmt.Println("fileLocal的数量: ", len(fileLocal))
+	var args []interface{}
+	for _, v := range fileLocal {
+
+		// 读取图像文件
+		v := strings.ReplaceAll(v, " ", "")
+		fmt.Println("文件地址:", v)
+		imageData, err := os.ReadFile(v)
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		args = append(args, &imageData)
+	}
+
+	fmt.Println("sql查询:", sql)
+	stmt, err := db.Prepare(sql)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	_, err = stmt.Exec(args...)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// // 获取影响的行数
+	// rowsAffected, err := result.RowsAffected()
+	// if err != nil {
+	// 	log.Fatal(err)
+	// }
+	// sqlResult += fmt.Sprintf("Total %d records effected.", rowsAffected)
+	// sqlResult += fmt.Sprintf("\nUse time:1 ms.")
+	// return sqlResult
+}

+ 59 - 0
internal/dbBase/db_test.go

@@ -0,0 +1,59 @@
+package dbBase
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"testing"
+)
+
+func TestDbLink(t1 *testing.T) {
+
+	InitDb("10.28.20.101", "5190", "TESTDB", "SYSDBA", "SYSDBA")
+	db := GetDb()
+	defer db.Close()
+
+}
+
+func TestIns(t1 *testing.T) {
+
+	InitDb("10.28.20.101", "5190", "TESTDB", "SYSDBA", "SYSDBA")
+	db := GetDb()
+	defer db.Close()
+	a := "<# /home/gtong/xugu_work/xgtest/file/test_pic_1.png;"
+	ExecString(db, fmt.Sprintf("insert into t3 values(%s,'a');", a))
+}
+
+func TestInsPrepare(t1 *testing.T) {
+
+	InitDb("10.28.20.101", "5190", "TESTDB", "SYSDBA", "SYSDBA")
+	db := GetDb()
+	defer db.Close()
+	var args []interface{}
+	// 读取图像文件
+	imageData, err := os.ReadFile("/home/gtong/xugu_work/xgtest/file/test_pic_1.png")
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	stmt, err := db.Prepare("insert into t3 values(?,'a')")
+	if err != nil {
+		log.Fatal(err)
+	}
+	args = append(args, imageData)
+	_, err = stmt.Exec(args...)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	stmt.Close()
+}
+
+func TestInsPrepare2(t1 *testing.T) {
+
+	InitDb("10.28.20.101", "5190", "TESTDB", "SYSDBA", "SYSDBA")
+	db := GetDb()
+	defer db.Close()
+	abc := []string{" ../../file/test.txt"}
+	ExecPrepareString(db, "     insert into t3 values(?,'a');", abc)
+}

+ 89 - 0
internal/logs/logs.go

@@ -0,0 +1,89 @@
+package logs
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"path"
+	"time"
+
+	"github.com/sirupsen/logrus"
+)
+
+var Log *logrus.Logger
+
+const (
+	red    = 31
+	yellow = 33
+	blue   = 36
+	gray   = 37
+)
+
+type LogFormatter struct {
+}
+
+func (t LogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
+
+	//根据不同的level展示颜色
+	var levelColor int
+	switch entry.Level {
+	case logrus.DebugLevel, logrus.TraceLevel:
+		levelColor = gray
+	case logrus.WarnLevel:
+		levelColor = yellow
+	case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
+		levelColor = red
+	default:
+		levelColor = blue
+	}
+
+	//字节缓冲区
+	var b *bytes.Buffer
+	if entry.Buffer != nil {
+		b = entry.Buffer
+	} else {
+		b = &bytes.Buffer{}
+	}
+	//自定义日期格式
+	timestamp := entry.Time.Format("2006-01-02 15:04:06")
+	if entry.HasCaller() {
+		//自定义文件路径
+		//fmt.Println("自定义文件路径")
+		funcVal := entry.Caller.Function
+		fileVal := fmt.Sprintf("%s:%d", path.Base(entry.Caller.File), entry.Caller.Line)
+		//自定义输出格式
+		fmt.Fprintf(b, "[%s] \033[%dm[%s]\033[0m %s %s %s \n", timestamp, levelColor, entry.Level, fileVal, funcVal, entry.Message)
+	} else {
+		fmt.Println(" else else自定义文件路径")
+		fmt.Fprintf(b, "[%s] \033[%dm[%s]\033[0m %s  %s %s  \n", timestamp, levelColor, entry.Level, entry.Message)
+	}
+
+	return b.Bytes(), nil
+}
+func InitLogger() *logrus.Logger {
+	// 定义logs文件夹的路径
+	logsDir := "./logs"
+
+	// 尝试获取logs文件夹的信息
+	_, err := os.Stat(logsDir)
+	if os.IsNotExist(err) {
+		// 如果文件夹不存在,则创建它
+		err = os.MkdirAll(logsDir, 0755)
+		if err != nil {
+			// 处理创建文件夹时可能遇到的错误
+			fmt.Println("创建文件夹时出错:", err)
+		}
+	}
+
+	mLog := logrus.New() //新建一个实例
+	currentTime := time.Now().Format("2006-01-02 15.04.06")
+	logName := "./logs/xuguALL_" + currentTime + "txt"
+	file, _ := os.OpenFile(logName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0755)
+	mLog.SetOutput(io.MultiWriter(os.Stdout, file)) //设置输出类型
+	mLog.SetReportCaller(true)                      //开启返回函数名和行号
+	//mLog.SetFormatter(&logrus.JSONFormatter{})//设置自定义的Formatter
+	mLog.SetFormatter(&LogFormatter{}) //设置自定义的Formatter
+	mLog.SetLevel(logrus.DebugLevel)   //设置最低等级
+	return mLog
+}

+ 101 - 0
internal/produce/image.go

@@ -0,0 +1,101 @@
+package produce
+
+import (
+	"bytes"
+	"fmt"
+	"image/png"
+	"os"
+
+	"github.com/fogleman/gg"
+)
+
+type imageInfo struct {
+	dc *gg.Context
+}
+
+func (*imageInfo) Runimage(s string) ([]byte, error) {
+	// 创建一个新的gg.Context实例,根据字符串长度动态设置图像大小
+	const padding = 20    // 上下留白
+	const charWidth = 10  // 字符宽度
+	const lineHeight = 15 // 行高
+	const maxWidth = 800  // 最大宽度
+
+	// 计算图像高度和行数
+	lines := 0
+	width := 0.0
+	height := padding * 2
+	lineWidth := 0.0
+	dc := gg.NewContext(1, 1)
+	//加载字体和字体大小
+	if err := dc.LoadFontFace("../assets/SimHei.ttf", 12); err != nil {
+		fmt.Println(err.Error())
+		return nil, nil
+	}
+	//计算图像高度和行数
+	for _, r := range s {
+		w, _ := dc.MeasureString(string(r))
+		if r == '\n' || lineWidth+w > float64(maxWidth-padding*2) {
+			lines++
+			if lineWidth > width {
+				width = lineWidth
+			}
+			lineWidth = 0.0
+		}
+		lineWidth += w
+	}
+
+	lines++
+	if lineWidth > width {
+		width = lineWidth
+	}
+	height += (lines) * lineHeight
+
+	dc = gg.NewContext(int(width+float64(padding*2)), int(height))
+	dc.SetRGB(0, 0, 0)
+	dc.Clear()
+	dc.SetRGB(1, 1, 1)
+
+	// 绘制字符串
+	x := padding
+	y := padding
+	lineWidth = 0.0
+	for _, r := range s {
+		w, _ := dc.MeasureString(string(r))
+		if r == '\n' || lineWidth+w > float64(maxWidth-padding*2) {
+			y += lineHeight
+			lineWidth = 0.0
+			if r == '\n' {
+				continue
+			}
+		}
+		dc.DrawString(string(r), float64(x)+lineWidth, float64(y))
+		lineWidth += w
+	}
+
+	// 将图像编码为PNG格式的二进制数据
+	var buf bytes.Buffer
+	if err := png.Encode(&buf, dc.Image()); err != nil {
+		return nil, nil
+	}
+	//SaveImage(dc, "")
+	return buf.Bytes(), nil
+}
+
+func (im *imageInfo) SaveImage(fileName string) {
+	// 保存图片
+	name := "../file/test_pic_1.png"
+	newfile, err := os.Create(name)
+	if err != nil {
+		fmt.Println(err.Error())
+		return
+	}
+	defer newfile.Close()
+
+	// 将文件保存输出,并设置压缩比
+	//err = jpeg.Encode(newfile, dc.Image(), &jpeg.Options{Quality: 150})
+	err = png.Encode(newfile, im.dc.Image())
+	if err != nil {
+		fmt.Println(err.Error())
+		return
+	}
+}

+ 47 - 0
internal/utils/print_Fmt.go

@@ -0,0 +1,47 @@
+package utils
+
+import (
+	"fmt"
+	"strings"
+)
+
+// 定义一个自定义类型
+type MyFmt struct {
+	str string
+}
+
+// 实现 Stringer 接口
+func (m MyFmt) String() string {
+	return fmt.Sprintf("---------------------%v----------------------", m.str)
+}
+
+func (m MyFmt) SetStr(str string) string {
+	m.str = str
+	return m.str
+}
+func SplitFileLocal(sql string) []string {
+	fmt.Println("SplitFileLocal.sql = ", sql)
+	var fileLocal []string
+	var f func(sql string)
+	f = func(sql string) {
+		// 找到第一个<的位置
+		semicolonIndex := strings.Index(sql, "<")
+		if semicolonIndex != -1 {
+			lastIndex := strings.LastIndex(sql, "<")
+			fileLocal = append(fileLocal, sql[lastIndex+2:])
+			fmt.Println(" rear[lastIndex+2:]", sql[lastIndex+2:])
+			sql = sql[:lastIndex]
+			fmt.Println(" sql[:lastIndex]", sql[:lastIndex])
+			f(sql)
+		} else {
+			fmt.Println("未找到<。")
+		}
+	}
+	f(sql)
+
+	for i, j := 0, len(fileLocal)-1; i < j; i, j = i+1, j-1 {
+		fileLocal[i], fileLocal[j] = fileLocal[j], fileLocal[i]
+	}
+	fmt.Printf("\nfileLocal排序后:%v\n", fileLocal)
+	return fileLocal
+}

+ 38 - 0
internal/utils/utils.go

@@ -0,0 +1,38 @@
+package utils
+
+import (
+	"fmt"
+	"regexp"
+	"strings"
+)
+
+// 切分;分号前后,分为俩个字符串
+func SplitSemicolon(sql string) (string, string) {
+	// 找到第一个分号的位置
+	semicolonIndex := strings.Index(sql, ";")
+
+	if semicolonIndex != -1 {
+		// 切分分号前的语句
+		front := sql[:semicolonIndex+1]
+		rear := sql[semicolonIndex+1:]
+		return front, rear
+	} else {
+		fmt.Println("未找到分号。")
+		return "", ""
+	}
+}
+
+// 检查字符串中是否包含指定的关键字
+func ContainsKeyword(input string, keyword string) bool {
+	return strings.Contains(input, keyword)
+}
+
+func IsInsertBlob(input string) int {
+
+	re := regexp.MustCompile(`values\(([^)]*)\)`)
+	match := re.FindStringSubmatch(input)
+	if len(match) > 1 {
+		return strings.Count(match[1], "?")
+	}
+	return 0
+}

+ 7 - 0
logs/xuguALL_2024-03-25 11.07.24txt

@@ -0,0 +1,7 @@
+[2024-03-25 11:07:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString 
+QueryString().sql: 
+%!(EXTRA string=select * from t3;) 
+[2024-03-25 11:07:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: 
+%!(EXTRA string=select * from t3;) 
+[2024-03-25 11:07:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t3;
+ 

+ 6 - 0
logs/xuguALL_2024-03-25 11.14.24txt

@@ -0,0 +1,6 @@
+[2024-03-25 11:14:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t3;
+ 
+[2024-03-25 11:14:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t1;
+ 
+[2024-03-25 11:14:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t2;
+ 

+ 4 - 0
logs/xuguALL_2024-03-25 11.15.24txt

@@ -0,0 +1,4 @@
+[2024-03-25 11:15:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t1;
+ 
+[2024-03-25 11:15:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t2;
+ 

+ 12 - 0
logs/xuguALL_2024-03-25 11.16.24txt

@@ -0,0 +1,12 @@
+[2024-03-25 11:16:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t1;
+ 
+[2024-03-25 11:16:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t2;
+ 
+[2024-03-25 11:16:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t4;
+ 
+[2024-03-25 11:16:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t1;
+ 
+[2024-03-25 11:16:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t2;
+ 
+[2024-03-25 11:16:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t4;
+ 

+ 0 - 0
logs/xuguALL_2024-03-25 11.22.24txt


+ 6 - 0
logs/xuguALL_2024-03-25 11.27.24txt

@@ -0,0 +1,6 @@
+[2024-03-25 11:27:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t1;
+ 
+[2024-03-25 11:27:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t2;
+ 
+[2024-03-25 11:27:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t4;
+ 

+ 6 - 0
logs/xuguALL_2024-03-25 11.48.24txt

@@ -0,0 +1,6 @@
+[2024-03-25 11:48:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t1;
+ 
+[2024-03-25 11:48:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t2;
+ 
+[2024-03-25 11:48:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t4;
+ 

+ 6 - 0
logs/xuguALL_2024-03-25 11.50.24txt

@@ -0,0 +1,6 @@
+[2024-03-25 11:50:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t1;
+ 
+[2024-03-25 11:50:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t2;
+ 
+[2024-03-25 11:50:24] [info] db.go:37 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t4;
+ 

+ 6 - 0
logs/xuguALL_2024-03-25 11.53.24txt

@@ -0,0 +1,6 @@
+[2024-03-25 11:53:24] [info] db.go:38 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t1;
+ 
+[2024-03-25 11:53:24] [info] db.go:38 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t2;
+ 
+[2024-03-25 11:53:24] [info] db.go:38 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t4;
+ 

+ 6 - 0
logs/xuguALL_2024-03-25 11.54.24txt

@@ -0,0 +1,6 @@
+[2024-03-25 11:54:24] [info] db.go:38 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t1;
+ 
+[2024-03-25 11:54:24] [info] db.go:38 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t2;
+ 
+[2024-03-25 11:54:24] [info] db.go:38 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t4;
+ 

+ 6 - 0
logs/xuguALL_2024-03-25 11.57.24txt

@@ -0,0 +1,6 @@
+[2024-03-25 11:57:24] [info] db.go:38 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t1;
+ 
+[2024-03-25 11:57:24] [info] db.go:38 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t2;
+ 
+[2024-03-25 11:57:24] [info] db.go:38 xgAutoTest/internal/dbBase.QueryString QueryString().sql: select * from t4;
+ 

+ 16 - 0
main.go

@@ -0,0 +1,16 @@
+package main
+
+import (
+	"xgAutoTest/internal/auto"
+	"xgAutoTest/internal/dbBase"
+	"xgAutoTest/internal/logs"
+)
+
+func main() {
+	logs.Log = logs.InitLogger()
+	dbBase.InitDb("10.28.20.101", "5190", "TESTDB", "SYSDBA", "SYSDBA")
+	auto.AutoRun()
+	db := dbBase.GetDb()
+	defer db.Close()
+
+}

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


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

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

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

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

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

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

+ 220 - 0
pkg/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
pkg/go-driver-xugusql/xugusql_connector.go

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

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

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

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

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

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

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

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

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

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

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

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

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