package xugu import ( "context" "database/sql/driver" "fmt" "net" "strings" "time" ) // SQL类型常量 const ( SQL_UNKNOWN = iota SQL_SELECT SQL_INSERT SQL_UPDATE SQL_DELETE SQL_CREATE SQL_ALTER SQL_PROCEDURE SQL_OTHER ) const ( XG_OK = iota ) 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 } // func NewConnector(dsn string) *connector { // dsnL := strings.ToLower(dsn) // fmt.Println("dsnL: ", dsnL) // return &connector{dsn: dsnL} // } var IPS_COUNTER int = 0 // Driver implements driver.Connector interface. // Driver returns &XuguDriver{} func (self *connector) Driver() driver.Driver { return &XuguDriver{} } // 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) dsnConfig := parseDSN(self.dsn) fmt.Println("self.dsn:", strings.ToLower(self.dsn)) obj.dsnConfig = dsnConfig fmt.Println("connector: ", self.dsn) fmt.Println("dsnConfig: ", dsnConfig) defer func() { // cgo_c_free(unsafe.Pointer(connKeyValue)) }() re, _ := xg_connect(ctx, obj) if re < 0 { return nil, obj.get_error() // pos := strings.Index(strings.ToUpper(self.dsn), "IPS=") // if pos != -1 { // IPS_COUNTER++ // re := xgc_connect_ips(ctx, &self.dsn, &obj.conn) // if re < 0 { // return nil, obj.get_error() // } // } else { // re, _ := xgc_connect(ctx, self.dsn, &obj.conn) // if re < 0 { // return nil, obj.get_error() // } } return obj, nil } func xg_connect(ctx context.Context, __pConn *xugusqlConn) (int, error) { return xgSockOpenConn(ctx, __pConn) } // ips未实现 func xg_connect_ips(ctx context.Context, __pConn *net.Conn) int { return 0 } func xgSockOpenConn(ctx context.Context, __pConn *xugusqlConn) (int, error) { fmt.Println("XGSOpenConn") nd := net.Dialer{Timeout: 5 * time.Second} netConn, err := nd.DialContext(ctx, "tcp", fmt.Sprintf("%s:%s", __pConn.IP, __pConn.Port)) if err != nil { fmt.Println("tcp", err) return -8, err } // 启用 TCP 保活 if tc, ok := netConn.(*net.TCPConn); ok { if err := tc.SetKeepAlive(true); err != nil { //c.cfg.Logger.Print(err) // 如果设置保活失败,记录错误但不终止 } } //发送 //fmt.Printf("login database = '%s' user = '%s' password = '%s' version='201' ", __pConn.Database, __pConn.User, __pConn.Password) // message := "login database = 'SYSTEM' user = 'SYSDBA' password = 'SYSDBA' version='201' " dsnMessage := generateLoginString(__pConn.dsnConfig) _, err = netConn.Write([]byte(dsnMessage)) if err != nil { fmt.Println("发送数据失败:", err) } fmt.Println("数据已发送:", dsnMessage) buffer := make([]byte, 1024) n, err := __pConn.conn.Read(buffer) if err != nil { fmt.Println("Error reading from server:", err) } fmt.Println("Message from server:", string(buffer[:n])) return 1, nil } func parseDSN(dsn string) dsnConfig { // Initialize a dsnConfig struct var config dsnConfig // Split the string by semicolons pairs := strings.Split(dsn, ";") // Iterate over the pairs and map them to the struct fields for _, pair := range pairs { // Split each pair by the equals sign kv := strings.SplitN(pair, "=", 2) if len(kv) != 2 { continue } key, value := strings.TrimSpace(kv[0]), strings.Trim(strings.TrimSpace(kv[1]), "'") keyL := strings.ToLower(key) // Map the key to the appropriate struct field switch keyL { case "ip": config.IP = value case "port": config.Port = value case "db": config.Database = value case "user": config.User = value case "pwd": config.Password = value case "encryptor": config.Encryptor = value case "char_set": config.CharSet = value case "time_zone": config.TimeZone = value case "iso_level": config.IsoLevel = value case "lock_timeout": config.LockTimeout = value case "auto_commit": config.AutoCommit = value case "strict_commit": config.StrictCommit = value case "result": config.Result = value case "return_schema": config.ReturnSchema = value case "return_cursor_id": config.ReturnCursorID = value case "lob_ret": config.LobRet = value case "return_rowid": config.ReturnRowid = value case "version": config.Version = value } } return config } func generateLoginString(config dsnConfig) string { baseString := "login database = '%s' user = '%s' password = '%s' " additionalParams := "" if config.Encryptor != "" { additionalParams += fmt.Sprintf(" encryptor='%s'", config.Encryptor) } if config.CharSet != "" { additionalParams += fmt.Sprintf(" char_set='%s'", config.CharSet) } if config.TimeZone != "" { additionalParams += fmt.Sprintf(" time_zone='%s'", config.TimeZone) } if config.IsoLevel != "" { additionalParams += fmt.Sprintf(" iso_level='%s'", config.IsoLevel) } if config.LockTimeout != "" { additionalParams += fmt.Sprintf(" lock_timeout='%s'", config.LockTimeout) } if config.AutoCommit != "" { additionalParams += fmt.Sprintf(" auto_commit='%s'", config.AutoCommit) } if config.StrictCommit != "" { additionalParams += fmt.Sprintf(" strict_commit='%s'", config.StrictCommit) } if config.Result != "" { additionalParams += fmt.Sprintf(" result='%s'", config.Result) } if config.ReturnSchema != "" { additionalParams += fmt.Sprintf(" return_schema='%s'", config.ReturnSchema) } if config.ReturnCursorID != "" { additionalParams += fmt.Sprintf(" return_cursor_id='%s'", config.ReturnCursorID) } if config.LobRet != "" { additionalParams += fmt.Sprintf(" lob_ret='%s'", config.LobRet) } if config.ReturnRowid != "" { additionalParams += fmt.Sprintf(" return_rowid='%s'", config.ReturnRowid) } if config.Version != "" { additionalParams += fmt.Sprintf(" version='%s'", config.Version) } else { additionalParams += " version='201'" } finalString := fmt.Sprintf(baseString, config.Database, config.User, config.Password) if additionalParams != "" { finalString += additionalParams } //finalString += " version='201'" return finalString }