diff --git a/.gitignore b/.gitignore index 66fd13c..3fa5ce2 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,9 @@ # Dependency directories (remove the comment below to include it) # vendor/ + +# IDE +.idea + +# sys +go.sum diff --git a/clauses/merge.go b/clauses/merge.go new file mode 100644 index 0000000..d661d64 --- /dev/null +++ b/clauses/merge.go @@ -0,0 +1,49 @@ +package clauses + +import ( + "gorm.io/gorm/clause" +) + +type Merge struct { + Table clause.Table + Using []clause.Interface + On []clause.Expression +} + +func (merge Merge) Name() string { + return "MERGE" +} + +func MergeDefaultExcludeName() string { + return "exclude" +} + +// Build build from clause +func (merge Merge) Build(builder clause.Builder) { + clause.Insert{}.Build(builder) + builder.WriteString(" USING (") + for idx, iface := range merge.Using { + if idx > 0 { + builder.WriteByte(' ') + } + builder.WriteString(iface.Name()) + builder.WriteByte(' ') + iface.Build(builder) + } + builder.WriteString(") ") + builder.WriteString(MergeDefaultExcludeName()) + builder.WriteString(" ON (") + for idx, on := range merge.On { + if idx > 0 { + builder.WriteString(", ") + } + on.Build(builder) + } + builder.WriteString(")") +} + +// MergeClause merge values clauses +func (merge Merge) MergeClause(clause *clause.Clause) { + clause.Name = merge.Name() + clause.Expression = merge +} diff --git a/clauses/returning_into.go b/clauses/returning_into.go new file mode 100644 index 0000000..0f2857b --- /dev/null +++ b/clauses/returning_into.go @@ -0,0 +1,10 @@ +package clauses + +import ( + "gorm.io/gorm/clause" +) + +type ReturningInto struct { + Variables []clause.Column + Into []*clause.Values +} diff --git a/clauses/when_matched.go b/clauses/when_matched.go new file mode 100644 index 0000000..b44cfb7 --- /dev/null +++ b/clauses/when_matched.go @@ -0,0 +1,39 @@ +package clauses + +import ( + "gorm.io/gorm/clause" +) + +type WhenMatched struct { + clause.Set + Where, Delete clause.Where +} + +func (w WhenMatched) Name() string { + return "WHEN MATCHED" +} + +func (w WhenMatched) Build(builder clause.Builder) { + if len(w.Set) > 0 { + builder.WriteString(" THEN") + builder.WriteString(" UPDATE ") + builder.WriteString(w.Name()) + builder.WriteByte(' ') + w.Build(builder) + + buildWhere := func(where clause.Where) { + builder.WriteString(where.Name()) + builder.WriteByte(' ') + where.Build(builder) + } + + if len(w.Where.Exprs) > 0 { + buildWhere(w.Where) + } + + if len(w.Delete.Exprs) > 0 { + builder.WriteString(" DELETE ") + buildWhere(w.Delete) + } + } +} diff --git a/clauses/when_not_matched.go b/clauses/when_not_matched.go new file mode 100644 index 0000000..8877554 --- /dev/null +++ b/clauses/when_not_matched.go @@ -0,0 +1,32 @@ +package clauses + +import ( + "gorm.io/gorm/clause" +) + +type WhenNotMatched struct { + clause.Values + Where clause.Where +} + +func (w WhenNotMatched) Name() string { + return "WHEN NOT MATCHED" +} + +func (w WhenNotMatched) Build(builder clause.Builder) { + if len(w.Columns) > 0 { + if len(w.Values.Values) != 1 { + panic("cannot insert more than one rows due to DM SQL language restriction") + } + + builder.WriteString(" THEN") + builder.WriteString(" INSERT ") + w.Build(builder) + + if len(w.Where.Exprs) > 0 { + builder.WriteString(w.Where.Name()) + builder.WriteByte(' ') + w.Where.Build(builder) + } + } +} diff --git a/create.go b/create.go new file mode 100644 index 0000000..8519d5b --- /dev/null +++ b/create.go @@ -0,0 +1,154 @@ +package dm + +import ( + "bytes" + "database/sql" + "reflect" + + "github.com/thoas/go-funk" + "gorm.io/gorm" + "gorm.io/gorm/callbacks" + "gorm.io/gorm/clause" + gormSchema "gorm.io/gorm/schema" + + "github.com/nfjBill/gorm-driver-dm/clauses" +) + +func Create(db *gorm.DB) { + stmt := db.Statement + schema := stmt.Schema + boundVars := make(map[string]int) + + if stmt == nil || schema == nil { + return + } + + hasDefaultValues := len(schema.FieldsWithDefaultDBValue) > 0 + + if !stmt.Unscoped { + for _, c := range schema.CreateClauses { + stmt.AddClause(c) + } + } + + if stmt.SQL.String() == "" { + values := callbacks.ConvertToCreateValues(stmt) + onConflict, hasConflict := stmt.Clauses["ON CONFLICT"].Expression.(clause.OnConflict) + // are all columns in value the primary fields in schema only? + if hasConflict && funk.Contains( + funk.Map(values.Columns, func(c clause.Column) string { return c.Name }), + funk.Map(schema.PrimaryFields, func(field *gormSchema.Field) string { return field.DBName }), + ) { + stmt.AddClauseIfNotExists(clauses.Merge{ + Using: []clause.Interface{ + clause.Select{ + Columns: funk.Map(values.Columns, func(column clause.Column) clause.Column { + // HACK: I can not come up with a better alternative for now + // I want to add a value to the list of variable and then capture the bind variable position as well + buf := bytes.NewBufferString("") + stmt.Vars = append(stmt.Vars, values.Values[0][funk.IndexOf(values.Columns, column)]) + stmt.BindVarTo(buf, stmt, nil) + + column.Alias = column.Name + // then the captured bind var will be the name + column.Name = buf.String() + return column + }).([]clause.Column), + }, + clause.From{ + Tables: []clause.Table{{Name: db.Dialector.(Dialector).DummyTableName()}}, + }, + }, + On: funk.Map(schema.PrimaryFields, func(field *gormSchema.Field) clause.Expression { + return clause.Eq{ + Column: clause.Column{Table: stmt.Table, Name: field.DBName}, + Value: clause.Column{Table: clauses.MergeDefaultExcludeName(), Name: field.DBName}, + } + }).([]clause.Expression), + }) + stmt.AddClauseIfNotExists(clauses.WhenMatched{Set: onConflict.DoUpdates}) + stmt.AddClauseIfNotExists(clauses.WhenNotMatched{Values: values}) + + stmt.Build("MERGE", "WHEN MATCHED", "WHEN NOT MATCHED") + } else { + stmt.AddClauseIfNotExists(clause.Insert{Table: clause.Table{Name: stmt.Table}}) + stmt.AddClause(clause.Values{Columns: values.Columns, Values: [][]interface{}{values.Values[0]}}) + if hasDefaultValues { + stmt.AddClauseIfNotExists(clause.Returning{ + Columns: funk.Map(schema.FieldsWithDefaultDBValue, func(field *gormSchema.Field) clause.Column { + return clause.Column{Name: field.DBName} + }).([]clause.Column), + }) + } + stmt.Build("INSERT", "VALUES") + // 返回自增主键 + //stmt.Build("INSERT", "VALUES", "RETURNING") + //if hasDefaultValues { + // stmt.WriteString(" INTO ") + // for idx, field := range schema.FieldsWithDefaultDBValue { + // if idx > 0 { + // stmt.WriteByte(',') + // } + // boundVars[field.Name] = len(stmt.Vars) + // stmt.AddVar(stmt, sql.Out{Dest: reflect.New(field.FieldType).Interface()}) + // } + //} + } + + if !db.DryRun { + for idx, vals := range values.Values { + // HACK HACK: replace values one by one, assuming its value layout will be the same all the time, i.e. aligned + for idx, val := range vals { + switch v := val.(type) { + case bool: + if v { + val = 1 + } else { + val = 0 + } + } + + stmt.Vars[idx] = val + } + // and then we insert each row one by one then put the returning values back (i.e. last return id => smart insert) + // we keep track of the index so that the sub-reflected value is also correct + + // BIG BUG: what if any of the transactions failed? some result might already be inserted that dm is so + // sneaky that some transaction inserts will exceed the buffer and so will be pushed at unknown point, + // resulting in dangling row entries, so we might need to delete them if an error happens + + switch result, err := stmt.ConnPool.ExecContext(stmt.Context, stmt.SQL.String(), stmt.Vars...); err { + case nil: // success + db.RowsAffected, _ = result.RowsAffected() + + insertTo := stmt.ReflectValue + switch insertTo.Kind() { + case reflect.Slice, reflect.Array: + insertTo = insertTo.Index(idx) + } + + if hasDefaultValues { + // bind returning value back to reflected value in the respective fields + funk.ForEach( + funk.Filter(schema.FieldsWithDefaultDBValue, func(field *gormSchema.Field) bool { + return funk.Contains(boundVars, field.Name) + }), + func(field *gormSchema.Field) { + switch insertTo.Kind() { + case reflect.Struct: + if err = field.Set(insertTo, stmt.Vars[boundVars[field.Name]].(sql.Out).Dest); err != nil { + db.AddError(err) + } + case reflect.Map: + // todo 设置id的值 + } + }, + ) + } + default: // failure + db.AddError(err) + } + } + } + } +} diff --git a/dm.go b/dm.go new file mode 100644 index 0000000..5f371e9 --- /dev/null +++ b/dm.go @@ -0,0 +1,236 @@ +package dm + +import ( + "database/sql" + "fmt" + "gorm.io/gorm/utils" + "regexp" + "strconv" + "strings" + + _ "github.com/nfjBill/gorm-driver-dm/dmr" + "github.com/thoas/go-funk" + "gorm.io/gorm" + "gorm.io/gorm/callbacks" + "gorm.io/gorm/clause" + "gorm.io/gorm/logger" + "gorm.io/gorm/migrator" + "gorm.io/gorm/schema" +) + +type Config struct { + DriverName string + DSN string + Conn *sql.DB + DefaultStringSize uint +} + +type Dialector struct { + *Config +} + +func Open(dsn string) gorm.Dialector { + return &Dialector{Config: &Config{DSN: dsn}} +} + +func New(config Config) gorm.Dialector { + return &Dialector{Config: &config} +} + +func (d Dialector) DummyTableName() string { + return "DUAL" +} + +func (d Dialector) Name() string { + return "dm" +} + +func (d Dialector) Initialize(db *gorm.DB) (err error) { + db.NamingStrategy = Namer{} + d.DefaultStringSize = 1024 + + // register callbacks + callbacks.RegisterDefaultCallbacks(db, &callbacks.Config{}) + + d.DriverName = "dm" + + if d.Conn != nil { + db.ConnPool = d.Conn + } else { + db.ConnPool, err = sql.Open(d.DriverName, d.DSN) + } + + if err = db.Callback().Create().Replace("gorm:create", Create); err != nil { + return + } + + for k, v := range d.ClauseBuilders() { + db.ClauseBuilders[k] = v + } + return +} + +func (d Dialector) ClauseBuilders() map[string]clause.ClauseBuilder { + return map[string]clause.ClauseBuilder{ + "LIMIT": d.RewriteLimit, + } +} + +func (d Dialector) RewriteLimit(c clause.Clause, builder clause.Builder) { + if limit, ok := c.Expression.(clause.Limit); ok { + if stmt, ok := builder.(*gorm.Statement); ok { + if _, ok := stmt.Clauses["ORDER BY"]; !ok { + s := stmt.Schema + builder.WriteString("ORDER BY ") + if s != nil && s.PrioritizedPrimaryField != nil { + builder.WriteQuoted(s.PrioritizedPrimaryField.DBName) + builder.WriteByte(' ') + } else { + builder.WriteString("(SELECT NULL FROM ") + builder.WriteString(d.DummyTableName()) + builder.WriteString(")") + } + } + } + + if offset := limit.Offset; offset > 0 { + builder.WriteString(" OFFSET ") + builder.WriteString(strconv.Itoa(offset)) + builder.WriteString(" ROWS") + } + if limit := limit.Limit; limit > 0 { + builder.WriteString(" FETCH NEXT ") + builder.WriteString(strconv.Itoa(limit)) + builder.WriteString(" ROWS ONLY") + } + } +} + +func (d Dialector) DefaultValueOf(*schema.Field) clause.Expression { + return clause.Expr{SQL: "VALUES (DEFAULT)"} +} + +func (d Dialector) Migrator(db *gorm.DB) gorm.Migrator { + return Migrator{ + Migrator: migrator.Migrator{ + Config: migrator.Config{ + DB: db, + Dialector: d, + CreateIndexAfterCreateTable: true, + }, + }, + } +} + +func (d Dialector) BindVarTo(writer clause.Writer, stmt *gorm.Statement, v interface{}) { + writer.WriteString(":") + writer.WriteString(strconv.Itoa(len(stmt.Vars))) +} + +func (d Dialector) QuoteTo(writer clause.Writer, str string) { + writer.WriteString(str) +} + +var numericPlaceholder = regexp.MustCompile(`:(\d+)`) + +func (d Dialector) Explain(sql string, vars ...interface{}) string { + return logger.ExplainSQL(sql, numericPlaceholder, `'`, funk.Map(vars, func(v interface{}) interface{} { + switch v := v.(type) { + case bool: + if v { + return 1 + } + return 0 + default: + return v + } + }).([]interface{})...) +} + +func (d Dialector) DataTypeOf(field *schema.Field) string { + if _, found := field.TagSettings["RESTRICT"]; found { + delete(field.TagSettings, "RESTRICT") + } + + var sqlType string + + switch field.DataType { + case schema.Bool, schema.Int, schema.Uint, schema.Float: + sqlType = "INTEGER" + + switch { + case field.DataType == schema.Float: + sqlType = "FLOAT" + case field.Size <= 8: + sqlType = "SMALLINT" + } + + if val, ok := field.TagSettings["AUTOINCREMENT"]; ok && utils.CheckTruth(val) { + sqlType += " GENERATED BY DEFAULT AS IDENTITY" + } + case schema.String, "VARCHAR2": + size := field.Size + defaultSize := d.DefaultStringSize + + if size == 0 { + if defaultSize > 0 { + size = int(defaultSize) + } else { + hasIndex := field.TagSettings["INDEX"] != "" || field.TagSettings["UNIQUE"] != "" + // TEXT, GEOMETRY or JSON column can't have a default value + if field.PrimaryKey || field.HasDefaultValue || hasIndex { + size = 191 // utf8mb4 + } + } + } + + if size >= 2000 { + sqlType = "CLOB" + } else { + sqlType = fmt.Sprintf("VARCHAR2(%d)", size) + } + + case schema.Time: + sqlType = "TIMESTAMP WITH TIME ZONE" + if field.NotNull || field.PrimaryKey { + sqlType += " NOT NULL" + } + case schema.Bytes: + sqlType = "BLOB" + default: + sqlType = string(field.DataType) + + if strings.EqualFold(sqlType, "text") { + sqlType = "CLOB" + } + + if sqlType == "" { + panic(fmt.Sprintf("invalid sql type %s (%s) for dm", field.FieldType.Name(), field.FieldType.String())) + } + + notNull, _ := field.TagSettings["NOT NULL"] + unique, _ := field.TagSettings["UNIQUE"] + additionalType := fmt.Sprintf("%s %s", notNull, unique) + if value, ok := field.TagSettings["DEFAULT"]; ok { + additionalType = fmt.Sprintf("%s %s %s%s", "DEFAULT", value, additionalType, func() string { + if value, ok := field.TagSettings["COMMENT"]; ok { + return " COMMENT " + value + } + return "" + }()) + } + sqlType = fmt.Sprintf("%v %v", sqlType, additionalType) + } + + return sqlType +} + +func (d Dialector) SavePoint(tx *gorm.DB, name string) error { + tx.Exec("SAVEPOINT " + name) + return tx.Error +} + +func (d Dialector) RollbackTo(tx *gorm.DB, name string) error { + tx.Exec("ROLLBACK TO SAVEPOINT " + name) + return tx.Error +} diff --git a/dm_test.go b/dm_test.go new file mode 100644 index 0000000..eaaaf2a --- /dev/null +++ b/dm_test.go @@ -0,0 +1,111 @@ +package dm + +import ( + "fmt" + dmSchema "github.com/nfjBill/gorm-driver-dm/schema" + "gorm.io/gorm" + "testing" + "time" +) + +var db *gorm.DB + +func init() { + var err error + dsn := "dm://sysdba:aaaaaaaaa@192.168.31.192:5236?autoCommit=true" + db, err = gorm.Open(Open(dsn), &gorm.Config{ + DisableForeignKeyConstraintWhenMigrating: true, + }) + + if err != nil { + fmt.Printf("Error: failed to connect dm server: %v\n", err) + return + } + + TB(db) +} + +type Model struct { + ID uint `gorm:"primarykey,autoIncrement"` + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt gorm.DeletedAt `gorm:"index"` +} + +type User struct { + Model + Key string `gorm:"index:idx_key,unique,comment:备注"` + Name string + Age int + Content dmSchema.Clob `gorm:"size:1024000"` + Birthday time.Time +} + +func TestAutoMigrate(t *testing.T) { + if Table().HasTable(&User{}) { + err := Table().DropTable(&User{}) + + if err != nil { + fmt.Printf("Error: failed to DropTable: %v\n", err) + return + } + } + + err := Table().AutoMigrate(&User{}) + + if err != nil { + fmt.Printf("Error: failed to AutoMigrate: %v\n", err) + return + } +} + +func TestCreate(t *testing.T) { + err := Table(&User{Key: "1", Name: "Jinzhu", Age: 18, Content: "asdfdasfasdfasdfj手机卡是点击", Birthday: time.Now()}).Create() + _ = Table(&User{Key: "2", Name: "Jinzhu", Age: 19, Content: "bbb", Birthday: time.Now()}).Create() + _ = Table(&User{Key: "3", Name: "Jinzhu2", Age: 20, Content: "ccc", Birthday: time.Now()}).Create() + + if err != nil { + fmt.Printf("Error: failed to Create: %v\n", err) + return + } +} + +func TestGet(t *testing.T) { + var data User + err := Table(&User{Name: "Jinzhu"}).Get(&data) + + if err != nil { + fmt.Printf("Error: failed to Get: %v\n", err) + return + } +} + +func TestWhere(t *testing.T) { + var data []User + err := Table(&User{Name: "Jinzhu"}).GetWhere(&data) + + if err != nil { + fmt.Printf("Error: failed to Where: %v\n", err) + return + } +} + +func TestAll(t *testing.T) { + var data []User + err := Table().GetAll(&data) + + if err != nil { + fmt.Printf("Error: failed to All: %v\n", err) + return + } +} + +// err +func TestClausesAssignmentColumns(t *testing.T) { + err := Table(&User{Key: "3", Content: "DDDD"}).ClausesAssignmentColumns("KEY", []string{"DELETED_AT", "CONTENT"}) + + if err != nil { + fmt.Printf("Error: failed to ClausesAssignmentColumns: %v\n", err) + return + } +} diff --git a/dmr/a.go b/dmr/a.go new file mode 100644 index 0000000..914c31b --- /dev/null +++ b/dmr/a.go @@ -0,0 +1,803 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "bytes" + "crypto/tls" + "net" + "strconv" + "time" + + "github.com/nfjBill/gorm-driver-dm/dmr/security" +) + +const ( + Dm_build_330 = 8192 + Dm_build_331 = 2 * time.Second +) + +type dm_build_332 struct { + dm_build_333 *net.TCPConn + dm_build_334 *tls.Conn + dm_build_335 *Dm_build_0 + dm_build_336 *DmConnection + dm_build_337 security.Cipher + dm_build_338 bool + dm_build_339 bool + dm_build_340 *security.DhKey + + dm_build_341 bool + dm_build_342 string + dm_build_343 bool +} + +func dm_build_344(dm_build_345 *DmConnection) (*dm_build_332, error) { + dm_build_346, dm_build_347 := dm_build_349(dm_build_345.dmConnector.host+":"+strconv.Itoa(int(dm_build_345.dmConnector.port)), time.Duration(dm_build_345.dmConnector.socketTimeout)*time.Second) + if dm_build_347 != nil { + return nil, dm_build_347 + } + + dm_build_348 := dm_build_332{} + dm_build_348.dm_build_333 = dm_build_346 + dm_build_348.dm_build_335 = Dm_build_3(Dm_build_604) + dm_build_348.dm_build_336 = dm_build_345 + dm_build_348.dm_build_338 = false + dm_build_348.dm_build_339 = false + dm_build_348.dm_build_341 = false + dm_build_348.dm_build_342 = "" + dm_build_348.dm_build_343 = false + dm_build_345.Access = &dm_build_348 + + return &dm_build_348, nil +} + +func dm_build_349(dm_build_350 string, dm_build_351 time.Duration) (*net.TCPConn, error) { + dm_build_352, dm_build_353 := net.DialTimeout("tcp", dm_build_350, dm_build_351) + if dm_build_353 != nil { + return nil, ECGO_COMMUNITION_ERROR.addDetail("\tdial address: " + dm_build_350).throw() + } + + if tcpConn, ok := dm_build_352.(*net.TCPConn); ok { + + tcpConn.SetKeepAlive(true) + tcpConn.SetKeepAlivePeriod(Dm_build_331) + tcpConn.SetNoDelay(true) + + return tcpConn, nil + } + + return nil, nil +} + +func (dm_build_355 *dm_build_332) dm_build_354(dm_build_356 dm_build_725) bool { + var dm_build_357 = dm_build_355.dm_build_336.dmConnector.compress + if dm_build_356.dm_build_740() == Dm_build_632 || dm_build_357 == Dm_build_681 { + return false + } + + if dm_build_357 == Dm_build_679 { + return true + } else if dm_build_357 == Dm_build_680 { + return !dm_build_355.dm_build_336.Local && dm_build_356.dm_build_738() > Dm_build_678 + } + + return false +} + +func (dm_build_359 *dm_build_332) dm_build_358(dm_build_360 dm_build_725) bool { + var dm_build_361 = dm_build_359.dm_build_336.dmConnector.compress + if dm_build_360.dm_build_740() == Dm_build_632 || dm_build_361 == Dm_build_681 { + return false + } + + if dm_build_361 == Dm_build_679 { + return true + } else if dm_build_361 == Dm_build_680 { + return dm_build_359.dm_build_335.Dm_build_263(Dm_build_640) == 1 + } + + return false +} + +func (dm_build_363 *dm_build_332) dm_build_362(dm_build_364 dm_build_725) (err error) { + defer func() { + if p := recover(); p != nil { + if _, ok := p.(string); ok { + err = ECGO_COMMUNITION_ERROR.addDetail("\t" + p.(string)).throw() + } else { + panic(p) + } + } + }() + + dm_build_366 := dm_build_364.dm_build_738() + + if dm_build_366 > 0 { + + if dm_build_363.dm_build_354(dm_build_364) { + var retBytes, err = Compress(dm_build_363.dm_build_335, Dm_build_633, int(dm_build_366), int(dm_build_363.dm_build_336.dmConnector.compressID)) + if err != nil { + return err + } + + dm_build_363.dm_build_335.Dm_build_14(Dm_build_633) + + dm_build_363.dm_build_335.Dm_build_51(dm_build_366) + + dm_build_363.dm_build_335.Dm_build_79(retBytes) + + dm_build_364.dm_build_739(int32(len(retBytes)) + ULINT_SIZE) + + dm_build_363.dm_build_335.Dm_build_183(Dm_build_640, 1) + } + + if dm_build_363.dm_build_339 { + dm_build_366 = dm_build_364.dm_build_738() + var retBytes = dm_build_363.dm_build_337.Encrypt(dm_build_363.dm_build_335.Dm_build_290(Dm_build_633, int(dm_build_366)), true) + + dm_build_363.dm_build_335.Dm_build_14(Dm_build_633) + + dm_build_363.dm_build_335.Dm_build_79(retBytes) + + dm_build_364.dm_build_739(int32(len(retBytes))) + } + } + + if dm_build_363.dm_build_335.Dm_build_12() > Dm_build_605 { + return ECGO_MSG_TOO_LONG.throw() + } + + dm_build_364.dm_build_734() + if dm_build_363.dm_build_594(dm_build_364) { + if dm_build_363.dm_build_334 != nil { + dm_build_363.dm_build_335.Dm_build_17(0) + dm_build_363.dm_build_335.Dm_build_36(dm_build_363.dm_build_334) + } + } else { + dm_build_363.dm_build_335.Dm_build_17(0) + dm_build_363.dm_build_335.Dm_build_36(dm_build_363.dm_build_333) + } + return nil +} + +func (dm_build_368 *dm_build_332) dm_build_367(dm_build_369 dm_build_725) (err error) { + defer func() { + if p := recover(); p != nil { + if _, ok := p.(string); ok { + err = ECGO_COMMUNITION_ERROR.addDetail("\t" + p.(string)).throw() + } else { + panic(p) + } + } + }() + + dm_build_371 := int32(0) + if dm_build_368.dm_build_594(dm_build_369) { + if dm_build_368.dm_build_334 != nil { + dm_build_368.dm_build_335.Dm_build_14(0) + dm_build_368.dm_build_335.Dm_build_30(dm_build_368.dm_build_334, Dm_build_633) + dm_build_371 = dm_build_369.dm_build_738() + if dm_build_371 > 0 { + dm_build_368.dm_build_335.Dm_build_30(dm_build_368.dm_build_334, int(dm_build_371)) + } + } + } else { + + dm_build_368.dm_build_335.Dm_build_14(0) + dm_build_368.dm_build_335.Dm_build_30(dm_build_368.dm_build_333, Dm_build_633) + dm_build_371 = dm_build_369.dm_build_738() + + if dm_build_371 > 0 { + dm_build_368.dm_build_335.Dm_build_30(dm_build_368.dm_build_333, int(dm_build_371)) + } + } + + dm_build_369.dm_build_735() + + dm_build_371 = dm_build_369.dm_build_738() + if dm_build_371 <= 0 { + return nil + } + + if dm_build_368.dm_build_339 { + ebytes := dm_build_368.dm_build_335.Dm_build_290(Dm_build_633, int(dm_build_371)) + bytes, err := dm_build_368.dm_build_337.Decrypt(ebytes, true) + if err != nil { + return err + } + dm_build_368.dm_build_335.Dm_build_14(Dm_build_633) + dm_build_368.dm_build_335.Dm_build_79(bytes) + dm_build_369.dm_build_739(int32(len(bytes))) + } + + if dm_build_368.dm_build_358(dm_build_369) { + + dm_build_371 = dm_build_369.dm_build_738() + cbytes := dm_build_368.dm_build_335.Dm_build_290(Dm_build_633+ULINT_SIZE, int(dm_build_371-ULINT_SIZE)) + bytes, err := UnCompress(cbytes, int(dm_build_368.dm_build_336.dmConnector.compressID)) + if err != nil { + return err + } + dm_build_368.dm_build_335.Dm_build_14(Dm_build_633) + dm_build_368.dm_build_335.Dm_build_79(bytes) + dm_build_369.dm_build_739(int32(len(bytes))) + } + return nil +} + +func (dm_build_373 *dm_build_332) dm_build_372(dm_build_374 dm_build_725) (dm_build_375 interface{}, dm_build_376 error) { + dm_build_376 = dm_build_374.dm_build_729(dm_build_374) + if dm_build_376 != nil { + return nil, dm_build_376 + } + + dm_build_376 = dm_build_373.dm_build_362(dm_build_374) + if dm_build_376 != nil { + return nil, dm_build_376 + } + + dm_build_376 = dm_build_373.dm_build_367(dm_build_374) + if dm_build_376 != nil { + return nil, dm_build_376 + } + + return dm_build_374.dm_build_733(dm_build_374) +} + +func (dm_build_378 *dm_build_332) dm_build_377() (*dm_build_1162, error) { + + Dm_build_379 := dm_build_1168(dm_build_378) + _, dm_build_380 := dm_build_378.dm_build_372(Dm_build_379) + if dm_build_380 != nil { + return nil, dm_build_380 + } + + return Dm_build_379, nil +} + +func (dm_build_382 *dm_build_332) dm_build_381() error { + + dm_build_383 := dm_build_1030(dm_build_382) + _, dm_build_384 := dm_build_382.dm_build_372(dm_build_383) + if dm_build_384 != nil { + return dm_build_384 + } + + return nil +} + +func (dm_build_386 *dm_build_332) dm_build_385() error { + + var dm_build_387 *dm_build_1162 + var err error + if dm_build_387, err = dm_build_386.dm_build_377(); err != nil { + return err + } + + if dm_build_386.dm_build_336.sslEncrypt == 2 { + if err = dm_build_386.dm_build_590(false); err != nil { + return ECGO_INIT_SSL_FAILED.addDetail("\n" + err.Error()).throw() + } + } else if dm_build_386.dm_build_336.sslEncrypt == 1 { + if err = dm_build_386.dm_build_590(true); err != nil { + return ECGO_INIT_SSL_FAILED.addDetail("\n" + err.Error()).throw() + } + } + + if dm_build_386.dm_build_339 || dm_build_386.dm_build_338 { + k, err := dm_build_386.dm_build_580() + if err != nil { + return err + } + sessionKey := security.ComputeSessionKey(k, dm_build_387.Dm_build_1166) + encryptType := dm_build_387.dm_build_1164 + hashType := int(dm_build_387.Dm_build_1165) + if encryptType == -1 { + encryptType = security.DES_CFB + } + if hashType == -1 { + hashType = security.MD5 + } + err = dm_build_386.dm_build_583(encryptType, sessionKey, dm_build_386.dm_build_336.dmConnector.cipherPath, hashType) + if err != nil { + return err + } + } + + if err := dm_build_386.dm_build_381(); err != nil { + return err + } + return nil +} + +func (dm_build_390 *dm_build_332) Dm_build_389(dm_build_391 *DmStatement) error { + dm_build_392 := dm_build_1191(dm_build_390, dm_build_391) + _, dm_build_393 := dm_build_390.dm_build_372(dm_build_392) + if dm_build_393 != nil { + return dm_build_393 + } + + return nil +} + +func (dm_build_395 *dm_build_332) Dm_build_394(dm_build_396 int32) error { + dm_build_397 := dm_build_1201(dm_build_395, dm_build_396) + _, dm_build_398 := dm_build_395.dm_build_372(dm_build_397) + if dm_build_398 != nil { + return dm_build_398 + } + + return nil +} + +func (dm_build_400 *dm_build_332) Dm_build_399(dm_build_401 *DmStatement, dm_build_402 bool, dm_build_403 int16) (*execRetInfo, error) { + dm_build_404 := dm_build_1068(dm_build_400, dm_build_401, dm_build_402, dm_build_403) + dm_build_405, dm_build_406 := dm_build_400.dm_build_372(dm_build_404) + if dm_build_406 != nil { + return nil, dm_build_406 + } + return dm_build_405.(*execRetInfo), nil +} + +func (dm_build_408 *dm_build_332) Dm_build_407(dm_build_409 *DmStatement, dm_build_410 int16) (*execRetInfo, error) { + return dm_build_408.Dm_build_399(dm_build_409, false, Dm_build_685) +} + +func (dm_build_412 *dm_build_332) Dm_build_411(dm_build_413 *DmStatement, dm_build_414 []OptParameter) (*execRetInfo, error) { + dm_build_415, dm_build_416 := dm_build_412.dm_build_372(dm_build_827(dm_build_412, dm_build_413, dm_build_414)) + if dm_build_416 != nil { + return nil, dm_build_416 + } + + return dm_build_415.(*execRetInfo), nil +} + +func (dm_build_418 *dm_build_332) Dm_build_417(dm_build_419 *DmStatement, dm_build_420 int16) (*execRetInfo, error) { + return dm_build_418.Dm_build_399(dm_build_419, true, dm_build_420) +} + +func (dm_build_422 *dm_build_332) Dm_build_421(dm_build_423 *DmStatement, dm_build_424 [][]interface{}) (*execRetInfo, error) { + dm_build_425 := dm_build_850(dm_build_422, dm_build_423, dm_build_424) + dm_build_426, dm_build_427 := dm_build_422.dm_build_372(dm_build_425) + if dm_build_427 != nil { + return nil, dm_build_427 + } + return dm_build_426.(*execRetInfo), nil +} + +func (dm_build_429 *dm_build_332) Dm_build_428(dm_build_430 *DmStatement, dm_build_431 [][]interface{}, dm_build_432 bool) (*execRetInfo, error) { + var dm_build_433, dm_build_434 = 0, 0 + var dm_build_435 = len(dm_build_431) + var dm_build_436 [][]interface{} + var dm_build_437 = NewExceInfo() + dm_build_437.updateCounts = make([]int64, dm_build_435) + var dm_build_438 = false + for dm_build_433 < dm_build_435 { + for dm_build_434 = dm_build_433; dm_build_434 < dm_build_435; dm_build_434++ { + paramData := dm_build_431[dm_build_434] + bindData := make([]interface{}, dm_build_430.paramCount) + dm_build_438 = false + for icol := 0; icol < int(dm_build_430.paramCount); icol++ { + if dm_build_430.params[icol].ioType == IO_TYPE_OUT { + continue + } + if dm_build_429.dm_build_563(bindData, paramData, icol) { + dm_build_438 = true + break + } + } + + if dm_build_438 { + break + } + dm_build_436 = append(dm_build_436, bindData) + } + + if dm_build_434 != dm_build_433 { + tmpExecInfo, err := dm_build_429.Dm_build_421(dm_build_430, dm_build_436) + if err != nil { + return nil, err + } + dm_build_436 = dm_build_436[0:0] + dm_build_437.union(tmpExecInfo, dm_build_433, dm_build_434-dm_build_433) + } + + if dm_build_434 < dm_build_435 { + tmpExecInfo, err := dm_build_429.Dm_build_439(dm_build_430, dm_build_431[dm_build_434], dm_build_432) + if err != nil { + return nil, err + } + + dm_build_432 = true + dm_build_437.union(tmpExecInfo, dm_build_434, 1) + } + + dm_build_433 = dm_build_434 + 1 + } + for _, i := range dm_build_437.updateCounts { + if i > 0 { + dm_build_437.updateCount += i + } + } + return dm_build_437, nil +} + +func (dm_build_440 *dm_build_332) Dm_build_439(dm_build_441 *DmStatement, dm_build_442 []interface{}, dm_build_443 bool) (*execRetInfo, error) { + + var dm_build_444 = make([]interface{}, dm_build_441.paramCount) + for icol := 0; icol < int(dm_build_441.paramCount); icol++ { + if dm_build_441.params[icol].ioType == IO_TYPE_OUT { + continue + } + if dm_build_440.dm_build_563(dm_build_444, dm_build_442, icol) { + + if !dm_build_443 { + preExecute := dm_build_1058(dm_build_440, dm_build_441, dm_build_441.params) + dm_build_440.dm_build_372(preExecute) + dm_build_443 = true + } + + dm_build_440.dm_build_569(dm_build_441, dm_build_441.params[icol], icol, dm_build_442[icol].(iOffRowBinder)) + dm_build_444[icol] = ParamDataEnum_OFF_ROW + } + } + + var dm_build_445 = make([][]interface{}, 1, 1) + dm_build_445[0] = dm_build_444 + + dm_build_446 := dm_build_850(dm_build_440, dm_build_441, dm_build_445) + dm_build_447, dm_build_448 := dm_build_440.dm_build_372(dm_build_446) + if dm_build_448 != nil { + return nil, dm_build_448 + } + return dm_build_447.(*execRetInfo), nil +} + +func (dm_build_450 *dm_build_332) Dm_build_449(dm_build_451 *DmStatement, dm_build_452 int16) (*execRetInfo, error) { + dm_build_453 := dm_build_1045(dm_build_450, dm_build_451, dm_build_452) + + dm_build_454, dm_build_455 := dm_build_450.dm_build_372(dm_build_453) + if dm_build_455 != nil { + return nil, dm_build_455 + } + return dm_build_454.(*execRetInfo), nil +} + +func (dm_build_457 *dm_build_332) Dm_build_456(dm_build_458 *innerRows, dm_build_459 int64) (*execRetInfo, error) { + dm_build_460 := dm_build_950(dm_build_457, dm_build_458, dm_build_459, INT64_MAX) + dm_build_461, dm_build_462 := dm_build_457.dm_build_372(dm_build_460) + if dm_build_462 != nil { + return nil, dm_build_462 + } + return dm_build_461.(*execRetInfo), nil +} + +func (dm_build_464 *dm_build_332) Commit() error { + dm_build_465 := dm_build_813(dm_build_464) + _, dm_build_466 := dm_build_464.dm_build_372(dm_build_465) + if dm_build_466 != nil { + return dm_build_466 + } + + return nil +} + +func (dm_build_468 *dm_build_332) Rollback() error { + dm_build_469 := dm_build_1106(dm_build_468) + _, dm_build_470 := dm_build_468.dm_build_372(dm_build_469) + if dm_build_470 != nil { + return dm_build_470 + } + + return nil +} + +func (dm_build_472 *dm_build_332) Dm_build_471(dm_build_473 *DmConnection) error { + dm_build_474 := dm_build_1111(dm_build_472, dm_build_473.IsoLevel) + _, dm_build_475 := dm_build_472.dm_build_372(dm_build_474) + if dm_build_475 != nil { + return dm_build_475 + } + + return nil +} + +func (dm_build_477 *dm_build_332) Dm_build_476(dm_build_478 *DmStatement, dm_build_479 string) error { + dm_build_480 := dm_build_818(dm_build_477, dm_build_478, dm_build_479) + _, dm_build_481 := dm_build_477.dm_build_372(dm_build_480) + if dm_build_481 != nil { + return dm_build_481 + } + + return nil +} + +func (dm_build_483 *dm_build_332) Dm_build_482(dm_build_484 []uint32) ([]int64, error) { + dm_build_485 := dm_build_1209(dm_build_483, dm_build_484) + dm_build_486, dm_build_487 := dm_build_483.dm_build_372(dm_build_485) + if dm_build_487 != nil { + return nil, dm_build_487 + } + return dm_build_486.([]int64), nil +} + +func (dm_build_489 *dm_build_332) Close() error { + if dm_build_489.dm_build_343 { + return nil + } + + dm_build_490 := dm_build_489.dm_build_333.Close() + if dm_build_490 != nil { + return dm_build_490 + } + + dm_build_489.dm_build_336 = nil + dm_build_489.dm_build_343 = true + return nil +} + +func (dm_build_492 *dm_build_332) dm_build_491(dm_build_493 *lob) (int64, error) { + dm_build_494 := dm_build_981(dm_build_492, dm_build_493) + dm_build_495, dm_build_496 := dm_build_492.dm_build_372(dm_build_494) + if dm_build_496 != nil { + return 0, dm_build_496 + } + return dm_build_495.(int64), nil +} + +func (dm_build_498 *dm_build_332) dm_build_497(dm_build_499 *lob, dm_build_500 int32, dm_build_501 int32) ([]byte, error) { + dm_build_502 := dm_build_968(dm_build_498, dm_build_499, int(dm_build_500), int(dm_build_501)) + dm_build_503, dm_build_504 := dm_build_498.dm_build_372(dm_build_502) + if dm_build_504 != nil { + return nil, dm_build_504 + } + return dm_build_503.([]byte), nil +} + +func (dm_build_506 *dm_build_332) dm_build_505(dm_build_507 *DmBlob, dm_build_508 int32, dm_build_509 int32) ([]byte, error) { + var dm_build_510 = make([]byte, dm_build_509) + var dm_build_511 int32 = 0 + var dm_build_512 int32 = 0 + var dm_build_513 []byte + var dm_build_514 error + for dm_build_511 < dm_build_509 { + dm_build_512 = dm_build_509 - dm_build_511 + if dm_build_512 > Dm_build_718 { + dm_build_512 = Dm_build_718 + } + dm_build_513, dm_build_514 = dm_build_506.dm_build_497(&dm_build_507.lob, dm_build_508, dm_build_512) + if dm_build_514 != nil { + return nil, dm_build_514 + } + if dm_build_513 == nil || len(dm_build_513) == 0 { + break + } + Dm_build_1220.Dm_build_1276(dm_build_510, int(dm_build_511), dm_build_513, 0, len(dm_build_513)) + dm_build_511 += int32(len(dm_build_513)) + dm_build_508 += int32(len(dm_build_513)) + if dm_build_507.readOver { + break + } + } + return dm_build_510, nil +} + +func (dm_build_516 *dm_build_332) dm_build_515(dm_build_517 *DmClob, dm_build_518 int32, dm_build_519 int32) (string, error) { + var dm_build_520 bytes.Buffer + var dm_build_521 int32 = 0 + var dm_build_522 int32 = 0 + var dm_build_523 []byte + var dm_build_524 string + var dm_build_525 error + for dm_build_521 < dm_build_519 { + dm_build_522 = dm_build_519 - dm_build_521 + if dm_build_522 > Dm_build_718/2 { + dm_build_522 = Dm_build_718 / 2 + } + dm_build_523, dm_build_525 = dm_build_516.dm_build_497(&dm_build_517.lob, dm_build_518, dm_build_522) + if dm_build_525 != nil { + return "", dm_build_525 + } + if dm_build_523 == nil || len(dm_build_523) == 0 { + break + } + dm_build_524 = Dm_build_1220.Dm_build_1377(dm_build_523, 0, len(dm_build_523), dm_build_517.serverEncoding, dm_build_516.dm_build_336) + + dm_build_520.WriteString(dm_build_524) + dm_build_521 += int32(len(dm_build_524)) + dm_build_518 += int32(len(dm_build_524)) + if dm_build_517.readOver { + break + } + } + return dm_build_520.String(), nil +} + +func (dm_build_527 *dm_build_332) dm_build_526(dm_build_528 *DmClob, dm_build_529 int, dm_build_530 string, dm_build_531 string) (int, error) { + var dm_build_532 = Dm_build_1220.Dm_build_1433(dm_build_530, dm_build_531, dm_build_527.dm_build_336) + var dm_build_533 = 0 + var dm_build_534 = len(dm_build_532) + var dm_build_535 = 0 + var dm_build_536 = 0 + var dm_build_537 = 0 + var dm_build_538 = dm_build_534/Dm_build_717 + 1 + var dm_build_539 byte = 0 + var dm_build_540 byte = 0x01 + var dm_build_541 byte = 0x02 + for i := 0; i < dm_build_538; i++ { + dm_build_539 = 0 + if i == 0 { + dm_build_539 |= dm_build_540 + } + if i == dm_build_538-1 { + dm_build_539 |= dm_build_541 + } + dm_build_537 = dm_build_534 - dm_build_536 + if dm_build_537 > Dm_build_717 { + dm_build_537 = Dm_build_717 + } + + setLobData := dm_build_1125(dm_build_527, &dm_build_528.lob, dm_build_539, dm_build_529, dm_build_532, dm_build_533, dm_build_537) + ret, err := dm_build_527.dm_build_372(setLobData) + if err != nil { + return 0, err + } + tmp := ret.(int32) + if err != nil { + return -1, err + } + if tmp <= 0 { + return dm_build_535, nil + } else { + dm_build_529 += int(tmp) + dm_build_535 += int(tmp) + dm_build_536 += dm_build_537 + dm_build_533 += dm_build_537 + } + } + return dm_build_535, nil +} + +func (dm_build_543 *dm_build_332) dm_build_542(dm_build_544 *DmBlob, dm_build_545 int, dm_build_546 []byte) (int, error) { + var dm_build_547 = 0 + var dm_build_548 = len(dm_build_546) + var dm_build_549 = 0 + var dm_build_550 = 0 + var dm_build_551 = 0 + var dm_build_552 = dm_build_548/Dm_build_717 + 1 + var dm_build_553 byte = 0 + var dm_build_554 byte = 0x01 + var dm_build_555 byte = 0x02 + for i := 0; i < dm_build_552; i++ { + dm_build_553 = 0 + if i == 0 { + dm_build_553 |= dm_build_554 + } + if i == dm_build_552-1 { + dm_build_553 |= dm_build_555 + } + dm_build_551 = dm_build_548 - dm_build_550 + if dm_build_551 > Dm_build_717 { + dm_build_551 = Dm_build_717 + } + + setLobData := dm_build_1125(dm_build_543, &dm_build_544.lob, dm_build_553, dm_build_545, dm_build_546, dm_build_547, dm_build_551) + ret, err := dm_build_543.dm_build_372(setLobData) + if err != nil { + return 0, err + } + tmp := ret.(int32) + if tmp <= 0 { + return dm_build_549, nil + } else { + dm_build_545 += int(tmp) + dm_build_549 += int(tmp) + dm_build_550 += dm_build_551 + dm_build_547 += dm_build_551 + } + } + return dm_build_549, nil +} + +func (dm_build_557 *dm_build_332) dm_build_556(dm_build_558 *lob, dm_build_559 int) (int64, error) { + dm_build_560 := dm_build_992(dm_build_557, dm_build_558, dm_build_559) + dm_build_561, dm_build_562 := dm_build_557.dm_build_372(dm_build_560) + if dm_build_562 != nil { + return dm_build_558.length, dm_build_562 + } + return dm_build_561.(int64), nil +} + +func (dm_build_564 *dm_build_332) dm_build_563(dm_build_565 []interface{}, dm_build_566 []interface{}, dm_build_567 int) bool { + var dm_build_568 = false + if dm_build_567 >= len(dm_build_566) || dm_build_566[dm_build_567] == nil { + dm_build_565[dm_build_567] = ParamDataEnum_Null + } else if binder, ok := dm_build_566[dm_build_567].(iOffRowBinder); ok { + dm_build_568 = true + dm_build_565[dm_build_567] = ParamDataEnum_OFF_ROW + var lob lob + if l, ok := binder.getObj().(DmBlob); ok { + lob = l.lob + } else if l, ok := binder.getObj().(DmClob); ok { + lob = l.lob + } + if &lob != nil && lob.canOptimized(dm_build_564.dm_build_336) { + dm_build_565[dm_build_567] = &lobCtl{lob.buildCtlData()} + dm_build_568 = false + } + } else { + dm_build_565[dm_build_567] = dm_build_566[dm_build_567] + } + return dm_build_568 +} + +func (dm_build_570 *dm_build_332) dm_build_569(dm_build_571 *DmStatement, dm_build_572 parameter, dm_build_573 int, dm_build_574 iOffRowBinder) error { + var dm_build_575 = Dm_build_1503() + dm_build_574.read(dm_build_575) + var dm_build_576 = 0 + for !dm_build_574.isReadOver() || dm_build_575.Dm_build_1504() > 0 { + if !dm_build_574.isReadOver() && dm_build_575.Dm_build_1504() < Dm_build_717 { + dm_build_574.read(dm_build_575) + } + if dm_build_575.Dm_build_1504() > Dm_build_717 { + dm_build_576 = Dm_build_717 + } else { + dm_build_576 = dm_build_575.Dm_build_1504() + } + + putData := dm_build_1096(dm_build_570, dm_build_571, int16(dm_build_573), dm_build_575, int32(dm_build_576)) + _, err := dm_build_570.dm_build_372(putData) + if err != nil { + return err + } + } + return nil +} + +func (dm_build_578 *dm_build_332) dm_build_577() ([]byte, error) { + var dm_build_579 error + if dm_build_578.dm_build_340 == nil { + if dm_build_578.dm_build_340, dm_build_579 = security.NewClientKeyPair(); dm_build_579 != nil { + return nil, dm_build_579 + } + } + return security.Bn2Bytes(dm_build_578.dm_build_340.GetY(), security.DH_KEY_LENGTH), nil +} + +func (dm_build_581 *dm_build_332) dm_build_580() (*security.DhKey, error) { + var dm_build_582 error + if dm_build_581.dm_build_340 == nil { + if dm_build_581.dm_build_340, dm_build_582 = security.NewClientKeyPair(); dm_build_582 != nil { + return nil, dm_build_582 + } + } + return dm_build_581.dm_build_340, nil +} + +func (dm_build_584 *dm_build_332) dm_build_583(dm_build_585 int, dm_build_586 []byte, dm_build_587 string, dm_build_588 int) (dm_build_589 error) { + if dm_build_585 > 0 && dm_build_585 < security.MIN_EXTERNAL_CIPHER_ID && dm_build_586 != nil { + dm_build_584.dm_build_337, dm_build_589 = security.NewSymmCipher(dm_build_585, dm_build_586) + } else if dm_build_585 >= security.MIN_EXTERNAL_CIPHER_ID { + if dm_build_584.dm_build_337, dm_build_589 = security.NewThirdPartCipher(dm_build_585, dm_build_586, dm_build_587, dm_build_588); dm_build_589 != nil { + dm_build_589 = THIRD_PART_CIPHER_INIT_FAILED.addDetailln(dm_build_589.Error()).throw() + } + } + return +} + +func (dm_build_591 *dm_build_332) dm_build_590(dm_build_592 bool) (dm_build_593 error) { + if dm_build_591.dm_build_334, dm_build_593 = security.NewTLSFromTCP(dm_build_591.dm_build_333, dm_build_591.dm_build_336.dmConnector.sslCertPath, dm_build_591.dm_build_336.dmConnector.sslKeyPath, dm_build_591.dm_build_336.dmConnector.user); dm_build_593 != nil { + return + } + if !dm_build_592 { + dm_build_591.dm_build_334 = nil + } + return +} + +func (dm_build_595 *dm_build_332) dm_build_594(dm_build_596 dm_build_725) bool { + return dm_build_596.dm_build_740() != Dm_build_632 && dm_build_595.dm_build_336.sslEncrypt == 1 +} diff --git a/dmr/b.go b/dmr/b.go new file mode 100644 index 0000000..aaacc76 --- /dev/null +++ b/dmr/b.go @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +type ArrayDescriptor struct { + m_typeDesc *TypeDescriptor +} + +func newArrayDescriptor(fulName string, conn *DmConnection) (*ArrayDescriptor, error) { + + ad := new(ArrayDescriptor) + + if fulName == "" { + return nil, ECGO_INVALID_COMPLEX_TYPE_NAME.throw() + } + + ad.m_typeDesc = newTypeDescriptorWithFulName(fulName, conn) + err := ad.m_typeDesc.parseDescByName() + if err != nil { + return nil, err + } + + return ad, nil +} + +func newArrayDescriptorByTypeDescriptor(desc *TypeDescriptor) *ArrayDescriptor { + ad := new(ArrayDescriptor) + ad.m_typeDesc = desc + return ad +} + +func (ad *ArrayDescriptor) getMDesc() *TypeDescriptor { + return ad.m_typeDesc +} + +func (ad *ArrayDescriptor) getItemDesc() *TypeDescriptor { + return ad.m_typeDesc.m_arrObj +} + +func (ad *ArrayDescriptor) getLength() int { + return ad.m_typeDesc.m_length +} diff --git a/dmr/c.go b/dmr/c.go new file mode 100644 index 0000000..767aa35 --- /dev/null +++ b/dmr/c.go @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "io" + "math" +) + +type Dm_build_0 struct { + dm_build_1 []byte + dm_build_2 int +} + +func Dm_build_3(dm_build_4 int) *Dm_build_0 { + return &Dm_build_0{make([]byte, 0, dm_build_4), 0} +} + +func Dm_build_5(dm_build_6 []byte) *Dm_build_0 { + return &Dm_build_0{dm_build_6, 0} +} + +func (dm_build_8 *Dm_build_0) dm_build_7(dm_build_9 int) *Dm_build_0 { + + dm_build_10 := len(dm_build_8.dm_build_1) + dm_build_11 := cap(dm_build_8.dm_build_1) + + if dm_build_10+dm_build_9 <= dm_build_11 { + dm_build_8.dm_build_1 = dm_build_8.dm_build_1[:dm_build_10+dm_build_9] + } else { + remain := dm_build_9 + dm_build_10 - dm_build_11 + nbuf := make([]byte, dm_build_9+dm_build_10, 2*dm_build_11+remain) + copy(nbuf, dm_build_8.dm_build_1) + dm_build_8.dm_build_1 = nbuf + } + + return dm_build_8 +} + +func (dm_build_13 *Dm_build_0) Dm_build_12() int { + return len(dm_build_13.dm_build_1) +} + +func (dm_build_15 *Dm_build_0) Dm_build_14(dm_build_16 int) *Dm_build_0 { + for i := dm_build_16; i < len(dm_build_15.dm_build_1); i++ { + dm_build_15.dm_build_1[i] = 0 + } + dm_build_15.dm_build_1 = dm_build_15.dm_build_1[:dm_build_16] + return dm_build_15 +} + +func (dm_build_18 *Dm_build_0) Dm_build_17(dm_build_19 int) *Dm_build_0 { + dm_build_18.dm_build_2 = dm_build_19 + return dm_build_18 +} + +func (dm_build_21 *Dm_build_0) Dm_build_20() int { + return dm_build_21.dm_build_2 +} + +func (dm_build_23 *Dm_build_0) Dm_build_22(dm_build_24 bool) int { + return len(dm_build_23.dm_build_1) - dm_build_23.dm_build_2 +} + +func (dm_build_26 *Dm_build_0) Dm_build_25(dm_build_27 int, dm_build_28 bool, dm_build_29 bool) *Dm_build_0 { + + if dm_build_28 { + if dm_build_29 { + dm_build_26.dm_build_7(dm_build_27) + } else { + dm_build_26.dm_build_1 = dm_build_26.dm_build_1[:len(dm_build_26.dm_build_1)-dm_build_27] + } + } else { + if dm_build_29 { + dm_build_26.dm_build_2 += dm_build_27 + } else { + dm_build_26.dm_build_2 -= dm_build_27 + } + } + + return dm_build_26 +} + +func (dm_build_31 *Dm_build_0) Dm_build_30(dm_build_32 io.Reader, dm_build_33 int) int { + dm_build_34 := len(dm_build_31.dm_build_1) + dm_build_31.dm_build_7(dm_build_33) + dm_build_35 := 0 + for dm_build_33 > 0 { + n, err := dm_build_32.Read(dm_build_31.dm_build_1[dm_build_34+dm_build_35:]) + if n > 0 && err == io.EOF { + dm_build_35 += n + dm_build_31.dm_build_1 = dm_build_31.dm_build_1[:dm_build_34+dm_build_35] + return dm_build_35 + } else if n > 0 && err == nil { + dm_build_33 -= n + dm_build_35 += n + } else if n == 0 && err != nil { + panic("load err") + } + } + + return dm_build_35 +} + +func (dm_build_37 *Dm_build_0) Dm_build_36(dm_build_38 io.Writer) *Dm_build_0 { + dm_build_38.Write(dm_build_37.dm_build_1) + return dm_build_37 +} + +func (dm_build_40 *Dm_build_0) Dm_build_39(dm_build_41 bool) int { + dm_build_42 := len(dm_build_40.dm_build_1) + dm_build_40.dm_build_7(1) + + if dm_build_41 { + return copy(dm_build_40.dm_build_1[dm_build_42:], []byte{1}) + } else { + return copy(dm_build_40.dm_build_1[dm_build_42:], []byte{0}) + } +} + +func (dm_build_44 *Dm_build_0) Dm_build_43(dm_build_45 byte) int { + dm_build_46 := len(dm_build_44.dm_build_1) + dm_build_44.dm_build_7(1) + + return copy(dm_build_44.dm_build_1[dm_build_46:], Dm_build_1220.Dm_build_1398(dm_build_45)) +} + +func (dm_build_48 *Dm_build_0) Dm_build_47(dm_build_49 int16) int { + dm_build_50 := len(dm_build_48.dm_build_1) + dm_build_48.dm_build_7(2) + + return copy(dm_build_48.dm_build_1[dm_build_50:], Dm_build_1220.Dm_build_1401(dm_build_49)) +} + +func (dm_build_52 *Dm_build_0) Dm_build_51(dm_build_53 int32) int { + dm_build_54 := len(dm_build_52.dm_build_1) + dm_build_52.dm_build_7(4) + + return copy(dm_build_52.dm_build_1[dm_build_54:], Dm_build_1220.Dm_build_1404(dm_build_53)) +} + +func (dm_build_56 *Dm_build_0) Dm_build_55(dm_build_57 uint8) int { + dm_build_58 := len(dm_build_56.dm_build_1) + dm_build_56.dm_build_7(1) + + return copy(dm_build_56.dm_build_1[dm_build_58:], Dm_build_1220.Dm_build_1416(dm_build_57)) +} + +func (dm_build_60 *Dm_build_0) Dm_build_59(dm_build_61 uint16) int { + dm_build_62 := len(dm_build_60.dm_build_1) + dm_build_60.dm_build_7(2) + + return copy(dm_build_60.dm_build_1[dm_build_62:], Dm_build_1220.Dm_build_1419(dm_build_61)) +} + +func (dm_build_64 *Dm_build_0) Dm_build_63(dm_build_65 uint32) int { + dm_build_66 := len(dm_build_64.dm_build_1) + dm_build_64.dm_build_7(4) + + return copy(dm_build_64.dm_build_1[dm_build_66:], Dm_build_1220.Dm_build_1422(dm_build_65)) +} + +func (dm_build_68 *Dm_build_0) Dm_build_67(dm_build_69 uint64) int { + dm_build_70 := len(dm_build_68.dm_build_1) + dm_build_68.dm_build_7(8) + + return copy(dm_build_68.dm_build_1[dm_build_70:], Dm_build_1220.Dm_build_1425(dm_build_69)) +} + +func (dm_build_72 *Dm_build_0) Dm_build_71(dm_build_73 float32) int { + dm_build_74 := len(dm_build_72.dm_build_1) + dm_build_72.dm_build_7(4) + + return copy(dm_build_72.dm_build_1[dm_build_74:], Dm_build_1220.Dm_build_1422(math.Float32bits(dm_build_73))) +} + +func (dm_build_76 *Dm_build_0) Dm_build_75(dm_build_77 float64) int { + dm_build_78 := len(dm_build_76.dm_build_1) + dm_build_76.dm_build_7(8) + + return copy(dm_build_76.dm_build_1[dm_build_78:], Dm_build_1220.Dm_build_1425(math.Float64bits(dm_build_77))) +} + +func (dm_build_80 *Dm_build_0) Dm_build_79(dm_build_81 []byte) int { + dm_build_82 := len(dm_build_80.dm_build_1) + dm_build_80.dm_build_7(len(dm_build_81)) + return copy(dm_build_80.dm_build_1[dm_build_82:], dm_build_81) +} + +func (dm_build_84 *Dm_build_0) Dm_build_83(dm_build_85 []byte) int { + return dm_build_84.Dm_build_51(int32(len(dm_build_85))) + dm_build_84.Dm_build_79(dm_build_85) +} + +func (dm_build_87 *Dm_build_0) Dm_build_86(dm_build_88 []byte) int { + return dm_build_87.Dm_build_55(uint8(len(dm_build_88))) + dm_build_87.Dm_build_79(dm_build_88) +} + +func (dm_build_90 *Dm_build_0) Dm_build_89(dm_build_91 []byte) int { + return dm_build_90.Dm_build_59(uint16(len(dm_build_91))) + dm_build_90.Dm_build_79(dm_build_91) +} + +func (dm_build_93 *Dm_build_0) Dm_build_92(dm_build_94 []byte) int { + return dm_build_93.Dm_build_79(dm_build_94) + dm_build_93.Dm_build_43(0) +} + +func (dm_build_96 *Dm_build_0) Dm_build_95(dm_build_97 string, dm_build_98 string, dm_build_99 *DmConnection) int { + dm_build_100 := Dm_build_1220.Dm_build_1433(dm_build_97, dm_build_98, dm_build_99) + return dm_build_96.Dm_build_83(dm_build_100) +} + +func (dm_build_102 *Dm_build_0) Dm_build_101(dm_build_103 string, dm_build_104 string, dm_build_105 *DmConnection) int { + dm_build_106 := Dm_build_1220.Dm_build_1433(dm_build_103, dm_build_104, dm_build_105) + return dm_build_102.Dm_build_86(dm_build_106) +} + +func (dm_build_108 *Dm_build_0) Dm_build_107(dm_build_109 string, dm_build_110 string, dm_build_111 *DmConnection) int { + dm_build_112 := Dm_build_1220.Dm_build_1433(dm_build_109, dm_build_110, dm_build_111) + return dm_build_108.Dm_build_89(dm_build_112) +} + +func (dm_build_114 *Dm_build_0) Dm_build_113(dm_build_115 string, dm_build_116 string, dm_build_117 *DmConnection) int { + dm_build_118 := Dm_build_1220.Dm_build_1433(dm_build_115, dm_build_116, dm_build_117) + return dm_build_114.Dm_build_92(dm_build_118) +} + +func (dm_build_120 *Dm_build_0) Dm_build_119() byte { + dm_build_121 := Dm_build_1220.Dm_build_1313(dm_build_120.dm_build_1, dm_build_120.dm_build_2) + dm_build_120.dm_build_2++ + return dm_build_121 +} + +func (dm_build_123 *Dm_build_0) Dm_build_122() int16 { + dm_build_124 := Dm_build_1220.Dm_build_1317(dm_build_123.dm_build_1, dm_build_123.dm_build_2) + dm_build_123.dm_build_2 += 2 + return dm_build_124 +} + +func (dm_build_126 *Dm_build_0) Dm_build_125() int32 { + dm_build_127 := Dm_build_1220.Dm_build_1322(dm_build_126.dm_build_1, dm_build_126.dm_build_2) + dm_build_126.dm_build_2 += 4 + return dm_build_127 +} + +func (dm_build_129 *Dm_build_0) Dm_build_128() int64 { + dm_build_130 := Dm_build_1220.Dm_build_1327(dm_build_129.dm_build_1, dm_build_129.dm_build_2) + dm_build_129.dm_build_2 += 8 + return dm_build_130 +} + +func (dm_build_132 *Dm_build_0) Dm_build_131() float32 { + dm_build_133 := Dm_build_1220.Dm_build_1332(dm_build_132.dm_build_1, dm_build_132.dm_build_2) + dm_build_132.dm_build_2 += 4 + return dm_build_133 +} + +func (dm_build_135 *Dm_build_0) Dm_build_134() float64 { + dm_build_136 := Dm_build_1220.Dm_build_1336(dm_build_135.dm_build_1, dm_build_135.dm_build_2) + dm_build_135.dm_build_2 += 8 + return dm_build_136 +} + +func (dm_build_138 *Dm_build_0) Dm_build_137() uint8 { + dm_build_139 := Dm_build_1220.Dm_build_1340(dm_build_138.dm_build_1, dm_build_138.dm_build_2) + dm_build_138.dm_build_2 += 1 + return dm_build_139 +} + +func (dm_build_141 *Dm_build_0) Dm_build_140() uint16 { + dm_build_142 := Dm_build_1220.Dm_build_1344(dm_build_141.dm_build_1, dm_build_141.dm_build_2) + dm_build_141.dm_build_2 += 2 + return dm_build_142 +} + +func (dm_build_144 *Dm_build_0) Dm_build_143() uint32 { + dm_build_145 := Dm_build_1220.Dm_build_1349(dm_build_144.dm_build_1, dm_build_144.dm_build_2) + dm_build_144.dm_build_2 += 4 + return dm_build_145 +} + +func (dm_build_147 *Dm_build_0) Dm_build_146(dm_build_148 int) []byte { + dm_build_149 := Dm_build_1220.Dm_build_1371(dm_build_147.dm_build_1, dm_build_147.dm_build_2, dm_build_148) + dm_build_147.dm_build_2 += dm_build_148 + return dm_build_149 +} + +func (dm_build_151 *Dm_build_0) Dm_build_150() []byte { + return dm_build_151.Dm_build_146(int(dm_build_151.Dm_build_125())) +} + +func (dm_build_153 *Dm_build_0) Dm_build_152() []byte { + return dm_build_153.Dm_build_146(int(dm_build_153.Dm_build_119())) +} + +func (dm_build_155 *Dm_build_0) Dm_build_154() []byte { + return dm_build_155.Dm_build_146(int(dm_build_155.Dm_build_122())) +} + +func (dm_build_157 *Dm_build_0) Dm_build_156(dm_build_158 int) []byte { + return dm_build_157.Dm_build_146(dm_build_158) +} + +func (dm_build_160 *Dm_build_0) Dm_build_159() []byte { + dm_build_161 := 0 + for dm_build_160.Dm_build_119() != 0 { + dm_build_161++ + } + dm_build_160.Dm_build_25(dm_build_161, false, false) + return dm_build_160.Dm_build_146(dm_build_161) +} + +func (dm_build_163 *Dm_build_0) Dm_build_162(dm_build_164 int, dm_build_165 string, dm_build_166 *DmConnection) string { + return Dm_build_1220.Dm_build_1470(dm_build_163.Dm_build_146(dm_build_164), dm_build_165, dm_build_166) +} + +func (dm_build_168 *Dm_build_0) Dm_build_167(dm_build_169 string, dm_build_170 *DmConnection) string { + return Dm_build_1220.Dm_build_1470(dm_build_168.Dm_build_150(), dm_build_169, dm_build_170) +} + +func (dm_build_172 *Dm_build_0) Dm_build_171(dm_build_173 string, dm_build_174 *DmConnection) string { + return Dm_build_1220.Dm_build_1470(dm_build_172.Dm_build_152(), dm_build_173, dm_build_174) +} + +func (dm_build_176 *Dm_build_0) Dm_build_175(dm_build_177 string, dm_build_178 *DmConnection) string { + return Dm_build_1220.Dm_build_1470(dm_build_176.Dm_build_154(), dm_build_177, dm_build_178) +} + +func (dm_build_180 *Dm_build_0) Dm_build_179(dm_build_181 string, dm_build_182 *DmConnection) string { + return Dm_build_1220.Dm_build_1470(dm_build_180.Dm_build_159(), dm_build_181, dm_build_182) +} + +func (dm_build_184 *Dm_build_0) Dm_build_183(dm_build_185 int, dm_build_186 byte) int { + return dm_build_184.Dm_build_219(dm_build_185, Dm_build_1220.Dm_build_1398(dm_build_186)) +} + +func (dm_build_188 *Dm_build_0) Dm_build_187(dm_build_189 int, dm_build_190 int16) int { + return dm_build_188.Dm_build_219(dm_build_189, Dm_build_1220.Dm_build_1401(dm_build_190)) +} + +func (dm_build_192 *Dm_build_0) Dm_build_191(dm_build_193 int, dm_build_194 int32) int { + return dm_build_192.Dm_build_219(dm_build_193, Dm_build_1220.Dm_build_1404(dm_build_194)) +} + +func (dm_build_196 *Dm_build_0) Dm_build_195(dm_build_197 int, dm_build_198 int64) int { + return dm_build_196.Dm_build_219(dm_build_197, Dm_build_1220.Dm_build_1407(dm_build_198)) +} + +func (dm_build_200 *Dm_build_0) Dm_build_199(dm_build_201 int, dm_build_202 float32) int { + return dm_build_200.Dm_build_219(dm_build_201, Dm_build_1220.Dm_build_1410(dm_build_202)) +} + +func (dm_build_204 *Dm_build_0) Dm_build_203(dm_build_205 int, dm_build_206 float64) int { + return dm_build_204.Dm_build_219(dm_build_205, Dm_build_1220.Dm_build_1413(dm_build_206)) +} + +func (dm_build_208 *Dm_build_0) Dm_build_207(dm_build_209 int, dm_build_210 uint8) int { + return dm_build_208.Dm_build_219(dm_build_209, Dm_build_1220.Dm_build_1416(dm_build_210)) +} + +func (dm_build_212 *Dm_build_0) Dm_build_211(dm_build_213 int, dm_build_214 uint16) int { + return dm_build_212.Dm_build_219(dm_build_213, Dm_build_1220.Dm_build_1419(dm_build_214)) +} + +func (dm_build_216 *Dm_build_0) Dm_build_215(dm_build_217 int, dm_build_218 uint32) int { + return dm_build_216.Dm_build_219(dm_build_217, Dm_build_1220.Dm_build_1422(dm_build_218)) +} + +func (dm_build_220 *Dm_build_0) Dm_build_219(dm_build_221 int, dm_build_222 []byte) int { + return copy(dm_build_220.dm_build_1[dm_build_221:], dm_build_222) +} + +func (dm_build_224 *Dm_build_0) Dm_build_223(dm_build_225 int, dm_build_226 []byte) int { + return dm_build_224.Dm_build_191(dm_build_225, int32(len(dm_build_226))) + dm_build_224.Dm_build_219(dm_build_225+4, dm_build_226) +} + +func (dm_build_228 *Dm_build_0) Dm_build_227(dm_build_229 int, dm_build_230 []byte) int { + return dm_build_228.Dm_build_183(dm_build_229, byte(len(dm_build_230))) + dm_build_228.Dm_build_219(dm_build_229+1, dm_build_230) +} + +func (dm_build_232 *Dm_build_0) Dm_build_231(dm_build_233 int, dm_build_234 []byte) int { + return dm_build_232.Dm_build_187(dm_build_233, int16(len(dm_build_234))) + dm_build_232.Dm_build_219(dm_build_233+2, dm_build_234) +} + +func (dm_build_236 *Dm_build_0) Dm_build_235(dm_build_237 int, dm_build_238 []byte) int { + return dm_build_236.Dm_build_219(dm_build_237, dm_build_238) + dm_build_236.Dm_build_183(dm_build_237+len(dm_build_238), 0) +} + +func (dm_build_240 *Dm_build_0) Dm_build_239(dm_build_241 int, dm_build_242 string, dm_build_243 string, dm_build_244 *DmConnection) int { + return dm_build_240.Dm_build_223(dm_build_241, Dm_build_1220.Dm_build_1433(dm_build_242, dm_build_243, dm_build_244)) +} + +func (dm_build_246 *Dm_build_0) Dm_build_245(dm_build_247 int, dm_build_248 string, dm_build_249 string, dm_build_250 *DmConnection) int { + return dm_build_246.Dm_build_227(dm_build_247, Dm_build_1220.Dm_build_1433(dm_build_248, dm_build_249, dm_build_250)) +} + +func (dm_build_252 *Dm_build_0) Dm_build_251(dm_build_253 int, dm_build_254 string, dm_build_255 string, dm_build_256 *DmConnection) int { + return dm_build_252.Dm_build_231(dm_build_253, Dm_build_1220.Dm_build_1433(dm_build_254, dm_build_255, dm_build_256)) +} + +func (dm_build_258 *Dm_build_0) Dm_build_257(dm_build_259 int, dm_build_260 string, dm_build_261 string, dm_build_262 *DmConnection) int { + return dm_build_258.Dm_build_235(dm_build_259, Dm_build_1220.Dm_build_1433(dm_build_260, dm_build_261, dm_build_262)) +} + +func (dm_build_264 *Dm_build_0) Dm_build_263(dm_build_265 int) byte { + return Dm_build_1220.Dm_build_1438(dm_build_264.Dm_build_290(dm_build_265, 1)) +} + +func (dm_build_267 *Dm_build_0) Dm_build_266(dm_build_268 int) int16 { + return Dm_build_1220.Dm_build_1441(dm_build_267.Dm_build_290(dm_build_268, 2)) +} + +func (dm_build_270 *Dm_build_0) Dm_build_269(dm_build_271 int) int32 { + return Dm_build_1220.Dm_build_1444(dm_build_270.Dm_build_290(dm_build_271, 4)) +} + +func (dm_build_273 *Dm_build_0) Dm_build_272(dm_build_274 int) int64 { + return Dm_build_1220.Dm_build_1447(dm_build_273.Dm_build_290(dm_build_274, 8)) +} + +func (dm_build_276 *Dm_build_0) Dm_build_275(dm_build_277 int) float32 { + return Dm_build_1220.Dm_build_1450(dm_build_276.Dm_build_290(dm_build_277, 4)) +} + +func (dm_build_279 *Dm_build_0) Dm_build_278(dm_build_280 int) float64 { + return Dm_build_1220.Dm_build_1453(dm_build_279.Dm_build_290(dm_build_280, 8)) +} + +func (dm_build_282 *Dm_build_0) Dm_build_281(dm_build_283 int) uint8 { + return Dm_build_1220.Dm_build_1456(dm_build_282.Dm_build_290(dm_build_283, 1)) +} + +func (dm_build_285 *Dm_build_0) Dm_build_284(dm_build_286 int) uint16 { + return Dm_build_1220.Dm_build_1459(dm_build_285.Dm_build_290(dm_build_286, 2)) +} + +func (dm_build_288 *Dm_build_0) Dm_build_287(dm_build_289 int) uint32 { + return Dm_build_1220.Dm_build_1462(dm_build_288.Dm_build_290(dm_build_289, 4)) +} + +func (dm_build_291 *Dm_build_0) Dm_build_290(dm_build_292 int, dm_build_293 int) []byte { + return dm_build_291.dm_build_1[dm_build_292 : dm_build_292+dm_build_293] +} + +func (dm_build_295 *Dm_build_0) Dm_build_294(dm_build_296 int) []byte { + dm_build_297 := dm_build_295.Dm_build_269(dm_build_296) + return dm_build_295.Dm_build_290(dm_build_296+4, int(dm_build_297)) +} + +func (dm_build_299 *Dm_build_0) Dm_build_298(dm_build_300 int) []byte { + dm_build_301 := dm_build_299.Dm_build_263(dm_build_300) + return dm_build_299.Dm_build_290(dm_build_300+1, int(dm_build_301)) +} + +func (dm_build_303 *Dm_build_0) Dm_build_302(dm_build_304 int) []byte { + dm_build_305 := dm_build_303.Dm_build_266(dm_build_304) + return dm_build_303.Dm_build_290(dm_build_304+2, int(dm_build_305)) +} + +func (dm_build_307 *Dm_build_0) Dm_build_306(dm_build_308 int) []byte { + dm_build_309 := 0 + for dm_build_307.Dm_build_263(dm_build_308) != 0 { + dm_build_308++ + dm_build_309++ + } + + return dm_build_307.Dm_build_290(dm_build_308-dm_build_309, int(dm_build_309)) +} + +func (dm_build_311 *Dm_build_0) Dm_build_310(dm_build_312 int, dm_build_313 string, dm_build_314 *DmConnection) string { + return Dm_build_1220.Dm_build_1470(dm_build_311.Dm_build_294(dm_build_312), dm_build_313, dm_build_314) +} + +func (dm_build_316 *Dm_build_0) Dm_build_315(dm_build_317 int, dm_build_318 string, dm_build_319 *DmConnection) string { + return Dm_build_1220.Dm_build_1470(dm_build_316.Dm_build_298(dm_build_317), dm_build_318, dm_build_319) +} + +func (dm_build_321 *Dm_build_0) Dm_build_320(dm_build_322 int, dm_build_323 string, dm_build_324 *DmConnection) string { + return Dm_build_1220.Dm_build_1470(dm_build_321.Dm_build_302(dm_build_322), dm_build_323, dm_build_324) +} + +func (dm_build_326 *Dm_build_0) Dm_build_325(dm_build_327 int, dm_build_328 string, dm_build_329 *DmConnection) string { + return Dm_build_1220.Dm_build_1470(dm_build_326.Dm_build_306(dm_build_327), dm_build_328, dm_build_329) +} diff --git a/dmr/d.go b/dmr/d.go new file mode 100644 index 0000000..38866c7 --- /dev/null +++ b/dmr/d.go @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "container/list" + "io" +) + +type Dm_build_1499 struct { + dm_build_1500 *list.List + dm_build_1501 *dm_build_1553 + dm_build_1502 int +} + +func Dm_build_1503() *Dm_build_1499 { + return &Dm_build_1499{ + dm_build_1500: list.New(), + dm_build_1502: 0, + } +} + +func (dm_build_1505 *Dm_build_1499) Dm_build_1504() int { + return dm_build_1505.dm_build_1502 +} + +func (dm_build_1507 *Dm_build_1499) Dm_build_1506(dm_build_1508 *Dm_build_0, dm_build_1509 int) int { + var dm_build_1510 = 0 + var dm_build_1511 = 0 + for dm_build_1510 < dm_build_1509 && dm_build_1507.dm_build_1501 != nil { + dm_build_1511 = dm_build_1507.dm_build_1501.dm_build_1561(dm_build_1508, dm_build_1509-dm_build_1510) + if dm_build_1507.dm_build_1501.dm_build_1556 == 0 { + dm_build_1507.dm_build_1543() + } + dm_build_1510 += dm_build_1511 + dm_build_1507.dm_build_1502 -= dm_build_1511 + } + return dm_build_1510 +} + +func (dm_build_1513 *Dm_build_1499) Dm_build_1512(dm_build_1514 []byte, dm_build_1515 int, dm_build_1516 int) int { + var dm_build_1517 = 0 + var dm_build_1518 = 0 + for dm_build_1517 < dm_build_1516 && dm_build_1513.dm_build_1501 != nil { + dm_build_1518 = dm_build_1513.dm_build_1501.dm_build_1565(dm_build_1514, dm_build_1515, dm_build_1516-dm_build_1517) + if dm_build_1513.dm_build_1501.dm_build_1556 == 0 { + dm_build_1513.dm_build_1543() + } + dm_build_1517 += dm_build_1518 + dm_build_1513.dm_build_1502 -= dm_build_1518 + dm_build_1515 += dm_build_1518 + } + return dm_build_1517 +} + +func (dm_build_1520 *Dm_build_1499) Dm_build_1519(dm_build_1521 io.Writer, dm_build_1522 int) int { + var dm_build_1523 = 0 + var dm_build_1524 = 0 + for dm_build_1523 < dm_build_1522 && dm_build_1520.dm_build_1501 != nil { + dm_build_1524 = dm_build_1520.dm_build_1501.dm_build_1570(dm_build_1521, dm_build_1522-dm_build_1523) + if dm_build_1520.dm_build_1501.dm_build_1556 == 0 { + dm_build_1520.dm_build_1543() + } + dm_build_1523 += dm_build_1524 + dm_build_1520.dm_build_1502 -= dm_build_1524 + } + return dm_build_1523 +} + +func (dm_build_1526 *Dm_build_1499) Dm_build_1525(dm_build_1527 []byte, dm_build_1528 int, dm_build_1529 int) { + if dm_build_1529 == 0 { + return + } + var dm_build_1530 = dm_build_1557(dm_build_1527, dm_build_1528, dm_build_1529) + if dm_build_1526.dm_build_1501 == nil { + dm_build_1526.dm_build_1501 = dm_build_1530 + } else { + dm_build_1526.dm_build_1500.PushBack(dm_build_1530) + } + dm_build_1526.dm_build_1502 += dm_build_1529 +} + +func (dm_build_1532 *Dm_build_1499) dm_build_1531(dm_build_1533 int) byte { + var dm_build_1534 = dm_build_1533 + var dm_build_1535 = dm_build_1532.dm_build_1501 + for dm_build_1534 > 0 && dm_build_1535 != nil { + if dm_build_1535.dm_build_1556 == 0 { + continue + } + if dm_build_1534 > dm_build_1535.dm_build_1556-1 { + dm_build_1534 -= dm_build_1535.dm_build_1556 + dm_build_1535 = dm_build_1532.dm_build_1500.Front().Value.(*dm_build_1553) + } else { + break + } + } + return dm_build_1535.dm_build_1574(dm_build_1534) +} +func (dm_build_1537 *Dm_build_1499) Dm_build_1536(dm_build_1538 *Dm_build_1499) { + if dm_build_1538.dm_build_1502 == 0 { + return + } + var dm_build_1539 = dm_build_1538.dm_build_1501 + for dm_build_1539 != nil { + dm_build_1537.dm_build_1540(dm_build_1539) + dm_build_1538.dm_build_1543() + dm_build_1539 = dm_build_1538.dm_build_1501 + } + dm_build_1538.dm_build_1502 = 0 +} +func (dm_build_1541 *Dm_build_1499) dm_build_1540(dm_build_1542 *dm_build_1553) { + if dm_build_1542.dm_build_1556 == 0 { + return + } + if dm_build_1541.dm_build_1501 == nil { + dm_build_1541.dm_build_1501 = dm_build_1542 + } else { + dm_build_1541.dm_build_1500.PushBack(dm_build_1542) + } + dm_build_1541.dm_build_1502 += dm_build_1542.dm_build_1556 +} + +func (dm_build_1544 *Dm_build_1499) dm_build_1543() { + var dm_build_1545 = dm_build_1544.dm_build_1500.Front() + if dm_build_1545 == nil { + dm_build_1544.dm_build_1501 = nil + } else { + dm_build_1544.dm_build_1501 = dm_build_1545.Value.(*dm_build_1553) + dm_build_1544.dm_build_1500.Remove(dm_build_1545) + } +} + +func (dm_build_1547 *Dm_build_1499) Dm_build_1546() []byte { + var dm_build_1548 = make([]byte, dm_build_1547.dm_build_1502) + var dm_build_1549 = dm_build_1547.dm_build_1501 + var dm_build_1550 = 0 + var dm_build_1551 = len(dm_build_1548) + var dm_build_1552 = 0 + for dm_build_1549 != nil { + if dm_build_1549.dm_build_1556 > 0 { + if dm_build_1551 > dm_build_1549.dm_build_1556 { + dm_build_1552 = dm_build_1549.dm_build_1556 + } else { + dm_build_1552 = dm_build_1551 + } + copy(dm_build_1548[dm_build_1550:dm_build_1550+dm_build_1552], dm_build_1549.dm_build_1554[dm_build_1549.dm_build_1555:dm_build_1549.dm_build_1555+dm_build_1552]) + dm_build_1550 += dm_build_1552 + dm_build_1551 -= dm_build_1552 + } + if dm_build_1547.dm_build_1500.Front() == nil { + dm_build_1549 = nil + } else { + dm_build_1549 = dm_build_1547.dm_build_1500.Front().Value.(*dm_build_1553) + } + } + return dm_build_1548 +} + +type dm_build_1553 struct { + dm_build_1554 []byte + dm_build_1555 int + dm_build_1556 int +} + +func dm_build_1557(dm_build_1558 []byte, dm_build_1559 int, dm_build_1560 int) *dm_build_1553 { + return &dm_build_1553{ + dm_build_1558, + dm_build_1559, + dm_build_1560, + } +} + +func (dm_build_1562 *dm_build_1553) dm_build_1561(dm_build_1563 *Dm_build_0, dm_build_1564 int) int { + if dm_build_1562.dm_build_1556 <= dm_build_1564 { + dm_build_1564 = dm_build_1562.dm_build_1556 + } + dm_build_1563.Dm_build_79(dm_build_1562.dm_build_1554[dm_build_1562.dm_build_1555 : dm_build_1562.dm_build_1555+dm_build_1564]) + dm_build_1562.dm_build_1555 += dm_build_1564 + dm_build_1562.dm_build_1556 -= dm_build_1564 + return dm_build_1564 +} + +func (dm_build_1566 *dm_build_1553) dm_build_1565(dm_build_1567 []byte, dm_build_1568 int, dm_build_1569 int) int { + if dm_build_1566.dm_build_1556 <= dm_build_1569 { + dm_build_1569 = dm_build_1566.dm_build_1556 + } + copy(dm_build_1567[dm_build_1568:dm_build_1568+dm_build_1569], dm_build_1566.dm_build_1554[dm_build_1566.dm_build_1555:dm_build_1566.dm_build_1555+dm_build_1569]) + dm_build_1566.dm_build_1555 += dm_build_1569 + dm_build_1566.dm_build_1556 -= dm_build_1569 + return dm_build_1569 +} + +func (dm_build_1571 *dm_build_1553) dm_build_1570(dm_build_1572 io.Writer, dm_build_1573 int) int { + if dm_build_1571.dm_build_1556 <= dm_build_1573 { + dm_build_1573 = dm_build_1571.dm_build_1556 + } + dm_build_1572.Write(dm_build_1571.dm_build_1554[dm_build_1571.dm_build_1555 : dm_build_1571.dm_build_1555+dm_build_1573]) + dm_build_1571.dm_build_1555 += dm_build_1573 + dm_build_1571.dm_build_1556 -= dm_build_1573 + return dm_build_1573 +} +func (dm_build_1575 *dm_build_1553) dm_build_1574(dm_build_1576 int) byte { + return dm_build_1575.dm_build_1554[dm_build_1575.dm_build_1555+dm_build_1576] +} diff --git a/dmr/e.go b/dmr/e.go new file mode 100644 index 0000000..eb3b84a --- /dev/null +++ b/dmr/e.go @@ -0,0 +1,543 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "bytes" + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/ianaindex" + "golang.org/x/text/transform" + "io" + "io/ioutil" + "math" +) + +type dm_build_1219 struct{} + +var Dm_build_1220 = &dm_build_1219{} + +func (Dm_build_1222 *dm_build_1219) Dm_build_1221(dm_build_1223 []byte, dm_build_1224 int, dm_build_1225 byte) int { + dm_build_1223[dm_build_1224] = dm_build_1225 + return 1 +} + +func (Dm_build_1227 *dm_build_1219) Dm_build_1226(dm_build_1228 []byte, dm_build_1229 int, dm_build_1230 int8) int { + dm_build_1228[dm_build_1229] = byte(dm_build_1230) + return 1 +} + +func (Dm_build_1232 *dm_build_1219) Dm_build_1231(dm_build_1233 []byte, dm_build_1234 int, dm_build_1235 int16) int { + dm_build_1233[dm_build_1234] = byte(dm_build_1235) + dm_build_1234++ + dm_build_1233[dm_build_1234] = byte(dm_build_1235 >> 8) + return 2 +} + +func (Dm_build_1237 *dm_build_1219) Dm_build_1236(dm_build_1238 []byte, dm_build_1239 int, dm_build_1240 int32) int { + dm_build_1238[dm_build_1239] = byte(dm_build_1240) + dm_build_1239++ + dm_build_1238[dm_build_1239] = byte(dm_build_1240 >> 8) + dm_build_1239++ + dm_build_1238[dm_build_1239] = byte(dm_build_1240 >> 16) + dm_build_1239++ + dm_build_1238[dm_build_1239] = byte(dm_build_1240 >> 24) + dm_build_1239++ + return 4 +} + +func (Dm_build_1242 *dm_build_1219) Dm_build_1241(dm_build_1243 []byte, dm_build_1244 int, dm_build_1245 int64) int { + dm_build_1243[dm_build_1244] = byte(dm_build_1245) + dm_build_1244++ + dm_build_1243[dm_build_1244] = byte(dm_build_1245 >> 8) + dm_build_1244++ + dm_build_1243[dm_build_1244] = byte(dm_build_1245 >> 16) + dm_build_1244++ + dm_build_1243[dm_build_1244] = byte(dm_build_1245 >> 24) + dm_build_1244++ + dm_build_1243[dm_build_1244] = byte(dm_build_1245 >> 32) + dm_build_1244++ + dm_build_1243[dm_build_1244] = byte(dm_build_1245 >> 40) + dm_build_1244++ + dm_build_1243[dm_build_1244] = byte(dm_build_1245 >> 48) + dm_build_1244++ + dm_build_1243[dm_build_1244] = byte(dm_build_1245 >> 56) + return 8 +} + +func (Dm_build_1247 *dm_build_1219) Dm_build_1246(dm_build_1248 []byte, dm_build_1249 int, dm_build_1250 float32) int { + return Dm_build_1247.Dm_build_1266(dm_build_1248, dm_build_1249, math.Float32bits(dm_build_1250)) +} + +func (Dm_build_1252 *dm_build_1219) Dm_build_1251(dm_build_1253 []byte, dm_build_1254 int, dm_build_1255 float64) int { + return Dm_build_1252.Dm_build_1271(dm_build_1253, dm_build_1254, math.Float64bits(dm_build_1255)) +} + +func (Dm_build_1257 *dm_build_1219) Dm_build_1256(dm_build_1258 []byte, dm_build_1259 int, dm_build_1260 uint8) int { + dm_build_1258[dm_build_1259] = byte(dm_build_1260) + return 1 +} + +func (Dm_build_1262 *dm_build_1219) Dm_build_1261(dm_build_1263 []byte, dm_build_1264 int, dm_build_1265 uint16) int { + dm_build_1263[dm_build_1264] = byte(dm_build_1265) + dm_build_1264++ + dm_build_1263[dm_build_1264] = byte(dm_build_1265 >> 8) + return 2 +} + +func (Dm_build_1267 *dm_build_1219) Dm_build_1266(dm_build_1268 []byte, dm_build_1269 int, dm_build_1270 uint32) int { + dm_build_1268[dm_build_1269] = byte(dm_build_1270) + dm_build_1269++ + dm_build_1268[dm_build_1269] = byte(dm_build_1270 >> 8) + dm_build_1269++ + dm_build_1268[dm_build_1269] = byte(dm_build_1270 >> 16) + dm_build_1269++ + dm_build_1268[dm_build_1269] = byte(dm_build_1270 >> 24) + return 3 +} + +func (Dm_build_1272 *dm_build_1219) Dm_build_1271(dm_build_1273 []byte, dm_build_1274 int, dm_build_1275 uint64) int { + dm_build_1273[dm_build_1274] = byte(dm_build_1275) + dm_build_1274++ + dm_build_1273[dm_build_1274] = byte(dm_build_1275 >> 8) + dm_build_1274++ + dm_build_1273[dm_build_1274] = byte(dm_build_1275 >> 16) + dm_build_1274++ + dm_build_1273[dm_build_1274] = byte(dm_build_1275 >> 24) + dm_build_1274++ + dm_build_1273[dm_build_1274] = byte(dm_build_1275 >> 32) + dm_build_1274++ + dm_build_1273[dm_build_1274] = byte(dm_build_1275 >> 40) + dm_build_1274++ + dm_build_1273[dm_build_1274] = byte(dm_build_1275 >> 48) + dm_build_1274++ + dm_build_1273[dm_build_1274] = byte(dm_build_1275 >> 56) + return 3 +} + +func (Dm_build_1277 *dm_build_1219) Dm_build_1276(dm_build_1278 []byte, dm_build_1279 int, dm_build_1280 []byte, dm_build_1281 int, dm_build_1282 int) int { + copy(dm_build_1278[dm_build_1279:dm_build_1279+dm_build_1282], dm_build_1280[dm_build_1281:dm_build_1281+dm_build_1282]) + return dm_build_1282 +} + +func (Dm_build_1284 *dm_build_1219) Dm_build_1283(dm_build_1285 []byte, dm_build_1286 int, dm_build_1287 []byte, dm_build_1288 int, dm_build_1289 int) int { + dm_build_1286 += Dm_build_1284.Dm_build_1266(dm_build_1285, dm_build_1286, uint32(dm_build_1289)) + return 4 + Dm_build_1284.Dm_build_1276(dm_build_1285, dm_build_1286, dm_build_1287, dm_build_1288, dm_build_1289) +} + +func (Dm_build_1291 *dm_build_1219) Dm_build_1290(dm_build_1292 []byte, dm_build_1293 int, dm_build_1294 []byte, dm_build_1295 int, dm_build_1296 int) int { + dm_build_1293 += Dm_build_1291.Dm_build_1261(dm_build_1292, dm_build_1293, uint16(dm_build_1296)) + return 2 + Dm_build_1291.Dm_build_1276(dm_build_1292, dm_build_1293, dm_build_1294, dm_build_1295, dm_build_1296) +} + +func (Dm_build_1298 *dm_build_1219) Dm_build_1297(dm_build_1299 []byte, dm_build_1300 int, dm_build_1301 string, dm_build_1302 string, dm_build_1303 *DmConnection) int { + dm_build_1304 := Dm_build_1298.Dm_build_1433(dm_build_1301, dm_build_1302, dm_build_1303) + dm_build_1300 += Dm_build_1298.Dm_build_1266(dm_build_1299, dm_build_1300, uint32(len(dm_build_1304))) + return 4 + Dm_build_1298.Dm_build_1276(dm_build_1299, dm_build_1300, dm_build_1304, 0, len(dm_build_1304)) +} + +func (Dm_build_1306 *dm_build_1219) Dm_build_1305(dm_build_1307 []byte, dm_build_1308 int, dm_build_1309 string, dm_build_1310 string, dm_build_1311 *DmConnection) int { + dm_build_1312 := Dm_build_1306.Dm_build_1433(dm_build_1309, dm_build_1310, dm_build_1311) + + dm_build_1308 += Dm_build_1306.Dm_build_1261(dm_build_1307, dm_build_1308, uint16(len(dm_build_1312))) + return 2 + Dm_build_1306.Dm_build_1276(dm_build_1307, dm_build_1308, dm_build_1312, 0, len(dm_build_1312)) +} + +func (Dm_build_1314 *dm_build_1219) Dm_build_1313(dm_build_1315 []byte, dm_build_1316 int) byte { + return dm_build_1315[dm_build_1316] +} + +func (Dm_build_1318 *dm_build_1219) Dm_build_1317(dm_build_1319 []byte, dm_build_1320 int) int16 { + var dm_build_1321 int16 + dm_build_1321 = int16(dm_build_1319[dm_build_1320] & 0xff) + dm_build_1320++ + dm_build_1321 |= int16(dm_build_1319[dm_build_1320]&0xff) << 8 + return dm_build_1321 +} + +func (Dm_build_1323 *dm_build_1219) Dm_build_1322(dm_build_1324 []byte, dm_build_1325 int) int32 { + var dm_build_1326 int32 + dm_build_1326 = int32(dm_build_1324[dm_build_1325] & 0xff) + dm_build_1325++ + dm_build_1326 |= int32(dm_build_1324[dm_build_1325]&0xff) << 8 + dm_build_1325++ + dm_build_1326 |= int32(dm_build_1324[dm_build_1325]&0xff) << 16 + dm_build_1325++ + dm_build_1326 |= int32(dm_build_1324[dm_build_1325]&0xff) << 24 + return dm_build_1326 +} + +func (Dm_build_1328 *dm_build_1219) Dm_build_1327(dm_build_1329 []byte, dm_build_1330 int) int64 { + var dm_build_1331 int64 + dm_build_1331 = int64(dm_build_1329[dm_build_1330] & 0xff) + dm_build_1330++ + dm_build_1331 |= int64(dm_build_1329[dm_build_1330]&0xff) << 8 + dm_build_1330++ + dm_build_1331 |= int64(dm_build_1329[dm_build_1330]&0xff) << 16 + dm_build_1330++ + dm_build_1331 |= int64(dm_build_1329[dm_build_1330]&0xff) << 24 + dm_build_1330++ + dm_build_1331 |= int64(dm_build_1329[dm_build_1330]&0xff) << 32 + dm_build_1330++ + dm_build_1331 |= int64(dm_build_1329[dm_build_1330]&0xff) << 40 + dm_build_1330++ + dm_build_1331 |= int64(dm_build_1329[dm_build_1330]&0xff) << 48 + dm_build_1330++ + dm_build_1331 |= int64(dm_build_1329[dm_build_1330]&0xff) << 56 + return dm_build_1331 +} + +func (Dm_build_1333 *dm_build_1219) Dm_build_1332(dm_build_1334 []byte, dm_build_1335 int) float32 { + return math.Float32frombits(Dm_build_1333.Dm_build_1349(dm_build_1334, dm_build_1335)) +} + +func (Dm_build_1337 *dm_build_1219) Dm_build_1336(dm_build_1338 []byte, dm_build_1339 int) float64 { + return math.Float64frombits(Dm_build_1337.Dm_build_1354(dm_build_1338, dm_build_1339)) +} + +func (Dm_build_1341 *dm_build_1219) Dm_build_1340(dm_build_1342 []byte, dm_build_1343 int) uint8 { + return uint8(dm_build_1342[dm_build_1343] & 0xff) +} + +func (Dm_build_1345 *dm_build_1219) Dm_build_1344(dm_build_1346 []byte, dm_build_1347 int) uint16 { + var dm_build_1348 uint16 + dm_build_1348 = uint16(dm_build_1346[dm_build_1347] & 0xff) + dm_build_1347++ + dm_build_1348 |= uint16(dm_build_1346[dm_build_1347]&0xff) << 8 + return dm_build_1348 +} + +func (Dm_build_1350 *dm_build_1219) Dm_build_1349(dm_build_1351 []byte, dm_build_1352 int) uint32 { + var dm_build_1353 uint32 + dm_build_1353 = uint32(dm_build_1351[dm_build_1352] & 0xff) + dm_build_1352++ + dm_build_1353 |= uint32(dm_build_1351[dm_build_1352]&0xff) << 8 + dm_build_1352++ + dm_build_1353 |= uint32(dm_build_1351[dm_build_1352]&0xff) << 16 + dm_build_1352++ + dm_build_1353 |= uint32(dm_build_1351[dm_build_1352]&0xff) << 24 + return dm_build_1353 +} + +func (Dm_build_1355 *dm_build_1219) Dm_build_1354(dm_build_1356 []byte, dm_build_1357 int) uint64 { + var dm_build_1358 uint64 + dm_build_1358 = uint64(dm_build_1356[dm_build_1357] & 0xff) + dm_build_1357++ + dm_build_1358 |= uint64(dm_build_1356[dm_build_1357]&0xff) << 8 + dm_build_1357++ + dm_build_1358 |= uint64(dm_build_1356[dm_build_1357]&0xff) << 16 + dm_build_1357++ + dm_build_1358 |= uint64(dm_build_1356[dm_build_1357]&0xff) << 24 + dm_build_1357++ + dm_build_1358 |= uint64(dm_build_1356[dm_build_1357]&0xff) << 32 + dm_build_1357++ + dm_build_1358 |= uint64(dm_build_1356[dm_build_1357]&0xff) << 40 + dm_build_1357++ + dm_build_1358 |= uint64(dm_build_1356[dm_build_1357]&0xff) << 48 + dm_build_1357++ + dm_build_1358 |= uint64(dm_build_1356[dm_build_1357]&0xff) << 56 + return dm_build_1358 +} + +func (Dm_build_1360 *dm_build_1219) Dm_build_1359(dm_build_1361 []byte, dm_build_1362 int) []byte { + dm_build_1363 := Dm_build_1360.Dm_build_1349(dm_build_1361, dm_build_1362) + + dm_build_1364 := make([]byte, dm_build_1363) + copy(dm_build_1364[:int(dm_build_1363)], dm_build_1361[dm_build_1362+4:dm_build_1362+4+int(dm_build_1363)]) + return dm_build_1364 +} + +func (Dm_build_1366 *dm_build_1219) Dm_build_1365(dm_build_1367 []byte, dm_build_1368 int) []byte { + dm_build_1369 := Dm_build_1366.Dm_build_1344(dm_build_1367, dm_build_1368) + + dm_build_1370 := make([]byte, dm_build_1369) + copy(dm_build_1370[:int(dm_build_1369)], dm_build_1367[dm_build_1368+2:dm_build_1368+2+int(dm_build_1369)]) + return dm_build_1370 +} + +func (Dm_build_1372 *dm_build_1219) Dm_build_1371(dm_build_1373 []byte, dm_build_1374 int, dm_build_1375 int) []byte { + + dm_build_1376 := make([]byte, dm_build_1375) + copy(dm_build_1376[:dm_build_1375], dm_build_1373[dm_build_1374:dm_build_1374+dm_build_1375]) + return dm_build_1376 +} + +func (Dm_build_1378 *dm_build_1219) Dm_build_1377(dm_build_1379 []byte, dm_build_1380 int, dm_build_1381 int, dm_build_1382 string, dm_build_1383 *DmConnection) string { + return Dm_build_1378.Dm_build_1470(dm_build_1379[dm_build_1380:dm_build_1380+dm_build_1381], dm_build_1382, dm_build_1383) +} + +func (Dm_build_1385 *dm_build_1219) Dm_build_1384(dm_build_1386 []byte, dm_build_1387 int, dm_build_1388 string, dm_build_1389 *DmConnection) string { + dm_build_1390 := Dm_build_1385.Dm_build_1349(dm_build_1386, dm_build_1387) + dm_build_1387 += 4 + return Dm_build_1385.Dm_build_1377(dm_build_1386, dm_build_1387, int(dm_build_1390), dm_build_1388, dm_build_1389) +} + +func (Dm_build_1392 *dm_build_1219) Dm_build_1391(dm_build_1393 []byte, dm_build_1394 int, dm_build_1395 string, dm_build_1396 *DmConnection) string { + dm_build_1397 := Dm_build_1392.Dm_build_1344(dm_build_1393, dm_build_1394) + dm_build_1394 += 2 + return Dm_build_1392.Dm_build_1377(dm_build_1393, dm_build_1394, int(dm_build_1397), dm_build_1395, dm_build_1396) +} + +func (Dm_build_1399 *dm_build_1219) Dm_build_1398(dm_build_1400 byte) []byte { + return []byte{dm_build_1400} +} + +func (Dm_build_1402 *dm_build_1219) Dm_build_1401(dm_build_1403 int16) []byte { + return []byte{byte(dm_build_1403), byte(dm_build_1403 >> 8)} +} + +func (Dm_build_1405 *dm_build_1219) Dm_build_1404(dm_build_1406 int32) []byte { + return []byte{byte(dm_build_1406), byte(dm_build_1406 >> 8), byte(dm_build_1406 >> 16), byte(dm_build_1406 >> 24)} +} + +func (Dm_build_1408 *dm_build_1219) Dm_build_1407(dm_build_1409 int64) []byte { + return []byte{byte(dm_build_1409), byte(dm_build_1409 >> 8), byte(dm_build_1409 >> 16), byte(dm_build_1409 >> 24), byte(dm_build_1409 >> 32), + byte(dm_build_1409 >> 40), byte(dm_build_1409 >> 48), byte(dm_build_1409 >> 56)} +} + +func (Dm_build_1411 *dm_build_1219) Dm_build_1410(dm_build_1412 float32) []byte { + return Dm_build_1411.Dm_build_1422(math.Float32bits(dm_build_1412)) +} + +func (Dm_build_1414 *dm_build_1219) Dm_build_1413(dm_build_1415 float64) []byte { + return Dm_build_1414.Dm_build_1425(math.Float64bits(dm_build_1415)) +} + +func (Dm_build_1417 *dm_build_1219) Dm_build_1416(dm_build_1418 uint8) []byte { + return []byte{byte(dm_build_1418)} +} + +func (Dm_build_1420 *dm_build_1219) Dm_build_1419(dm_build_1421 uint16) []byte { + return []byte{byte(dm_build_1421), byte(dm_build_1421 >> 8)} +} + +func (Dm_build_1423 *dm_build_1219) Dm_build_1422(dm_build_1424 uint32) []byte { + return []byte{byte(dm_build_1424), byte(dm_build_1424 >> 8), byte(dm_build_1424 >> 16), byte(dm_build_1424 >> 24)} +} + +func (Dm_build_1426 *dm_build_1219) Dm_build_1425(dm_build_1427 uint64) []byte { + return []byte{byte(dm_build_1427), byte(dm_build_1427 >> 8), byte(dm_build_1427 >> 16), byte(dm_build_1427 >> 24), byte(dm_build_1427 >> 32), byte(dm_build_1427 >> 40), byte(dm_build_1427 >> 48), byte(dm_build_1427 >> 56)} +} + +func (Dm_build_1429 *dm_build_1219) Dm_build_1428(dm_build_1430 []byte, dm_build_1431 string, dm_build_1432 *DmConnection) []byte { + if dm_build_1431 == "UTF-8" { + return dm_build_1430 + } + + if dm_build_1432 == nil { + if e := dm_build_1475(dm_build_1431); e != nil { + tmp, err := ioutil.ReadAll( + transform.NewReader(bytes.NewReader(dm_build_1430), e.NewEncoder()), + ) + if err != nil { + panic("UTF8 To Charset error!") + } + + return tmp + } + + panic("Unsupported Charset!") + } + + if dm_build_1432.encodeBuffer == nil { + dm_build_1432.encodeBuffer = bytes.NewBuffer(nil) + dm_build_1432.encode = dm_build_1475(dm_build_1432.getServerEncoding()) + dm_build_1432.transformReaderDst = make([]byte, 4096) + dm_build_1432.transformReaderSrc = make([]byte, 4096) + } + + if e := dm_build_1432.encode; e != nil { + + dm_build_1432.encodeBuffer.Reset() + + n, err := dm_build_1432.encodeBuffer.ReadFrom( + Dm_build_1489(bytes.NewReader(dm_build_1430), e.NewEncoder(), dm_build_1432.transformReaderDst, dm_build_1432.transformReaderSrc), + ) + if err != nil { + panic("UTF8 To Charset error!") + } + var tmp = make([]byte, n) + if _, err = dm_build_1432.encodeBuffer.Read(tmp); err != nil { + panic("UTF8 To Charset error!") + } + return tmp + } + + panic("Unsupported Charset!") +} + +func (Dm_build_1434 *dm_build_1219) Dm_build_1433(dm_build_1435 string, dm_build_1436 string, dm_build_1437 *DmConnection) []byte { + return Dm_build_1434.Dm_build_1428([]byte(dm_build_1435), dm_build_1436, dm_build_1437) +} + +func (Dm_build_1439 *dm_build_1219) Dm_build_1438(dm_build_1440 []byte) byte { + return Dm_build_1439.Dm_build_1313(dm_build_1440, 0) +} + +func (Dm_build_1442 *dm_build_1219) Dm_build_1441(dm_build_1443 []byte) int16 { + return Dm_build_1442.Dm_build_1317(dm_build_1443, 0) +} + +func (Dm_build_1445 *dm_build_1219) Dm_build_1444(dm_build_1446 []byte) int32 { + return Dm_build_1445.Dm_build_1322(dm_build_1446, 0) +} + +func (Dm_build_1448 *dm_build_1219) Dm_build_1447(dm_build_1449 []byte) int64 { + return Dm_build_1448.Dm_build_1327(dm_build_1449, 0) +} + +func (Dm_build_1451 *dm_build_1219) Dm_build_1450(dm_build_1452 []byte) float32 { + return Dm_build_1451.Dm_build_1332(dm_build_1452, 0) +} + +func (Dm_build_1454 *dm_build_1219) Dm_build_1453(dm_build_1455 []byte) float64 { + return Dm_build_1454.Dm_build_1336(dm_build_1455, 0) +} + +func (Dm_build_1457 *dm_build_1219) Dm_build_1456(dm_build_1458 []byte) uint8 { + return Dm_build_1457.Dm_build_1340(dm_build_1458, 0) +} + +func (Dm_build_1460 *dm_build_1219) Dm_build_1459(dm_build_1461 []byte) uint16 { + return Dm_build_1460.Dm_build_1344(dm_build_1461, 0) +} + +func (Dm_build_1463 *dm_build_1219) Dm_build_1462(dm_build_1464 []byte) uint32 { + return Dm_build_1463.Dm_build_1349(dm_build_1464, 0) +} + +func (Dm_build_1466 *dm_build_1219) Dm_build_1465(dm_build_1467 []byte, dm_build_1468 string, dm_build_1469 *DmConnection) []byte { + if dm_build_1468 == "UTF-8" { + return dm_build_1467 + } + + if dm_build_1469 == nil { + if e := dm_build_1475(dm_build_1468); e != nil { + + tmp, err := ioutil.ReadAll( + transform.NewReader(bytes.NewReader(dm_build_1467), e.NewDecoder()), + ) + if err != nil { + + panic("Charset To UTF8 error!") + } + + return tmp + } + + panic("Unsupported Charset!") + } + + if dm_build_1469.encodeBuffer == nil { + dm_build_1469.encodeBuffer = bytes.NewBuffer(nil) + dm_build_1469.encode = dm_build_1475(dm_build_1469.getServerEncoding()) + dm_build_1469.transformReaderDst = make([]byte, 4096) + dm_build_1469.transformReaderSrc = make([]byte, 4096) + } + + if e := dm_build_1469.encode; e != nil { + + dm_build_1469.encodeBuffer.Reset() + + n, err := dm_build_1469.encodeBuffer.ReadFrom( + Dm_build_1489(bytes.NewReader(dm_build_1467), e.NewDecoder(), dm_build_1469.transformReaderDst, dm_build_1469.transformReaderSrc), + ) + if err != nil { + + panic("Charset To UTF8 error!") + } + + return dm_build_1469.encodeBuffer.Next(int(n)) + } + + panic("Unsupported Charset!") +} + +func (Dm_build_1471 *dm_build_1219) Dm_build_1470(dm_build_1472 []byte, dm_build_1473 string, dm_build_1474 *DmConnection) string { + return string(Dm_build_1471.Dm_build_1465(dm_build_1472, dm_build_1473, dm_build_1474)) +} + +func dm_build_1475(dm_build_1476 string) encoding.Encoding { + if e, err := ianaindex.MIB.Encoding(dm_build_1476); err == nil && e != nil { + return e + } + return nil +} + +type Dm_build_1477 struct { + dm_build_1478 io.Reader + dm_build_1479 transform.Transformer + dm_build_1480 error + + dm_build_1481 []byte + dm_build_1482, dm_build_1483 int + + dm_build_1484 []byte + dm_build_1485, dm_build_1486 int + + dm_build_1487 bool +} + +const dm_build_1488 = 4096 + +func Dm_build_1489(dm_build_1490 io.Reader, dm_build_1491 transform.Transformer, dm_build_1492 []byte, dm_build_1493 []byte) *Dm_build_1477 { + dm_build_1491.Reset() + return &Dm_build_1477{ + dm_build_1478: dm_build_1490, + dm_build_1479: dm_build_1491, + dm_build_1481: dm_build_1492, + dm_build_1484: dm_build_1493, + } +} + +func (dm_build_1495 *Dm_build_1477) Read(dm_build_1496 []byte) (int, error) { + dm_build_1497, dm_build_1498 := 0, error(nil) + for { + + if dm_build_1495.dm_build_1482 != dm_build_1495.dm_build_1483 { + dm_build_1497 = copy(dm_build_1496, dm_build_1495.dm_build_1481[dm_build_1495.dm_build_1482:dm_build_1495.dm_build_1483]) + dm_build_1495.dm_build_1482 += dm_build_1497 + if dm_build_1495.dm_build_1482 == dm_build_1495.dm_build_1483 && dm_build_1495.dm_build_1487 { + return dm_build_1497, dm_build_1495.dm_build_1480 + } + return dm_build_1497, nil + } else if dm_build_1495.dm_build_1487 { + return 0, dm_build_1495.dm_build_1480 + } + + if dm_build_1495.dm_build_1485 != dm_build_1495.dm_build_1486 || dm_build_1495.dm_build_1480 != nil { + dm_build_1495.dm_build_1482 = 0 + dm_build_1495.dm_build_1483, dm_build_1497, dm_build_1498 = dm_build_1495.dm_build_1479.Transform(dm_build_1495.dm_build_1481, dm_build_1495.dm_build_1484[dm_build_1495.dm_build_1485:dm_build_1495.dm_build_1486], dm_build_1495.dm_build_1480 == io.EOF) + dm_build_1495.dm_build_1485 += dm_build_1497 + + switch { + case dm_build_1498 == nil: + if dm_build_1495.dm_build_1485 != dm_build_1495.dm_build_1486 { + dm_build_1495.dm_build_1480 = nil + } + + dm_build_1495.dm_build_1487 = dm_build_1495.dm_build_1480 != nil + continue + case dm_build_1498 == transform.ErrShortDst && (dm_build_1495.dm_build_1483 != 0 || dm_build_1497 != 0): + + continue + case dm_build_1498 == transform.ErrShortSrc && dm_build_1495.dm_build_1486-dm_build_1495.dm_build_1485 != len(dm_build_1495.dm_build_1484) && dm_build_1495.dm_build_1480 == nil: + + default: + dm_build_1495.dm_build_1487 = true + + if dm_build_1495.dm_build_1480 == nil || dm_build_1495.dm_build_1480 == io.EOF { + dm_build_1495.dm_build_1480 = dm_build_1498 + } + continue + } + } + + if dm_build_1495.dm_build_1485 != 0 { + dm_build_1495.dm_build_1485, dm_build_1495.dm_build_1486 = 0, copy(dm_build_1495.dm_build_1484, dm_build_1495.dm_build_1484[dm_build_1495.dm_build_1485:dm_build_1495.dm_build_1486]) + } + dm_build_1497, dm_build_1495.dm_build_1480 = dm_build_1495.dm_build_1478.Read(dm_build_1495.dm_build_1484[dm_build_1495.dm_build_1486:]) + dm_build_1495.dm_build_1486 += dm_build_1497 + } +} diff --git a/dmr/f.go b/dmr/f.go new file mode 100644 index 0000000..69912fa --- /dev/null +++ b/dmr/f.go @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "bytes" + "compress/zlib" + "github.com/golang/snappy" +) + +func Compress(srcBuffer *Dm_build_0, offset int, length int, compressID int) ([]byte, error) { + if compressID == Dm_build_683 { + return snappy.Encode(nil, srcBuffer.Dm_build_290(offset, length)), nil + } + return GzlibCompress(srcBuffer, offset, length) +} + +func UnCompress(srcBytes []byte, compressID int) ([]byte, error) { + if compressID == Dm_build_683 { + return snappy.Decode(nil, srcBytes) + } + return GzlibUncompress(srcBytes) +} + +func GzlibCompress(srcBuffer *Dm_build_0, offset int, length int) ([]byte, error) { + var ret bytes.Buffer + var w = zlib.NewWriter(&ret) + w.Write(srcBuffer.Dm_build_290(offset, length)) + w.Close() + return ret.Bytes(), nil +} + +func GzlibUncompress(srcBytes []byte) ([]byte, error) { + var bytesBuf = new(bytes.Buffer) + r, err := zlib.NewReader(bytes.NewReader(srcBytes)) + if err != nil { + return nil, err + } + defer r.Close() + _, err = bytesBuf.ReadFrom(r) + if err != nil { + return nil, err + } + return bytesBuf.Bytes(), nil +} diff --git a/dmr/g.go b/dmr/g.go new file mode 100644 index 0000000..27d0dd4 --- /dev/null +++ b/dmr/g.go @@ -0,0 +1,2155 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "fmt" + "math" + "os" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +type ExecuteTypeEnum int + +const ( + Execute ExecuteTypeEnum = iota + ExecuteQuery + ExecuteUpdate +) + +var idGenerator int64 = 0 + +func generateId() string { + return time.Now().String() + strconv.Itoa(int(atomic.AddInt64(&idGenerator, 1))) +} + +func getInt64(counter *int64, reset bool) int64 { + if reset { + return atomic.SwapInt64(counter, 0) + } + return atomic.LoadInt64(counter) +} + +type SqlStatValue struct { + id string + + sql string + + sqlHash int64 + + dataSource string + + dataSourceId string + + executeLastStartTime int64 + + executeBatchSizeTotal int64 + + executeBatchSizeMax int64 + + executeSuccessCount int64 + + executeSpanNanoTotal int64 + + executeSpanNanoMax int64 + + runningCount int64 + + concurrentMax int64 + + resultSetHoldTimeNano int64 + + executeAndResultSetHoldTime int64 + + executeNanoSpanMaxOccurTime int64 + + executeErrorCount int64 + + executeErrorLast error + + executeErrorLastMessage string + + executeErrorLastStackTrace string + + executeErrorLastTime int64 + + updateCount int64 + + updateCountMax int64 + + fetchRowCount int64 + + fetchRowCountMax int64 + + inTransactionCount int64 + + lastSlowParameters string + + clobOpenCount int64 + + blobOpenCount int64 + + readStringLength int64 + + readBytesLength int64 + + inputStreamOpenCount int64 + + readerOpenCount int64 + + histogram_0_1 int64 + + histogram_1_10 int64 + + histogram_10_100 int64 + + histogram_100_1000 int64 + + histogram_1000_10000 int64 + + histogram_10000_100000 int64 + + histogram_100000_1000000 int64 + + histogram_1000000_more int64 + + executeAndResultHoldTime_0_1 int64 + + executeAndResultHoldTime_1_10 int64 + + executeAndResultHoldTime_10_100 int64 + + executeAndResultHoldTime_100_1000 int64 + + executeAndResultHoldTime_1000_10000 int64 + + executeAndResultHoldTime_10000_100000 int64 + + executeAndResultHoldTime_100000_1000000 int64 + + executeAndResultHoldTime_1000000_more int64 + + fetchRowCount_0_1 int64 + + fetchRowCount_1_10 int64 + + fetchRowCount_10_100 int64 + + fetchRowCount_100_1000 int64 + + fetchRowCount_1000_10000 int64 + + fetchRowCount_10000_more int64 + + updateCount_0_1 int64 + + updateCount_1_10 int64 + + updateCount_10_100 int64 + + updateCount_100_1000 int64 + + updateCount_1000_10000 int64 + + updateCount_10000_more int64 +} + +func newSqlStatValue() *SqlStatValue { + ssv := new(SqlStatValue) + return ssv +} + +func (ssv *SqlStatValue) getExecuteHistogram() []int64 { + return []int64{ + ssv.histogram_0_1, + ssv.histogram_1_10, + ssv.histogram_10_100, + ssv.histogram_100_1000, + ssv.histogram_1000_10000, + ssv.histogram_10000_100000, + ssv.histogram_100000_1000000, + ssv.histogram_1000000_more, + } +} + +func (ssv *SqlStatValue) getExecuteAndResultHoldHistogram() []int64 { + return []int64{ssv.executeAndResultHoldTime_0_1, + ssv.executeAndResultHoldTime_1_10, + ssv.executeAndResultHoldTime_10_100, + ssv.executeAndResultHoldTime_100_1000, + ssv.executeAndResultHoldTime_1000_10000, + ssv.executeAndResultHoldTime_10000_100000, + ssv.executeAndResultHoldTime_100000_1000000, + ssv.executeAndResultHoldTime_1000000_more, + } +} + +func (ssv *SqlStatValue) getFetchRowHistogram() []int64 { + return []int64{ssv.fetchRowCount_0_1, + ssv.fetchRowCount_1_10, + ssv.fetchRowCount_10_100, + ssv.fetchRowCount_100_1000, + ssv.fetchRowCount_1000_10000, + ssv.fetchRowCount_10000_more, + } +} + +func (ssv *SqlStatValue) getUpdateHistogram() []int64 { + return []int64{ssv.updateCount_0_1, + ssv.updateCount_1_10, + ssv.updateCount_10_100, + ssv.updateCount_100_1000, + ssv.updateCount_1000_10000, + ssv.updateCount_10000_more, + } +} + +func (ssv *SqlStatValue) getExecuteCount() int64 { + return ssv.executeErrorCount + ssv.executeSuccessCount +} + +func (ssv *SqlStatValue) getExecuteMillisMax() int64 { + return ssv.executeSpanNanoMax / (1000 * 1000) +} + +func (ssv *SqlStatValue) getExecuteMillisTotal() int64 { + return ssv.executeSpanNanoTotal / (1000 * 1000) +} + +func (ssv *SqlStatValue) getHistogramValues() []int64 { + return []int64{ + + ssv.histogram_0_1, + ssv.histogram_1_10, + ssv.histogram_10_100, + ssv.histogram_100_1000, + ssv.histogram_1000_10000, + ssv.histogram_10000_100000, + ssv.histogram_100000_1000000, + ssv.histogram_1000000_more, + } +} + +func (ssv *SqlStatValue) getFetchRowCountHistogramValues() []int64 { + return []int64{ + + ssv.fetchRowCount_0_1, + ssv.fetchRowCount_1_10, + ssv.fetchRowCount_10_100, + ssv.fetchRowCount_100_1000, + ssv.fetchRowCount_1000_10000, + ssv.fetchRowCount_10000_more, + } +} + +func (ssv *SqlStatValue) getUpdateCountHistogramValues() []int64 { + return []int64{ + + ssv.updateCount_0_1, + ssv.updateCount_1_10, + ssv.updateCount_10_100, + ssv.updateCount_100_1000, + ssv.updateCount_1000_10000, + ssv.updateCount_10000_more, + } +} + +func (ssv *SqlStatValue) getExecuteAndResultHoldTimeHistogramValues() []int64 { + return []int64{ + + ssv.executeAndResultHoldTime_0_1, + ssv.executeAndResultHoldTime_1_10, + ssv.executeAndResultHoldTime_10_100, + ssv.executeAndResultHoldTime_100_1000, + ssv.executeAndResultHoldTime_1000_10000, + ssv.executeAndResultHoldTime_10000_100000, + ssv.executeAndResultHoldTime_100000_1000000, + ssv.executeAndResultHoldTime_1000000_more, + } +} + +func (ssv *SqlStatValue) getResultSetHoldTimeMilis() int64 { + return ssv.resultSetHoldTimeNano / (1000 * 1000) +} + +func (ssv *SqlStatValue) getExecuteAndResultSetHoldTimeMilis() int64 { + return ssv.executeAndResultSetHoldTime / (1000 * 1000) +} + +func (ssv *SqlStatValue) getData() map[string]interface{} { + m := make(map[string]interface{}) + + m[idConstStr] = ssv.id + m[dataSourceConstStr] = ssv.dataSource + m["DataSourceId"] = ssv.dataSourceId + m[sqlConstStr] = ssv.sql + m[executeCountConstStr] = ssv.getExecuteCount() + m[errorCountConstStr] = ssv.executeErrorCount + + m[totalTimeConstStr] = ssv.getExecuteMillisTotal() + m["LastTime"] = ssv.executeLastStartTime + m[maxTimespanConstStr] = ssv.getExecuteMillisMax() + m["LastError"] = ssv.executeErrorLast + m[effectedRowCountConstStr] = ssv.updateCount + + m[fetchRowCountConstStr] = ssv.fetchRowCount + m["MaxTimespanOccurTime"] = ssv.executeNanoSpanMaxOccurTime + m["BatchSizeMax"] = ssv.executeBatchSizeMax + m["BatchSizeTotal"] = ssv.executeBatchSizeTotal + m[concurrentMaxConstStr] = ssv.concurrentMax + + m[runningCountConstStr] = ssv.runningCount + + if ssv.executeErrorLastMessage != "" { + m["LastErrorMessage"] = ssv.executeErrorLastMessage + m["LastErrorStackTrace"] = ssv.executeErrorLastStackTrace + m["LastErrorTime"] = ssv.executeErrorLastTime + } else { + m["LastErrorMessage"] = "" + m["LastErrorClass"] = "" + m["LastErrorStackTrace"] = "" + m["LastErrorTime"] = "" + } + + m[urlConstStr] = "" + m[inTransactionCountConstStr] = ssv.inTransactionCount + + m["Histogram"] = ssv.getHistogramValues() + m["LastSlowParameters"] = ssv.lastSlowParameters + m["ResultSetHoldTime"] = ssv.getResultSetHoldTimeMilis() + m["ExecuteAndResultSetHoldTime"] = ssv.getExecuteAndResultSetHoldTimeMilis() + m[fetchRowCountConstStr] = ssv.getFetchRowCountHistogramValues() + + m[effectedRowCountHistogramConstStr] = ssv.getUpdateCountHistogramValues() + m[executeAndResultHoldTimeHistogramConstStr] = ssv.getExecuteAndResultHoldTimeHistogramValues() + m["EffectedRowCountMax"] = ssv.updateCountMax + m["FetchRowCountMax"] = ssv.fetchRowCountMax + m[clobOpenCountConstStr] = ssv.clobOpenCount + + m[blobOpenCountConstStr] = ssv.blobOpenCount + m["ReadStringLength"] = ssv.readStringLength + m["ReadBytesLength"] = ssv.readBytesLength + m["InputStreamOpenCount"] = ssv.inputStreamOpenCount + m["ReaderOpenCount"] = ssv.readerOpenCount + + m["HASH"] = ssv.sqlHash + + m[executeHoldTimeHistogramConstStr] = ssv.getExecuteHistogram() + + return m +} + +type sqlStat struct { + Sql string + + SqlHash int64 + + Id string + + ExecuteLastStartTime int64 + + ExecuteBatchSizeTotal int64 + + ExecuteBatchSizeMax int64 + + ExecuteSuccessCount int64 + + ExecuteSpanNanoTotal int64 + + ExecuteSpanNanoMax int64 + + RunningCount int64 + + ConcurrentMax int64 + + ResultSetHoldTimeNano int64 + + ExecuteAndResultSetHoldTime int64 + + DataSource string + + File string + + ExecuteNanoSpanMaxOccurTime int64 + + ExecuteErrorCount int64 + + ExecuteErrorLast error + + ExecuteErrorLastTime int64 + + UpdateCount int64 + + UpdateCountMax int64 + + FetchRowCount int64 + + FetchRowCountMax int64 + + InTransactionCount int64 + + LastSlowParameters string + + Removed int64 + + ClobOpenCount int64 + + BlobOpenCount int64 + + ReadStringLength int64 + + ReadBytesLength int64 + + InputStreamOpenCount int64 + + ReaderOpenCount int64 + + Histogram_0_1 int64 + + Histogram_1_10 int64 + + Histogram_10_100 int64 + + Histogram_100_1000 int64 + + Histogram_1000_10000 int64 + + Histogram_10000_100000 int64 + + Histogram_100000_1000000 int64 + + Histogram_1000000_more int64 + + ExecuteAndResultHoldTime_0_1 int64 + + ExecuteAndResultHoldTime_1_10 int64 + + ExecuteAndResultHoldTime_10_100 int64 + + ExecuteAndResultHoldTime_100_1000 int64 + + ExecuteAndResultHoldTime_1000_10000 int64 + + ExecuteAndResultHoldTime_10000_100000 int64 + + ExecuteAndResultHoldTime_100000_1000000 int64 + + ExecuteAndResultHoldTime_1000000_more int64 + + FetchRowCount_0_1 int64 + + FetchRowCount_1_10 int64 + + FetchRowCount_10_100 int64 + + FetchRowCount_100_1000 int64 + + FetchRowCount_1000_10000 int64 + + FetchRowCount_10000_more int64 + + UpdateCount_0_1 int64 + + UpdateCount_1_10 int64 + + UpdateCount_10_100 int64 + + UpdateCount_100_1000 int64 + + UpdateCount_1000_10000 int64 + + UpdateCount_10000_more int64 + + DataSourceId string +} + +func NewSqlStat(sql string) *sqlStat { + s := new(sqlStat) + s.Sql = sql + s.Id = "SQL" + generateId() + return s +} + +func (s *sqlStat) reset() { + s.ExecuteLastStartTime = 0 + + s.ExecuteBatchSizeTotal = 0 + s.ExecuteBatchSizeMax = 0 + + s.ExecuteSuccessCount = 0 + s.ExecuteSpanNanoTotal = 0 + s.ExecuteSpanNanoMax = 0 + s.ExecuteNanoSpanMaxOccurTime = 0 + s.ConcurrentMax = 0 + + s.ExecuteErrorCount = 0 + s.ExecuteErrorLast = nil + s.ExecuteErrorLastTime = 0 + + s.UpdateCount = 0 + s.UpdateCountMax = 0 + s.FetchRowCount = 0 + s.FetchRowCountMax = 0 + + s.Histogram_0_1 = 0 + s.Histogram_1_10 = 0 + s.Histogram_10_100 = 0 + s.Histogram_100_1000 = 0 + s.Histogram_1000_10000 = 0 + s.Histogram_10000_100000 = 0 + s.Histogram_100000_1000000 = 0 + s.Histogram_1000000_more = 0 + + s.LastSlowParameters = "" + s.InTransactionCount = 0 + s.ResultSetHoldTimeNano = 0 + s.ExecuteAndResultSetHoldTime = 0 + + s.FetchRowCount_0_1 = 0 + s.FetchRowCount_1_10 = 0 + s.FetchRowCount_10_100 = 0 + s.FetchRowCount_100_1000 = 0 + s.FetchRowCount_1000_10000 = 0 + s.FetchRowCount_10000_more = 0 + + s.UpdateCount_0_1 = 0 + s.UpdateCount_1_10 = 0 + s.UpdateCount_10_100 = 0 + s.UpdateCount_100_1000 = 0 + s.UpdateCount_1000_10000 = 0 + s.UpdateCount_10000_more = 0 + + s.ExecuteAndResultHoldTime_0_1 = 0 + s.ExecuteAndResultHoldTime_1_10 = 0 + s.ExecuteAndResultHoldTime_10_100 = 0 + s.ExecuteAndResultHoldTime_100_1000 = 0 + s.ExecuteAndResultHoldTime_1000_10000 = 0 + s.ExecuteAndResultHoldTime_10000_100000 = 0 + s.ExecuteAndResultHoldTime_100000_1000000 = 0 + s.ExecuteAndResultHoldTime_1000000_more = 0 + + s.BlobOpenCount = 0 + s.ClobOpenCount = 0 + s.ReadStringLength = 0 + s.ReadBytesLength = 0 + s.InputStreamOpenCount = 0 + s.ReaderOpenCount = 0 +} + +func (s *sqlStat) getValueAndReset() *SqlStatValue { + return s.getValue(true) +} + +func (s *sqlStat) getValue(reset bool) *SqlStatValue { + ssv := newSqlStatValue() + ssv.dataSource = s.DataSource + ssv.dataSourceId = s.DataSourceId + ssv.sql = s.Sql + ssv.sqlHash = s.SqlHash + ssv.id = s.Id + ssv.executeLastStartTime = s.ExecuteLastStartTime + if reset { + s.ExecuteLastStartTime = 0 + } + + ssv.executeBatchSizeTotal = getInt64(&s.ExecuteBatchSizeTotal, reset) + ssv.executeBatchSizeMax = getInt64(&s.ExecuteBatchSizeMax, reset) + ssv.executeSuccessCount = getInt64(&s.ExecuteSuccessCount, reset) + ssv.executeSpanNanoTotal = getInt64(&s.ExecuteSpanNanoTotal, reset) + ssv.executeSpanNanoMax = getInt64(&s.ExecuteSpanNanoMax, reset) + ssv.executeNanoSpanMaxOccurTime = s.ExecuteNanoSpanMaxOccurTime + if reset { + s.ExecuteNanoSpanMaxOccurTime = 0 + } + + ssv.runningCount = s.RunningCount + ssv.concurrentMax = getInt64(&s.ConcurrentMax, reset) + ssv.executeErrorCount = getInt64(&s.ExecuteErrorCount, reset) + ssv.executeErrorLast = s.ExecuteErrorLast + if reset { + s.ExecuteErrorLast = nil + } + + ssv.executeErrorLastTime = s.ExecuteErrorLastTime + if reset { + ssv.executeErrorLastTime = 0 + } + + ssv.updateCount = getInt64(&s.UpdateCount, reset) + ssv.updateCountMax = getInt64(&s.UpdateCountMax, reset) + ssv.fetchRowCount = getInt64(&s.FetchRowCount, reset) + ssv.fetchRowCountMax = getInt64(&s.FetchRowCountMax, reset) + ssv.histogram_0_1 = getInt64(&s.Histogram_0_1, reset) + ssv.histogram_1_10 = getInt64(&s.Histogram_1_10, reset) + ssv.histogram_10_100 = getInt64(&s.Histogram_10_100, reset) + ssv.histogram_100_1000 = getInt64(&s.Histogram_100_1000, reset) + ssv.histogram_1000_10000 = getInt64(&s.Histogram_1000_10000, reset) + ssv.histogram_10000_100000 = getInt64(&s.Histogram_10000_100000, reset) + ssv.histogram_100000_1000000 = getInt64(&s.Histogram_100000_1000000, reset) + ssv.histogram_1000000_more = getInt64(&s.Histogram_1000000_more, reset) + ssv.lastSlowParameters = s.LastSlowParameters + if reset { + s.LastSlowParameters = "" + } + + ssv.inTransactionCount = getInt64(&s.InTransactionCount, reset) + ssv.resultSetHoldTimeNano = getInt64(&s.ResultSetHoldTimeNano, reset) + ssv.executeAndResultSetHoldTime = getInt64(&s.ExecuteAndResultSetHoldTime, reset) + ssv.fetchRowCount_0_1 = getInt64(&s.FetchRowCount_0_1, reset) + ssv.fetchRowCount_1_10 = getInt64(&s.FetchRowCount_1_10, reset) + ssv.fetchRowCount_10_100 = getInt64(&s.FetchRowCount_10_100, reset) + ssv.fetchRowCount_100_1000 = getInt64(&s.FetchRowCount_100_1000, reset) + ssv.fetchRowCount_1000_10000 = getInt64(&s.FetchRowCount_1000_10000, reset) + ssv.fetchRowCount_10000_more = getInt64(&s.FetchRowCount_10000_more, reset) + ssv.updateCount_0_1 = getInt64(&s.UpdateCount_0_1, reset) + ssv.updateCount_1_10 = getInt64(&s.UpdateCount_1_10, reset) + ssv.updateCount_10_100 = getInt64(&s.UpdateCount_10_100, reset) + ssv.updateCount_100_1000 = getInt64(&s.UpdateCount_100_1000, reset) + ssv.updateCount_1000_10000 = getInt64(&s.UpdateCount_1000_10000, reset) + ssv.updateCount_10000_more = getInt64(&s.UpdateCount_10000_more, reset) + ssv.executeAndResultHoldTime_0_1 = getInt64(&s.ExecuteAndResultHoldTime_0_1, reset) + ssv.executeAndResultHoldTime_1_10 = getInt64(&s.ExecuteAndResultHoldTime_1_10, reset) + ssv.executeAndResultHoldTime_10_100 = getInt64(&s.ExecuteAndResultHoldTime_10_100, reset) + ssv.executeAndResultHoldTime_100_1000 = getInt64(&s.ExecuteAndResultHoldTime_100_1000, reset) + ssv.executeAndResultHoldTime_1000_10000 = getInt64(&s.ExecuteAndResultHoldTime_1000_10000, reset) + ssv.executeAndResultHoldTime_10000_100000 = getInt64(&s.ExecuteAndResultHoldTime_10000_100000, reset) + ssv.executeAndResultHoldTime_100000_1000000 = getInt64(&s.ExecuteAndResultHoldTime_100000_1000000, reset) + ssv.executeAndResultHoldTime_1000000_more = getInt64(&s.ExecuteAndResultHoldTime_1000000_more, reset) + ssv.blobOpenCount = getInt64(&s.BlobOpenCount, reset) + ssv.clobOpenCount = getInt64(&s.ClobOpenCount, reset) + ssv.readStringLength = getInt64(&s.ReadStringLength, reset) + ssv.readBytesLength = getInt64(&s.ReadBytesLength, reset) + ssv.inputStreamOpenCount = getInt64(&s.InputStreamOpenCount, reset) + ssv.readerOpenCount = getInt64(&s.ReaderOpenCount, reset) + return ssv +} + +func (s *sqlStat) addUpdateCount(delta int64) { + if delta > 0 { + atomic.AddInt64(&s.UpdateCount, delta) + } + + for { + max := atomic.LoadInt64(&s.UpdateCountMax) + if delta <= max { + break + } + if atomic.CompareAndSwapInt64(&s.UpdateCountMax, max, delta) { + break + } + } + + if delta < 1 { + atomic.AddInt64(&s.UpdateCount_0_1, 1) + } else if delta < 10 { + atomic.AddInt64(&s.UpdateCount_1_10, 1) + } else if delta < 100 { + atomic.AddInt64(&s.UpdateCount_10_100, 1) + } else if delta < 1000 { + atomic.AddInt64(&s.UpdateCount_100_1000, 1) + } else if delta < 10000 { + atomic.AddInt64(&s.UpdateCount_1000_10000, 1) + } else { + atomic.AddInt64(&s.UpdateCount_10000_more, 1) + } +} + +func (s *sqlStat) incrementClobOpenCount() { + atomic.AddInt64(&s.ClobOpenCount, 1) +} + +func (s *sqlStat) incrementBlobOpenCount() { + atomic.AddInt64(&s.BlobOpenCount, 1) +} + +func (s *sqlStat) addStringReadLength(length int64) { + atomic.AddInt64(&s.ReadStringLength, length) +} + +func (s *sqlStat) addReadBytesLength(length int64) { + atomic.AddInt64(&s.ReadBytesLength, length) +} + +func (s *sqlStat) addReaderOpenCount(count int64) { + atomic.AddInt64(&s.ReaderOpenCount, count) +} + +func (s *sqlStat) addInputStreamOpenCount(count int64) { + atomic.AddInt64(&s.InputStreamOpenCount, count) +} + +func (s *sqlStat) addFetchRowCount(delta int64) { + atomic.AddInt64(&s.FetchRowCount, delta) + for { + max := atomic.LoadInt64(&s.FetchRowCountMax) + if delta <= max { + break + } + if atomic.CompareAndSwapInt64(&s.FetchRowCountMax, max, delta) { + break + } + } + + if delta < 1 { + atomic.AddInt64(&s.FetchRowCount_0_1, 1) + } else if delta < 10 { + atomic.AddInt64(&s.FetchRowCount_1_10, 1) + } else if delta < 100 { + atomic.AddInt64(&s.FetchRowCount_10_100, 1) + } else if delta < 1000 { + atomic.AddInt64(&s.FetchRowCount_100_1000, 1) + } else if delta < 10000 { + atomic.AddInt64(&s.FetchRowCount_1000_10000, 1) + } else { + atomic.AddInt64(&s.FetchRowCount_10000_more, 1) + } + +} + +func (s *sqlStat) addExecuteBatchCount(batchSize int64) { + atomic.AddInt64(&s.ExecuteBatchSizeTotal, batchSize) + + for { + current := atomic.LoadInt64(&s.ExecuteBatchSizeMax) + if current < batchSize { + if atomic.CompareAndSwapInt64(&s.ExecuteBatchSizeMax, current, batchSize) { + break + } else { + continue + } + } else { + break + } + } +} + +func (s *sqlStat) incrementExecuteSuccessCount() { + atomic.AddInt64(&s.ExecuteSuccessCount, 1) +} + +func (s *sqlStat) incrementRunningCount() { + val := atomic.AddInt64(&s.RunningCount, 1) + + for { + max := atomic.LoadInt64(&s.ConcurrentMax) + if val > max { + if atomic.CompareAndSwapInt64(&s.ConcurrentMax, max, val) { + break + } else { + continue + } + } else { + break + } + } +} + +func (s *sqlStat) decrementRunningCount() { + atomic.AddInt64(&s.RunningCount, -1) +} + +func (s *sqlStat) addExecuteTimeAndResultHoldTimeHistogramRecord(executeType ExecuteTypeEnum, firstResultSet bool, nanoSpan int64, parameters string) { + s.addExecuteTime(nanoSpan, parameters) + + if ExecuteQuery != executeType && !firstResultSet { + s.executeAndResultHoldTimeHistogramRecord(nanoSpan) + } +} + +func (s *sqlStat) executeAndResultHoldTimeHistogramRecord(nanoSpan int64) { + millis := nanoSpan / 1000 / 1000 + + if millis < 1 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_0_1, 1) + } else if millis < 10 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_1_10, 1) + } else if millis < 100 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_10_100, 1) + } else if millis < 1000 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_100_1000, 1) + } else if millis < 10000 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_1000_10000, 1) + } else if millis < 100000 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_10000_100000, 1) + } else if millis < 1000000 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_100000_1000000, 1) + } else { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_1000000_more, 1) + } +} + +func (s *sqlStat) histogramRecord(nanoSpan int64) { + millis := nanoSpan / 1000 / 1000 + + if millis < 1 { + atomic.AddInt64(&s.Histogram_0_1, 1) + } else if millis < 10 { + atomic.AddInt64(&s.Histogram_1_10, 1) + } else if millis < 100 { + atomic.AddInt64(&s.Histogram_10_100, 1) + } else if millis < 1000 { + atomic.AddInt64(&s.Histogram_100_1000, 1) + } else if millis < 10000 { + atomic.AddInt64(&s.Histogram_1000_10000, 1) + } else if millis < 100000 { + atomic.AddInt64(&s.Histogram_10000_100000, 1) + } else if millis < 1000000 { + atomic.AddInt64(&s.Histogram_100000_1000000, 1) + } else { + atomic.AddInt64(&s.Histogram_1000000_more, 1) + } +} + +func (s *sqlStat) addExecuteTime(nanoSpan int64, parameters string) { + atomic.AddInt64(&s.ExecuteSpanNanoTotal, nanoSpan) + + for { + current := atomic.LoadInt64(&s.ExecuteSpanNanoMax) + if current < nanoSpan { + if atomic.CompareAndSwapInt64(&s.ExecuteSpanNanoMax, current, nanoSpan) { + + s.ExecuteNanoSpanMaxOccurTime = time.Now().UnixNano() + s.LastSlowParameters = parameters + + break + } else { + continue + } + } else { + break + } + } + + s.histogramRecord(nanoSpan) +} + +func (s *sqlStat) getExecuteMillisTotal() int64 { + return s.ExecuteSpanNanoTotal / (1000 * 1000) +} + +func (s *sqlStat) getExecuteMillisMax() int64 { + return s.ExecuteSpanNanoMax / (1000 * 1000) +} + +func (s *sqlStat) incrementInTransactionCount() { + atomic.AddInt64(&s.InTransactionCount, 1) +} + +func (s *sqlStat) getExecuteCount() int64 { + return s.ExecuteErrorCount + s.ExecuteSuccessCount +} + +func (s *sqlStat) getData() map[string]interface{} { + return s.getValue(false).getData() +} + +func (s *sqlStat) getHistogramValues() []int64 { + return []int64{ + + s.Histogram_0_1, + s.Histogram_1_10, + s.Histogram_10_100, + s.Histogram_100_1000, + s.Histogram_1000_10000, + s.Histogram_10000_100000, + s.Histogram_100000_1000000, + s.Histogram_1000000_more, + } +} + +func (s *sqlStat) getHistogramSum() int64 { + values := s.getHistogramValues() + var sum int64 = 0 + for i := 0; i < len(values); i++ { + sum += values[i] + } + return sum +} + +func (s *sqlStat) error(err error) { + atomic.AddInt64(&s.ExecuteErrorCount, 1) + s.ExecuteErrorLastTime = time.Now().UnixNano() + s.ExecuteErrorLast = err +} + +func (s *sqlStat) getResultSetHoldTimeMilis() int64 { + return s.ResultSetHoldTimeNano / (1000 * 1000) +} + +func (s *sqlStat) getExecuteAndResultSetHoldTimeMilis() int64 { + return s.ExecuteAndResultSetHoldTime / (1000 * 1000) +} + +func (s *sqlStat) getFetchRowCountHistogramValues() []int64 { + return []int64{ + + s.FetchRowCount_0_1, + s.FetchRowCount_1_10, + s.FetchRowCount_10_100, + s.FetchRowCount_100_1000, + s.FetchRowCount_1000_10000, + s.FetchRowCount_10000_more, + } +} + +func (s *sqlStat) getUpdateCountHistogramValues() []int64 { + return []int64{ + + s.UpdateCount_0_1, + s.UpdateCount_1_10, + s.UpdateCount_10_100, + s.UpdateCount_100_1000, + s.UpdateCount_1000_10000, + s.UpdateCount_10000_more, + } +} + +func (s *sqlStat) getExecuteAndResultHoldTimeHistogramValues() []int64 { + return []int64{ + + s.ExecuteAndResultHoldTime_0_1, + s.ExecuteAndResultHoldTime_1_10, + s.ExecuteAndResultHoldTime_10_100, + s.ExecuteAndResultHoldTime_100_1000, + s.ExecuteAndResultHoldTime_1000_10000, + s.ExecuteAndResultHoldTime_10000_100000, + s.ExecuteAndResultHoldTime_100000_1000000, + s.ExecuteAndResultHoldTime_1000000_more, + } +} + +func (s *sqlStat) getExecuteAndResultHoldTimeHistogramSum() int64 { + values := s.getExecuteAndResultHoldTimeHistogramValues() + var sum int64 = 0 + for i := 0; i < len(values); i++ { + sum += values[i] + } + return sum +} + +func (s *sqlStat) addResultSetHoldTimeNano(nano int64) { + atomic.AddInt64(&s.ResultSetHoldTimeNano, nano) +} + +func (s *sqlStat) addResultSetHoldTimeNano2(statementExecuteNano int64, resultHoldTimeNano int64) { + atomic.AddInt64(&s.ResultSetHoldTimeNano, resultHoldTimeNano) + atomic.AddInt64(&s.ExecuteAndResultSetHoldTime, statementExecuteNano+resultHoldTimeNano) + s.executeAndResultHoldTimeHistogramRecord((statementExecuteNano + resultHoldTimeNano) / 1000 / 1000) + atomic.AddInt64(&s.UpdateCount_0_1, 1) +} + +type connectionStatValue struct { + id string + + url string + + connCount int64 + + activeConnCount int64 + + maxActiveConnCount int64 + + executeCount int64 + + errorCount int64 + + stmtCount int64 + + activeStmtCount int64 + + maxActiveStmtCount int64 + + commitCount int64 + + rollbackCount int64 + + clobOpenCount int64 + + blobOpenCount int64 + + properties string +} + +func newConnectionStatValue() *connectionStatValue { + csv := new(connectionStatValue) + return csv +} + +func (csv *connectionStatValue) getData() map[string]interface{} { + m := make(map[string]interface{}) + m[idConstStr] = csv.id + m[urlConstStr] = csv.url + m[connCountConstStr] = csv.connCount + m[activeConnCountConstStr] = csv.activeConnCount + m[maxActiveConnCountConstStr] = csv.maxActiveConnCount + + m[stmtCountConstStr] = csv.stmtCount + m[activeStmtCountConstStr] = csv.activeStmtCount + m[maxActiveStmtCountConstStr] = csv.maxActiveStmtCount + + m[executeCountConstStr] = csv.executeCount + m[errorCountConstStr] = csv.errorCount + m[commitCountConstStr] = csv.commitCount + m[rollbackCountConstStr] = csv.rollbackCount + + m[clobOpenCountConstStr] = csv.clobOpenCount + m[blobOpenCountConstStr] = csv.blobOpenCount + + m[propertiesConstStr] = csv.properties + return m +} + +type connectionStat struct { + id string + + url string + + connCount int64 + + activeConnCount int64 + + maxActiveConnCount int64 + + executeCount int64 + + errorCount int64 + + stmtCount int64 + + activeStmtCount int64 + + maxActiveStmtCount int64 + + commitCount int64 + + rollbackCount int64 + + clobOpenCount int64 + + blobOpenCount int64 + + sqlStatMap map[string]*sqlStat + + maxSqlSize int + + skipSqlCount int64 + + lock sync.RWMutex + + properties string +} + +func newConnectionStat(url string) *connectionStat { + cs := new(connectionStat) + cs.maxSqlSize = StatSqlMaxCount + cs.id = "DS" + generateId() + cs.url = url + cs.sqlStatMap = make(map[string]*sqlStat, 200) + return cs +} + +func (cs *connectionStat) createSqlStat(sql string) *sqlStat { + cs.lock.Lock() + defer cs.lock.Unlock() + sqlStat, ok := cs.sqlStatMap[sql] + if !ok { + sqlStat := NewSqlStat(sql) + sqlStat.DataSource = cs.url + sqlStat.DataSourceId = cs.id + if cs.putSqlStat(sqlStat) { + return sqlStat + } else { + return nil + } + } + + return sqlStat + +} + +func (cs *connectionStat) putSqlStat(sqlStat *sqlStat) bool { + if cs.maxSqlSize > 0 && len(cs.sqlStatMap) == cs.maxSqlSize { + if StatSqlRemoveMode == STAT_SQL_REMOVE_OLDEST { + removeSqlStat := cs.eliminateSqlStat() + if removeSqlStat.RunningCount > 0 || removeSqlStat.getExecuteCount() > 0 { + atomic.AddInt64(&cs.skipSqlCount, 1) + } + cs.sqlStatMap[sqlStat.Sql] = sqlStat + return true + } else { + if sqlStat.RunningCount > 0 || sqlStat.getExecuteCount() > 0 { + atomic.AddInt64(&cs.skipSqlCount, 1) + } + return false + } + } else { + cs.sqlStatMap[sqlStat.Sql] = sqlStat + return true + } +} + +func (cs *connectionStat) eliminateSqlStat() *sqlStat { + if cs.maxSqlSize > 0 && len(cs.sqlStatMap) == cs.maxSqlSize { + if StatSqlRemoveMode == STAT_SQL_REMOVE_OLDEST { + for s, item := range cs.sqlStatMap { + if item != nil { + delete(cs.sqlStatMap, s) + return item + } + } + } + } + return nil +} + +func (cs *connectionStat) getSqlStatMap() map[string]*sqlStat { + m := make(map[string]*sqlStat, len(cs.sqlStatMap)) + cs.lock.Lock() + defer cs.lock.Unlock() + for s, item := range cs.sqlStatMap { + m[s] = item + } + return m +} + +func (cs *connectionStat) getSqlStatMapAndReset() []*SqlStatValue { + stats := make([]*sqlStat, 0, len(cs.sqlStatMap)) + cs.lock.Lock() + defer cs.lock.Unlock() + + for s, stat := range cs.sqlStatMap { + + if stat.getExecuteCount() == 0 && stat.RunningCount == 0 { + stat.Removed = 1 + delete(cs.sqlStatMap, s) + } else { + stats = append(stats, stat) + } + } + + values := make([]*SqlStatValue, 0, len(stats)) + for _, stat := range stats { + value := stat.getValueAndReset() + if value.getExecuteCount() == 0 && value.runningCount == 0 { + continue + } + values = append(values, value) + } + return values +} + +func (cs *connectionStat) incrementConn() { + atomic.AddInt64(&cs.connCount, 1) + atomic.AddInt64(&cs.activeConnCount, 1) + count := atomic.LoadInt64(&cs.activeConnCount) + if count > atomic.LoadInt64(&cs.maxActiveConnCount) { + atomic.StoreInt64(&cs.maxActiveConnCount, count) + } +} + +func (cs *connectionStat) decrementConn() { + atomic.AddInt64(&cs.activeConnCount, -1) +} + +func (cs *connectionStat) incrementStmt() { + atomic.AddInt64(&cs.stmtCount, 1) + atomic.AddInt64(&cs.activeStmtCount, 1) + count := atomic.LoadInt64(&cs.activeStmtCount) + if count > atomic.LoadInt64(&cs.maxActiveStmtCount) { + atomic.StoreInt64(&cs.maxActiveStmtCount, count) + } +} + +func (cs *connectionStat) decrementStmt() { + atomic.AddInt64(&cs.activeStmtCount, -1) +} + +func (cs *connectionStat) decrementStmtByActiveStmtCount(activeStmtCount int64) { + atomic.AddInt64(&cs.activeStmtCount, -activeStmtCount) +} + +func (cs *connectionStat) incrementExecuteCount() { + atomic.AddInt64(&cs.executeCount, 1) +} + +func (cs *connectionStat) incrementErrorCount() { + atomic.AddInt64(&cs.errorCount, 1) +} + +func (cs *connectionStat) incrementCommitCount() { + atomic.AddInt64(&cs.commitCount, 1) +} + +func (cs *connectionStat) incrementRollbackCount() { + atomic.AddInt64(&cs.rollbackCount, 1) +} + +func (cs *connectionStat) getValue(reset bool) *connectionStatValue { + val := newConnectionStatValue() + val.id = cs.id + val.url = cs.url + + val.connCount = getInt64(&cs.connCount, reset) + val.activeConnCount = getInt64(&cs.activeConnCount, false) + val.maxActiveConnCount = getInt64(&cs.maxActiveConnCount, false) + + val.stmtCount = getInt64(&cs.stmtCount, reset) + val.activeStmtCount = getInt64(&cs.activeStmtCount, false) + val.maxActiveStmtCount = getInt64(&cs.maxActiveStmtCount, false) + + val.commitCount = getInt64(&cs.commitCount, reset) + val.rollbackCount = getInt64(&cs.rollbackCount, reset) + val.executeCount = getInt64(&cs.executeCount, reset) + val.errorCount = getInt64(&cs.errorCount, reset) + + val.blobOpenCount = getInt64(&cs.blobOpenCount, reset) + val.clobOpenCount = getInt64(&cs.clobOpenCount, reset) + + val.properties = cs.properties + return val +} + +func (cs *connectionStat) getData() map[string]interface{} { + return cs.getValue(false).getData() +} + +func (cs *connectionStat) getValueAndReset() *connectionStatValue { + return cs.getValue(true) +} + +type GoStat struct { + connStatMap map[string]*connectionStat + + lock sync.RWMutex + + maxConnSize int + + skipConnCount int64 +} + +func newGoStat(maxConnSize int) *GoStat { + gs := new(GoStat) + if maxConnSize > 0 { + gs.maxConnSize = maxConnSize + } else { + gs.maxConnSize = 1000 + } + + gs.connStatMap = make(map[string]*connectionStat, 16) + return gs +} + +func (gs *GoStat) createConnStat(conn *DmConnection) *connectionStat { + url := conn.dmConnector.host + ":" + strconv.Itoa(int(conn.dmConnector.port)) + gs.lock.Lock() + defer gs.lock.Unlock() + connstat, ok := gs.connStatMap[url] + if !ok { + connstat = newConnectionStat(url) + + remove := len(gs.connStatMap) > gs.maxConnSize + if remove && connstat.activeConnCount > 0 { + atomic.AddInt64(&gs.skipConnCount, 1) + } + + gs.connStatMap[url] = connstat + } + + return connstat +} + +func (gs *GoStat) getConnStatMap() map[string]*connectionStat { + m := make(map[string]*connectionStat, len(gs.connStatMap)) + gs.lock.Lock() + defer gs.lock.Unlock() + + for s, stat := range gs.connStatMap { + m[s] = stat + } + return m +} + +var sqlRowField = []string{rowNumConstStr, dataSourceConstStr, sqlConstStr, executeCountConstStr, + totalTimeConstStr, maxTimespanConstStr, inTransactionCountConstStr, errorCountConstStr, effectedRowCountConstStr, + fetchRowCountConstStr, runningCountConstStr, concurrentMaxConstStr, executeHoldTimeHistogramConstStr, + executeAndResultHoldTimeHistogramConstStr, fetchRowCountHistogramConstStr, effectedRowCountHistogramConstStr} + +var sqlColField = []string{"ID", "DataSource", "SQL", "ExecuteCount", + "ErrorCount", "TotalTime", "LastTime", "MaxTimespan", "LastError", "EffectedRowCount", + "FetchRowCount", "MaxTimespanOccurTime", "BatchSizeMax", "BatchSizeTotal", "ConcurrentMax", + "RunningCount", "Name", "File", "LastErrorMessage", "LastErrorClass", "LastErrorStackTrace", + "LastErrorTime", "DbType", "URL", "InTransactionCount", "Histogram", "LastSlowParameters", + "ResultSetHoldTime", "ExecuteAndResultSetHoldTime", "FetchRowCountHistogram", + "EffectedRowCountHistogram", "ExecuteAndResultHoldTimeHistogram", "EffectedRowCountMax", + "FetchRowCountMax", "ClobOpenCount"} + +const ( + rowNumConstStr = "rowNum" + idConstStr = "ID" + urlConstStr = "Url" + connCountConstStr = "ConnCount" + activeConnCountConstStr = "ActiveConnCount" + maxActiveConnCountConstStr = "MaxActiveConnCount" + stmtCountConstStr = "StmtCount" + activeStmtCountConstStr = "ActiveStmtCount" + maxActiveStmtCountConstStr = "MaxActiveStmtCount" + executeCountConstStr = "ExecuteCount" + errorCountConstStr = "ErrorCount" + commitCountConstStr = "CommitCount" + rollbackCountConstStr = "RollbackCount" + clobOpenCountConstStr = "ClobOpenCount" + blobOpenCountConstStr = "BlobOpenCount" + propertiesConstStr = "Properties" + dataSourceConstStr = "DataSource" + sqlConstStr = "SQL" + totalTimeConstStr = "TotalTime" + maxTimespanConstStr = "MaxTimespan" + inTransactionCountConstStr = "InTransactionCount" + effectedRowCountConstStr = "EffectedRowCount" + fetchRowCountConstStr = "FetchRowCount" + runningCountConstStr = "RunningCount" + concurrentMaxConstStr = "ConcurrentMax" + executeHoldTimeHistogramConstStr = "ExecuteHoldTimeHistogram" + executeAndResultHoldTimeHistogramConstStr = "ExecuteAndResultHoldTimeHistogram" + fetchRowCountHistogramConstStr = "FetchRowCountHistogram" + effectedRowCountHistogramConstStr = "EffectedRowCountHistogram" +) + +var dsRowField = []string{rowNumConstStr, urlConstStr, activeConnCountConstStr, + maxActiveConnCountConstStr, activeStmtCountConstStr, maxActiveStmtCountConstStr, executeCountConstStr, errorCountConstStr, + commitCountConstStr, rollbackCountConstStr} + +var dsColField = []string{"ID", "ConnCount", "ActiveConnCount", + "MaxActiveConnCount", "StmtCount", "ActiveStmtCount", "MaxActiveStmtCount", "ExecuteCount", + "ErrorCount", "CommitCount", "RollbackCount", "ClobOpenCount", "BlobOpenCount"} + +const ( + PROP_NAME_SORT = "sort" + PROP_NAME_SORT_FIELD = "field" + PROP_NAME_SORT_TYPE = "direction" + PROP_NAME_SEARCH = "search" + PROP_NAME_PAGE_NUM = "pageNum" + PROP_NAME_PAGE_SIZE = "pageSize" + PROP_NAME_PAGE_COUNT = "pageCount" + PROP_NAME_TOTAL_ROW_COUNT = "totalRowCount" + PROP_NAME_FLUSH_FREQ = "flushFreq" + PROP_NAME_DATASOURCE_ID = "dataSourceId" + PROP_NAME_SQL_ID = "sqlId" + + URL_SQL = "sql" + URL_SQL_DETAIL = "sqlDetail" + URL_DATASOURCE = "dataSource" + URL_DATASOURCE_DETAIL = "dataSourceDetail" + + RESULT_CODE_SUCCESS = 1 + RESULT_CODE_ERROR = -1 + DEFAULT_PAGE_NUM = 1 + DEFAULT_PAGE_SIZE = int(INT32_MAX) + DEFAULT_ORDER_TYPE = "asc" + DEFAULT_ORDERBY = "DataSourceId" +) + +type StatReader struct { + connStat []map[string]interface{} + + connStatColLens []int + + highFreqSqlStat []map[string]interface{} + + highFreqSqlStatColLens []int + + slowSqlStat []map[string]interface{} + + slowSqlStatColLens []int +} + +func newStatReader() *StatReader { + sr := new(StatReader) + return sr +} + +func (sr *StatReader) readConnStat(retList []string, maxCount int) (bool, []string) { + fields := dsRowField + isAppend := false + if sr.connStat == nil { + sr.connStat = sr.getConnStat("", fields) + sr.connStatColLens = calcColLens(sr.connStat, fields, COL_MAX_LEN) + isAppend = false + } else { + isAppend = true + } + var retContent []map[string]interface{} + if maxCount > 0 && len(sr.connStat) > maxCount { + retContent = sr.connStat[0:maxCount] + sr.connStat = sr.connStat[maxCount:len(sr.connStat)] + } else { + retContent = sr.connStat + sr.connStat = nil + } + retList = append(retList, sr.getFormattedOutput(retContent, fields, sr.connStatColLens, isAppend)) + return sr.connStat != nil, retList +} + +func (sr *StatReader) readHighFreqSqlStat(retList []string, maxCount int) (bool, []string) { + isAppend := false + if sr.highFreqSqlStat == nil { + sr.highFreqSqlStat = sr.getHighFreqSqlStat(StatHighFreqSqlCount, -1, sqlRowField) + sr.highFreqSqlStatColLens = calcColLens(sr.highFreqSqlStat, sqlRowField, COL_MAX_LEN) + isAppend = false + } else { + isAppend = true + } + var retContent []map[string]interface{} + if maxCount > 0 && len(sr.highFreqSqlStat) > maxCount { + retContent = sr.highFreqSqlStat[0:maxCount] + sr.highFreqSqlStat = sr.highFreqSqlStat[maxCount:len(sr.highFreqSqlStat)] + } else { + retContent = sr.highFreqSqlStat + sr.highFreqSqlStat = nil + } + retList = append(retList, sr.getFormattedOutput(retContent, sqlRowField, sr.highFreqSqlStatColLens, isAppend)) + return sr.highFreqSqlStat != nil, retList +} + +func (sr *StatReader) getHighFreqSqlStat(topCount int, sqlId int, + fields []string) []map[string]interface{} { + var content []map[string]interface{} + + if topCount != 0 { + parameters := NewProperties() + parameters.Set(PROP_NAME_SORT_FIELD, "ExecuteCount") + parameters.Set(PROP_NAME_SORT_TYPE, "desc") + parameters.Set(PROP_NAME_PAGE_NUM, "1") + parameters.Set(PROP_NAME_PAGE_SIZE, strconv.Itoa(topCount)) + content = sr.service(URL_SQL, parameters) + if sqlId != -1 { + matchedContent := make([]map[string]interface{}, 0) + for _, sqlStat := range content { + idStr := sqlStat["ID"] + if idStr == sqlId { + matchedContent = append(matchedContent, sqlStat) + break + } + } + content = matchedContent + } + } + + if content == nil { + content = make([]map[string]interface{}, 0) + } else { + i := 1 + for _, m := range content { + m[rowNumConstStr] = i + i++ + } + } + content = addTitles(content, fields) + return content +} + +func (sr *StatReader) readSlowSqlStat(retList []string, maxCount int) (bool, []string) { + isAppend := false + if sr.slowSqlStat == nil { + sr.slowSqlStat = sr.getSlowSqlStat(StatSlowSqlCount, -1, sqlRowField) + sr.slowSqlStatColLens = calcColLens(sr.slowSqlStat, sqlRowField, + COL_MAX_LEN) + isAppend = false + } else { + isAppend = true + } + var retContent []map[string]interface{} + if maxCount > 0 && len(sr.slowSqlStat) > maxCount { + retContent = sr.slowSqlStat[0:maxCount] + sr.slowSqlStat = sr.slowSqlStat[maxCount:len(sr.slowSqlStat)] + } else { + retContent = sr.slowSqlStat + sr.slowSqlStat = nil + } + retList = append(retList, sr.getFormattedOutput(retContent, sqlRowField, sr.slowSqlStatColLens, isAppend)) + return sr.slowSqlStat != nil, retList +} + +func (sr *StatReader) getSlowSqlStat(topCount int, sqlId int, fields []string) []map[string]interface{} { + var content []map[string]interface{} + + if topCount != 0 { + parameters := NewProperties() + parameters.Set(PROP_NAME_SORT_FIELD, "MaxTimespan") + parameters.Set(PROP_NAME_SORT_TYPE, "desc") + parameters.Set(PROP_NAME_PAGE_NUM, "1") + parameters.Set(PROP_NAME_PAGE_SIZE, strconv.Itoa(topCount)) + + content = sr.service(URL_SQL, parameters) + if sqlId != -1 { + matchedContent := make([]map[string]interface{}, 0) + for _, sqlStat := range content { + idStr := sqlStat["ID"] + if idStr == sqlId { + matchedContent = append(matchedContent, sqlStat) + break + } + } + content = matchedContent + } + } + + if content == nil { + content = make([]map[string]interface{}, 0) + } else { + i := 1 + for _, m := range content { + m["rowNum"] = i + i++ + } + } + content = addTitles(content, fields) + return content +} + +func (sr *StatReader) getConnStat(connId string, fields []string) []map[string]interface{} { + content := sr.service(URL_DATASOURCE, nil) + if connId != "" { + matchedContent := make([]map[string]interface{}, 0) + for _, dsStat := range content { + idStr := dsStat["Identity"] + if connId == idStr { + matchedContent = append(matchedContent, dsStat) + break + } + } + content = matchedContent + } + if content == nil { + content = make([]map[string]interface{}, 0) + } else { + i := 1 + for _, m := range content { + m["rowNum"] = i + i++ + } + } + content = addTitles(content, fields) + return content +} + +func (sr *StatReader) getFormattedOutput(content []map[string]interface{}, fields []string, colLens []int, + isAppend bool) string { + return toTable(content, fields, colLens, true, isAppend) +} + +func (sr *StatReader) parseUrl(url string) *Properties { + parameters := NewProperties() + + if url == "" || len(strings.TrimSpace(url)) == 0 { + return parameters + } + + parametersStr := util.StringUtil.SubstringBetween(url, "?", "") + if parametersStr == "" || len(parametersStr) == 0 { + return parameters + } + + parametersArray := strings.Split(parametersStr, "&") + + for _, parameterStr := range parametersArray { + index := strings.Index(parametersStr, "=") + if index <= 0 { + continue + } + + name := parameterStr[0:index] + value := parameterStr[index+1:] + parameters.Set(name, value) + } + return parameters +} + +func (sr *StatReader) service(url string, params *Properties) []map[string]interface{} { + if params != nil { + params.SetProperties(sr.parseUrl(url)) + } else { + params = sr.parseUrl(url) + } + + if strings.Index(url, URL_SQL) == 0 { + array := sr.getSqlStatList(params) + array = sr.comparatorOrderBy(array, params) + params.Set(PROP_NAME_FLUSH_FREQ, strconv.Itoa(StatFlushFreq)) + return array + } else if strings.Index(url, URL_SQL_DETAIL) == 0 { + array := sr.getSqlStatDetailList(params) + return array + } else if strings.Index(url, URL_DATASOURCE) == 0 { + array := sr.getConnStatList(params) + array = sr.comparatorOrderBy(array, params) + params.Set(PROP_NAME_FLUSH_FREQ, strconv.Itoa(StatFlushFreq)) + return array + } else if strings.Index(url, URL_DATASOURCE_DETAIL) == 0 { + array := sr.getConnStatDetailList(params) + return array + } else { + return nil + } +} + +func (sr *StatReader) getSqlStatList(params *Properties) []map[string]interface{} { + array := make([]map[string]interface{}, 0) + connStatMap := goStat.getConnStatMap() + var sqlStatMap map[string]*sqlStat + for _, connStat := range connStatMap { + sqlStatMap = connStat.getSqlStatMap() + for _, sqlStat := range sqlStatMap { + data := sqlStat.getData() + executeCount := data[executeCountConstStr] + runningCount := data[runningCountConstStr] + if executeCount == 0 && runningCount == 0 { + continue + } + + array = append(array, data) + } + } + + return array +} + +func (sr *StatReader) getSqlStatDetailList(params *Properties) []map[string]interface{} { + array := make([]map[string]interface{}, 0) + connStatMap := goStat.getConnStatMap() + var data *sqlStat + sqlId := "" + dsId := "" + if v := params.GetString(PROP_NAME_SQL_ID, ""); v != "" { + sqlId = v + } + if v := params.GetString(PROP_NAME_DATASOURCE_ID, ""); v != "" { + dsId = v + } + if sqlId != "" && dsId != "" { + for _, connStat := range connStatMap { + if dsId != connStat.id { + continue + } else { + sqlStatMap := connStat.getSqlStatMap() + for _, sqlStat := range sqlStatMap { + + if sqlId == sqlStat.Id { + data = sqlStat + break + } + } + } + break + } + } + if data != nil { + + array = append(array, data.getData()) + + } + return array +} + +func (sr *StatReader) getConnStatList(params *Properties) []map[string]interface{} { + array := make([]map[string]interface{}, 0) + connStatMap := goStat.getConnStatMap() + id := "" + if v := params.GetString(PROP_NAME_DATASOURCE_ID, ""); v != "" { + id = v + } + for _, connStat := range connStatMap { + data := connStat.getData() + + connCount := data["ConnCount"] + + if connCount == 0 { + continue + } + + if id != "" { + if id == connStat.id { + array = append(array, data) + break + } else { + continue + } + } else { + + array = append(array, data) + } + + } + return array +} + +func (sr *StatReader) getConnStatDetailList(params *Properties) []map[string]interface{} { + array := make([]map[string]interface{}, 0) + var data *connectionStat + connStatMap := goStat.getConnStatMap() + id := "" + if v := params.GetString(PROP_NAME_DATASOURCE_ID, ""); v != "" { + id = v + } + if id != "" { + for _, connStat := range connStatMap { + if id == connStat.id { + data = connStat + break + } + } + } + if data != nil { + dataValue := data.getValue(false) + m := make(map[string]interface{}, 2) + m["name"] = "数据源" + m["value"] = dataValue.url + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "总会话数" + m["value"] = dataValue.connCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "活动会话数" + m["value"] = dataValue.activeConnCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "活动会话数峰值" + m["value"] = dataValue.maxActiveStmtCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "总句柄数" + m["value"] = dataValue.stmtCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "活动句柄数" + m["value"] = dataValue.activeStmtCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "活动句柄数峰值" + m["value"] = dataValue.maxActiveStmtCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "执行次数" + m["value"] = dataValue.executeCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "执行出错次数" + m["value"] = dataValue.errorCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "提交次数" + m["value"] = dataValue.commitCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "回滚次数" + m["value"] = dataValue.rollbackCount + array = append(array, m) + + } + return array +} + +type mapSlice struct { + m []map[string]interface{} + isDesc bool + orderByKey string +} + +func newMapSlice(m []map[string]interface{}, isDesc bool, orderByKey string) *mapSlice { + ms := new(mapSlice) + ms.m = m + ms.isDesc = isDesc + ms.orderByKey = orderByKey + return ms +} + +func (ms mapSlice) Len() int { return len(ms.m) } + +func (ms mapSlice) Less(i, j int) bool { + m1 := ms.m[i] + m2 := ms.m[j] + v1 := m1[ms.orderByKey] + v2 := m2[ms.orderByKey] + if v1 == nil { + return true + } else if v2 == nil { + return false + } + + switch v1.(type) { + case int64: + return v1.(int64) < v2.(int64) + case float64: + return v1.(float64) < v2.(float64) + default: + return true + } +} + +func (ms mapSlice) Swap(i, j int) { + ms.m[i], ms.m[j] = ms.m[j], ms.m[i] +} + +func (sr *StatReader) comparatorOrderBy(array []map[string]interface{}, params *Properties) []map[string]interface{} { + if array == nil { + array = make([]map[string]interface{}, 0) + } + + orderBy := DEFAULT_ORDERBY + orderType := DEFAULT_ORDER_TYPE + pageNum := DEFAULT_PAGE_NUM + pageSize := DEFAULT_PAGE_SIZE + if params != nil { + if v := params.GetTrimString(PROP_NAME_SORT_FIELD, ""); v != "" { + orderBy = v + } + + if v := params.GetTrimString(PROP_NAME_SORT_TYPE, ""); v != "" { + orderType = v + } + + if v := params.GetTrimString(PROP_NAME_PAGE_NUM, ""); v != "" { + var err error + pageNum, err = strconv.Atoi(v) + if err != nil { + pageNum = DEFAULT_PAGE_NUM + } + } + if v := params.GetTrimString(PROP_NAME_PAGE_SIZE, ""); v != "" { + var err error + pageSize, err = strconv.Atoi(v) + if err != nil { + pageSize = DEFAULT_PAGE_SIZE + } + } + } + + rowCount := len(array) + pageCount := int(math.Ceil(float64(rowCount * 1.0 / pageSize))) + if pageCount < 1 { + pageCount = 1 + } + + if pageNum > pageCount { + pageNum = pageCount + } + + if len(array) > 0 { + + if orderBy != "" { + sort.Sort(newMapSlice(array, !(DEFAULT_ORDER_TYPE == orderType), orderBy)) + } + + fromIndex := (pageNum - 1) * pageSize + + toIndex := pageNum * pageSize + if toIndex > rowCount { + toIndex = rowCount + } + array = array[fromIndex:toIndex] + } + sr.resetPageInfo(params, rowCount, pageCount, pageNum) + return array +} + +func (sr *StatReader) resetPageInfo(params *Properties, rowCount int, pageCount int, pageNum int) { + + if params != nil { + v := params.GetString(PROP_NAME_PAGE_SIZE, "") + if v != "" { + + params.Set(PROP_NAME_PAGE_COUNT, strconv.Itoa(pageCount)) + params.Set(PROP_NAME_TOTAL_ROW_COUNT, strconv.Itoa(rowCount)) + params.Set(PROP_NAME_PAGE_NUM, strconv.Itoa(pageNum)) + } + } +} + +const COL_MAX_LEN = 32 + +func calcColLens(objList []map[string]interface{}, fields []string, maxColLen int) []int { + + colLen := 0 + colVal := "" + colLens := make([]int, len(fields)) + for _, obj := range objList { + for i := 0; i < len(fields); i++ { + colVal = getColValue(obj[fields[i]]) + colLen = len(colVal) + if colLen > colLens[i] { + colLens[i] = colLen + } + } + } + if maxColLen > 0 { + for i := 0; i < len(fields); i++ { + if colLens[i] > maxColLen { + colLens[i] = maxColLen + } + } + } + return colLens +} + +func addTitles(objList []map[string]interface{}, fields []string) []map[string]interface{} { + titleMap := make(map[string]interface{}, len(fields)) + for i := 0; i < len(fields); i++ { + titleMap[fields[i]] = fields[i] + } + + dst := append(objList, titleMap) + copy(dst[1:], dst[:len(dst)-1]) + dst[0] = titleMap + return dst +} + +func toTable(objList []map[string]interface{}, fields []string, colLens []int, + showAll bool, append bool) string { + if fields == nil || objList == nil { + return "" + } + + if colLens == nil { + colLens = calcColLens(objList, fields, COL_MAX_LEN) + } + + output := &strings.Builder{} + if !append { + sepLine(output, colLens) + } + + for _, obj := range objList { + objMore := obj + for objMore != nil { + objMore = formateLine(output, objMore, fields, colLens, showAll) + } + sepLine(output, colLens) + } + + return output.String() +} + +func formateLine(output *strings.Builder, obj map[string]interface{}, fields []string, colLens []int, + showAll bool) map[string]interface{} { + hasMore := false + objMore := make(map[string]interface{}) + colLen := 0 + colVal := "" + for i := 0; i < len(fields); i++ { + colVal = getColValue(obj[fields[i]]) + + colLen = len(colVal) + if colLen <= colLens[i] { + output.WriteString("|") + output.WriteString(colVal) + blanks(output, colLens[i]-colLen) + if showAll { + objMore[fields[i]] = "" + } + } else { + output.WriteString("|") + if showAll { + output.WriteString(colVal[0:colLens[i]]) + objMore[fields[i]] = colVal[colLens[i]:] + hasMore = true + } else { + output.WriteString(colVal[0:colLens[i]-3] + "...") + } + } + } + output.WriteString("|") + output.WriteString(util.StringUtil.LineSeparator()) + + if hasMore { + return objMore + } else { + return nil + } +} + +func sepLine(output *strings.Builder, colLens []int) { + output.WriteString("+") + for _, colLen := range colLens { + for i := 0; i < colLen; i++ { + output.WriteString("+") + } + output.WriteString("+") + } + output.WriteString(util.StringUtil.LineSeparator()) +} + +func blanks(output *strings.Builder, count int) { + for count > 0 { + output.WriteString(" ") + count-- + } +} + +func getColValue(colObj interface{}) string { + var colVal string + if colObj == nil { + colVal = "" + } else { + colVal = fmt.Sprint(colObj) + } + + colVal = strings.Replace(colVal, "\t", "", -1) + colVal = strings.Replace(colVal, "\n", "", -1) + colVal = strings.Replace(colVal, "\r", "", -1) + + return colVal +} + +const ( + READ_MAX_SIZE = 100 +) + +type statFlusher struct { + sr *StatReader + logList []string + date string + logFile *os.File + flushFreq int + filePath string + filePrefix string + buffer *Dm_build_1499 +} + +func newStatFlusher() *statFlusher { + sf := new(statFlusher) + sf.sr = newStatReader() + sf.logList = make([]string, 0, 32) + sf.date = time.Now().Format("2006-01-02") + sf.flushFreq = StatFlushFreq + sf.filePath = StatDir + sf.filePrefix = "dm_go_stat" + sf.buffer = Dm_build_1503() + return sf +} + +func (sf *statFlusher) isConnStatEnabled() bool { + return StatEnable +} + +func (sf *statFlusher) isSlowSqlStatEnabled() bool { + return StatEnable +} + +func (sf *statFlusher) isHighFreqSqlStatEnabled() bool { + return StatEnable +} + +func (sf *statFlusher) doRun() { + + for { + if len(goStat.connStatMap) > 0 { + sf.logList = append(sf.logList, time.Now().String()) + if sf.isConnStatEnabled() { + sf.logList = append(sf.logList, "#connection stat") + hasMore := true + for hasMore { + hasMore, sf.logList = sf.sr.readConnStat(sf.logList, READ_MAX_SIZE) + sf.writeAndFlush(sf.logList, 0, len(sf.logList)) + sf.logList = sf.logList[0:0] + } + } + if sf.isHighFreqSqlStatEnabled() { + sf.logList = append(sf.logList, "#top "+strconv.Itoa(StatHighFreqSqlCount)+" high freq sql stat") + hasMore := true + for hasMore { + hasMore, sf.logList = sf.sr.readHighFreqSqlStat(sf.logList, READ_MAX_SIZE) + sf.writeAndFlush(sf.logList, 0, len(sf.logList)) + sf.logList = sf.logList[0:0] + } + } + if sf.isSlowSqlStatEnabled() { + sf.logList = append(sf.logList, "#top "+strconv.Itoa(StatSlowSqlCount)+" slow sql stat") + hasMore := true + for hasMore { + hasMore, sf.logList = sf.sr.readSlowSqlStat(sf.logList, READ_MAX_SIZE) + sf.writeAndFlush(sf.logList, 0, len(sf.logList)) + sf.logList = sf.logList[0:0] + } + } + sf.logList = append(sf.logList, util.StringUtil.LineSeparator()) + sf.logList = append(sf.logList, util.StringUtil.LineSeparator()) + sf.writeAndFlush(sf.logList, 0, len(sf.logList)) + sf.logList = sf.logList[0:0] + time.Sleep(time.Duration(StatFlushFreq) * time.Second) + } + } +} + +func (sf *statFlusher) writeAndFlush(logs []string, startOff int, l int) { + var bytes []byte + for i := startOff; i < startOff+l; i++ { + bytes = []byte(logs[i] + util.StringUtil.LineSeparator()) + + sf.buffer.Dm_build_1525(bytes, 0, len(bytes)) + + if sf.buffer.Dm_build_1504() >= FLUSH_SIZE { + sf.doFlush(sf.buffer) + } + } + + if sf.buffer.Dm_build_1504() > 0 { + sf.doFlush(sf.buffer) + } +} + +func (sf *statFlusher) doFlush(buffer *Dm_build_1499) { + if sf.needCreateNewFile() { + sf.closeCurrentFile() + sf.logFile = sf.createNewFile() + } + buffer.Dm_build_1519(sf.logFile, buffer.Dm_build_1504()) +} +func (sf *statFlusher) closeCurrentFile() { + if sf.logFile != nil { + sf.logFile.Close() + sf.logFile = nil + } +} +func (sf *statFlusher) createNewFile() *os.File { + sf.date = time.Now().Format("2006-01-02") + fileName := sf.filePrefix + "_" + sf.date + "_" + strconv.Itoa(time.Now().Nanosecond()) + ".txt" + sf.filePath = StatDir + if len(sf.filePath) > 0 { + if _, err := os.Stat(sf.filePath); err != nil { + os.MkdirAll(sf.filePath, 0755) + } + if _, err := os.Stat(sf.filePath + fileName); err != nil { + logFile, err := os.Create(sf.filePath + fileName) + if err != nil { + panic(err) + } + return logFile + } + } + return nil +} +func (sf *statFlusher) needCreateNewFile() bool { + now := time.Now().Format("2006-01-02") + fileInfo, err := sf.logFile.Stat() + return now != sf.date || err != nil || sf.logFile == nil || fileInfo.Size() > int64(MAX_FILE_SIZE) +} diff --git a/dmr/h.go b/dmr/h.go new file mode 100644 index 0000000..945441e --- /dev/null +++ b/dmr/h.go @@ -0,0 +1,790 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "math" + "strconv" + "strings" + "time" + "unicode" +) + +func encodeByString(x string, dtype int, scale int, ltz int, dtz int) ([]byte, error) { + dt := make([]int, DT_LEN) + if _, err := toDTFromString(x, dt); err != nil { + return nil, err + } + return encode(dt, dtype, scale, ltz) +} + +func encodeByTime(x time.Time, dtype int, scale int, lTz int, dbTz int) ([]byte, error) { + dt := toDTFromTime(x) + return encode(dt, dtype, scale, lTz) +} + +func encodeByDateNumber(x int64, destDType int, scale int, lTz int, dbTz int16) ([]byte, error) { + switch destDType { + case DATETIME: + + if x > 2958463*24*60*60 { + return nil, ECGO_DATETIME_OVERFLOW.throw() + } + + dt := toDTFromUnix(x-Seconds_1900_1970, 0) + return encode(dt, destDType, scale, lTz) + + case TIME: + dt := toDTFromUnix(x, 0) + return encode(dt, destDType, scale, lTz) + + case DATE: + + if x > 2958463 { + return nil, ECGO_DATETIME_OVERFLOW.throw() + } + + dt := toDTFromUnix(x*24*60*60-Seconds_1900_1970, 0) + if dt[OFFSET_YEAR] < -4712 || dt[OFFSET_YEAR] > 9999 { + return nil, ECGO_DATETIME_OVERFLOW.throw() + } + return encode(dt, destDType, scale, lTz) + + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + + } +} + +func toTimeFromString(str string, ltz int) time.Time { + dt := make([]int, DT_LEN) + toDTFromString(str, dt) + return toTimeFromDT(dt, ltz) +} + +func toTimeFromDT(dt []int, ltz int) time.Time { + var year, month, day, hour, minute, second, nsec, tz int + + year = dt[OFFSET_YEAR] + + if dt[OFFSET_MONTH] > 0 { + month = dt[OFFSET_MONTH] + } else { + month = 1 + } + + if dt[OFFSET_DAY] > 0 { + day = dt[OFFSET_DAY] + } else { + day = 1 + } + + hour = dt[OFFSET_HOUR] + minute = dt[OFFSET_MINUTE] + second = dt[OFFSET_SECOND] + nsec = dt[OFFSET_MILLISECOND] * 1000 + if dt[OFFSET_TIMEZONE] == INVALID_VALUE { + tz = ltz * 60 + } else { + tz = dt[OFFSET_TIMEZONE] * 60 + } + return time.Date(year, time.Month(month), day, hour, minute, second, nsec, time.FixedZone("", tz)) +} + +func decode(value []byte, isBdta bool, colType int, scale int, ltz int, dbtz int) []int { + var dt []int + if isBdta { + dt = dmdtDecodeBdta(value) + } else { + dt = dmdtDecodeFast(value) + } + + if isLocalTimeZone(colType, scale) { + transformTZ(dt, dbtz, ltz) + scale = getLocalTimeZoneScale(colType, scale) + } + + if scale > 0 && scale < 6 { + tmp := math.Pow10(6 - scale) + dt[OFFSET_MILLISECOND] = int(float64(dt[OFFSET_MILLISECOND]) / tmp * tmp) + } + return dt +} + +func dmdtDecodeFast(value []byte) []int { + dt := make([]int, DT_LEN) + dt[OFFSET_TIMEZONE] = INVALID_VALUE + + if len(value) == 3 { + + dt[OFFSET_YEAR] = int(Dm_build_1220.Dm_build_1317(value, 0)) & 0x7FFF + if dt[OFFSET_YEAR] > 9999 { + dt[OFFSET_YEAR] = int(int16(dt[OFFSET_YEAR] | 0x8000)) + } + + dt[OFFSET_MONTH] = ((int(value[1]) >> 7) & 0x1) + ((int(value[2]) & 0x07) << 1) + + dt[OFFSET_DAY] = ((int(value[2]) & 0xF8) >> 3) & 0x1f + } else if len(value) < 8 { + + dt[OFFSET_HOUR] = int(value[0]) & 0x1F + dt[OFFSET_MINUTE] = ((int(value[0]) >> 5) & 0x07) + ((int(value[1]) & 0x07) << 3) + dt[OFFSET_SECOND] = ((int(value[1]) >> 3) & 0x1f) + ((int(value[2]) & 0x01) << 5) + dt[OFFSET_MILLISECOND] = ((int(value[2]) >> 1) & 0x7f) + ((int(value[3]) & 0x00ff) << 7) + ((int(value[4]) & 0x1F) << 15) + + if len(value) > 5 { + dt[OFFSET_TIMEZONE] = int(Dm_build_1220.Dm_build_1317(value, 5)) + } + } else { + + dt[OFFSET_YEAR] = int(Dm_build_1220.Dm_build_1317(value, 0)) & 0x7FFF + if dt[OFFSET_YEAR] > 9999 { + dt[OFFSET_YEAR] = int(int16(dt[OFFSET_YEAR] | 0x8000)) + } + + dt[OFFSET_MONTH] = ((int(value[1]) >> 7) & 0x1) + ((int(value[2]) & 0x07) << 1) + + dt[OFFSET_DAY] = ((int(value[2]) & 0xF8) >> 3) & 0x1f + + dt[OFFSET_HOUR] = (int(value[3]) & 0x1F) + + dt[OFFSET_MINUTE] = ((int(value[3]) >> 5) & 0x07) + ((int(value[4]) & 0x07) << 3) + + dt[OFFSET_SECOND] = ((int(value[4]) >> 3) & 0x1f) + ((int(value[5]) & 0x01) << 5) + + dt[OFFSET_MILLISECOND] = ((int(value[5]) >> 1) & 0x7f) + ((int(value[6]) & 0x00ff) << 7) + ((int(value[7]) & 0x1F) << 15) + + if len(value) > 8 { + dt[OFFSET_TIMEZONE] = int(Dm_build_1220.Dm_build_1317(value, 8)) + } + } + return dt +} + +func dmdtDecodeBdta(value []byte) []int { + dt := make([]int, DT_LEN) + dt[OFFSET_YEAR] = int(Dm_build_1220.Dm_build_1317(value, 0)) + dt[OFFSET_MONTH] = int(value[2] & 0xFF) + dt[OFFSET_DAY] = int(value[3] & 0xFF) + dt[OFFSET_HOUR] = int(value[4] & 0xFF) + dt[OFFSET_MINUTE] = int(value[5] & 0xFF) + dt[OFFSET_SECOND] = int(value[6] & 0xFF) + dt[OFFSET_MILLISECOND] = int((value[7] & 0xFF) + (value[8] << 8) + (value[9] << 16)) + dt[OFFSET_TIMEZONE] = int(Dm_build_1220.Dm_build_1317(value, 10)) + return dt +} + +func dtToStringByOracleFormat(dt []int, oracleFormatPattern string, language int) string { + return format(dt, oracleFormatPattern, language) +} + +func dtToString(dt []int, dtype int, scale int) string { + switch dtype { + case DATE: + return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + + case TIME: + if scale > 0 { + return format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + "." + formatMilliSecond(dt[OFFSET_MILLISECOND], scale) + } else { + return format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + } + + case TIME_TZ: + if scale > 0 { + return format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + "." + formatMilliSecond(dt[OFFSET_MILLISECOND], scale) + " " + formatTZ(dt[OFFSET_TIMEZONE]) + } else { + return format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + " " + formatTZ(dt[OFFSET_TIMEZONE]) + } + + case DATETIME: + if scale > 0 { + return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + " " + format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + "." + formatMilliSecond(dt[OFFSET_MILLISECOND], scale) + } else { + return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + " " + format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + } + + case DATETIME_TZ: + if scale > 0 { + return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + " " + format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + "." + formatMilliSecond(dt[OFFSET_MILLISECOND], scale) + " " + formatTZ(dt[OFFSET_TIMEZONE]) + } else { + return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + " " + format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + " " + formatTZ(dt[OFFSET_TIMEZONE]) + } + } + + return "" +} + +func formatYear(value int) string { + if value >= 0 { + if value < 10 { + return "000" + strconv.FormatInt(int64(value), 10) + } else if value < 100 { + return "00" + strconv.FormatInt(int64(value), 10) + } else if value < 1000 { + return "0" + strconv.FormatInt(int64(value), 10) + } else { + return strconv.FormatInt(int64(value), 10) + } + } else { + if value > -10 { + return "-000" + strconv.FormatInt(int64(-value), 10) + } else if value > -100 { + return "-00" + strconv.FormatInt(int64(-value), 10) + } else if value > -1000 { + return "-0" + strconv.FormatInt(int64(-value), 10) + } else { + return strconv.FormatInt(int64(-value), 10) + } + } +} + +func format2(value int) string { + if value < 10 { + return "0" + strconv.FormatInt(int64(value), 10) + } else { + return strconv.FormatInt(int64(value), 10) + } +} + +func formatMilliSecond(ms int, prec int) string { + var ret string + if ms < 10 { + ret = "00000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 100 { + ret = "0000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 1000 { + ret = "000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 10000 { + ret = "00" + strconv.FormatInt(int64(ms), 10) + } else if ms < 100000 { + ret = "0" + strconv.FormatInt(int64(ms), 10) + } else { + ret = strconv.FormatInt(int64(ms), 10) + } + + if prec < 6 { + ret = ret[:prec] + } + return ret +} + +func formatTZ(tz int) string { + tz_hour := int(math.Abs(float64(tz / 60))) + tz_min := int(math.Abs(float64(tz % 60))) + + if tz >= 0 { + return "+" + format2(tz_hour) + ":" + format2(tz_min) + } else { + return "-" + format2(tz_hour) + ":" + format2(tz_min) + } +} + +func toDTFromTime(x time.Time) []int { + hour, min, sec := x.Clock() + ts := make([]int, DT_LEN) + ts[OFFSET_YEAR] = x.Year() + ts[OFFSET_MONTH] = int(x.Month()) + ts[OFFSET_DAY] = x.Day() + ts[OFFSET_HOUR] = hour + ts[OFFSET_MINUTE] = min + ts[OFFSET_SECOND] = sec + ts[OFFSET_MILLISECOND] = (int)(x.Nanosecond() / 1000) + _, tz := x.Zone() + ts[OFFSET_TIMEZONE] = tz / 60 + return ts +} + +func toDTFromUnix(sec int64, nsec int64) []int { + return toDTFromTime(time.Unix(sec, nsec)) +} + +func toDTFromString(s string, dt []int) (dtype int, err error) { + defer func() { + if p := recover(); p != nil { + err = ECGO_INVALID_DATETIME_FORMAT.throw() + } + }() + date_s := "" + time_s := "" + nanos_s := "" + tz_s := "" + year := 0 + month := 0 + day := 0 + hour := 0 + minute := 0 + second := 0 + a_nanos := 0 + firstDash := -1 + secondDash := -1 + firstColon := -1 + secondColon := -1 + period := -1 + sign := 0 + ownTz := INVALID_VALUE + dtype = -1 + + zeros := "000000000" + + if s != "" && strings.TrimSpace(s) == "" { + return 0, ECGO_INVALID_DATETIME_FORMAT.throw() + } + s = strings.TrimSpace(s) + + if strings.Index(s, "-") == 0 { + s = strings.TrimSpace(s[1:]) + sign = 1 + } + + comps := strings.Split(s, " ") + + switch len(comps) { + case 3: + date_s = comps[0] + time_s = comps[1] + tz_s = comps[2] + dtype = DATETIME_TZ + + case 2: + if strings.Index(comps[0], ":") > 0 { + time_s = comps[0] + tz_s = comps[1] + dtype = TIME_TZ + } else { + date_s = comps[0] + time_s = comps[1] + dtype = DATETIME + } + + case 1: + if strings.Index(comps[0], ":") > 0 { + time_s = comps[0] + dtype = TIME + } else { + date_s = comps[0] + dtype = DATE + } + + default: + return 0, ECGO_INVALID_DATETIME_FORMAT.throw() + } + + if date_s != "" { + + firstDash = strings.Index(date_s, "-") + secondDash = strings.Index(date_s[firstDash+1:], "-") + + if firstDash < 0 || secondDash < 0 { + firstDash = strings.Index(s, ".") + secondDash = strings.Index(date_s[firstDash+1:], ".") + } + + if firstDash < 0 || secondDash < 0 { + firstDash = strings.Index(s, "/") + secondDash = strings.Index(date_s[firstDash+1:], "/") + } + if secondDash > 0 { + secondDash += firstDash + 1 + } + + if (firstDash > 0) && (secondDash > 0) && (secondDash < len(date_s)-1) { + + if sign == 1 { + i, err := strconv.ParseInt(date_s[:firstDash], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + year = 0 - int(i) - 1900 + } else { + i, err := strconv.ParseInt(date_s[:firstDash], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + year = int(i) - 1900 + } + + i, err := strconv.ParseInt(date_s[firstDash+1:secondDash], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + month = int(i) - 1 + + i, err = strconv.ParseInt(date_s[secondDash+1:], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + day = int(i) + + if !checkDate(year+1900, month+1, day) { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + } else { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + } + + if time_s != "" { + firstColon = strings.Index(time_s, ":") + secondColon = strings.Index(time_s[firstColon+1:], ":") + if secondColon > 0 { + secondColon += firstColon + 1 + } + + period = strings.Index(time_s[secondColon+1:], ".") + if period > 0 { + period += secondColon + 1 + } + + if (firstColon > 0) && (secondColon > 0) && (secondColon < len(time_s)-1) { + i, err := strconv.ParseInt(time_s[:firstColon], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + hour = int(i) + + i, err = strconv.ParseInt(time_s[firstColon+1:secondColon], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + minute = int(i) + + if period > 0 && period < len(time_s)-1 { + i, err = strconv.ParseInt(time_s[secondColon+1:period], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + second = int(i) + + nanos_s = time_s[period+1:] + if len(nanos_s) > 9 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + if !unicode.IsDigit(rune(nanos_s[0])) { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + nanos_s = nanos_s + zeros[0:9-len(nanos_s)] + + i, err = strconv.ParseInt(nanos_s[:6], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + a_nanos = int(i) + } else if period > 0 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } else { + i, err = strconv.ParseInt(time_s[secondColon+1:], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + second = int(i) + } + + if hour >= 24 || hour < 0 || minute >= 60 || minute < 0 || second >= 60 || second < 0 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + } else { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + } + + if tz_s != "" { + neg := false + if strings.Index(tz_s, "-") == 0 { + neg = true + } + + if strings.Index(tz_s, "-") == 0 || strings.Index(tz_s, "+") == 0 { + tz_s = strings.TrimSpace(tz_s[1:]) + } + + hm := strings.Split(tz_s, ":") + var tzh, tzm int16 = 0, 0 + switch len(hm) { + case 2: + s, err := strconv.ParseInt(strings.TrimSpace(hm[0]), 10, 16) + if err != nil { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + tzh = int16(s) + + s, err = strconv.ParseInt(strings.TrimSpace(hm[1]), 10, 16) + if err != nil { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + tzm = int16(s) + case 1: + s, err := strconv.ParseInt(strings.TrimSpace(hm[0]), 10, 16) + if err != nil { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + tzh = int16(s) + default: + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + + ownTz = int(tzh*60 + tzm) + if ownTz < 0 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + + if neg { + ownTz *= -1 + } + + if ownTz <= -13*60 || ownTz > 14*60 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + } + + dt[OFFSET_YEAR] = year + 1900 + dt[OFFSET_MONTH] = month + 1 + if day == 0 { + dt[OFFSET_DAY] = 1 + } else { + dt[OFFSET_DAY] = day + } + dt[OFFSET_HOUR] = hour + dt[OFFSET_MINUTE] = minute + dt[OFFSET_SECOND] = second + dt[OFFSET_MILLISECOND] = a_nanos + dt[OFFSET_TIMEZONE] = int(ownTz) + return dtype, nil +} + +func transformTZ(dt []int, defaultSrcTz int, destTz int) { + srcTz := defaultSrcTz + if dt[OFFSET_TIMEZONE] != INVALID_VALUE { + srcTz = dt[OFFSET_TIMEZONE] + } + + if destTz != srcTz { + dt = addMinute(dt, destTz-srcTz) + if dt[OFFSET_TIMEZONE] != INVALID_VALUE { + dt[OFFSET_TIMEZONE] = destTz + } + } +} + +func encode(dt []int, dtype int, scale int, lTz int) ([]byte, error) { + + if isLocalTimeZone(dtype, scale) && dt[OFFSET_TIMEZONE] != INVALID_VALUE && dt[OFFSET_TIMEZONE] != lTz { + transformTZ(dt, dt[OFFSET_TIMEZONE], lTz) + } + + if dt[OFFSET_YEAR] < -4712 || dt[OFFSET_YEAR] > 9999 { + return nil, ECGO_DATETIME_OVERFLOW.throw() + } + + year := dt[OFFSET_YEAR] + + month := dt[OFFSET_MONTH] + + day := dt[OFFSET_DAY] + + hour := dt[OFFSET_HOUR] + + min := dt[OFFSET_MINUTE] + + sec := dt[OFFSET_SECOND] + + msec := dt[OFFSET_MILLISECOND] + + var tz int + + if dt[OFFSET_TIMEZONE] == INVALID_VALUE { + tz = lTz + } else { + tz = dt[OFFSET_TIMEZONE] + } + + var ret []byte + + if dtype == DATE { + ret = make([]byte, 3) + + ret[0] = (byte)(year & 0xFF) + + if year >= 0 { + ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7)) + } else { + ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f)) + } + + ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3)) + } else if dtype == DATETIME { + ret = make([]byte, 8) + + ret[0] = (byte)(year & 0xFF) + + if year >= 0 { + ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7)) + } else { + ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f)) + } + + ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3)) + + ret[3] = (byte)(hour | ((min & 0x07) << 5)) + + ret[4] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3)) + + ret[5] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1)) + + ret[6] = (byte)((msec >> 7) & 0xFF) + + ret[7] = (byte)((msec >> 15) & 0xFF) + } else if dtype == DATETIME_TZ { + ret = make([]byte, 10) + + ret[0] = (byte)(year & 0xFF) + + if year >= 0 { + ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7)) + } else { + ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f)) + } + + ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3)) + + ret[3] = (byte)(hour | ((min & 0x07) << 5)) + + ret[4] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3)) + + ret[5] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1)) + + ret[6] = (byte)((msec >> 7) & 0xFF) + + ret[7] = (byte)((msec >> 15) & 0xFF) + + Dm_build_1220.Dm_build_1231(ret, 8, int16(tz)) + } else if dtype == TIME { + ret = make([]byte, 5) + + ret[0] = (byte)(hour | ((min & 0x07) << 5)) + + ret[1] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3)) + + ret[2] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1)) + + ret[3] = (byte)((msec >> 7) & 0xFF) + + ret[4] = (byte)((msec >> 15) & 0xFF) + } else if dtype == TIME_TZ { + ret = make([]byte, 7) + + ret[0] = (byte)(hour | ((min & 0x07) << 5)) + + ret[1] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3)) + + ret[2] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1)) + + ret[3] = (byte)((msec >> 7) & 0xFF) + + ret[4] = (byte)((msec >> 15) & 0xFF) + + Dm_build_1220.Dm_build_1231(ret, 5, int16(tz)) + } + + return ret, nil +} + +func checkDate(year int, month int, day int) bool { + if year > 9999 || year < -4712 || month > 12 || month < 1 { + return false + } + + monthDays := getDaysOfMonth(year, month) + if day > monthDays || day < 1 { + return false + } + return true +} + +func getDaysOfMonth(year int, month int) int { + switch month { + case 1, 3, 5, 7, 8, 10, 12: + return 31 + case 4, 6, 9, 11: + return 30 + case 2: + if isLeapYear(year) { + return 29 + } + return 28 + default: + return 0 + } +} + +func isLeapYear(year int) bool { + return ((year%4 == 0 && year%100 != 0) || year%400 == 0) +} + +func addYear(dt []int, n int) []int { + dt[OFFSET_YEAR] += n + return dt +} + +func addMonth(dt []int, n int) []int { + month := dt[OFFSET_MONTH] + n + addYearValue := month / 12 + if month %= 12; month < 1 { + month += 12 + addYearValue-- + } + + daysOfMonth := getDaysOfMonth(dt[OFFSET_YEAR], month) + if dt[OFFSET_DAY] > daysOfMonth { + dt[OFFSET_DAY] = daysOfMonth + } + + dt[OFFSET_MONTH] = month + addYear(dt, addYearValue) + return dt +} + +func addDay(dt []int, n int) []int { + tmp := dt[OFFSET_DAY] + n + monthDays := 0 + monthDays = getDaysOfMonth(dt[OFFSET_YEAR], dt[OFFSET_MONTH]) + for tmp > monthDays || tmp <= 0 { + if tmp > monthDays { + addMonth(dt, 1) + tmp -= monthDays + } else { + addMonth(dt, -1) + tmp += monthDays + } + } + dt[OFFSET_DAY] = tmp + return dt +} + +func addHour(dt []int, n int) []int { + hour := dt[OFFSET_HOUR] + n + addDayValue := hour / 24 + if hour %= 24; hour < 0 { + hour += 24 + addDayValue-- + } + + dt[OFFSET_HOUR] = hour + addDay(dt, addDayValue) + return dt +} + +func addMinute(dt []int, n int) []int { + minute := dt[OFFSET_MINUTE] + n + addHourValue := minute / 60 + if minute %= 60; minute < 0 { + minute += 60 + addHourValue-- + } + + dt[OFFSET_MINUTE] = minute + addHour(dt, addHourValue) + return dt +} diff --git a/dmr/i.go b/dmr/i.go new file mode 100644 index 0000000..30a28de --- /dev/null +++ b/dmr/i.go @@ -0,0 +1,896 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "strconv" + "time" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +var DB2G db2g + +type db2g struct { +} + +func (DB2G db2g) processVarchar2(bytes []byte, prec int) []byte { + rbytes := make([]byte, prec) + copy(rbytes[:len(bytes)], bytes[:]) + for i := len(bytes); i < len(rbytes); i++ { + rbytes[i] = ' ' + } + return rbytes +} + +func (DB2G db2g) charToString(bytes []byte, column *column, conn *DmConnection) string { + if column.colType == VARCHAR2 { + bytes = DB2G.processVarchar2(bytes, int(column.prec)) + } else if column.colType == CLOB { + clob := newClobFromDB(bytes, conn, column, true) + clobLen, _ := clob.GetLength() + clobStr, _ := clob.getSubString(1, int32(clobLen)) + return clobStr + } + return Dm_build_1220.Dm_build_1470(bytes, conn.serverEncoding, conn) +} + +func (DB2G db2g) charToFloat64(bytes []byte, column *column, conn *DmConnection) (float64, error) { + str := DB2G.charToString(bytes, column, conn) + val, err := strconv.ParseFloat(str, 64) + if err != nil { + return 0, ECGO_DATA_CONVERTION_ERROR.throw() + } + + return val, nil +} + +func (DB2G db2g) charToDeciaml(bytes []byte, column *column, conn *DmConnection) (*DmDecimal, error) { + str := DB2G.charToString(bytes, column, conn) + return NewDecimalFromString(str) +} + +func (DB2G db2g) BinaryToInt64(bytes []byte, column *column, conn *DmConnection) (int64, error) { + if column.colType == BLOB { + blob := newBlobFromDB(bytes, conn, column, true) + blobLen, err := blob.GetLength() + if err != nil { + return 0, err + } + bytes, err = blob.getBytes(1, int32(blobLen)) + if err != nil { + return 0, err + } + } + var n, b int64 = 0, 0 + + startIndex := 0 + var length int + if len(bytes) > 8 { + length = 8 + for j := 0; j < len(bytes)-8; j++ { + if bytes[j] != 0 { + return 0, ECGO_DATA_CONVERTION_ERROR.throw() + } + + startIndex = len(bytes) - 8 + length = 8 + } + } else { + length = len(bytes) + } + + for j := startIndex; j < startIndex+length; j++ { + b = int64(0xff & bytes[j]) + n = b | (n << 8) + } + + return n, nil +} + +func (DB2G db2g) decToDecimal(bytes []byte, prec int, scale int, compatibleOracle bool) (*DmDecimal, error) { + + if compatibleOracle { + prec = -1 + scale = -1 + } + return newDecimal(bytes, prec, scale) +} + +func (DB2G db2g) toBytes(bytes []byte, column *column, conn *DmConnection) ([]byte, error) { + retBytes := Dm_build_1220.Dm_build_1371(bytes, 0, len(bytes)) + switch column.colType { + case CLOB: + clob := newClobFromDB(retBytes, conn, column, true) + str, err := clob.getSubString(1, int32(clob.length)) + if err != nil { + return nil, err + } + + return Dm_build_1220.Dm_build_1433(str, conn.getServerEncoding(), conn), nil + case BLOB: + blob := newBlobFromDB(retBytes, conn, column, true) + bs, err := blob.getBytes(1, int32(blob.length)) + if err != nil { + return nil, err + } + + return bs, nil + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toString(bytes []byte, column *column, conn *DmConnection) string { + switch column.colType { + case CHAR, VARCHAR, VARCHAR2: + return DB2G.charToString(bytes, column, conn) + case BIT, BOOLEAN, TINYINT: + return strconv.FormatInt(int64(bytes[0]), 10) + case SMALLINT: + return strconv.FormatInt(int64(Dm_build_1220.Dm_build_1441(bytes)), 10) + case INT: + return strconv.FormatInt(int64(Dm_build_1220.Dm_build_1444(bytes)), 10) + case BIGINT: + return strconv.FormatInt(int64(Dm_build_1220.Dm_build_1447(bytes)), 10) + case REAL: + return strconv.FormatFloat(float64(Dm_build_1220.Dm_build_1450(bytes)), 'f', -1, 32) + case DOUBLE: + return strconv.FormatFloat(float64(Dm_build_1220.Dm_build_1453(bytes)), 'f', -1, 64) + case DECIMAL: + + case BINARY, VARBINARY: + util.StringUtil.BytesToHexString(bytes, false) + case BLOB: + + case CLOB: + + case DATE: + dt := decode(bytes, column.isBdta, int(column.colType), int(column.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + if conn.FormatDate != "" { + return dtToStringByOracleFormat(dt, conn.FormatDate, int(conn.OracleDateLanguage)) + } + case TIME: + dt := decode(bytes, column.isBdta, int(column.colType), int(column.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + if conn.FormatTime != "" { + return dtToStringByOracleFormat(dt, conn.FormatTime, int(conn.OracleDateLanguage)) + } + case DATETIME: + dt := decode(bytes, column.isBdta, int(column.colType), int(column.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + if conn.FormatTimestamp != "" { + return dtToStringByOracleFormat(dt, conn.FormatTimestamp, int(conn.OracleDateLanguage)) + } + case TIME_TZ: + dt := decode(bytes, column.isBdta, int(column.colType), int(column.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + if conn.FormatTimeTZ != "" { + return dtToStringByOracleFormat(dt, conn.FormatTimeTZ, int(conn.OracleDateLanguage)) + } + case DATETIME_TZ: + dt := decode(bytes, column.isBdta, int(column.colType), int(column.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + if conn.FormatTimestampTZ != "" { + return dtToStringByOracleFormat(dt, conn.FormatTimestampTZ, int(conn.OracleDateLanguage)) + } + case INTERVAL_DT: + return newDmIntervalDTByBytes(bytes).String() + case INTERVAL_YM: + return newDmIntervalYMByBytes(bytes).String() + case ARRAY: + + case SARRAY: + + case CLASS: + + case PLTYPE_RECORD: + + } + return "" +} + +func (DB2G db2g) toBool(bytes []byte, column *column, conn *DmConnection) (bool, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + return bytes[0] != 0, nil + case SMALLINT: + return Dm_build_1220.Dm_build_1317(bytes, 0) != 0, nil + case INT: + return Dm_build_1220.Dm_build_1322(bytes, 0) != 0, nil + case BIGINT: + return Dm_build_1220.Dm_build_1327(bytes, 0) != 0, nil + case REAL: + return Dm_build_1220.Dm_build_1332(bytes, 0) != 0, nil + case DOUBLE: + return Dm_build_1220.Dm_build_1336(bytes, 0) != 0, nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + return G2DB.toBool(DB2G.charToString(bytes, column, conn)) + } + + return false, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toByte(bytes []byte, column *column, conn *DmConnection) (byte, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + + if bytes == nil || len(bytes) == 0 { + return 0, nil + } else { + return bytes[0], nil + } + case SMALLINT: + tval := Dm_build_1220.Dm_build_1317(bytes, 0) + if tval < int16(BYTE_MIN) || tval > int16(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + case INT: + tval := Dm_build_1220.Dm_build_1322(bytes, 0) + if tval < int32(BYTE_MIN) || tval > int32(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + case BIGINT: + tval := Dm_build_1220.Dm_build_1327(bytes, 0) + if tval < int64(BYTE_MIN) || tval > int64(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + case REAL: + tval := Dm_build_1220.Dm_build_1332(bytes, 0) + if tval < float32(BYTE_MIN) || tval > float32(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + case DOUBLE: + tval := Dm_build_1220.Dm_build_1336(bytes, 0) + if tval < float64(BYTE_MIN) || tval > float64(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < float64(BYTE_MIN) || tval > float64(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + case BINARY, VARBINARY, BLOB: + { + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < int64(BYTE_MIN) || tval > int64(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + } + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toInt8(bytes []byte, column *column, conn *DmConnection) (int8, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + + return int8(bytes[0]), nil + case SMALLINT: + tval := Dm_build_1220.Dm_build_1317(bytes, 0) + if tval < int16(INT8_MIN) || tval < int16(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + case INT: + + tval := Dm_build_1220.Dm_build_1322(bytes, 0) + if tval < int32(INT8_MIN) || tval > int32(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + case BIGINT: + tval := Dm_build_1220.Dm_build_1327(bytes, 0) + if tval < int64(INT8_MIN) || tval > int64(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + case REAL: + tval := Dm_build_1220.Dm_build_1332(bytes, 0) + if tval < float32(INT8_MIN) || tval > float32(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + case DOUBLE: + tval := Dm_build_1220.Dm_build_1336(bytes, 0) + if tval < float64(INT8_MIN) || tval > float64(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < float64(INT8_MIN) || tval > float64(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + case BINARY, VARBINARY, BLOB: + { + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < int64(INT8_MIN) || tval > int64(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + } + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toInt16(bytes []byte, column *column, conn *DmConnection) (int16, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + + return int16(bytes[0]), nil + case SMALLINT: + return Dm_build_1220.Dm_build_1317(bytes, 0), nil + case INT: + + tval := Dm_build_1220.Dm_build_1322(bytes, 0) + if tval < int32(INT16_MIN) || tval > int32(INT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int16(tval), nil + case BIGINT: + tval := Dm_build_1220.Dm_build_1327(bytes, 0) + if tval < int64(INT16_MIN) || tval > int64(INT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int16(tval), nil + case REAL: + tval := Dm_build_1220.Dm_build_1332(bytes, 0) + if tval < float32(INT16_MIN) || tval > float32(INT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int16(tval), nil + case DOUBLE: + tval := Dm_build_1220.Dm_build_1336(bytes, 0) + if tval < float64(INT16_MIN) || tval > float64(INT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int16(tval), nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < float64(INT16_MIN) || tval > float64(INT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int16(tval), nil + case BINARY, VARBINARY, BLOB: + { + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < int64(INT16_MIN) || tval > int64(INT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int16(tval), nil + } + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toUInt16(bytes []byte, column *column, conn *DmConnection) (uint16, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + + return uint16(bytes[0]), nil + case SMALLINT: + return uint16(Dm_build_1220.Dm_build_1317(bytes, 0)), nil + case INT: + tval := Dm_build_1220.Dm_build_1322(bytes, 0) + if tval < int32(UINT16_MIN) || tval > int32(UINT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint16(tval), nil + case BIGINT: + tval := Dm_build_1220.Dm_build_1327(bytes, 0) + if tval < int64(UINT16_MIN) || tval > int64(UINT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint16(tval), nil + case REAL: + tval := Dm_build_1220.Dm_build_1332(bytes, 0) + if tval < float32(UINT16_MIN) || tval > float32(UINT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint16(tval), nil + case DOUBLE: + tval := Dm_build_1220.Dm_build_1336(bytes, 0) + if tval < float64(UINT16_MIN) || tval > float64(UINT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint16(tval), nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < float64(UINT16_MIN) || tval > float64(UINT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint16(tval), nil + case BINARY, VARBINARY, BLOB: + { + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < int64(UINT16_MIN) || tval > int64(UINT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint16(tval), nil + } + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toInt32(bytes []byte, column *column, conn *DmConnection) (int32, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + + return int32(bytes[0]), nil + case SMALLINT: + return int32(Dm_build_1220.Dm_build_1317(bytes, 0)), nil + case INT: + return Dm_build_1220.Dm_build_1322(bytes, 0), nil + case BIGINT: + tval := Dm_build_1220.Dm_build_1327(bytes, 0) + if tval < int64(INT32_MIN) || tval > int64(INT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int32(tval), nil + case REAL: + tval := Dm_build_1220.Dm_build_1332(bytes, 0) + if tval < float32(INT32_MIN) || tval > float32(INT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int32(tval), nil + case DOUBLE: + tval := Dm_build_1220.Dm_build_1336(bytes, 0) + if tval < float64(INT32_MIN) || tval > float64(INT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int32(tval), nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < float64(INT32_MIN) || tval > float64(INT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int32(tval), nil + case BINARY, VARBINARY, BLOB: + { + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < int64(INT32_MIN) || tval > int64(INT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int32(tval), nil + } + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toUInt32(bytes []byte, column *column, conn *DmConnection) (uint32, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + + return uint32(bytes[0]), nil + case SMALLINT: + return uint32(Dm_build_1220.Dm_build_1317(bytes, 0)), nil + case INT: + return uint32(Dm_build_1220.Dm_build_1322(bytes, 0)), nil + case BIGINT: + tval := Dm_build_1220.Dm_build_1327(bytes, 0) + if tval < int64(UINT32_MIN) || tval > int64(UINT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint32(tval), nil + case REAL: + tval := Dm_build_1220.Dm_build_1332(bytes, 0) + if tval < float32(UINT32_MIN) || tval > float32(UINT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint32(tval), nil + case DOUBLE: + tval := Dm_build_1220.Dm_build_1336(bytes, 0) + if tval < float64(UINT32_MIN) || tval > float64(UINT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint32(tval), nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < float64(UINT32_MIN) || tval > float64(UINT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint32(tval), nil + case BINARY, VARBINARY, BLOB: + { + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < int64(UINT32_MIN) || tval > int64(UINT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint32(tval), nil + } + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toInt64(bytes []byte, column *column, conn *DmConnection) (int64, error) { + switch column.colType { + case BOOLEAN, BIT, TINYINT: + if bytes == nil || len(bytes) == 0 { + return int64(0), nil + } else { + return int64(bytes[0]), nil + } + case SMALLINT: + return int64(Dm_build_1220.Dm_build_1441(bytes)), nil + case INT: + return int64(Dm_build_1220.Dm_build_1444(bytes)), nil + case BIGINT: + return int64(Dm_build_1220.Dm_build_1447(bytes)), nil + case REAL: + return int64(Dm_build_1220.Dm_build_1450(bytes)), nil + case DOUBLE: + return int64(Dm_build_1220.Dm_build_1453(bytes)), nil + + case CHAR, VARCHAR2, VARCHAR, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if int64(tval) < INT64_MIN || int64(tval) > INT64_MAX { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int64(tval), nil + case BINARY, VARBINARY, BLOB: + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + return tval, nil + } + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toUInt64(bytes []byte, column *column, conn *DmConnection) (uint64, error) { + switch column.colType { + case BOOLEAN, BIT, TINYINT: + if bytes == nil || len(bytes) == 0 { + return uint64(0), nil + } else { + return uint64(bytes[0]), nil + } + case SMALLINT: + return uint64(Dm_build_1220.Dm_build_1441(bytes)), nil + case INT: + return uint64(Dm_build_1220.Dm_build_1444(bytes)), nil + case BIGINT: + return uint64(Dm_build_1220.Dm_build_1447(bytes)), nil + case REAL: + return uint64(Dm_build_1220.Dm_build_1450(bytes)), nil + case DOUBLE: + return uint64(Dm_build_1220.Dm_build_1453(bytes)), nil + + case CHAR, VARCHAR2, VARCHAR, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if uint64(tval) < UINT64_MIN || uint64(tval) > UINT64_MAX { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint64(tval), nil + case BINARY, VARBINARY, BLOB: + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + return uint64(tval), nil + } + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toInt(bytes []byte, column *column, conn *DmConnection) (int, error) { + if strconv.IntSize == 32 { + tmp, err := DB2G.toInt32(bytes, column, conn) + return int(tmp), err + } else { + tmp, err := DB2G.toInt64(bytes, column, conn) + return int(tmp), err + } +} + +func (DB2G db2g) toUInt(bytes []byte, column *column, conn *DmConnection) (uint, error) { + if strconv.IntSize == 32 { + tmp, err := DB2G.toUInt32(bytes, column, conn) + return uint(tmp), err + } else { + tmp, err := DB2G.toUInt64(bytes, column, conn) + return uint(tmp), err + } +} + +func (DB2G db2g) toFloat32(bytes []byte, column *column, conn *DmConnection) (float32, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + return float32(bytes[0]), nil + case SMALLINT: + return float32(Dm_build_1220.Dm_build_1317(bytes, 0)), nil + case INT: + return float32(Dm_build_1220.Dm_build_1322(bytes, 0)), nil + case BIGINT: + return float32(Dm_build_1220.Dm_build_1327(bytes, 0)), nil + case REAL: + return Dm_build_1220.Dm_build_1332(bytes, 0), nil + case DOUBLE: + dval := Dm_build_1220.Dm_build_1336(bytes, 0) + return float32(dval), nil + case DECIMAL: + dval, err := DB2G.decToDecimal(bytes, int(column.prec), int(column.scale), conn.CompatibleOracle()) + if err != nil { + return 0, err + } + return float32(dval.ToFloat64()), nil + case CHAR, VARCHAR2, VARCHAR, CLOB: + dval, err := DB2G.charToDeciaml(bytes, column, conn) + if err != nil { + return 0, err + } + return float32(dval.ToFloat64()), nil + } + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toFloat64(bytes []byte, column *column, conn *DmConnection) (float64, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + return float64(bytes[0]), nil + case SMALLINT: + return float64(Dm_build_1220.Dm_build_1317(bytes, 0)), nil + case INT: + return float64(Dm_build_1220.Dm_build_1322(bytes, 0)), nil + case BIGINT: + return float64(Dm_build_1220.Dm_build_1327(bytes, 0)), nil + case REAL: + return float64(Dm_build_1220.Dm_build_1332(bytes, 0)), nil + case DOUBLE: + return Dm_build_1220.Dm_build_1336(bytes, 0), nil + case DECIMAL: + dval, err := DB2G.decToDecimal(bytes, int(column.prec), int(column.scale), conn.CompatibleOracle()) + if err != nil { + return 0, err + } + return dval.ToFloat64(), nil + case CHAR, VARCHAR2, VARCHAR, CLOB: + dval, err := DB2G.charToDeciaml(bytes, column, conn) + if err != nil { + return 0, err + } + return dval.ToFloat64(), nil + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toDmBlob(value []byte, column *column, conn *DmConnection) *DmBlob { + + switch column.colType { + case BLOB: + return newBlobFromDB(value, conn, column, conn.lobFetchAll()) + } + + return nil +} + +func (DB2G db2g) toDmClob(value []byte, conn *DmConnection, column *column) *DmClob { + + switch column.colType { + case CLOB: + return newClobFromDB(value, conn, column, conn.lobFetchAll()) + } + + return nil +} + +func (DB2G db2g) toDmDecimal(value []byte, column *column, conn *DmConnection) (*DmDecimal, error) { + + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if value == nil || len(value) == 0 { + return NewDecimalFromInt64(0) + } else { + return NewDecimalFromInt64(int64(value[0])) + } + case SMALLINT: + return NewDecimalFromInt64(int64(Dm_build_1220.Dm_build_1317(value, 0))) + case INT: + return NewDecimalFromInt64(int64(Dm_build_1220.Dm_build_1322(value, 0))) + case BIGINT: + return NewDecimalFromInt64(Dm_build_1220.Dm_build_1327(value, 0)) + case REAL: + return NewDecimalFromFloat64(float64(Dm_build_1220.Dm_build_1332(value, 0))) + case DOUBLE: + return NewDecimalFromFloat64(Dm_build_1220.Dm_build_1336(value, 0)) + case DECIMAL: + return decodeDecimal(value, int(column.prec), int(column.scale)) + case CHAR, VARCHAR, VARCHAR2, CLOB: + return DB2G.charToDeciaml(value, column, conn) + } + + return nil, ECGO_DATA_CONVERTION_ERROR +} + +func (DB2G db2g) toTime(bytes []byte, column *column, conn *DmConnection) (time.Time, error) { + switch column.colType { + case DATE, TIME, TIME_TZ, DATETIME_TZ, DATETIME: + dt := decode(bytes, column.isBdta, int(column.colType), int(column.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + return toTimeFromDT(dt, int(conn.dmConnector.localTimezone)), nil + case CHAR, VARCHAR2, VARCHAR, CLOB: + return toTimeFromString(DB2G.charToString(bytes, column, conn), int(conn.dmConnector.localTimezone)), nil + } + return time.Now(), ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toObject(bytes []byte, column *column, conn *DmConnection) (interface{}, error) { + + switch column.colType { + case BIT, BOOLEAN: + return bytes[0] != 0, nil + + case TINYINT: + + return Dm_build_1220.Dm_build_1313(bytes, 0), nil + case SMALLINT: + return Dm_build_1220.Dm_build_1317(bytes, 0), nil + case INT: + return Dm_build_1220.Dm_build_1322(bytes, 0), nil + case BIGINT: + return Dm_build_1220.Dm_build_1327(bytes, 0), nil + case DECIMAL: + + case REAL: + return Dm_build_1220.Dm_build_1332(bytes, 0), nil + case DOUBLE: + return Dm_build_1220.Dm_build_1336(bytes, 0), nil + case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ: + dt := decode(bytes, column.isBdta, int(column.colType), int(column.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + return toTimeFromDT(dt, int(conn.dmConnector.localTimezone)), nil + case BINARY, VARBINARY: + return bytes, nil + case BLOB: + blob := newBlobFromDB(bytes, conn, column, conn.lobFetchAll()) + + if util.StringUtil.EqualsIgnoreCase(column.typeName, "LONGVARBINARY") { + + l, err := blob.GetLength() + if err != nil { + return nil, err + } + return blob.getBytes(1, int32(l)) + } else { + return blob, nil + } + case CHAR, VARCHAR, VARCHAR2: + val := DB2G.charToString(bytes, column, conn) + if isBFile(int(column.colType), int(column.prec), int(column.scale)) { + + } + + return val, nil + case CLOB: + clob := newClobFromDB(bytes, conn, column, conn.lobFetchAll()) + if util.StringUtil.EqualsIgnoreCase(column.typeName, "LONGVARCHAR") { + + l, err := clob.GetLength() + if err != nil { + return nil, err + } + return clob.getSubString(1, int32(l)) + } else { + return clob, nil + } + case INTERVAL_YM: + return newDmIntervalYMByBytes(bytes), nil + case INTERVAL_DT: + return newDmIntervalDTByBytes(bytes), nil + case ARRAY: + return TypeDataSV.bytesToArray(bytes, nil, column.typeDescriptor) + case SARRAY: + return TypeDataSV.bytesToSArray(bytes, nil, column.typeDescriptor) + case CLASS: + + case PLTYPE_RECORD: + + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} diff --git a/dmr/i18n/zj.go b/dmr/i18n/zj.go new file mode 100644 index 0000000..62b5bfd --- /dev/null +++ b/dmr/i18n/zj.go @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package i18n + +import ( + "encoding/json" + "golang.org/x/text/language" + "golang.org/x/text/message" +) + +type msg struct { + Id string `json:"id"` + Translation string `json:"translation,omitempty"` +} + +type i18n struct { + Language string `json:"language"` + Messages []msg `json:"messages"` +} + +func InitConfig(jsonStr string) { + + var i18n i18n + json.Unmarshal([]byte(jsonStr), &i18n) + msaArry := i18n.Messages + tag := language.MustParse(i18n.Language) + for _, e := range msaArry { + message.SetString(tag, e.Id, e.Translation) + } +} + +func Get(key string, locale int) string { + var p *message.Printer + + switch locale { + case 0: + p = message.NewPrinter(language.SimplifiedChinese) + case 1: + p = message.NewPrinter(language.AmericanEnglish) + case 2: + p = message.NewPrinter(language.TraditionalChinese) + } + + return p.Sprintf(key) +} diff --git a/dmr/i18n/zk.go b/dmr/i18n/zk.go new file mode 100644 index 0000000..f69a9b8 --- /dev/null +++ b/dmr/i18n/zk.go @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package i18n + +const Messages_en_US = `{ + "language": "en-US", + "messages": [ + { + "id": "error.dsn.invalidSchema", + "translation": "DSN must start with dm://" + }, + { + "id": "error.unsupported.scan", + "translation": "Unsupported scan type" + }, + { + "id": "error.invalidParameterNumber", + "translation": "Invalid parameter number" + }, + { + "id": "error.initThirdPartCipherFailed", + "translation": "Init third part cipher failed" + }, + { + "id": "error.connectionSwitchFailed", + "translation": "Connection switch failed" + }, + { + "id": "error.connectionSwitched", + "translation": "Connection has been switched" + }, + { + "id": "error.invalidServerMode", + "translation": "Invalid server mode" + }, + { + "id": "error.osauthError", + "translation": "At the same time using the specifed user login and OS authentication login, please determine a way." + }, + { + "id": "error.notQuerySQL", + "translation": "The SQL is not a query SQL" + }, + { + "id": "error.notExecSQL", + "translation": "The SQL is not a execute SQL" + }, + { + "id": "error.invalidTranIsolation", + "translation": "invalid Transaltion Isolation" + }, + { + "id": "errorCommitInAutoCommitMode", + "translation": "Can't commit in Auto commit status" + }, + { + "id": "errorCommitInAutoCommitMode", + "translation": "Can't rollback in Auto commit status" + }, + { + "id": "errorStatementHandleClosed", + "translation": "Statement handle is closed" + }, + { + "id": "errorResultSetColsed", + "translation": "Resultset is closed" + }, + { + "id": "error.communicationError", + "translation": "Communication error" + }, + { + "id": "error.msgCheckError", + "translation": "Message check error" + }, + { + "id": "error.unkownNetWork", + "translation": "Unkown net work" + }, + { + "id": "error.serverVersion", + "translation": "Server version is too low" + }, + { + "id": "error.usernameTooLong", + "translation": "Username is too long." + }, + { + "id": "error.passwordTooLong", + "translation": "Password to login is too long." + }, + { + "id": "error.dataTooLong", + "translation": "The data is too large to support." + }, + { + "id": "error.invalidColumnType", + "translation": "Invalid column type" + }, + { + "id": "error.dataConvertionError", + "translation": "Data convertion error" + }, + { + "id": "error.invalidConn", + "translation": "Invalid connection" + }, + { + "id": "error.invalidHex", + "translation": "Invalid Hex Number." + }, + { + "id": "error.invalidBFile", + "translation": "Invalid BFile format string." + }, + { + "id": "error.dataOverflow", + "translation": "Digital overflow" + }, + { + "id": "error.invalidDateTimeFormat", + "translation": "Invalid datetime type format" + }, + { + "id": "error.datetimeOverflow", + "translation": "Digital overflow" + }, + { + "id": "error.invalidTimeInterval", + "translation": "Invalid time interval type value" + }, + { + "id": "error.unsupportedInparamType", + "translation": "Unsupported input parameter type" + }, + { + "id": "error.unsupportedOutparamType", + "translation": "Unsupported output parameter type" + }, + { + "id": "error.unsupportedType", + "translation": "Not support this type" + }, + { + "id": "error.invalidObjBlob", + "translation": "invalid Object Blob Data." + }, + { + "id": "error.structMemNotMatch", + "translation": "Members are not matched in Record or Class" + }, + { + "id": "error.invalidComplexTypeName", + "translation": "Invalid descriptor name." + }, + { + "id": "error.invalidParamterValue", + "translation": "Invalid parameter value" + }, + { + "id": "error.invalidArrayLen", + "translation": "the length of static array is bigger than the one when defined." + }, + { + "id": "error.invalidSequenceNumber", + "translation": "Invalid sequence no" + }, + { + "id": "error.resultsetInReadOnlyStatus", + "translation": "Resultset in readonly status" + }, + { + "id": "error.SSLInitFailed", + "translation": "Failed to initialize SSL" + }, + { + "id": "error.LobDataHasFreed", + "translation": "Lob Data has been freed" + }, + { + "id": "error.fatalError", + "translation": "Fatal error" + }, + { + "id": "error.invalidLenOrOffset", + "translation": "Invalid length or offset" + }, + { + "id": "error.intervalValueOverflow", + "translation": "interval type value overflow" + }, + { + "id": "error.invalidCipher", + "translation": "Invalid cipher type" + }, + { + "id": "error.storeInNilPointer", + "translation": "Can't store value into a nil pointer" + }, + { + "id": "error.batchError", + "translation": "Error in executing with batch" + }, + { + "id": "warning.bpWithErr", + "translation": "Warning:Partial failure on execute with batch" + }, + { + "id": "error.invalidSqlType", + "translation": "Invalid sql type" + }, + { + "id": "error.invalidDateTimeValue", + "translation": "Invalid datetime value" + }, + { + "id": "error.msgTooLong", + "translation": "Message too long, limit 512M" + }, + { + "id": "error.isNull", + "translation": "Data is NULL" + } + ] +}` \ No newline at end of file diff --git a/dmr/i18n/zl.go b/dmr/i18n/zl.go new file mode 100644 index 0000000..868b292 --- /dev/null +++ b/dmr/i18n/zl.go @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package i18n + +const Messages_zh_CN = `{ + "language": "zh-Hans", + "messages": [ + { + "id": "error.dsn.invalidSchema", + "translation": "DSN串必须以dm://开头" + }, + { + "id": "error.unsupported.scan", + "translation": "Scan类型转换出错" + }, + { + "id": "error.invalidParameterNumber", + "translation": "参数个数不匹配" + }, + { + "id": "error.initThirdPartCipherFailed", + "translation": "第三方加密初始化失败" + }, + { + "id": "error.connectionSwitchFailed", + "translation": "连接重置失败" + }, + { + "id": "error.connectionSwitched", + "translation": "连接已重置" + }, + { + "id": "error.invalidServerMode", + "translation": "服务器模式不匹配" + }, + { + "id": "error.osauthError", + "translation": "同时使用了指定用户登录和OS认证登录, 请确定一种方式." + }, + { + "id": "error.notQuerySQL", + "translation": "非查询SQL语句" + }, + { + "id": "error.notExecSQL", + "translation": "非执行SQL语句" + }, + { + "id": "error.invalidTranIsolation", + "translation": "非法的事务隔离级" + }, + { + "id": "errorCommitInAutoCommitMode", + "translation": "自动提交模式下不能手动提交" + }, + { + "id": "errorRollbackInAutoCommitMode", + "translation": "自动提交模式下不能手动回滚" + }, + { + "id": "errorStatementHandleClosed", + "translation": "语句已经关闭" + }, + { + "id": "errorResultSetColsed", + "translation": "结果集已经关闭" + }, + { + "id": "error.communicationError", + "translation": "网络通信异常" + }, + { + "id": "error.msgCheckError", + "translation": "消息校验异常" + }, + { + "id": "error.unkownNetWork", + "translation": "未知的网络" + }, + { + "id": "error.serverVersion", + "translation": "服务器版本太低" + }, + { + "id": "error.usernameTooLong", + "translation": "用户名超长" + }, + { + "id": "error.passwordTooLong", + "translation": "密码超长" + }, + { + "id": "error.dataTooLong", + "translation": "数据大小已超过可支持范围" + }, + { + "id": "error.invalidColumnType", + "translation": "无效的列类型" + }, + { + "id": "error.dataConvertionError", + "translation": "类型转换异常" + }, + { + "id": "error.invalidConn", + "translation": "连接失效" + }, + { + "id": "error.invalidHex", + "translation": "无效的十六进制数字" + }, + { + "id": "error.invalidBFile", + "translation": "无效的BFile格式串" + }, + { + "id": "error.dataOverflow", + "translation": "数字溢出" + }, + { + "id": "error.invalidDateTimeFormat", + "translation": "错误的日期时间类型格式" + }, + { + "id": "error.datetimeOverflow", + "translation": "数字溢出" + }, + { + "id": "error.invalidTimeInterval", + "translation": "错误的时间间隔类型数据" + }, + { + "id": "error.unsupportedInparamType", + "translation": "输入参数类型不支持" + }, + { + "id": "error.unsupportedOutparamType", + "translation": "输出参数类型不支持" + }, + { + "id": "error.unsupportedType", + "translation": "不支持该数据类型" + }, + { + "id": "error.invalidObjBlob", + "translation": "无效的对象BLOB数据" + }, + { + "id": "error.structMemNotMatch", + "translation": "记录或类数据成员不匹配" + }, + { + "id": "error.invalidComplexTypeName", + "translation": "无效的类型描述名称" + }, + { + "id": "error.invalidParamterValue", + "translation": "无效的参数值" + }, + { + "id": "error.invalidArrayLen", + "translation": "静态数组长度大于定义时长度" + }, + { + "id": "error.invalidSequenceNumber", + "translation": "无效的列序号" + }, + { + "id": "error.resultsetInReadOnlyStatus", + "translation": "结果集处于只读状态" + }, + { + "id": "error.SSLInitFailed", + "translation": "初始化SSL环境失败" + }, + { + "id": "error.LobDataHasFreed", + "translation": "LOB数据已经被释放" + }, + { + "id": "error.fatalError", + "translation": "致命错误" + }, + { + "id": "error.invalidLenOrOffset", + "translation": "长度或偏移错误" + }, + { + "id": "error.intervalValueOverflow", + "translation": "时间间隔类型数据溢出" + }, + { + "id": "error.invalidCipher", + "translation": "不支持的加密类型" + }, + { + "id": "error.storeInNilPointer", + "translation": "无法将数据存入空指针" + }, + { + "id": "error.batchError", + "translation": "批量执行出错" + }, + { + "id": "warning.bpWithErr", + "translation": "警告:批量执行部分行产生错误" + }, + { + "id": "error.invalidSqlType", + "translation": "非法的SQL语句类型" + }, + { + "id": "error.invalidDateTimeValue", + "translation": "无效的日期时间类型值" + }, + { + "id": "error.msgTooLong", + "translation": "消息长度超出限制512M" + }, + { + "id": "error.isNull", + "translation": "数据为NULL" + } + ] +}` \ No newline at end of file diff --git a/dmr/i18n/zm.go b/dmr/i18n/zm.go new file mode 100644 index 0000000..ebc8a5d --- /dev/null +++ b/dmr/i18n/zm.go @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package i18n + +const Messages_zh_TW = `{ + "language": "zh-Hant", + "messages": [ + { + "id": "error.dsn.invalidSchema", + "translation": "DSN串必須以dm://開頭" + }, + { + "id": "error.communicationError", + "translation": "網絡通信異常" + }, + { + "id": "error.msgCheckError", + "translation": "消息校驗異常" + }, + { + "id": "error.unkownNetWork", + "translation": "未知的網絡" + } + ] +}` \ No newline at end of file diff --git a/dmr/j.go b/dmr/j.go new file mode 100644 index 0000000..f70a685 --- /dev/null +++ b/dmr/j.go @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import "database/sql/driver" + +type DmArray struct { + TypeData + m_arrDesc *ArrayDescriptor // 数组的描述信息 + + m_arrData []TypeData // 数组中各行数据值 + + m_objArray interface{} // 从服务端获取的 + + m_itemCount int // 本次获取的行数 + + m_itemSize int // 数组中一个数组项的大小,单位bytes + + m_objCount int // 一个数组项中存在对象类型的个数(class、动态数组) + + m_strCount int // 一个数组项中存在字符串类型的个数 + + m_objStrOffs []int // 对象在前,字符串在后 + + typeName string + + elements []interface{} + + // Valid为false代表DmArray数据在数据库中为NULL + Valid bool +} + +func (da *DmArray) init() *DmArray { + da.initTypeData() + da.m_itemCount = 0 + da.m_itemSize = 0 + da.m_objCount = 0 + da.m_strCount = 0 + da.m_objStrOffs = nil + da.m_dumyData = nil + da.m_offset = 0 + + da.m_objArray = nil + da.Valid = true + return da +} + +func NewDmArray(typeName string, elements []interface{}) *DmArray { + da := new(DmArray) + da.typeName = typeName + da.elements = elements + da.Valid = true + return da +} + +func (da *DmArray) create(dc *DmConnection) (*DmArray, error) { + desc, err := newArrayDescriptor(da.typeName, dc) + if err != nil { + return nil, err + } + return da.createByArrayDescriptor(desc, dc) +} + +func (da *DmArray) createByArrayDescriptor(arrDesc *ArrayDescriptor, conn *DmConnection) (*DmArray, error) { + + if nil == arrDesc { + return nil, ECGO_INVALID_PARAMETER_VALUE.throw() + } + + da.init() + + da.m_arrDesc = arrDesc + if nil == da.elements { + da.m_arrData = make([]TypeData, 0) + } else { + // 若为静态数组,判断给定数组长度是否超过静态数组的上限 + if arrDesc.getMDesc() == nil || (arrDesc.getMDesc().getDType() == SARRAY && len(da.elements) > arrDesc.getMDesc().getStaticArrayLength()) { + return nil, ECGO_INVALID_ARRAY_LEN.throw() + } + + var err error + da.m_arrData, err = TypeDataSV.toArray(da.elements, da.m_arrDesc.getMDesc()) + if err != nil { + return nil, err + } + } + + da.m_itemCount = len(da.m_arrData) + return da, nil +} + +func newDmArrayByTypeData(atData []TypeData, desc *TypeDescriptor) *DmArray { + da := new(DmArray) + da.init() + da.m_arrDesc = newArrayDescriptorByTypeDescriptor(desc) + da.m_arrData = atData + return da +} + +func (da *DmArray) checkIndex(index int64) error { + if index < 0 || index > int64(len(da.m_arrData)-1) { + return ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + return nil +} + +func (da *DmArray) checkIndexAndCount(index int64, count int) error { + err := da.checkIndex(index) + if err != nil { + return err + } + + if count <= 0 || index+int64(count) > int64(len(da.m_arrData)) { + return ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + return nil +} + +func (da *DmArray) GetBaseTypeName() (string, error) { + if err := da.checkValid(); err != nil { + return "", err + } + return da.m_arrDesc.m_typeDesc.getFulName() +} + +func (da *DmArray) GetObjArray(index int64, count int) (interface{}, error) { + var err error + if err = da.checkValid(); err != nil { + return nil, err + } + if err = da.checkIndexAndCount(index, count); err != nil { + return nil, err + } + + return TypeDataSV.toJavaArray(da, index, count, da.m_arrDesc.getItemDesc().getDType()) +} + +func (da *DmArray) GetIntArray(index int64, count int) ([]int, error) { + var err error + if err = da.checkValid(); err != nil { + return nil, err + } + if err = da.checkIndexAndCount(index, count); err != nil { + return nil, err + } + + tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_INTEGER) + if err != nil { + return nil, err + } + return tmp.([]int), nil +} + +func (da *DmArray) GetInt16Array(index int64, count int) ([]int16, error) { + var err error + if err = da.checkValid(); err != nil { + return nil, err + } + if err = da.checkIndexAndCount(index, count); err != nil { + return nil, err + } + + tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_SHORT) + if err != nil { + return nil, err + } + return tmp.([]int16), nil +} + +func (da *DmArray) GetInt64Array(index int64, count int) ([]int64, error) { + var err error + if err = da.checkValid(); err != nil { + return nil, err + } + if err = da.checkIndexAndCount(index, count); err != nil { + return nil, err + } + + tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_LONG) + if err != nil { + return nil, err + } + + return tmp.([]int64), nil +} + +func (da *DmArray) GetFloatArray(index int64, count int) ([]float32, error) { + var err error + if err = da.checkValid(); err != nil { + return nil, err + } + if err = da.checkIndexAndCount(index, count); err != nil { + return nil, err + } + + tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_FLOAT) + if err != nil { + return nil, err + } + + return tmp.([]float32), nil +} + +func (da *DmArray) GetDoubleArray(index int64, count int) ([]float64, error) { + var err error + if err = da.checkValid(); err != nil { + return nil, err + } + if err = da.checkIndexAndCount(index, count); err != nil { + return nil, err + } + + tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_DOUBLE) + if err != nil { + return nil, err + } + + return tmp.([]float64), nil +} + +func (dest *DmArray) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmArray) + // 将Valid标志置false表示数据库中该列为NULL + (*dest).Valid = false + return nil + case *DmArray: + *dest = *src + return nil + default: + return UNSUPPORTED_SCAN.throw() + } +} + +func (array DmArray) Value() (driver.Value, error) { + if !array.Valid { + return nil, nil + } + return array, nil +} + +func (array *DmArray) checkValid() error { + if !array.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} diff --git a/dmr/k.go b/dmr/k.go new file mode 100644 index 0000000..9468aa9 --- /dev/null +++ b/dmr/k.go @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "database/sql/driver" + "io" +) + +type DmBlob struct { + lob + data []byte + offset int64 +} + +func newDmBlob() *DmBlob { + return &DmBlob{ + lob: lob{ + inRow: true, + groupId: -1, + fileId: -1, + pageNo: -1, + readOver: false, + local: true, + updateable: true, + length: -1, + compatibleOracle: false, + fetchAll: false, + freed: false, + modify: false, + Valid: true, + }, + offset: 1, + } +} + +func newBlobFromDB(value []byte, conn *DmConnection, column *column, fetchAll bool) *DmBlob { + var blob = newDmBlob() + blob.connection = conn + blob.lobFlag = LOB_FLAG_BYTE + blob.compatibleOracle = conn.CompatibleOracle() + blob.local = false + blob.updateable = !column.readonly + blob.tabId = column.lobTabId + blob.colId = column.lobColId + + blob.inRow = Dm_build_1220.Dm_build_1313(value, NBLOB_HEAD_IN_ROW_FLAG) == LOB_IN_ROW + blob.blobId = Dm_build_1220.Dm_build_1327(value, NBLOB_HEAD_BLOBID) + if !blob.inRow { + blob.groupId = Dm_build_1220.Dm_build_1317(value, NBLOB_HEAD_OUTROW_GROUPID) + blob.fileId = Dm_build_1220.Dm_build_1317(value, NBLOB_HEAD_OUTROW_FILEID) + blob.pageNo = Dm_build_1220.Dm_build_1322(value, NBLOB_HEAD_OUTROW_PAGENO) + } + if conn.NewLobFlag { + blob.tabId = Dm_build_1220.Dm_build_1322(value, NBLOB_EX_HEAD_TABLE_ID) + blob.colId = Dm_build_1220.Dm_build_1317(value, NBLOB_EX_HEAD_COL_ID) + blob.rowId = Dm_build_1220.Dm_build_1327(value, NBLOB_EX_HEAD_ROW_ID) + blob.exGroupId = Dm_build_1220.Dm_build_1317(value, NBLOB_EX_HEAD_FPA_GRPID) + blob.exFileId = Dm_build_1220.Dm_build_1317(value, NBLOB_EX_HEAD_FPA_FILEID) + blob.exPageNo = Dm_build_1220.Dm_build_1322(value, NBLOB_EX_HEAD_FPA_PAGENO) + } + blob.resetCurrentInfo() + + blob.length = blob.getLengthFromHead(value) + if blob.inRow { + blob.data = make([]byte, blob.length) + if conn.NewLobFlag { + Dm_build_1220.Dm_build_1276(blob.data, 0, value, NBLOB_EX_HEAD_SIZE, len(blob.data)) + } else { + Dm_build_1220.Dm_build_1276(blob.data, 0, value, NBLOB_INROW_HEAD_SIZE, len(blob.data)) + } + } else if fetchAll { + blob.loadAllData() + } + return blob +} + +func newBlobOfLocal(value []byte, conn *DmConnection) *DmBlob { + var blob = newDmBlob() + blob.connection = conn + blob.lobFlag = LOB_FLAG_BYTE + blob.data = value + blob.length = int64(len(blob.data)) + return blob +} + +func NewBlob(value []byte) *DmBlob { + var blob = newDmBlob() + + blob.lobFlag = LOB_FLAG_BYTE + blob.data = value + blob.length = int64(len(blob.data)) + return blob +} + +func (blob *DmBlob) Read(dest []byte) (n int, err error) { + if err = blob.checkValid(); err != nil { + return + } + result, err := blob.getBytes(blob.offset, int32(len(dest))) + if err != nil { + return 0, err + } + blob.offset += int64(len(result)) + copy(dest, result) + if len(result) == 0 { + return 0, io.EOF + } + return len(result), nil +} + +func (blob *DmBlob) ReadAt(pos int, dest []byte) (n int, err error) { + if err = blob.checkValid(); err != nil { + return + } + result, err := blob.getBytes(int64(pos), int32(len(dest))) + if err != nil { + return 0, err + } + if len(result) == 0 { + return 0, io.EOF + } + copy(dest[0:len(result)], result) + return len(result), nil +} + +func (blob *DmBlob) Write(pos int, src []byte) (n int, err error) { + if err = blob.checkValid(); err != nil { + return + } + if err = blob.checkFreed(); err != nil { + return + } + if pos < 1 { + err = ECGO_INVALID_LENGTH_OR_OFFSET.throw() + return + } + if !blob.updateable { + err = ECGO_RESULTSET_IS_READ_ONLY.throw() + return + } + pos -= 1 + if blob.local || blob.fetchAll { + if int64(pos) > blob.length { + err = ECGO_INVALID_LENGTH_OR_OFFSET.throw() + return + } + blob.setLocalData(pos, src) + n = len(src) + } else { + if err = blob.connection.checkClosed(); err != nil { + return -1, err + } + var writeLen, err = blob.connection.Access.dm_build_542(blob, pos, src) + if err != nil { + return -1, err + } + + if blob.groupId == -1 { + blob.setLocalData(pos, src) + } else { + blob.inRow = false + blob.length = -1 + } + n = writeLen + + } + blob.modify = true + return +} + +func (blob *DmBlob) Truncate(length int64) error { + var err error + if err = blob.checkValid(); err != nil { + return err + } + if err = blob.checkFreed(); err != nil { + return err + } + if length < 0 { + return ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + if !blob.updateable { + return ECGO_RESULTSET_IS_READ_ONLY.throw() + } + if blob.local || blob.fetchAll { + if length >= int64(len(blob.data)) { + return nil + } + tmp := make([]byte, length) + Dm_build_1220.Dm_build_1276(tmp, 0, blob.data, 0, len(tmp)) + blob.data = tmp + blob.length = int64(len(tmp)) + } else { + if err = blob.connection.checkClosed(); err != nil { + return err + } + blob.length, err = blob.connection.Access.dm_build_556(&blob.lob, int(length)) + if err != nil { + return err + } + if blob.groupId == -1 { + tmp := make([]byte, blob.length) + Dm_build_1220.Dm_build_1276(tmp, 0, blob.data, 0, int(blob.length)) + blob.data = tmp + } + } + blob.modify = true + return nil +} + +func (dest *DmBlob) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmBlob) + + (*dest).Valid = false + return nil + case []byte: + *dest = *NewBlob(src) + return nil + case *DmBlob: + *dest = *src + return nil + default: + return UNSUPPORTED_SCAN.throw() + } +} + +func (blob DmBlob) Value() (driver.Value, error) { + if !blob.Valid { + return nil, nil + } + return blob, nil +} + +func (blob *DmBlob) getBytes(pos int64, length int32) ([]byte, error) { + var err error + var leaveLength int64 + if err = blob.checkFreed(); err != nil { + return nil, err + } + if pos < 1 || length < 0 { + return nil, ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + pos = pos - 1 + if leaveLength, err = blob.GetLength(); err != nil { + return nil, err + } + leaveLength -= pos + if leaveLength < 0 { + return nil, ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + if int64(length) > leaveLength { + length = int32(leaveLength) + } + if blob.local || blob.inRow || blob.fetchAll { + return blob.data[pos : pos+int64(length)], nil + } else { + + return blob.connection.Access.dm_build_505(blob, int32(pos), length) + } +} + +func (blob *DmBlob) loadAllData() { + blob.checkFreed() + if blob.local || blob.inRow || blob.fetchAll { + return + } + len, _ := blob.GetLength() + blob.data, _ = blob.getBytes(1, int32(len)) + blob.fetchAll = true +} + +func (blob *DmBlob) setLocalData(pos int, p []byte) { + if pos+len(p) >= int(blob.length) { + var tmp = make([]byte, pos+len(p)) + Dm_build_1220.Dm_build_1276(tmp, 0, blob.data, 0, pos) + Dm_build_1220.Dm_build_1276(tmp, pos, p, 0, len(p)) + blob.data = tmp + } else { + Dm_build_1220.Dm_build_1276(blob.data, pos, p, 0, len(p)) + } + blob.length = int64(len(blob.data)) +} diff --git a/dmr/l.go b/dmr/l.go new file mode 100644 index 0000000..b682ae2 --- /dev/null +++ b/dmr/l.go @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "database/sql/driver" + "io" +) + +type DmClob struct { + lob + data []rune + serverEncoding string +} + +func newDmClob() *DmClob { + return &DmClob{ + lob: lob{ + inRow: true, + groupId: -1, + fileId: -1, + pageNo: -1, + readOver: false, + local: true, + updateable: true, + length: -1, + compatibleOracle: false, + fetchAll: false, + freed: false, + modify: false, + Valid: true, + }, + } +} + +func newClobFromDB(value []byte, conn *DmConnection, column *column, fetchAll bool) *DmClob { + var clob = newDmClob() + clob.connection = conn + clob.lobFlag = LOB_FLAG_CHAR + clob.compatibleOracle = conn.CompatibleOracle() + clob.local = false + clob.updateable = !column.readonly + clob.tabId = column.lobTabId + clob.colId = column.lobColId + + clob.inRow = Dm_build_1220.Dm_build_1313(value, NBLOB_HEAD_IN_ROW_FLAG) == LOB_IN_ROW + clob.blobId = Dm_build_1220.Dm_build_1327(value, NBLOB_HEAD_BLOBID) + if !clob.inRow { + clob.groupId = Dm_build_1220.Dm_build_1317(value, NBLOB_HEAD_OUTROW_GROUPID) + clob.fileId = Dm_build_1220.Dm_build_1317(value, NBLOB_HEAD_OUTROW_FILEID) + clob.pageNo = Dm_build_1220.Dm_build_1322(value, NBLOB_HEAD_OUTROW_PAGENO) + } + if conn.NewLobFlag { + clob.tabId = Dm_build_1220.Dm_build_1322(value, NBLOB_EX_HEAD_TABLE_ID) + clob.colId = Dm_build_1220.Dm_build_1317(value, NBLOB_EX_HEAD_COL_ID) + clob.rowId = Dm_build_1220.Dm_build_1327(value, NBLOB_EX_HEAD_ROW_ID) + clob.exGroupId = Dm_build_1220.Dm_build_1317(value, NBLOB_EX_HEAD_FPA_GRPID) + clob.exFileId = Dm_build_1220.Dm_build_1317(value, NBLOB_EX_HEAD_FPA_FILEID) + clob.exPageNo = Dm_build_1220.Dm_build_1322(value, NBLOB_EX_HEAD_FPA_PAGENO) + } + clob.resetCurrentInfo() + + clob.serverEncoding = conn.getServerEncoding() + if clob.inRow { + if conn.NewLobFlag { + clob.data = []rune(Dm_build_1220.Dm_build_1377(value, NBLOB_EX_HEAD_SIZE, int(clob.getLengthFromHead(value)), clob.serverEncoding, conn)) + } else { + clob.data = []rune(Dm_build_1220.Dm_build_1377(value, NBLOB_INROW_HEAD_SIZE, int(clob.getLengthFromHead(value)), clob.serverEncoding, conn)) + } + clob.length = int64(len(clob.data)) + } else if fetchAll { + clob.loadAllData() + } + return clob +} + +func newClobOfLocal(value string, conn *DmConnection) *DmClob { + var clob = newDmClob() + clob.connection = conn + clob.lobFlag = LOB_FLAG_CHAR + clob.data = []rune(value) + clob.length = int64(len(clob.data)) + return clob +} + +func NewClob(value string) *DmClob { + var clob = newDmClob() + + clob.lobFlag = LOB_FLAG_CHAR + clob.data = []rune(value) + clob.length = int64(len(clob.data)) + return clob +} + +func (clob *DmClob) ReadString(pos int, length int) (result string, err error) { + if err = clob.checkValid(); err != nil { + return + } + result, err = clob.getSubString(int64(pos), int32(length)) + if err != nil { + return + } + if len(result) == 0 { + err = io.EOF + return + } + return +} + +func (clob *DmClob) WriteString(pos int, s string) (n int, err error) { + if err = clob.checkValid(); err != nil { + return + } + if err = clob.checkFreed(); err != nil { + return + } + if pos < 1 { + err = ECGO_INVALID_LENGTH_OR_OFFSET.throw() + return + } + if !clob.updateable { + err = ECGO_RESULTSET_IS_READ_ONLY.throw() + return + } + pos -= 1 + if clob.local || clob.fetchAll { + if int64(pos) > clob.length { + err = ECGO_INVALID_LENGTH_OR_OFFSET.throw() + return + } + clob.setLocalData(pos, s) + n = len(s) + } else { + if err = clob.connection.checkClosed(); err != nil { + return -1, err + } + var writeLen, err = clob.connection.Access.dm_build_526(clob, pos, s, clob.serverEncoding) + if err != nil { + return -1, err + } + + if clob.groupId == -1 { + clob.setLocalData(pos, s) + } else { + clob.inRow = false + clob.length = -1 + } + n = writeLen + } + clob.modify = true + return +} + +func (clob *DmClob) Truncate(length int64) error { + var err error + if err = clob.checkValid(); err != nil { + return err + } + if err = clob.checkFreed(); err != nil { + return err + } + if length < 0 { + return ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + if !clob.updateable { + return ECGO_RESULTSET_IS_READ_ONLY.throw() + } + if clob.local || clob.fetchAll { + if length >= int64(len(clob.data)) { + return nil + } + clob.data = clob.data[0:length] + clob.length = int64(len(clob.data)) + } else { + if err = clob.connection.checkClosed(); err != nil { + return err + } + clob.length, err = clob.connection.Access.dm_build_556(&clob.lob, int(length)) + if err != nil { + return err + } + if clob.groupId == -1 { + clob.data = clob.data[0:clob.length] + } + } + clob.modify = true + return nil +} + +func (dest *DmClob) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmClob) + + (*dest).Valid = false + return nil + case string: + *dest = *NewClob(src) + return nil + case *DmClob: + *dest = *src + return nil + default: + return UNSUPPORTED_SCAN.throw() + } +} + +func (clob DmClob) Value() (driver.Value, error) { + if !clob.Valid { + return nil, nil + } + return clob, nil +} + +func (clob *DmClob) getSubString(pos int64, len int32) (string, error) { + var err error + var leaveLength int64 + if err = clob.checkFreed(); err != nil { + return "", err + } + if pos < 1 || len < 0 { + return "", ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + pos = pos - 1 + if leaveLength, err = clob.GetLength(); err != nil { + return "", err + } + if pos > leaveLength { + pos = leaveLength + } + leaveLength -= pos + if leaveLength < 0 { + return "", ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + if int64(len) > leaveLength { + len = int32(leaveLength) + } + if clob.local || clob.inRow || clob.fetchAll { + if pos > clob.length { + return "", ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + return string(clob.data[pos : pos+int64(len)]), nil + } else { + + return clob.connection.Access.dm_build_515(clob, int32(pos), len) + } +} + +func (clob *DmClob) loadAllData() { + clob.checkFreed() + if clob.local || clob.inRow || clob.fetchAll { + return + } + len, _ := clob.GetLength() + s, _ := clob.getSubString(1, int32(len)) + clob.data = []rune(s) + clob.fetchAll = true +} + +func (clob *DmClob) setLocalData(pos int, str string) { + if pos+len(str) >= int(clob.length) { + clob.data = []rune(string(clob.data[0:pos]) + str) + } else { + clob.data = []rune(string(clob.data[0:pos]) + str + string(clob.data[pos+len(str):len(clob.data)])) + } + clob.length = int64(len(clob.data)) +} diff --git a/dmr/m.go b/dmr/m.go new file mode 100644 index 0000000..ea3d782 --- /dev/null +++ b/dmr/m.go @@ -0,0 +1,867 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "bytes" + "context" + "database/sql" + "database/sql/driver" + "fmt" + "sync/atomic" + + "github.com/nfjBill/gorm-driver-dm/dmr/parser" + "golang.org/x/text/encoding" +) + +type DmConnection struct { + filterable + + dmConnector *DmConnector + Access *dm_build_332 + stmtMap map[int32]*DmStatement + stmtPool []stmtPoolInfo + lastExecInfo *execRetInfo + lexer *parser.Lexer + encode encoding.Encoding + encodeBuffer *bytes.Buffer + transformReaderDst []byte + transformReaderSrc []byte + + serverEncoding string + GlobalServerSeries int + ServerVersion string + Malini2 bool + Execute2 bool + LobEmptyCompOrcl bool + IsoLevel int32 + ReadOnly bool + NewLobFlag bool + sslEncrypt int + MaxRowSize int32 + DDLAutoCommit bool + BackslashEscape bool + SvrStat int32 + SvrMode int32 + ConstParaOpt bool + DbTimezone int16 + LifeTimeRemainder int16 + InstanceName string + Schema string + LastLoginIP string + LastLoginTime string + FailedAttempts int32 + LoginWarningID int32 + GraceTimeRemainder int32 + Guid string + DbName string + StandbyHost string + StandbyPort int32 + StandbyCount int32 + SessionID int64 + OracleDateLanguage byte + FormatDate string + FormatTimestamp string + FormatTimestampTZ string + FormatTime string + FormatTimeTZ string + Local bool + MsgVersion int32 + TrxStatus int32 + dscControl bool + trxFinish bool + sessionID int64 + autoCommit bool + isBatch bool + + watching bool + watcher chan<- context.Context + closech chan struct{} + finished chan<- struct{} + canceled atomicError + closed atomicBool +} + +func (conn *DmConnection) setTrxFinish(status int32) { + switch status & Dm_build_722 { + case Dm_build_719, Dm_build_720, Dm_build_721: + conn.trxFinish = true + default: + conn.trxFinish = false + } +} + +func (dmConn *DmConnection) init() { + if dmConn.dmConnector.stmtPoolMaxSize > 0 { + dmConn.stmtPool = make([]stmtPoolInfo, 0, dmConn.dmConnector.stmtPoolMaxSize) + } + + dmConn.stmtMap = make(map[int32]*DmStatement) + dmConn.DbTimezone = 0 + dmConn.GlobalServerSeries = 0 + dmConn.MaxRowSize = 0 + dmConn.LobEmptyCompOrcl = false + dmConn.ReadOnly = false + dmConn.DDLAutoCommit = false + dmConn.ConstParaOpt = false + dmConn.IsoLevel = -1 + dmConn.sessionID = -1 + dmConn.Malini2 = true + dmConn.NewLobFlag = true + dmConn.Execute2 = true + dmConn.serverEncoding = ENCODING_GB18030 + dmConn.TrxStatus = Dm_build_670 + dmConn.OracleDateLanguage = byte(Locale) + dmConn.lastExecInfo = NewExceInfo() + dmConn.MsgVersion = Dm_build_603 + + dmConn.idGenerator = dmConnIDGenerator +} + +func (dmConn *DmConnection) reset() { + dmConn.DbTimezone = 0 + dmConn.GlobalServerSeries = 0 + dmConn.MaxRowSize = 0 + dmConn.LobEmptyCompOrcl = false + dmConn.ReadOnly = false + dmConn.DDLAutoCommit = false + dmConn.ConstParaOpt = false + dmConn.IsoLevel = -1 + dmConn.sessionID = -1 + dmConn.Malini2 = true + dmConn.NewLobFlag = true + dmConn.Execute2 = true + dmConn.serverEncoding = ENCODING_GB18030 + dmConn.TrxStatus = Dm_build_670 +} + +func (dc *DmConnection) checkClosed() error { + if dc.closed.IsSet() { + return driver.ErrBadConn + } + + return nil +} + +func (dc *DmConnection) executeInner(query string, execType int16) (interface{}, error) { + + stmt, err := NewDmStmt(dc, query) + + if err != nil { + return nil, err + } + + if execType == Dm_build_687 { + defer stmt.close() + } + + stmt.innerUsed = true + if stmt.dmConn.dmConnector.escapeProcess { + stmt.nativeSql, err = stmt.dmConn.escape(stmt.nativeSql, stmt.dmConn.dmConnector.keyWords) + if err != nil { + stmt.close() + return nil, err + } + } + + var optParamList []OptParameter + + if stmt.dmConn.ConstParaOpt { + optParamList = make([]OptParameter, 0) + stmt.nativeSql, optParamList, err = stmt.dmConn.execOpt(stmt.nativeSql, optParamList, stmt.dmConn.getServerEncoding()) + if err != nil { + stmt.close() + optParamList = nil + } + } + + if execType == Dm_build_686 && dc.dmConnector.enRsCache { + rpv, err := rp.get(stmt, query) + if err != nil { + return nil, err + } + + if rpv != nil { + stmt.execInfo = rpv.execInfo + dc.lastExecInfo = rpv.execInfo + return newDmRows(rpv.getResultSet(stmt)), nil + } + } + + var info *execRetInfo + + if optParamList != nil && len(optParamList) > 0 { + info, err = dc.Access.Dm_build_411(stmt, optParamList) + if err != nil { + stmt.nativeSql = query + info, err = dc.Access.Dm_build_417(stmt, execType) + } + } else { + info, err = dc.Access.Dm_build_417(stmt, execType) + } + + if err != nil { + stmt.close() + return nil, err + } + dc.lastExecInfo = info + + if info.hasResultSet { + return newDmRows(newInnerRows(0, stmt, info)), nil + } else { + return newDmResult(stmt, info), nil + } +} + +func g2dbIsoLevel(isoLevel int32) int32 { + switch isoLevel { + case 1: + return Dm_build_674 + case 2: + return Dm_build_675 + case 4: + return Dm_build_676 + case 6: + return Dm_build_677 + default: + return -1 + } +} + +func (dc *DmConnection) Begin() (driver.Tx, error) { + if len(dc.filterChain.filters) == 0 { + return dc.begin() + } else { + return dc.filterChain.reset().DmConnectionBegin(dc) + } +} + +func (dc *DmConnection) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + if len(dc.filterChain.filters) == 0 { + return dc.beginTx(ctx, opts) + } + return dc.filterChain.reset().DmConnectionBeginTx(dc, ctx, opts) +} + +func (dc *DmConnection) Commit() error { + if len(dc.filterChain.filters) == 0 { + return dc.commit() + } else { + return dc.filterChain.reset().DmConnectionCommit(dc) + } +} + +func (dc *DmConnection) Rollback() error { + if len(dc.filterChain.filters) == 0 { + return dc.rollback() + } else { + return dc.filterChain.reset().DmConnectionRollback(dc) + } +} + +func (dc *DmConnection) Close() error { + if len(dc.filterChain.filters) == 0 { + return dc.close() + } else { + return dc.filterChain.reset().DmConnectionClose(dc) + } +} + +func (dc *DmConnection) Ping(ctx context.Context) error { + if len(dc.filterChain.filters) == 0 { + return dc.ping(ctx) + } else { + return dc.filterChain.reset().DmConnectionPing(dc, ctx) + } +} + +func (dc *DmConnection) Exec(query string, args []driver.Value) (driver.Result, error) { + if len(dc.filterChain.filters) == 0 { + return dc.exec(query, args) + } + return dc.filterChain.reset().DmConnectionExec(dc, query, args) +} + +func (dc *DmConnection) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { + if len(dc.filterChain.filters) == 0 { + return dc.execContext(ctx, query, args) + } + return dc.filterChain.reset().DmConnectionExecContext(dc, ctx, query, args) +} + +func (dc *DmConnection) Query(query string, args []driver.Value) (driver.Rows, error) { + if len(dc.filterChain.filters) == 0 { + return dc.query(query, args) + } + return dc.filterChain.reset().DmConnectionQuery(dc, query, args) +} + +func (dc *DmConnection) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { + if len(dc.filterChain.filters) == 0 { + return dc.queryContext(ctx, query, args) + } + return dc.filterChain.reset().DmConnectionQueryContext(dc, ctx, query, args) +} + +func (dc *DmConnection) Prepare(query string) (driver.Stmt, error) { + if len(dc.filterChain.filters) == 0 { + return dc.prepare(query) + } + return dc.filterChain.reset().DmConnectionPrepare(dc, query) +} + +func (dc *DmConnection) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { + if len(dc.filterChain.filters) == 0 { + return dc.prepareContext(ctx, query) + } + return dc.filterChain.reset().DmConnectionPrepareContext(dc, ctx, query) +} + +func (dc *DmConnection) ResetSession(ctx context.Context) error { + if len(dc.filterChain.filters) == 0 { + return dc.resetSession(ctx) + } + return dc.filterChain.reset().DmConnectionResetSession(dc, ctx) +} + +func (dc *DmConnection) CheckNamedValue(nv *driver.NamedValue) error { + if len(dc.filterChain.filters) == 0 { + return dc.checkNamedValue(nv) + } + return dc.filterChain.reset().DmConnectionCheckNamedValue(dc, nv) +} + +func (dc *DmConnection) begin() (*DmConnection, error) { + return dc.beginTx(context.Background(), driver.TxOptions{driver.IsolationLevel(sql.LevelDefault), false}) +} + +func (dc *DmConnection) beginTx(ctx context.Context, opts driver.TxOptions) (*DmConnection, error) { + if err := dc.watchCancel(ctx); err != nil { + return nil, err + } + defer dc.finish() + + err := dc.checkClosed() + if err != nil { + return nil, err + } + + dc.autoCommit = false + + if sql.IsolationLevel(opts.Isolation) == sql.LevelDefault { + opts.Isolation = driver.IsolationLevel(sql.LevelReadCommitted) + } + + dc.ReadOnly = opts.ReadOnly + + if dc.IsoLevel == int32(opts.Isolation) { + return dc, nil + } + + switch sql.IsolationLevel(opts.Isolation) { + case sql.LevelDefault, sql.LevelReadUncommitted: + return dc, nil + case sql.LevelReadCommitted, sql.LevelSerializable: + dc.IsoLevel = int32(opts.Isolation) + case sql.LevelRepeatableRead: + if dc.CompatibleMysql() { + dc.IsoLevel = int32(sql.LevelReadCommitted) + } else { + return nil, ECGO_INVALID_TRAN_ISOLATION.throw() + } + default: + return nil, ECGO_INVALID_TRAN_ISOLATION.throw() + } + + err = dc.Access.Dm_build_471(dc) + if err != nil { + return nil, err + } + return dc, nil +} + +func (dc *DmConnection) commit() error { + err := dc.checkClosed() + if err != nil { + return err + } + + defer func() { + dc.autoCommit = dc.dmConnector.autoCommit + }() + + if !dc.autoCommit { + err = dc.Access.Commit() + if err != nil { + return err + } + dc.trxFinish = true + return nil + } else if !dc.dmConnector.alwayseAllowCommit { + return ECGO_COMMIT_IN_AUTOCOMMIT_MODE.throw() + } + + return nil +} + +func (dc *DmConnection) rollback() error { + err := dc.checkClosed() + if err != nil { + return err + } + + defer func() { + dc.autoCommit = dc.dmConnector.autoCommit + }() + + if !dc.autoCommit { + err = dc.Access.Rollback() + if err != nil { + return err + } + dc.trxFinish = true + return nil + } else if !dc.dmConnector.alwayseAllowCommit { + return ECGO_ROLLBACK_IN_AUTOCOMMIT_MODE.throw() + } + + return nil +} + +func (dc *DmConnection) reconnect() error { + err := dc.Access.Close() + if err != nil { + return err + } + + for _, stmt := range dc.stmtMap { + stmt.closed = true + for id, _ := range stmt.rsMap { + delete(stmt.rsMap, id) + } + } + + if dc.stmtPool != nil { + dc.stmtPool = dc.stmtPool[:0] + } + + dc.dmConnector.reConnection = dc + + if dc.dmConnector.group != nil { + _, err = dc.dmConnector.group.connect(dc.dmConnector) + if err != nil { + return err + } + } else { + _, err = dc.dmConnector.connect(context.Background()) + } + + for _, stmt := range dc.stmtMap { + err = dc.Access.Dm_build_389(stmt) + if err != nil { + return err + } + + if stmt.paramCount > 0 { + err = stmt.prepare() + if err != nil { + return err + } + } + } + + return nil +} + +func (dc *DmConnection) cleanup() { + dc.close() +} + +func (dc *DmConnection) close() error { + if !dc.closed.TrySet(true) { + return nil + } + + close(dc.closech) + if dc.Access == nil { + return nil + } + + dc.rollback() + + for _, stmt := range dc.stmtMap { + stmt.free() + } + + if dc.stmtPool != nil { + for _, spi := range dc.stmtPool { + dc.Access.Dm_build_394(spi.id) + } + dc.stmtPool = nil + } + + dc.Access.Close() + + return nil +} + +func (dc *DmConnection) ping(ctx context.Context) error { + if err := dc.watchCancel(ctx); err != nil { + return err + } + defer dc.finish() + + rows, err := dc.query("select 1", nil) + if err != nil { + return err + } + return rows.close() +} + +func (dc *DmConnection) exec(query string, args []driver.Value) (*DmResult, error) { + err := dc.checkClosed() + if err != nil { + return nil, err + } + + if args != nil && len(args) > 0 { + stmt, err := dc.prepare(query) + defer stmt.close() + if err != nil { + return nil, err + } + dc.lastExecInfo = stmt.execInfo + + return stmt.exec(args) + } else { + r1, err := dc.executeInner(query, Dm_build_687) + if err != nil { + return nil, err + } + + if r2, ok := r1.(*DmResult); ok { + return r2, nil + } else { + return nil, ECGO_NOT_EXEC_SQL.throw() + } + } +} + +func (dc *DmConnection) execContext(ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) { + + if err := dc.watchCancel(ctx); err != nil { + return nil, err + } + defer dc.finish() + + err := dc.checkClosed() + if err != nil { + return nil, err + } + + if args != nil && len(args) > 0 { + stmt, err := dc.prepare(query) + defer stmt.close() + if err != nil { + return nil, err + } + dc.lastExecInfo = stmt.execInfo + + return stmt.execContext(ctx, args) + } else { + r1, err := dc.executeInner(query, Dm_build_687) + if err != nil { + return nil, err + } + + if r2, ok := r1.(*DmResult); ok { + return r2, nil + } else { + return nil, ECGO_NOT_EXEC_SQL.throw() + } + } +} + +func (dc *DmConnection) query(query string, args []driver.Value) (*DmRows, error) { + + err := dc.checkClosed() + if err != nil { + return nil, err + } + + if args != nil && len(args) > 0 { + stmt, err := dc.prepare(query) + if err != nil { + stmt.close() + return nil, err + } + dc.lastExecInfo = stmt.execInfo + + stmt.innerUsed = true + return stmt.query(args) + + } else { + r1, err := dc.executeInner(query, Dm_build_686) + if err != nil { + return nil, err + } + + if r2, ok := r1.(*DmRows); ok { + return r2, nil + } else { + return nil, ECGO_NOT_QUERY_SQL.throw() + } + } +} + +func (dc *DmConnection) queryContext(ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) { + if err := dc.watchCancel(ctx); err != nil { + return nil, err + } + defer dc.finish() + + err := dc.checkClosed() + if err != nil { + return nil, err + } + + if args != nil && len(args) > 0 { + stmt, err := dc.prepare(query) + if err != nil { + stmt.close() + return nil, err + } + dc.lastExecInfo = stmt.execInfo + + stmt.innerUsed = true + return stmt.queryContext(ctx, args) + + } else { + r1, err := dc.executeInner(query, Dm_build_686) + if err != nil { + return nil, err + } + + if r2, ok := r1.(*DmRows); ok { + return r2, nil + } else { + return nil, ECGO_NOT_QUERY_SQL.throw() + } + } + +} + +func (dc *DmConnection) prepare(query string) (*DmStatement, error) { + err := dc.checkClosed() + if err != nil { + return nil, err + } + + stmt, err := NewDmStmt(dc, query) + if err != nil { + return nil, err + } + + err = stmt.prepare() + return stmt, err +} + +func (dc *DmConnection) prepareContext(ctx context.Context, query string) (*DmStatement, error) { + if err := dc.watchCancel(ctx); err != nil { + return nil, err + } + defer dc.finish() + + err := dc.checkClosed() + if err != nil { + return nil, err + } + + stmt, err := dc.prepare(query) + if err != nil { + return nil, err + } + + return stmt, nil +} + +func (dc *DmConnection) resetSession(ctx context.Context) error { + err := dc.checkClosed() + if err != nil { + return err + } + + for _, stmt := range dc.stmtMap { + stmt.inUse = false + } + + return nil +} + +func (dc *DmConnection) checkNamedValue(nv *driver.NamedValue) error { + var err error + var cvt = converter{dc, false} + nv.Value, err = cvt.ConvertValue(nv.Value) + dc.isBatch = cvt.isBatch + return err +} + +func (dc *DmConnection) driverQuery(query string) (*DmStatement, *DmRows, error) { + stmt, err := NewDmStmt(dc, query) + if err != nil { + return nil, nil, err + } + stmt.innerUsed = true + stmt.innerExec = true + info, err := dc.Access.Dm_build_417(stmt, Dm_build_686) + if err != nil { + return nil, nil, err + } + dc.lastExecInfo = info + stmt.innerExec = false + return stmt, newDmRows(newInnerRows(0, stmt, info)), nil +} + +func (dc *DmConnection) getIndexOnEPGroup() int32 { + if dc.dmConnector.group == nil || dc.dmConnector.group.epList == nil { + return -1 + } + for i := 0; i < len(dc.dmConnector.group.epList); i++ { + ep := dc.dmConnector.group.epList[i] + if dc.dmConnector.host == ep.host && dc.dmConnector.port == ep.port { + return int32(i) + } + } + return -1 +} + +func (dc *DmConnection) getServerEncoding() string { + if dc.dmConnector.charCode != "" { + return dc.dmConnector.charCode + } + return dc.serverEncoding +} + +func (dc *DmConnection) lobFetchAll() bool { + return dc.dmConnector.lobMode == 2 +} + +func (conn *DmConnection) CompatibleOracle() bool { + return conn.dmConnector.compatibleMode == COMPATIBLE_MODE_ORACLE +} + +func (conn *DmConnection) CompatibleMysql() bool { + return conn.dmConnector.compatibleMode == COMPATIBLE_MODE_MYSQL +} + +func (conn *DmConnection) cancel(err error) { + conn.canceled.Set(err) + fmt.Println(conn.close()) +} + +func (conn *DmConnection) finish() { + if !conn.watching || conn.finished == nil { + return + } + select { + case conn.finished <- struct{}{}: + conn.watching = false + case <-conn.closech: + } +} + +func (conn *DmConnection) startWatcher() { + watcher := make(chan context.Context, 1) + conn.watcher = watcher + finished := make(chan struct{}) + conn.finished = finished + go func() { + for { + var ctx context.Context + select { + case ctx = <-watcher: + case <-conn.closech: + return + } + + select { + case <-ctx.Done(): + conn.cancel(ctx.Err()) + case <-finished: + case <-conn.closech: + return + } + } + }() +} + +func (conn *DmConnection) watchCancel(ctx context.Context) error { + if conn.watching { + + conn.cleanup() + return nil + } + + if err := ctx.Err(); err != nil { + return err + } + + if ctx.Done() == nil { + return nil + } + + if conn.watcher == nil { + return nil + } + + conn.watching = true + conn.watcher <- ctx + return nil +} + +type noCopy struct{} + +func (*noCopy) Lock() {} + +type atomicBool struct { + _noCopy noCopy + value uint32 +} + +func (ab *atomicBool) IsSet() bool { + return atomic.LoadUint32(&ab.value) > 0 +} + +func (ab *atomicBool) Set(value bool) { + if value { + atomic.StoreUint32(&ab.value, 1) + } else { + atomic.StoreUint32(&ab.value, 0) + } +} + +func (ab *atomicBool) TrySet(value bool) bool { + if value { + return atomic.SwapUint32(&ab.value, 1) == 0 + } + return atomic.SwapUint32(&ab.value, 0) > 0 +} + +type atomicError struct { + _noCopy noCopy + value atomic.Value +} + +func (ae *atomicError) Set(value error) { + ae.value.Store(value) +} + +func (ae *atomicError) Value() error { + if v := ae.value.Load(); v != nil { + + return v.(error) + } + return nil +} diff --git a/dmr/n.go b/dmr/n.go new file mode 100644 index 0000000..8c329b7 --- /dev/null +++ b/dmr/n.go @@ -0,0 +1,897 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "bytes" + "context" + "database/sql/driver" + "net" + "net/url" + "os" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +const ( + TimeZoneKey = "timeZone" + EnRsCacheKey = "enRsCache" + RsCacheSizeKey = "rsCacheSize" + RsRefreshFreqKey = "rsRefreshFreq" + LoginPrimary = "loginPrimary" + LoginModeKey = "loginMode" + LoginStatusKey = "loginStatus" + LoginDscCtrlKey = "loginDscCtrl" + SwitchTimesKey = "switchTimes" + SwitchIntervalKey = "switchInterval" + EpSelectorKey = "epSelector" + PrimaryKey = "primaryKey" + KeywordsKey = "keywords" + CompressKey = "compress" + CompressIdKey = "compressId" + LoginEncryptKey = "loginEncrypt" + CommunicationEncryptKey = "communicationEncrypt" + DirectKey = "direct" + Dec2DoubleKey = "dec2double" + RwSeparateKey = "rwSeparate" + RwPercentKey = "rwPercent" + RwAutoDistributeKey = "rwAutoDistribute" + CompatibleModeKey = "compatibleMode" + CompatibleOraKey = "comOra" + CipherPathKey = "cipherPath" + DoSwitchKey = "doSwitch" + ClusterKey = "cluster" + LanguageKey = "language" + DbAliveCheckFreqKey = "dbAliveCheckFreq" + RwStandbyRecoverTimeKey = "rwStandbyRecoverTime" + LogLevelKey = "logLevel" + LogDirKey = "logDir" + LogBufferPoolSizeKey = "logBufferPoolSize" + LogBufferSizeKey = "logBufferSize" + LogFlusherQueueSizeKey = "logFlusherQueueSize" + LogFlushFreqKey = "logFlushFreq" + StatEnableKey = "statEnable" + StatDirKey = "statDir" + StatFlushFreqKey = "statFlushFreq" + StatHighFreqSqlCountKey = "statHighFreqSqlCount" + StatSlowSqlCountKey = "statSlowSqlCount" + StatSqlMaxCountKey = "statSqlMaxCount" + StatSqlRemoveModeKey = "statSqlRemoveMode" + AddressRemapKey = "addressRemap" + UserRemapKey = "userRemap" + ConnectTimeoutKey = "connectTimeout" + LoginCertificateKey = "loginCertificate" + UrlKey = "url" + HostKey = "host" + PortKey = "port" + UserKey = "user" + PasswordKey = "password" + RwStandbyKey = "rwStandby" + IsCompressKey = "isCompress" + RwHAKey = "rwHA" + RwIgnoreSqlKey = "rwIgnoreSql" + AppNameKey = "appName" + OsNameKey = "osName" + MppLocalKey = "mppLocal" + SocketTimeoutKey = "socketTimeout" + SessionTimeoutKey = "sessionTimeout" + ContinueBatchOnErrorKey = "continueBatchOnError" + BatchAllowMaxErrorsKey = "batchAllowMaxErrors" + EscapeProcessKey = "escapeProcess" + AutoCommitKey = "autoCommit" + MaxRowsKey = "maxRows" + RowPrefetchKey = "rowPrefetch" + BufPrefetchKey = "bufPrefetch" + LobModeKey = "LobMode" + StmtPoolSizeKey = "StmtPoolSize" + IgnoreCaseKey = "ignoreCase" + AlwayseAllowCommitKey = "AlwayseAllowCommit" + BatchTypeKey = "batchType" + BatchNotOnCallKey = "batchNotOnCall" + IsBdtaRSKey = "isBdtaRS" + ClobAsStringKey = "clobAsString" + SslCertPathKey = "sslCertPath" + SslKeyPathKey = "sslKeyPath" + SslFilesPathKey = "sslFilesPath" + KerberosLoginConfPathKey = "kerberosLoginConfPath" + UKeyNameKey = "uKeyName" + UKeyPinKey = "uKeyPin" + ColumnNameUpperCaseKey = "columnNameUpperCase" + ColumnNameCaseKey = "columnNameCase" + DatabaseProductNameKey = "databaseProductName" + OsAuthTypeKey = "osAuthType" + SchemaKey = "schema" + + TIME_ZONE_DEFAULT int16 = 480 + + DO_SWITCH_OFF int32 = 0 + DO_SWITCH_WHEN_CONN_ERROR int32 = 1 + DO_SWITCH_WHEN_EP_RECOVER int32 = 2 + + CLUSTER_TYPE_NORMAL int32 = 0 + CLUSTER_TYPE_RW int32 = 1 + CLUSTER_TYPE_DW int32 = 2 + CLUSTER_TYPE_DSC int32 = 3 + CLUSTER_TYPE_MPP int32 = 4 + + EP_STATUS_OK int32 = 1 + EP_STATUS_ERROR int32 = 2 + + LOGIN_MODE_PRIMARY_FIRST int32 = 0 + + LOGIN_MODE_PRIMARY_ONLY int32 = 1 + + LOGIN_MODE_STANDBY_ONLY int32 = 2 + + LOGIN_MODE_STANDBY_FIRST int32 = 3 + + LOGIN_MODE_NORMAL_FIRST int32 = 4 + + SERVER_MODE_NORMAL int32 = 0 + + SERVER_MODE_PRIMARY int32 = 1 + + SERVER_MODE_STANDBY int32 = 2 + + SERVER_STATUS_MOUNT int32 = 3 + + SERVER_STATUS_OPEN int32 = 4 + + SERVER_STATUS_SUSPEND int32 = 5 + + COMPATIBLE_MODE_ORACLE int = 1 + + COMPATIBLE_MODE_MYSQL int = 2 + + LANGUAGE_CN int = 0 + + LANGUAGE_EN int = 1 + + COLUMN_NAME_NATURAL_CASE = 0 + + COLUMN_NAME_UPPER_CASE = 1 + + COLUMN_NAME_LOWER_CASE = 2 + + compressDef = Dm_build_681 + compressIDDef = Dm_build_682 + + charCodeDef = "" + + enRsCacheDef = false + + rsCacheSizeDef = 20 + + rsRefreshFreqDef = 10 + + loginModeDef = LOGIN_MODE_NORMAL_FIRST + + loginStatusDef = 0 + + loginEncryptDef = true + + loginCertificateDef = "" + + dec2DoubleDef = false + + rwHADef = false + + rwStandbyDef = false + + rwSeparateDef = false + + rwPercentDef = 25 + + rwAutoDistributeDef = true + + rwStandbyRecoverTimeDef = 1000 + + cipherPathDef = "" + + urlDef = "" + + userDef = "SYSDBA" + + passwordDef = "SYSDBA" + + hostDef = "localhost" + + portDef = DEFAULT_PORT + + appNameDef = "" + + mppLocalDef = false + + socketTimeoutDef = 0 + + connectTimeoutDef = 5000 + + sessionTimeoutDef = 0 + + osAuthTypeDef = Dm_build_664 + + continueBatchOnErrorDef = false + + escapeProcessDef = false + + autoCommitDef = true + + maxRowsDef = 0 + + rowPrefetchDef = Dm_build_665 + + bufPrefetchDef = 0 + + lobModeDef = 1 + + stmtPoolMaxSizeDef = 15 + + ignoreCaseDef = true + + alwayseAllowCommitDef = true + + isBdtaRSDef = false + + kerberosLoginConfPathDef = "" + + uKeyNameDef = "" + + uKeyPinDef = "" + + databaseProductNameDef = "" + + caseSensitiveDef = true + + compatibleModeDef = 0 + + localTimezoneDef = TIME_ZONE_DEFAULT +) + +type DmConnector struct { + filterable + + dmDriver *DmDriver + + compress int + + compressID int8 + + newClientType bool + + charCode string + + enRsCache bool + + rsCacheSize int + + rsRefreshFreq int + + loginMode int32 + + loginStatus int + + loginDscCtrl bool + + switchTimes int32 + + switchInterval int + + epSelector int32 + + keyWords []string + + loginEncrypt bool + + loginCertificate string + + dec2Double bool + + rwHA bool + + rwStandby bool + + rwSeparate bool + + rwPercent int32 + + rwAutoDistribute bool + + rwStandbyRecoverTime int + + rwIgnoreSql bool + + doSwitch int32 + + cluster int32 + + cipherPath string + + url string + + user string + + password string + + host string + + group *epGroup + + port int32 + + appName string + + osName string + + mppLocal bool + + socketTimeout int + + connectTimeout int + + sessionTimeout int + + osAuthType byte + + continueBatchOnError bool + + batchAllowMaxErrors int32 + + escapeProcess bool + + autoCommit bool + + maxRows int + + rowPrefetch int + + bufPrefetch int + + lobMode int + + stmtPoolMaxSize int + + ignoreCase bool + + alwayseAllowCommit bool + + batchType int + + batchNotOnCall bool + + isBdtaRS bool + + sslCertPath string + + sslKeyPath string + + sslFilesPath string + + kerberosLoginConfPath string + + uKeyName string + + uKeyPin string + + svcConfPath string + + columnNameCase int + + caseSensitive bool + + compatibleMode int + + localTimezone int16 + + schema string + + reConnection *DmConnection + + logLevel int + + logDir string + + logFlushFreq int + + logFlushQueueSize int + + logBufferSize int + + statEnable bool + + statDir string + + statFlushFreq int + + statSlowSqlCount int + + statHighFreqSqlCount int + + statSqlMaxCount int + + statSqlRemoveMode int +} + +func (c *DmConnector) init() *DmConnector { + c.compress = compressDef + c.compressID = compressIDDef + c.charCode = charCodeDef + c.enRsCache = enRsCacheDef + c.rsCacheSize = rsCacheSizeDef + c.rsRefreshFreq = rsRefreshFreqDef + c.loginMode = loginModeDef + c.loginStatus = loginStatusDef + c.loginDscCtrl = false + c.switchTimes = 1 + c.switchInterval = 1000 + c.epSelector = 0 + c.keyWords = nil + c.loginEncrypt = loginEncryptDef + c.loginCertificate = loginCertificateDef + c.dec2Double = dec2DoubleDef + c.rwHA = rwHADef + c.rwStandby = rwStandbyDef + c.rwSeparate = rwSeparateDef + c.rwPercent = rwPercentDef + c.rwAutoDistribute = rwAutoDistributeDef + c.rwStandbyRecoverTime = rwStandbyRecoverTimeDef + c.rwIgnoreSql = false + c.doSwitch = DO_SWITCH_OFF + c.cluster = CLUSTER_TYPE_NORMAL + c.cipherPath = cipherPathDef + c.url = urlDef + c.user = userDef + c.password = passwordDef + c.host = hostDef + c.port = portDef + c.appName = appNameDef + c.osName = runtime.GOOS + c.mppLocal = mppLocalDef + c.socketTimeout = socketTimeoutDef + c.connectTimeout = connectTimeoutDef + c.sessionTimeout = sessionTimeoutDef + c.osAuthType = osAuthTypeDef + c.continueBatchOnError = continueBatchOnErrorDef + c.batchAllowMaxErrors = 0 + c.escapeProcess = escapeProcessDef + c.autoCommit = autoCommitDef + c.maxRows = maxRowsDef + c.rowPrefetch = rowPrefetchDef + c.bufPrefetch = bufPrefetchDef + c.lobMode = lobModeDef + c.stmtPoolMaxSize = stmtPoolMaxSizeDef + c.ignoreCase = ignoreCaseDef + c.alwayseAllowCommit = alwayseAllowCommitDef + c.batchType = 1 + c.batchNotOnCall = false + c.isBdtaRS = isBdtaRSDef + c.kerberosLoginConfPath = kerberosLoginConfPathDef + c.uKeyName = uKeyNameDef + c.uKeyPin = uKeyPinDef + c.columnNameCase = COLUMN_NAME_NATURAL_CASE + c.caseSensitive = caseSensitiveDef + c.compatibleMode = compatibleModeDef + c.localTimezone = localTimezoneDef + c.idGenerator = dmConntorIDGenerator + + c.logDir = LogDirDef + c.logFlushFreq = LogFlushFreqDef + c.logFlushQueueSize = LogFlushQueueSizeDef + c.logBufferSize = LogBufferSizeDef + c.statEnable = StatEnableDef + c.statDir = StatDirDef + c.statFlushFreq = StatFlushFreqDef + c.statSlowSqlCount = StatSlowSqlCountDef + c.statHighFreqSqlCount = StatHighFreqSqlCountDef + c.statSqlMaxCount = StatSqlMaxCountDef + c.statSqlRemoveMode = StatSqlRemoveModeDef + return c +} + +func (c *DmConnector) setAttributes(props *Properties) error { + if props == nil || props.Len() == 0 { + return nil + } + + c.url = props.GetTrimString(UrlKey, c.url) + c.host = props.GetTrimString(HostKey, c.host) + c.port = int32(props.GetInt(PortKey, int(c.port), 0, 65535)) + c.user = props.GetString(UserKey, c.user) + c.password = props.GetString(PasswordKey, c.password) + c.rwStandby = props.GetBool(RwStandbyKey, c.rwStandby) + + if b := props.GetBool(IsCompressKey, false); b { + c.compress = Dm_build_680 + } + + c.compress = props.GetInt(CompressKey, c.compress, 0, 2) + c.compressID = int8(props.GetInt(CompressIdKey, int(c.compressID), 0, 1)) + c.enRsCache = props.GetBool(EnRsCacheKey, c.enRsCache) + c.localTimezone = int16(props.GetInt(TimeZoneKey, int(c.localTimezone), -720, 720)) + c.rsCacheSize = props.GetInt(RsCacheSizeKey, c.rsCacheSize, 0, int(INT32_MAX)) + c.rsRefreshFreq = props.GetInt(RsRefreshFreqKey, c.rsRefreshFreq, 0, int(INT32_MAX)) + c.loginMode = int32(props.GetInt(LoginModeKey, int(c.loginMode), 0, 4)) + c.loginStatus = props.GetInt(LoginStatusKey, c.loginStatus, 0, int(INT32_MAX)) + c.loginDscCtrl = props.GetBool(LoginDscCtrlKey, c.loginDscCtrl) + c.switchTimes = int32(props.GetInt(SwitchTimesKey, int(c.switchTimes), 0, int(INT32_MAX))) + c.switchInterval = props.GetInt(SwitchIntervalKey, c.switchInterval, 0, int(INT32_MAX)) + c.epSelector = int32(props.GetInt(EpSelectorKey, int(c.epSelector), 0, 1)) + c.loginEncrypt = props.GetBool(LoginEncryptKey, c.loginEncrypt) + c.loginCertificate = props.GetTrimString(LoginCertificateKey, c.loginCertificate) + c.dec2Double = props.GetBool(Dec2DoubleKey, c.dec2Double) + + c.rwSeparate = props.GetBool(RwSeparateKey, c.rwSeparate) + c.rwAutoDistribute = props.GetBool(RwAutoDistributeKey, c.rwAutoDistribute) + c.rwPercent = int32(props.GetInt(RwPercentKey, int(c.rwPercent), 0, 100)) + c.rwHA = props.GetBool(RwHAKey, c.rwHA) + c.rwStandbyRecoverTime = props.GetInt(RwStandbyRecoverTimeKey, c.rwStandbyRecoverTime, 0, int(INT32_MAX)) + c.rwIgnoreSql = props.GetBool(RwIgnoreSqlKey, c.rwIgnoreSql) + c.doSwitch = int32(props.GetInt(DoSwitchKey, int(c.doSwitch), 0, 2)) + c.parseCluster(props) + c.cipherPath = props.GetTrimString(CipherPathKey, c.cipherPath) + + if props.GetBool(CompatibleOraKey, false) { + c.compatibleMode = int(COMPATIBLE_MODE_ORACLE) + } + c.parseCompatibleMode(props) + c.keyWords = props.GetStringArray(KeywordsKey, c.keyWords) + + c.appName = props.GetTrimString(AppNameKey, c.appName) + c.osName = props.GetTrimString(OsNameKey, c.osName) + c.mppLocal = props.GetBool(MppLocalKey, c.mppLocal) + c.socketTimeout = props.GetInt(SocketTimeoutKey, c.socketTimeout, 0, int(INT32_MAX)) + c.connectTimeout = props.GetInt(ConnectTimeoutKey, c.connectTimeout, 0, int(INT32_MAX)) + c.sessionTimeout = props.GetInt(SessionTimeoutKey, c.sessionTimeout, 0, int(INT32_MAX)) + + err := c.parseOsAuthType(props) + if err != nil { + return err + } + c.continueBatchOnError = props.GetBool(ContinueBatchOnErrorKey, c.continueBatchOnError) + c.batchAllowMaxErrors = int32(props.GetInt(BatchAllowMaxErrorsKey, int(c.batchAllowMaxErrors), 0, int(INT32_MAX))) + c.escapeProcess = props.GetBool(EscapeProcessKey, c.escapeProcess) + c.autoCommit = props.GetBool(AutoCommitKey, c.autoCommit) + c.maxRows = props.GetInt(MaxRowsKey, c.maxRows, 0, int(INT32_MAX)) + c.rowPrefetch = props.GetInt(RowPrefetchKey, c.rowPrefetch, 0, int(INT32_MAX)) + c.bufPrefetch = props.GetInt(BufPrefetchKey, c.bufPrefetch, int(Dm_build_666), int(Dm_build_667)) + c.lobMode = props.GetInt(LobModeKey, c.lobMode, 1, 2) + c.stmtPoolMaxSize = props.GetInt(StmtPoolSizeKey, c.stmtPoolMaxSize, 0, int(INT32_MAX)) + c.ignoreCase = props.GetBool(IgnoreCaseKey, c.ignoreCase) + c.alwayseAllowCommit = props.GetBool(AlwayseAllowCommitKey, c.alwayseAllowCommit) + c.batchType = props.GetInt(BatchTypeKey, c.batchType, 1, 2) + c.batchNotOnCall = props.GetBool(BatchNotOnCallKey, c.batchNotOnCall) + c.isBdtaRS = props.GetBool(IsBdtaRSKey, c.isBdtaRS) + c.sslFilesPath = props.GetTrimString(SslFilesPathKey, c.sslFilesPath) + c.sslCertPath = props.GetTrimString(SslCertPathKey, c.sslCertPath) + if c.sslCertPath == "" && c.sslFilesPath != "" { + c.sslCertPath = filepath.Join(c.sslFilesPath, "client-cert.pem") + } + c.sslKeyPath = props.GetTrimString(SslKeyPathKey, c.sslKeyPath) + if c.sslKeyPath == "" && c.sslFilesPath != "" { + c.sslKeyPath = filepath.Join(c.sslKeyPath, "client-key.pem") + } + + c.kerberosLoginConfPath = props.GetTrimString(KerberosLoginConfPathKey, c.kerberosLoginConfPath) + + c.uKeyName = props.GetTrimString(UKeyNameKey, c.uKeyName) + c.uKeyPin = props.GetTrimString(UKeyPinKey, c.uKeyPin) + + c.svcConfPath = props.GetString("confPath", "") + + if props.GetBool(ColumnNameUpperCaseKey, false) { + c.columnNameCase = COLUMN_NAME_UPPER_CASE + } + + v := props.GetTrimString(ColumnNameCaseKey, "") + if util.StringUtil.EqualsIgnoreCase(v, "upper") { + c.columnNameCase = COLUMN_NAME_UPPER_CASE + } else if util.StringUtil.EqualsIgnoreCase(v, "lower") { + c.columnNameCase = COLUMN_NAME_LOWER_CASE + } + + c.schema = props.GetTrimString(SchemaKey, c.schema) + + c.logLevel = ParseLogLevel(props) + LogLevel = c.logLevel + c.logDir = util.StringUtil.FormatDir(props.GetTrimString(LogDirKey, LogDirDef)) + LogDir = c.logDir + c.logBufferSize = props.GetInt(LogBufferSizeKey, LogBufferSizeDef, 1, int(INT32_MAX)) + LogBufferSize = c.logBufferSize + c.logFlushFreq = props.GetInt(LogFlushFreqKey, LogFlushFreqDef, 1, int(INT32_MAX)) + LogFlushFreq = c.logFlushFreq + c.logFlushQueueSize = props.GetInt(LogFlusherQueueSizeKey, LogFlushQueueSizeDef, 1, int(INT32_MAX)) + LogFlushQueueSize = c.logFlushQueueSize + + c.statEnable = props.GetBool(StatEnableKey, StatEnableDef) + StatEnable = c.statEnable + c.statDir = util.StringUtil.FormatDir(props.GetTrimString(StatDirKey, StatDirDef)) + StatDir = c.statDir + c.statFlushFreq = props.GetInt(StatFlushFreqKey, StatFlushFreqDef, 1, int(INT32_MAX)) + StatFlushFreq = c.statFlushFreq + c.statHighFreqSqlCount = props.GetInt(StatHighFreqSqlCountKey, StatHighFreqSqlCountDef, 0, 1000) + StatHighFreqSqlCount = c.statHighFreqSqlCount + c.statSlowSqlCount = props.GetInt(StatSlowSqlCountKey, StatSlowSqlCountDef, 0, 1000) + StatSlowSqlCount = c.statSlowSqlCount + c.statSqlMaxCount = props.GetInt(StatSqlMaxCountKey, StatSqlMaxCountDef, 0, 100000) + StatSqlMaxCount = c.statSqlMaxCount + c.parseStatSqlRemoveMode(props) + return nil +} + +func (c *DmConnector) parseOsAuthType(props *Properties) error { + value := props.GetString(OsAuthTypeKey, "") + if value != "" && !util.StringUtil.IsDigit(value) { + if util.StringUtil.EqualsIgnoreCase(value, "ON") { + c.osAuthType = Dm_build_664 + } else if util.StringUtil.EqualsIgnoreCase(value, "SYSDBA") { + c.osAuthType = Dm_build_660 + } else if util.StringUtil.EqualsIgnoreCase(value, "SYSAUDITOR") { + c.osAuthType = Dm_build_662 + } else if util.StringUtil.EqualsIgnoreCase(value, "SYSSSO") { + c.osAuthType = Dm_build_661 + } else if util.StringUtil.EqualsIgnoreCase(value, "AUTO") { + c.osAuthType = Dm_build_663 + } else if util.StringUtil.EqualsIgnoreCase(value, "OFF") { + c.osAuthType = Dm_build_659 + } + } else { + c.osAuthType = byte(props.GetInt(OsAuthTypeKey, int(c.osAuthType), 0, 4)) + } + if c.user == "" && c.osAuthType == Dm_build_659 { + c.user = "SYSDBA" + } else if c.osAuthType != Dm_build_659 && c.user != "" { + return ECGO_OSAUTH_ERROR.throw() + } else if c.osAuthType != Dm_build_659 { + c.user = os.Getenv("user") + c.password = "" + } + return nil +} + +func (c *DmConnector) parseCompatibleMode(props *Properties) { + value := props.GetString(CompatibleModeKey, "") + if value != "" && !util.StringUtil.IsDigit(value) { + if util.StringUtil.EqualsIgnoreCase(value, "oracle") { + c.compatibleMode = COMPATIBLE_MODE_ORACLE + } else if util.StringUtil.EqualsIgnoreCase(value, "mysql") { + c.compatibleMode = COMPATIBLE_MODE_MYSQL + } + } else { + c.compatibleMode = props.GetInt(CompatibleModeKey, c.compatibleMode, 0, 2) + } +} + +func (c *DmConnector) parseStatSqlRemoveMode(props *Properties) { + value := props.GetString(StatSqlRemoveModeKey, "") + if value != "" && !util.StringUtil.IsDigit(value) { + if util.StringUtil.EqualsIgnoreCase("oldest", value) || util.StringUtil.EqualsIgnoreCase("eldest", value) { + c.statSqlRemoveMode = STAT_SQL_REMOVE_OLDEST + } else if util.StringUtil.EqualsIgnoreCase("latest", value) { + c.statSqlRemoveMode = STAT_SQL_REMOVE_LATEST + } + } else { + c.statSqlRemoveMode = props.GetInt(StatSqlRemoveModeKey, StatSqlRemoveModeDef, 1, 2) + } +} + +func (c *DmConnector) parseCluster(props *Properties) { + value := props.GetTrimString(ClusterKey, "") + if util.StringUtil.EqualsIgnoreCase(value, "DSC") { + c.cluster = CLUSTER_TYPE_DSC + } else if util.StringUtil.EqualsIgnoreCase(value, "RW") { + c.cluster = CLUSTER_TYPE_RW + } else if util.StringUtil.EqualsIgnoreCase(value, "DW") { + c.cluster = CLUSTER_TYPE_DW + } else if util.StringUtil.EqualsIgnoreCase(value, "MPP") { + c.cluster = CLUSTER_TYPE_MPP + } else { + c.cluster = CLUSTER_TYPE_NORMAL + } +} + +func (c *DmConnector) parseDSN(dsn string) (*Properties, string, error) { + var dsnProps = NewProperties() + url, err := url.Parse(dsn) + if err != nil { + return nil, "", err + } + if url.Scheme != "dm" { + return nil, "", DSN_INVALID_SCHEMA + } + + if url.User != nil { + c.user = url.User.Username() + c.password, _ = url.User.Password() + } + + q := url.Query() + for k := range q { + dsnProps.Set(k, q.Get(k)) + } + + return dsnProps, url.Host, nil +} + +func (c *DmConnector) BuildDSN() string { + var buf bytes.Buffer + + buf.WriteString("dm://") + + if len(c.user) > 0 { + buf.WriteString(url.QueryEscape(c.user)) + if len(c.password) > 0 { + buf.WriteByte(':') + buf.WriteString(url.QueryEscape(c.password)) + } + buf.WriteByte('@') + } + + if len(c.host) > 0 { + buf.WriteString(c.host) + if c.port > 0 { + buf.WriteByte(':') + buf.WriteString(strconv.Itoa(int(c.port))) + } + } + + hasParam := false + if c.connectTimeout > 0 { + if hasParam { + buf.WriteString("&timeout=") + } else { + buf.WriteString("?timeout=") + hasParam = true + } + buf.WriteString(strconv.Itoa(c.connectTimeout)) + } + return buf.String() +} + +func (c *DmConnector) mergeConfigs(dsn string) error { + props, host, err := c.parseDSN(dsn) + if err != nil { + return err + } + + driverInit(props.GetString("svcConfPath", "")) + + addressRemapStr := props.GetTrimString(AddressRemapKey, "") + userRemapStr := props.GetTrimString(UserRemapKey, "") + if addressRemapStr == "" { + addressRemapStr = GlobalProperties.GetTrimString(AddressRemapKey, "") + } + if userRemapStr == "" { + userRemapStr = GlobalProperties.GetTrimString(UserRemapKey, "") + } + + host = c.remap(host, addressRemapStr) + + c.user = c.remap(c.user, userRemapStr) + + if group, ok := ServerGroupMap[strings.ToLower(host)]; ok { + c.group = group + } else { + host, port, err := net.SplitHostPort(host) + if err != nil || net.ParseIP(host) == nil { + c.host = hostDef + } else { + c.host = host + } + tmpPort, err := strconv.Atoi(port) + if err != nil { + c.port = portDef + } else { + c.port = int32(tmpPort) + } + + c.group = newEPGroup(c.host+":"+strconv.Itoa(int(c.port)), []*ep{newEP(c.host, c.port)}) + } + + props.SetDiffProperties(c.group.props) + + props.SetDiffProperties(GlobalProperties) + + if props.GetBool(RwSeparateKey, false) { + props.SetIfNotExist(LoginModeKey, strconv.Itoa(int(LOGIN_MODE_PRIMARY_ONLY))) + props.SetIfNotExist(LoginStatusKey, strconv.Itoa(int(SERVER_STATUS_OPEN))) + + props.SetIfNotExist(DoSwitchKey, "true") + } + + if err = c.setAttributes(props); err != nil { + return err + } + return nil +} + +func (c *DmConnector) remap(origin string, cfgStr string) string { + if cfgStr == "" || origin == "" { + return origin + } + + maps := regexp.MustCompile("\\(.*?,.*?\\)").FindAllString(cfgStr, -1) + for _, kvStr := range maps { + kv := strings.Split(strings.TrimSpace(kvStr[1:len(kvStr)-1]), ",") + if util.StringUtil.Equals(strings.TrimSpace(kv[0]), origin) { + return strings.TrimSpace(kv[1]) + } + } + return origin +} + +func (c *DmConnector) Connect(ctx context.Context) (driver.Conn, error) { + return c.filterChain.reset().DmConnectorConnect(c, ctx) +} + +func (c *DmConnector) Driver() driver.Driver { + return c.filterChain.reset().DmConnectorDriver(c) +} + +func (c *DmConnector) connect(ctx context.Context) (*DmConnection, error) { + if c.group != nil && len(c.group.epList) > 0 { + return c.group.connect(c) + } else { + return c.connectSingle(ctx) + } +} + +func (c *DmConnector) driver() *DmDriver { + return c.dmDriver +} + +func (c *DmConnector) connectSingle(ctx context.Context) (*DmConnection, error) { + var err error + var dc *DmConnection + if c.reConnection == nil { + dc = &DmConnection{ + closech: make(chan struct{}), + } + dc.dmConnector = c + dc.autoCommit = c.autoCommit + dc.createFilterChain(c, nil) + + dc.objId = -1 + dc.init() + } else { + dc = c.reConnection + dc.reset() + } + + dc.Access, err = dm_build_344(dc) + if err != nil { + return nil, err + } + + dc.startWatcher() + if err = dc.watchCancel(ctx); err != nil { + return nil, err + } + defer dc.finish() + + if err = dc.Access.dm_build_385(); err != nil { + + if !dc.closed.IsSet() { + close(dc.closech) + if dc.Access != nil { + dc.Access.Close() + } + dc.closed.Set(true) + } + return nil, err + } + + if c.schema != "" { + _, err = dc.exec("set schema "+c.schema, nil) + if err != nil { + return nil, err + } + } + + return dc, nil +} diff --git a/dmr/o.go b/dmr/o.go new file mode 100644 index 0000000..627a56a --- /dev/null +++ b/dmr/o.go @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "database/sql/driver" + "math/big" + "reflect" + "strconv" + "strings" +) + +const ( + XDEC_MAX_PREC int = 38 + XDEC_SIZE = 21 + + FLAG_ZERO int = 0x80 + FLAG_POSITIVE int = 0xC1 + FLAG_NEGTIVE int = 0x3E + EXP_MAX int = 0xFF - 1 - FLAG_POSITIVE + EXP_MIN int = FLAG_NEGTIVE + 1 - 0x7F + + NUM_POSITIVE int = 1 + NUM_NEGTIVE int = 101 +) + +type DmDecimal struct { + sign int + weight int + prec int + scale int + digits string + + Valid bool +} + +func NewDecimalFromInt64(x int64) (*DmDecimal, error) { + return NewDecimalFromBigInt(big.NewInt(x)) +} + +func (d DmDecimal) ToInt64() int64 { + return d.ToBigInt().Int64() +} + +func NewDecimalFromFloat64(x float64) (*DmDecimal, error) { + return NewDecimalFromBigFloat(big.NewFloat(x)) +} + +func (d DmDecimal) ToFloat64() float64 { + f, _ := d.ToBigFloat().Float64() + return f +} + +func NewDecimalFromBigInt(bigInt *big.Int) (*DmDecimal, error) { + return newDecimal(bigInt, len(bigInt.String()), 0) +} + +func (d DmDecimal) ToBigInt() *big.Int { + if d.isZero() { + return big.NewInt(0) + } + var digits = d.digits + if d.sign < 0 { + digits = "-" + digits + } + i1, ok := new(big.Int).SetString(digits, 10) + if !ok { + return nil + } + if d.weight > 0 { + i2, ok := new(big.Int).SetString("1"+strings.Repeat("0", d.weight), 10) + if !ok { + return nil + } + i1.Mul(i1, i2) + } else if d.weight < 0 { + i2, ok := new(big.Int).SetString("1"+strings.Repeat("0", -d.weight), 10) + if !ok { + return nil + } + i1.Quo(i1, i2) + } + return i1 +} + +func NewDecimalFromBigFloat(bigFloat *big.Float) (*DmDecimal, error) { + return newDecimal(bigFloat, int(bigFloat.Prec()), int(bigFloat.Prec())) +} + +func (d DmDecimal) ToBigFloat() *big.Float { + if d.isZero() { + return big.NewFloat(0.0) + } + var digits = d.digits + if d.sign < 0 { + digits = "-" + digits + } + f1, ok := new(big.Float).SetString(digits) + if !ok { + return nil + } + if d.weight > 0 { + f2, ok := new(big.Float).SetString("1" + strings.Repeat("0", d.weight)) + if !ok { + return nil + } + f1.Mul(f1, f2) + } else if d.weight < 0 { + f2, ok := new(big.Float).SetString("1" + strings.Repeat("0", -d.weight)) + if !ok { + return nil + } + f1.Quo(f1, f2) + } + return f1 +} + +func NewDecimalFromString(s string) (*DmDecimal, error) { + num, ok := new(big.Float).SetString(strings.TrimSpace(s)) + if !ok { + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return NewDecimalFromBigFloat(num) +} + +func (d DmDecimal) String() string { + + if d.isZero() { + return "0" + } + digitsStr := d.digits + if d.weight > 0 { + digitsStr = digitsStr + strings.Repeat("0", d.weight) + } else if d.weight < 0 { + if len(digitsStr) < -d.weight { + digitsStr = strings.Repeat("0", -d.weight-len(digitsStr)+1) + digitsStr + } + indexOfDot := len(digitsStr) + d.weight + digitsStr = digitsStr[:indexOfDot] + "." + digitsStr[indexOfDot:] + } + + if digitsStr[0] == '0' && digitsStr[1] != '.' { + digitsStr = digitsStr[1:] + } + + if digitsStr[len(digitsStr)-1] == '0' && strings.IndexRune(digitsStr, '.') >= 0 { + digitsStr = digitsStr[0 : len(digitsStr)-1] + } + + if d.sign < 0 { + digitsStr = "-" + digitsStr + } + + return digitsStr +} + +func (d DmDecimal) Sign() int { + return d.sign +} + +func (dest *DmDecimal) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmDecimal) + + (*dest).Valid = false + return nil + case int, int8, int16, int32, int64: + d, err := NewDecimalFromInt64(reflect.ValueOf(src).Int()) + if err != nil { + return err + } + *dest = *d + return nil + case uint, uint8, uint16, uint32, uint64: + d, err := NewDecimalFromBigInt(new(big.Int).SetUint64(reflect.ValueOf(src).Uint())) + if err != nil { + return err + } + *dest = *d + return nil + case string: + d, err := NewDecimalFromString(src) + if err != nil { + return err + } + *dest = *d + return nil + case *DmDecimal: + *dest = *src + return nil + default: + return UNSUPPORTED_SCAN + } +} + +func (d DmDecimal) Value() (driver.Value, error) { + if !d.Valid { + return nil, nil + } + return d, nil +} + +func newDecimal(dec interface{}, prec int, scale int) (*DmDecimal, error) { + d := &DmDecimal{ + prec: prec, + scale: scale, + Valid: true, + } + if isFloat(DECIMAL, scale) { + d.prec = getFloatPrec(prec) + d.scale = -1 + } + switch de := dec.(type) { + case *big.Int: + d.sign = de.Sign() + + if d.isZero() { + return d, nil + } + str := de.String() + + if d.sign < 0 { + str = str[1:] + } + + if err := checkPrec(len(str), prec); err != nil { + return d, err + } + i := 0 + istart := len(str) - 1 + + for i = istart; i > 0; i-- { + if str[i] != '0' { + break + } + } + str = str[:i+1] + d.weight += istart - i + + if isOdd(d.weight) { + str += "0" + d.weight -= 1 + } + if isOdd(len(str)) { + str = "0" + str + } + d.digits = str + case *big.Float: + d.sign = de.Sign() + + if d.isZero() { + return d, nil + } + str := de.Text('f', -1) + + if d.sign < 0 { + str = str[1:] + } + + pointIndex := strings.IndexByte(str, '.') + i, istart, length := 0, 0, len(str) + + if pointIndex != -1 { + if str[0] == '0' { + + istart = 2 + for i = istart; i < length; i++ { + if str[i] != '0' { + break + } + } + str = str[i:] + d.weight -= i - istart + len(str) + } else { + str = str[:pointIndex] + str[pointIndex+1:] + d.weight -= length - pointIndex - 1 + } + } + + length = len(str) + istart = length - 1 + for i = istart; i > 0; i-- { + if str[i] != '0' { + break + } + } + str = str[:i+1] + str[length:] + d.weight += istart - i + + if isOdd(d.weight) { + str += "0" + d.weight -= 1 + } + if isOdd(len(str)) { + str = "0" + str + } + d.digits = str + case []byte: + return decodeDecimal(de, prec, scale) + } + return d, nil +} + +func (d DmDecimal) encodeDecimal() ([]byte, error) { + if d.isZero() { + return []byte{byte(FLAG_ZERO)}, nil + } + exp := (d.weight+len(d.digits))/2 - 1 + if exp > EXP_MAX || exp < EXP_MIN { + return nil, ECGO_DATA_TOO_LONG.throw() + } + validLen := len(d.digits)/2 + 1 + + if d.sign < 0 && validLen >= XDEC_SIZE { + validLen = XDEC_SIZE - 1 + } else if validLen > XDEC_SIZE { + validLen = XDEC_SIZE + } + retLen := validLen + if d.sign < 0 { + retLen = validLen + 1 + } + retBytes := make([]byte, retLen) + if d.sign > 0 { + retBytes[0] = byte(exp + FLAG_POSITIVE) + } else { + retBytes[0] = byte(FLAG_NEGTIVE - exp) + } + + ibytes := 1 + for ichar := 0; ibytes < validLen; { + digit1, err := strconv.Atoi(string(d.digits[ichar])) + if err != nil { + return nil, err + } + ichar++ + digit2, err := strconv.Atoi(string(d.digits[ichar])) + ichar++ + if err != nil { + return nil, err + } + + digit := digit1*10 + digit2 + if d.sign > 0 { + retBytes[ibytes] = byte(digit + NUM_POSITIVE) + } else { + retBytes[ibytes] = byte(NUM_NEGTIVE - digit) + } + ibytes++ + } + if d.sign < 0 && ibytes < retLen { + retBytes[ibytes] = 0x66 + ibytes++ + } + if ibytes < retLen { + retBytes[ibytes] = 0x00 + } + return retBytes, nil +} + +func decodeDecimal(values []byte, prec int, scale int) (*DmDecimal, error) { + var decimal = &DmDecimal{ + prec: prec, + scale: scale, + sign: 0, + weight: 0, + Valid: true, + } + if values == nil || len(values) == 0 || len(values) > XDEC_SIZE { + return nil, ECGO_FATAL_ERROR.throw() + } + if values[0] == byte(FLAG_ZERO) || len(values) == 1 { + return decimal, nil + } + if values[0]&byte(FLAG_ZERO) != 0 { + decimal.sign = 1 + } else { + decimal.sign = -1 + } + + var flag = int(Dm_build_1220.Dm_build_1340(values, 0)) + var exp int + if decimal.sign > 0 { + exp = flag - FLAG_POSITIVE + } else { + exp = FLAG_NEGTIVE - flag + } + var digit = 0 + var sf = "" + for ival := 1; ival < len(values); ival++ { + if decimal.sign > 0 { + digit = int(values[ival]) - NUM_POSITIVE + } else { + digit = NUM_NEGTIVE - int(values[ival]) + } + if digit < 0 || digit > 99 { + break + } + if digit < 10 { + sf += "0" + } + sf += strconv.Itoa(digit) + } + decimal.digits = sf + decimal.weight = exp*2 - (len(decimal.digits) - 2) + + return decimal, nil +} + +func (d DmDecimal) isZero() bool { + return d.sign == 0 +} + +func checkPrec(len int, prec int) error { + if prec > 0 && len > prec || len > XDEC_MAX_PREC { + return ECGO_DATA_TOO_LONG.throw() + } + return nil +} + +func isOdd(val int) bool { + return val%2 != 0 +} + +func (d *DmDecimal) checkValid() error { + if !d.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} diff --git a/dmr/p.go b/dmr/p.go new file mode 100644 index 0000000..3d83be1 --- /dev/null +++ b/dmr/p.go @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "context" + "database/sql" + "database/sql/driver" + "sync" + + "github.com/nfjBill/gorm-driver-dm/dmr/i18n" +) + +// 发版标记 +var version = "8.1.2.94" +var build_date = "2021.11.11" +var svn = "8453" + +var globalDmDriver = newDmDriver() + +func init() { + sql.Register("dm", globalDmDriver) +} + +func driverInit(svcConfPath string) { + load(svcConfPath) + if GlobalProperties != nil && GlobalProperties.Len() > 0 { + setDriverAttributes(GlobalProperties) + } + globalDmDriver.createFilterChain(nil, GlobalProperties) + + switch Locale { + case 0: + i18n.InitConfig(i18n.Messages_zh_CN) + case 1: + i18n.InitConfig(i18n.Messages_en_US) + case 2: + i18n.InitConfig(i18n.Messages_zh_TW) + } +} + +type DmDriver struct { + filterable + readPropMutex sync.Mutex +} + +func newDmDriver() *DmDriver { + d := new(DmDriver) + d.idGenerator = dmDriverIDGenerator + return d +} + +/************************************************************* + ** PUBLIC METHODS AND FUNCTIONS + *************************************************************/ +func (d *DmDriver) Open(dsn string) (driver.Conn, error) { + return d.open(dsn) +} + +func (d *DmDriver) OpenConnector(dsn string) (driver.Connector, error) { + return d.openConnector(dsn) +} + +func (d *DmDriver) open(dsn string) (*DmConnection, error) { + c, err := d.openConnector(dsn) + if err != nil { + return nil, err + } + return c.connect(context.Background()) +} + +func (d *DmDriver) openConnector(dsn string) (*DmConnector, error) { + connector := new(DmConnector).init() + connector.url = dsn + connector.dmDriver = d + d.readPropMutex.Lock() + err := connector.mergeConfigs(dsn) + d.readPropMutex.Unlock() + if err != nil { + return nil, err + } + connector.createFilterChain(connector, nil) + return connector, nil +} diff --git a/dmr/parser/zt.go b/dmr/parser/zt.go new file mode 100644 index 0000000..04963dd --- /dev/null +++ b/dmr/parser/zt.go @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package parser + +import "strconv" + +const ( + MAX_DEC_LEN = 38 +) + +const ( + NORMAL int = iota + INT + DOUBLE + DECIMAL + STRING + HEX_INT + WHITESPACE_OR_COMMENT + NULL +) + +type LVal struct { + Value string + Tp int + Position int +} + +func newLValNoParams() *LVal { + return new(LVal).reset() +} + +func newLVal(value string, tp int) *LVal { + return &LVal{Value: value, Tp: tp} +} + +func (l *LVal) reset() *LVal { + l.Value = "" + l.Tp = NORMAL + return l +} + +func (l *LVal) String() string { + return strconv.Itoa(l.Tp) + ":" + l.Value +} diff --git a/dmr/parser/zu.go b/dmr/parser/zu.go new file mode 100644 index 0000000..f516536 --- /dev/null +++ b/dmr/parser/zu.go @@ -0,0 +1,1206 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package parser + +import ( + "io" + "strconv" + "unicode/utf8" +) + +const ( + YYEOF = -1 /** This character denotes the end of file */ + ZZ_BUFFERSIZE = 16384 /** initial size of the lookahead buffer */ + /** lexical states */ + YYINITIAL = 0 + xc = 2 + xq = 4 + xdq = 6 + xsb = 8 + xbin = 10 + xhex = 12 + xhint = 14 + xq2 = 16 + xq2_2 = 18 +) + +/** +* ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l +* ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l +* at the beginning of a line +* l is of the form l = 2*k, k a non negative integer + */ +var ZZ_LEXSTATE []int = []int{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 4, 4, 7, 7, 8, 8} + +/** +* Translates characters to character classes + */ +var ZZ_CMAP_PACKED []rune = []rune{0011, 0000, 0001, 0026, 0001, 0025, 0001, 0030, 0001, 0026, 0001, 0025, 0022, 0000, 0001, 0026, 0001, 0017, 0001, 0002, + 0002, 0012, 0002, 0017, 0001, 0001, 0002, 0017, 0001, 0004, 0001, 0023, 0001, 0017, 0001, 0027, 0001, 0016, 0001, 0003, + 0001, 0020, 0011, 0013, 0001, 0014, 0001, 0017, 0001, 0017, 0001, 0015, 0003, 0017, 0001, 0021, 0001, 0010, 0001, 0021, + 0001, 0024, 0001, 0022, 0001, 0024, 0002, 0012, 0001, 0034, 0002, 0012, 0001, 0033, 0001, 0012, 0001, 0031, 0001, 0036, + 0001, 0012, 0001, 0007, 0001, 0012, 0001, 0035, 0001, 0037, 0001, 0032, 0002, 0012, 0001, 0011, 0002, 0012, 0001, 0005, + 0001, 0000, 0001, 0006, 0001, 0017, 0001, 0012, 0001, 0000, 0001, 0021, 0001, 0010, 0001, 0021, 0001, 0024, 0001, 0022, + 0001, 0024, 0002, 0012, 0001, 0034, 0002, 0012, 0001, 0033, 0001, 0012, 0001, 0031, 0001, 0036, 0001, 0012, 0001, 0007, + 0001, 0012, 0001, 0035, 0001, 0037, 0001, 0032, 0002, 0012, 0001, 0011, 0002, 0012, 0001, 0017, 0001, 0017, 0002, 0017, + 0001, 0000, 0005, 0012, 0001, 0012, 0172, 0012, 0x1f28, 0000, 0001, 0030, 0001, 0030, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xdfe6, 0000} + +/** +* Translates characters to character classes + */ +var ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED) + +/** +* Translates DFA states to action switch labels. + */ +var ZZ_ACTION = zzUnpackActionNoParams() + +var ZZ_ACTION_PACKED_0 []rune = []rune{0011, 0000, 0001, 0001, 0001, 0002, 0001, 0003, 0002, 0004, 0004, 0005, 0001, 0006, 0002, 0004, + 0001, 0006, 0001, 0007, 0001, 0004, 0002, 0005, 0001, 0010, 0002, 0011, 0001, 0012, 0001, 0013, + 0001, 0014, 0001, 0015, 0001, 0016, 0001, 0017, 0001, 0020, 0001, 0021, 0001, 0022, 0001, 0023, + 0001, 0024, 0001, 0025, 0001, 0026, 0001, 0007, 0001, 0027, 0001, 0000, 0001, 0030, 0001, 0031, + 0001, 0032, 0001, 0000, 0001, 0033, 0001, 0034, 0001, 0035, 0001, 0032, 0001, 0036, 0001, 0000, + 0003, 0005, 0001, 0037, 0001, 0040, 0001, 0000, 0001, 0041, 0002, 0000, 0001, 0042, 0004, 0000, + 0001, 0043, 0001, 0044, 0001, 0033, 0001, 0000, 0001, 0045, 0002, 0005, 0003, 0000, 0001, 0046, + 0001, 0047, 0001, 0050, 0001, 0051, 0020, 0000, 0001, 0052, 0001, 0000, 0001, 0053, 0001, 0052, + 0001, 0053} + +func zzUnpackActionNoParams() []int { + result := make([]int, 104) + offset := 0 + offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result) + return result +} + +func zzUnpackAction(packed []rune, offset int, result []int) int { + i := 0 /* index in packed string */ + j := offset /* index in unpacked array */ + l := len(packed) //130 + for i < l { + count := packed[i] + i++ + value := packed[i] + i++ + result[j] = int(value) + j++ + count-- + for count > 0 { + result[j] = int(value) + j++ + count-- + } + } + return j +} + +/** +* Translates a state to a row index in the transition table + */ +var ZZ_ROWMAP = zzUnpackRowMapNoParams() + +var ZZ_ROWMAP_PACKED_0 []rune = []rune{0000, 0000, 0000, 0040, 0000, 0100, 0000, 0140, 0000, 0200, 0000, 0240, 0000, 0300, 0000, 0340, + 0000, 0x0100, 0000, 0200, 0000, 0200, 0000, 0200, 0000, 0x0120, 0000, 0200, 0000, 0x0140, 0000, 0x0160, + 0000, 0x0180, 0000, 0x01a0, 0000, 0x01c0, 0000, 0x01e0, 0000, 0x0200, 0000, 0x0220, 0000, 0200, 0000, 0x0240, + 0000, 0x0260, 0000, 0x0280, 0000, 0x02a0, 0000, 0x02c0, 0000, 0x02e0, 0000, 0x0300, 0000, 0x0320, 0000, 0x0340, + 0000, 0x0360, 0000, 0x0380, 0000, 0x03a0, 0000, 0x03c0, 0000, 0x03e0, 0000, 0x0400, 0000, 0200, 0000, 0200, + 0000, 0200, 0000, 0200, 0000, 0x0420, 0000, 0200, 0000, 0x0440, 0000, 0200, 0000, 0200, 0000, 0x0460, + 0000, 0x0480, 0000, 0200, 0000, 0200, 0000, 0200, 0000, 0x04a0, 0000, 0200, 0000, 0x04c0, 0000, 0x04e0, + 0000, 0x0500, 0000, 0x0520, 0000, 0200, 0000, 0200, 0000, 0x02e0, 0000, 0200, 0000, 0x0540, 0000, 0x0560, + 0000, 0200, 0000, 0x0580, 0000, 0x03a0, 0000, 0x05a0, 0000, 0x03e0, 0000, 0200, 0000, 0200, 0000, 0x05c0, + 0000, 0x05c0, 0000, 0x04c0, 0000, 0x05e0, 0000, 0x0600, 0000, 0x0620, 0000, 0x0640, 0000, 0x0660, 0000, 0200, + 0000, 0200, 0000, 0200, 0000, 0x01a0, 0000, 0x0680, 0000, 0x06a0, 0000, 0x06c0, 0000, 0x06e0, 0000, 0x0700, + 0000, 0x0720, 0000, 0x0740, 0000, 0x0760, 0000, 0x0780, 0000, 0x07a0, 0000, 0x07c0, 0000, 0x07e0, 0000, 0x0800, + 0000, 0x0820, 0000, 0x0840, 0000, 0x0860, 0000, 0200, 0000, 0x0880, 0000, 0200, 0000, 0x06e0, 0000, 0x0720} + +func zzUnpackRowMapNoParams() []int { + result := make([]int, 104) + offset := 0 + offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result) + return result +} + +func zzUnpackRowMap(packed []rune, offset int, result []int) int { + i := 0 /* index in packed string */ + j := offset /* index in unpacked array */ + l := len(packed) //208 + for i < l { + high := packed[i] << 16 + i++ + result[j] = int(high | packed[i]) + i++ + j++ + } + return j +} + +/** +* The transition table of the DFA + */ +var ZZ_TRANS []int = zzUnpackTransNoParams() + +var ZZ_TRANS_PACKED_0 []rune = []rune{0001, 0012, 0001, 0013, 0001, 0014, 0001, 0015, 0003, 0016, 0001, 0017, 0001, 0020, 0001, 0021, + 0001, 0022, 0001, 0023, 0001, 0024, 0001, 0016, 0001, 0025, 0001, 0016, 0001, 0026, 0002, 0022, + 0001, 0016, 0001, 0022, 0002, 0027, 0001, 0030, 0001, 0000, 0001, 0031, 0002, 0022, 0001, 0032, + 0003, 0022, 0003, 0033, 0001, 0034, 0001, 0035, 0033, 0033, 0001, 0036, 0001, 0037, 0036, 0036, + 0002, 0040, 0001, 0041, 0035, 0040, 0040, 0000, 0001, 0042, 0001, 0043, 0036, 0042, 0001, 0044, + 0001, 0045, 0036, 0044, 0006, 0046, 0001, 0047, 0031, 0046, 0001, 0050, 0001, 0051, 0004, 0050, + 0001, 0052, 0031, 0050, 0003, 0000, 0001, 0053, 0001, 0054, 0034, 0000, 0001, 0055, 0005, 0000, + 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, 0001, 0022, 0004, 0000, 0007, 0022, 0001, 0000, + 0001, 0056, 0005, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, 0001, 0022, 0004, 0000, + 0007, 0022, 0001, 0000, 0001, 0057, 0005, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, + 0001, 0022, 0004, 0000, 0007, 0022, 0007, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, + 0001, 0022, 0004, 0000, 0007, 0022, 0013, 0000, 0001, 0023, 0002, 0000, 0001, 0060, 0001, 0000, + 0001, 0023, 0001, 0000, 0001, 0061, 0001, 0000, 0001, 0062, 0030, 0000, 0001, 0063, 0026, 0000, + 0001, 0064, 0006, 0000, 0001, 0065, 0002, 0000, 0001, 0066, 0001, 0000, 0001, 0065, 0030, 0000, + 0001, 0067, 0001, 0000, 0001, 0023, 0002, 0000, 0001, 0060, 0001, 0000, 0001, 0023, 0001, 0000, + 0001, 0061, 0001, 0000, 0001, 0062, 0042, 0000, 0001, 0053, 0017, 0000, 0005, 0022, 0004, 0000, + 0003, 0022, 0001, 0000, 0001, 0022, 0004, 0000, 0001, 0022, 0001, 0070, 0003, 0022, 0001, 0071, + 0001, 0022, 0007, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, 0001, 0022, 0004, 0000, + 0004, 0022, 0001, 0072, 0002, 0022, 0003, 0033, 0002, 0000, 0033, 0033, 0004, 0000, 0001, 0073, + 0036, 0000, 0001, 0074, 0001, 0075, 0033, 0000, 0001, 0036, 0001, 0000, 0036, 0036, 0001, 0000, + 0001, 0076, 0023, 0000, 0001, 0077, 0001, 0100, 0011, 0000, 0002, 0040, 0001, 0000, 0035, 0040, + 0002, 0000, 0001, 0101, 0035, 0000, 0001, 0042, 0001, 0000, 0036, 0042, 0025, 0000, 0001, 0102, + 0001, 0103, 0011, 0000, 0001, 0044, 0001, 0000, 0036, 0044, 0025, 0000, 0001, 0104, 0001, 0105, + 0011, 0000, 0006, 0046, 0001, 0000, 0031, 0046, 0025, 0053, 0001, 0000, 0012, 0053, 0005, 0000, + 0001, 0106, 0045, 0000, 0001, 0065, 0002, 0000, 0001, 0107, 0001, 0000, 0001, 0065, 0001, 0000, + 0001, 0061, 0001, 0000, 0001, 0062, 0026, 0000, 0001, 0110, 0004, 0000, 0001, 0110, 0002, 0000, + 0001, 0111, 0003, 0000, 0001, 0111, 0023, 0000, 0001, 0065, 0004, 0000, 0001, 0065, 0001, 0000, + 0001, 0061, 0001, 0000, 0001, 0062, 0023, 0000, 0001, 0112, 0002, 0000, 0001, 0112, 0004, 0000, + 0003, 0112, 0001, 0000, 0001, 0112, 0022, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, + 0001, 0022, 0004, 0000, 0002, 0022, 0001, 0113, 0004, 0022, 0007, 0000, 0005, 0022, 0004, 0000, + 0003, 0022, 0001, 0000, 0001, 0022, 0004, 0000, 0006, 0022, 0001, 0114, 0003, 0000, 0001, 0115, + 0003, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, 0001, 0022, 0002, 0116, 0001, 0117, + 0001, 0000, 0007, 0022, 0001, 0000, 0001, 0120, 0023, 0000, 0002, 0077, 0036, 0000, 0001, 0077, + 0001, 0100, 0012, 0000, 0001, 0121, 0023, 0000, 0002, 0102, 0012, 0000, 0001, 0122, 0023, 0000, + 0002, 0104, 0024, 0000, 0001, 0110, 0004, 0000, 0001, 0110, 0026, 0000, 0005, 0022, 0004, 0000, + 0003, 0022, 0001, 0000, 0001, 0022, 0004, 0000, 0002, 0022, 0001, 0123, 0004, 0022, 0003, 0000, + 0001, 0124, 0003, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, 0001, 0022, 0002, 0125, + 0001, 0126, 0001, 0000, 0007, 0022, 0003, 0000, 0001, 0127, 0037, 0000, 0001, 0115, 0021, 0000, + 0002, 0116, 0001, 0117, 0001, 0000, 0001, 0130, 0035, 0000, 0001, 0127, 0013, 0000, 0001, 0131, + 0037, 0000, 0001, 0124, 0021, 0000, 0002, 0125, 0001, 0126, 0001, 0000, 0001, 0132, 0035, 0000, + 0001, 0131, 0010, 0000, 0025, 0127, 0001, 0116, 0003, 0127, 0001, 0133, 0006, 0127, 0032, 0000, + 0001, 0134, 0005, 0000, 0025, 0131, 0001, 0125, 0003, 0131, 0001, 0135, 0006, 0131, 0032, 0000, + 0001, 0136, 0005, 0000, 0025, 0127, 0001, 0116, 0003, 0127, 0001, 0133, 0001, 0137, 0005, 0127, + 0033, 0000, 0001, 0140, 0004, 0000, 0025, 0131, 0001, 0125, 0003, 0131, 0001, 0135, 0001, 0141, + 0005, 0131, 0033, 0000, 0001, 0142, 0004, 0000, 0025, 0127, 0001, 0116, 0003, 0127, 0001, 0133, + 0001, 0127, 0001, 0143, 0004, 0127, 0033, 0000, 0001, 0144, 0004, 0000, 0025, 0131, 0001, 0125, + 0003, 0131, 0001, 0135, 0001, 0131, 0001, 0145, 0004, 0131, 0033, 0000, 0001, 0146, 0004, 0000, + 0025, 0127, 0001, 0116, 0003, 0127, 0001, 0133, 0001, 0127, 0001, 0147, 0004, 0127, 0025, 0131, + 0001, 0125, 0003, 0131, 0001, 0135, 0001, 0131, 0001, 0150, 0004, 0131} + +func zzUnpackTransNoParams() []int { + result := make([]int, 2208) + offset := 0 + offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result) + return result +} + +func zzUnpackTrans(packed []rune, offset int, result []int) int { + i := 0 /* index in packed string */ + j := offset /* index in unpacked array */ + l := len(packed) //780 + for i < l { + count := packed[i] + i++ + value := packed[i] + i++ + value-- + result[j] = int(value) + j++ + count-- + for count > 0 { + result[j] = int(value) + j++ + count-- + } + } + return j +} + +/* error codes */ +const ( + ZZ_UNKNOWN_ERROR = 0 + ZZ_NO_MATCH = 1 + ZZ_PUSHBACK_2BIG = 2 +) + +/* error messages for the codes above */ +var ZZ_ERROR_MSG []string = []string{ + "Unknown internal scanner error", + "Error: could not match input", + "Error: pushback Value was too large"} + +/** +* ZZ_ATTRIBUTE[aState] contains the attributes of state aState + */ +var ZZ_ATTRIBUTE []int = zzUnpackAttributeNoParams() + +var ZZ_ATTRIBUTE_PACKED_0 []rune = []rune{0004, 0000, 0001, 0010, 0004, 0000, 0003, 0011, 0001, 0001, 0001, 0011, 0010, 0001, 0001, 0011, + 0017, 0001, 0004, 0011, 0001, 0001, 0001, 0011, 0001, 0000, 0002, 0011, 0001, 0001, 0001, 0000, + 0003, 0011, 0001, 0001, 0001, 0011, 0001, 0000, 0003, 0001, 0002, 0011, 0001, 0000, 0001, 0011, + 0002, 0000, 0001, 0011, 0004, 0000, 0002, 0011, 0001, 0001, 0001, 0000, 0003, 0001, 0003, 0000, + 0003, 0011, 0001, 0001, 0020, 0000, 0001, 0011, 0001, 0000, 0001, 0011, 0002, 0001} + +func zzUnpackAttributeNoParams() []int { + result := make([]int, 104) + offset := 0 + offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result) + return result +} + +func zzUnpackAttribute(packed []rune, offset int, result []int) int { + i := 0 /* index in packed string */ + j := offset /* index in unpacked array */ + l := len(packed) //78 + for i < l { + count := packed[i] + i++ + value := packed[i] + i++ + result[j] = int(value) + j++ + count-- + + for count > 0 { + result[j] = int(value) + j++ + count-- + } + } + return j +} + +type Lexer struct { + /** the input device */ + zzReader io.RuneReader + + /** the current state of the DFA */ + zzState int + + /** the current lexical state */ + zzLexicalState int + + /** this buffer contains the current text to be matched and is + the source of the yytext() string */ + zzBuffer []rune + + //zzBytesBuffer []byte + + /** the textposition at the last accepting state */ + zzMarkedPos int + + /** the current text Position in the buffer */ + zzCurrentPos int + + /** startRead marks the beginning of the yytext() string in the buffer */ + zzStartRead int + + /** endRead marks the last character in the buffer, that has been read + from input */ + zzEndRead int + + /** number of newlines encountered up to the start of the matched text */ + yyline int + + /** the number of characters up to the start of the matched text */ + yychar int + + /** + * the number of characters from the last newline up to the start of the + * matched text + */ + yycolumn int + + /** + * zzAtBOL == true <=> the scanner is currently at the beginning of a line + */ + zzAtBOL bool + + /** zzAtEOF == true <=> the scanner is at the EOF */ + zzAtEOF bool + + /** denotes if the user-EOF-code has already been executed */ + zzEOFDone bool + + /** + * The number of occupied positions in zzBuffer beyond zzEndRead. + * When a lead/high surrogate has been read from the input stream + * into the final zzBuffer Position, this will have a Value of 1; + * otherwise, it will have a Value of 0. + */ + zzFinalHighSurrogate int + + /* user code: */ + ltstr string + debugFlag bool +} + +func (lexer *Lexer) init() { + lexer.zzLexicalState = YYINITIAL + lexer.zzBuffer = make([]rune, ZZ_BUFFERSIZE) + lexer.zzAtBOL = true +} + +func (lexer *Lexer) Reset(in io.RuneReader) *Lexer { + lexer.zzLexicalState = YYINITIAL + lexer.zzAtBOL = true + lexer.zzReader = in + lexer.zzState = 0 + lexer.zzMarkedPos = 0 + lexer.zzCurrentPos = 0 + lexer.zzStartRead = 0 + lexer.zzEndRead = 0 + lexer.yyline = 0 + lexer.yychar = 0 + lexer.yycolumn = 0 + lexer.zzAtEOF = false + lexer.zzEOFDone = false + lexer.zzFinalHighSurrogate = 0 + lexer.ltstr = "" + return lexer +} + +func (lexer *Lexer) debug(info string) { + if !lexer.debugFlag { + return + } + +} + +func (lexer *Lexer) yyerror(msg string) { + locInfo := "(line: " + strconv.Itoa(lexer.yyline) + ", column: " + strconv.Itoa(lexer.yycolumn) + ", char: " + strconv.Itoa(lexer.yychar) + ")" + if msg == "" { + panic("syntex error" + locInfo) + } else { + panic("syntex error" + locInfo + ": " + msg) + } +} + +/** +* Creates a new scanner +* +* @param in the java.io.Reader to read input from. + */ +func NewLexer(in io.RuneReader, debug bool) *Lexer { + l := new(Lexer) + l.init() + l.debugFlag = debug + l.zzReader = in + return l +} + +/** +* Unpacks the compressed character translation table. +* +* @param packed the packed character translation table +* @return the unpacked character translation table + */ +func zzUnpackCMap(packed []rune) []rune { + m := make([]rune, 0x110000) + i := 0 /* index in packed string */ + j := 0 /* index in unpacked array */ + for i < 208 { + count := packed[i] + i++ + value := packed[i] + i++ + m[j] = value + j++ + count-- + for count > 0 { + m[j] = value + j++ + count-- + } + } + return m +} + +/** +* Refills the input buffer. +* +* @return false, iff there was new input. +* +* @exception java.io.IOException if any I/O-Error occurs + */ +func (lexer *Lexer) zzRefill() (bool, error) { + + /* first: make room (if you can) */ + if lexer.zzStartRead > 0 { + lexer.zzEndRead += lexer.zzFinalHighSurrogate + lexer.zzFinalHighSurrogate = 0 + l := lexer.zzEndRead - lexer.zzStartRead + if l > 0 { + copy(lexer.zzBuffer[:l], lexer.zzBuffer[lexer.zzStartRead:lexer.zzEndRead]) + } + + /* translate stored positions */ + lexer.zzEndRead -= lexer.zzStartRead + lexer.zzCurrentPos -= lexer.zzStartRead + lexer.zzMarkedPos -= lexer.zzStartRead + lexer.zzStartRead = 0 + } + + /* is the buffer big enough? */ + if lexer.zzCurrentPos >= len(lexer.zzBuffer)-lexer.zzFinalHighSurrogate { + /* if not: blow it up */ + newBuffer := make([]rune, len(lexer.zzBuffer)*2) + + copy(newBuffer[:len(lexer.zzBuffer)], lexer.zzBuffer[:len(lexer.zzBuffer)]) + lexer.zzBuffer = newBuffer + lexer.zzEndRead += lexer.zzFinalHighSurrogate + lexer.zzFinalHighSurrogate = 0 + } + + /* fill the buffer with new input */ + requested := len(lexer.zzBuffer) - lexer.zzEndRead + + var numRead = 0 + for i := lexer.zzEndRead; i < lexer.zzEndRead + requested; i ++ { + r, _, err := lexer.zzReader.ReadRune() + if err == io.EOF { + if numRead == 0 { + numRead = -1 + } + break + } else if err != nil { + return false, err + } else { + numRead++ + lexer.zzBuffer[i] = r + } + } + + /* not supposed to occur according to specification of java.io.Reader */ + if numRead == 0 { + panic("Reader returned 0 characters. See JFlex examples for workaround.") + } + + if numRead > 0 { + + lexer.zzEndRead += numRead + /* If numRead == requested, we might have requested to few chars to + encode a full Unicode character. We assume that a Reader would + otherwise never return half characters. */ + if numRead == requested { + if utf8.ValidRune(lexer.zzBuffer[lexer.zzEndRead-1]) { + lexer.zzEndRead-- + lexer.zzFinalHighSurrogate = 1 + } + } + /* potentially more input available */ + return false, nil + } + + /* numRead < 0 ==> end of stream */ + return true, nil +} + +/** +* Closes the input stream. + */ +func (lexer *Lexer) yyclose() error { + lexer.zzAtEOF = true /* indicate end of file */ + lexer.zzEndRead = lexer.zzStartRead /* invalidate buffer */ + + if lexer.zzReader != nil { + if c, ok := lexer.zzReader.(io.Closer); ok { + return c.Close() + } + } + return nil +} + +/** +* Resets the scanner to read from a new input stream. +* Does not close the old reader. +* +* All internal variables are reset, the old input stream +* cannot be reused (internal buffer is discarded and lost). +* Lexical state is set to ZZ_INITIAL. +* +* Internal scan buffer is resized down to its initial length, if it has grown. +* +* @param reader the new input stream + */ +func (lexer *Lexer) yyreset(reader io.RuneReader) { + lexer.zzReader = reader + lexer.zzAtBOL = true + lexer.zzAtEOF = false + lexer.zzEOFDone = false + lexer.zzEndRead = 0 + lexer.zzStartRead = 0 + lexer.zzCurrentPos = 0 + lexer.zzMarkedPos = 0 + lexer.zzFinalHighSurrogate = 0 + lexer.yyline = 0 + lexer.yychar = 0 + lexer.yycolumn = 0 + lexer.zzLexicalState = YYINITIAL + if len(lexer.zzBuffer) > ZZ_BUFFERSIZE { + lexer.zzBuffer = make([]rune, ZZ_BUFFERSIZE) + } +} + +/** +* Returns the current lexical state. + */ +func (lexer *Lexer) yystate() int { + return lexer.zzLexicalState +} + +/** +* Enters a new lexical state +* +* @param newState the new lexical state + */ +func (lexer *Lexer) yybegin(newState int) { + lexer.zzLexicalState = newState +} + +/** +* Returns the text matched by the current regular expression. + */ +func (lexer *Lexer) yytext() string { + return string(lexer.zzBuffer[lexer.zzStartRead:lexer.zzMarkedPos]) +} + +/** +* Returns the character at Position pos from the +* matched text. +* +* It is equivalent to yytext().charAt(pos), but faster +* +* @param pos the Position of the character to fetch. +* A Value from 0 to yylength()-1. +* +* @return the character at Position pos + */ +func (lexer *Lexer) yycharat(pos int) rune { + return lexer.zzBuffer[lexer.zzStartRead+pos] +} + +/** +* Returns the length of the matched text region. + */ +func (lexer *Lexer) yylength() int { + return lexer.zzMarkedPos - lexer.zzStartRead +} + +/** +* Reports an error that occured while scanning. +* +* In a wellformed scanner (no or only correct usage of +* yypushback(int) and a match-all fallback rule) this method +* will only be called with things that "Can't Possibly Happen". +* If this method is called, something is seriously wrong +* (e.g. a JFlex bug producing a faulty scanner etc.). +* +* Usual syntax/scanner level error handling should be done +* in error fallback rules. +* +* @param errorCode the code of the errormessage to display + */ +func (lexer *Lexer) zzScanError(errorCode int) { + var message string + + message = ZZ_ERROR_MSG[errorCode] + if message == "" { + message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR] + } + + panic(message) +} + +/** +* Pushes the specified amount of characters back into the input stream. +* +* They will be read again by then next call of the scanning method +* +* @param number the number of characters to be read again. +* This number must not be greater than yylength()! + */ +func (lexer *Lexer) yypushback(number int) { + if number > lexer.yylength() { + lexer.zzScanError(ZZ_PUSHBACK_2BIG) + } + + lexer.zzMarkedPos -= number +} + +/** +* Resumes scanning until the next regular expression is matched, +* the end of input is encountered or an I/O-Error occurs. +* +* @return the next token +* @exception java.io.IOException if any I/O-Error occurs + */ +func (lexer *Lexer) Yylex() (*LVal, error) { + var zzInput rune + var zzAction, zzCurrentPosL, zzMarkedPosL int + // cached fields: + zzEndReadL := lexer.zzEndRead + zzBufferL := lexer.zzBuffer + zzCMapL := ZZ_CMAP + + zzTransL := ZZ_TRANS + zzRowMapL := ZZ_ROWMAP + zzAttrL := ZZ_ATTRIBUTE + + for { + zzMarkedPosL = lexer.zzMarkedPos + + lexer.yychar += zzMarkedPosL - lexer.zzStartRead + + zzR := false + var zzCh rune + var zzCharCount int + zzCurrentPosL = lexer.zzStartRead + for zzCurrentPosL < zzMarkedPosL { + zzCh = zzBufferL[zzCurrentPosL] + zzCharCount = utf8.RuneLen(zzCh) + switch zzCh { + case '\u000B', '\u000C', '\u0085', '\u2028', '\u2029': + lexer.yyline++ + lexer.yycolumn = 0 + zzR = false + case '\r': + lexer.yyline++ + lexer.yycolumn = 0 + zzR = true + case '\n': + if zzR { + zzR = false + } else { + lexer.yyline++ + lexer.yycolumn = 0 + } + default: + zzR = false + lexer.yycolumn += zzCharCount + } + zzCurrentPosL += zzCharCount + } + + if zzR { + // peek one character ahead if it is \n (if we have counted one line too much) + var zzPeek bool + if zzMarkedPosL < zzEndReadL { + zzPeek = zzBufferL[zzMarkedPosL] == '\n' + } else if lexer.zzAtEOF { + zzPeek = false + } else { + eof, err := lexer.zzRefill() + if err != nil { + return nil, err + } + zzEndReadL = lexer.zzEndRead + zzMarkedPosL = lexer.zzMarkedPos + zzBufferL = lexer.zzBuffer + if eof { + zzPeek = false + } else { + zzPeek = zzBufferL[zzMarkedPosL] == '\n' + } + + } + if zzPeek { + lexer.yyline-- + } + } + zzAction = -1 + + zzCurrentPosL = zzMarkedPosL + lexer.zzCurrentPos = zzMarkedPosL + lexer.zzStartRead = zzMarkedPosL + lexer.zzState = ZZ_LEXSTATE[lexer.zzLexicalState] + + // set up zzAction for empty match case: + zzAttributes := zzAttrL[lexer.zzState] + if (zzAttributes & 1) == 1 { + zzAction = lexer.zzState + } + + { + for true { + + if zzCurrentPosL < zzEndReadL { + zzInput = zzBufferL[zzCurrentPosL] + zzCurrentPosL += 1//utf8.RuneLen(zzInput) + } else if lexer.zzAtEOF { + zzInput = YYEOF + goto zzForAction + } else { + // store back cached positions + lexer.zzCurrentPos = zzCurrentPosL + lexer.zzMarkedPos = zzMarkedPosL + eof, err := lexer.zzRefill() + if err != nil { + return nil, err + } + // get translated positions and possibly new buffer + zzCurrentPosL = lexer.zzCurrentPos + zzMarkedPosL = lexer.zzMarkedPos + zzBufferL = lexer.zzBuffer + zzEndReadL = lexer.zzEndRead + if eof { + zzInput = YYEOF + goto zzForAction + } else { + zzInput = zzBufferL[zzCurrentPosL] + zzCurrentPosL += 1//utf8.RuneLen(zzInput) + } + } + + zzNext := zzTransL[zzRowMapL[lexer.zzState]+int(zzCMapL[zzInput])] + if zzNext == -1 { + goto zzForAction + } + + lexer.zzState = zzNext + + zzAttributes = zzAttrL[lexer.zzState] + if (zzAttributes & 1) == 1 { + zzAction = lexer.zzState + zzMarkedPosL = zzCurrentPosL + if (zzAttributes & 8) == 8 { + goto zzForAction + } + } + + } + } + + zzForAction: + // store back cached Position + lexer.zzMarkedPos = zzMarkedPosL + + if zzInput == YYEOF && lexer.zzStartRead == lexer.zzCurrentPos { + lexer.zzAtEOF = true + switch lexer.zzLexicalState { + case xc: + { + lexer.debug("<>") + + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated /* comment") + } + case 105: + case xq: + { + lexer.debug("<>") + + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated quoted string") + } + fallthrough + case 106: + case xdq: + { + lexer.debug("<>") + + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated quoted identifier") + } + fallthrough + case 107: + case xbin: + { + lexer.debug("<>") + + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated binary string literal") + } + fallthrough + case 108: + case xhex: + { + lexer.debug("<>") + + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated hexadecimal integer") + } + fallthrough + case 109: + case xq2: + { + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated q2 string") + } + fallthrough + case 110: + case xq2_2: + { + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated q2 string") + } + fallthrough + case 111: + default: + return nil, nil + } + } else { + var action int + if zzAction < 0 { + action = zzAction + } else { + action = ZZ_ACTION[zzAction] + } + switch action { + case 1: + { + lexer.debug("{other}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 44: + case 2: + { + lexer.debug("{xq_start}") + + lexer.yybegin(xq) + lexer.ltstr = "" + } + fallthrough + case 45: + case 3: + { + lexer.debug("{xdq_start}") + + lexer.yybegin(xdq) + lexer.ltstr = "" + lexer.ltstr += lexer.yytext() + } + fallthrough + case 46: + case 4: + { + lexer.debug("{self} | {op_chars}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 47: + case 5: + { + lexer.debug("{identifier}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 48: + case 6: + { + lexer.debug("{integer}") + + return newLVal(lexer.yytext(), INT), nil + } + fallthrough + case 49: + case 7: + { + lexer.debug("{whitespace} | {comment} | {c_line_comment}") + + return newLVal(lexer.yytext(), WHITESPACE_OR_COMMENT), nil + } + fallthrough + case 50: + case 8: + { + lexer.debug("{xc_inside}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 51: + case 9: + { + lexer.debug("[\\/] | [\\*]") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 52: + case 10: + { + lexer.debug("{xq_inside}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 53: + case 11: + { + lexer.debug("{xq_stop}") + + lexer.yybegin(YYINITIAL) + return newLVal(lexer.ltstr, STRING), nil + } + fallthrough + case 54: + case 12: + { + lexer.debug("{xdq_inside}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 55: + case 13: + { + lexer.debug("{xdq_stop}") + + lexer.yybegin(YYINITIAL) + lexer.ltstr += lexer.yytext() + return newLVal(lexer.ltstr, NORMAL), nil + } + fallthrough + case 56: + case 14: + { + lexer.debug("{xbin_inside}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 57: + case 15: + { + lexer.debug("{xbin_stop}") + + lexer.yybegin(YYINITIAL) + lexer.ltstr += lexer.yytext() + return newLVal(lexer.ltstr, NORMAL), nil + } + fallthrough + case 58: + case 16: + { + lexer.debug("{xhex_inside}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 59: + case 17: + { + lexer.debug("{xhex_stop}") + + lexer.yybegin(YYINITIAL) + lexer.ltstr += lexer.yytext() + return newLVal(lexer.ltstr, NORMAL), nil + } + fallthrough + case 60: + case 18: + { + lexer.ltstr += lexer.yytext() + } + fallthrough + case 61: + case 19: + { + lexer.yybegin(xq2_2) + } + fallthrough + case 62: + case 20: + { + lexer.ltstr += "]" + lexer.ltstr += lexer.yytext() + lexer.yybegin(xq2) + } + fallthrough + case 63: + case 21: + { + lexer.yybegin(YYINITIAL) + + return newLVal(lexer.ltstr, STRING), nil + } + fallthrough + case 64: + case 22: + { + lexer.ltstr += "]" + lexer.yybegin(xq2_2) + } + fallthrough + case 65: + case 23: + { + lexer.debug("{xc_start}") + + lexer.yybegin(xc) + lexer.ltstr = lexer.yytext() + } + fallthrough + case 66: + case 24: + { + lexer.debug("{xbin_start}") + + lexer.yybegin(xbin) + lexer.ltstr = "" + lexer.ltstr += lexer.yytext() + } + fallthrough + case 67: + case 25: + { + lexer.debug("{xhex_start}") + + lexer.yybegin(xhex) + lexer.ltstr = "" + lexer.ltstr += lexer.yytext() + } + fallthrough + case 68: + case 26: + { + lexer.debug("{decimal}") + + return newLVal(lexer.yytext(), DECIMAL), nil + } + fallthrough + case 69: + case 27: + { + lexer.debug("{real}") + + return newLVal(lexer.yytext(), DOUBLE), nil + } + fallthrough + case 70: + case 28: + { + lexer.debug("{assign}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 71: + case 29: + { + lexer.debug("{selstar}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 72: + case 30: + { + lexer.debug("{boundary}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 73: + case 31: + { + lexer.debug("{xc_start}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 74: + case 32: + { + lexer.debug("{xc_stop}") + + lexer.yybegin(YYINITIAL) + lexer.ltstr += lexer.yytext() + return newLVal(lexer.ltstr, WHITESPACE_OR_COMMENT), nil + } + fallthrough + case 75: + case 33: + { + lexer.debug("{xq_double}") + + lexer.ltstr += "\\'" + } + fallthrough + case 76: + case 34: + { // keep original string + lexer.debug("{xdq_double}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 77: + case 35: + { + lexer.yybegin(xq2) + lexer.ltstr = "" + } + fallthrough + case 78: + case 36: + { + lexer.debug("{integer_with_boundary}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 79: + case 37: + { + lexer.debug("{hex_integer}") + + return newLVal(lexer.yytext(), HEX_INT), nil + } + fallthrough + case 80: + case 38: + { + lexer.debug("{xq_cat}") + } + fallthrough + case 81: + case 39: + { /* ignore */ + lexer.debug("{xbin_cat}") + } + fallthrough + case 82: + case 40: + { + lexer.debug("{xhex_cat}") + } + fallthrough + case 83: + case 41: + { + lexer.debug("{null}") + + return newLVal("null", NULL), nil + } + fallthrough + case 84: + case 42: + { + lexer.debug("{is_null}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 85: + case 43: + { + lexer.debug("{not_null}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 86: + default: + lexer.zzScanError(ZZ_NO_MATCH) + } + } + } +} diff --git a/dmr/q.go b/dmr/q.go new file mode 100644 index 0000000..b5628cd --- /dev/null +++ b/dmr/q.go @@ -0,0 +1,1451 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "database/sql/driver" + "math" + "strconv" + "strings" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +const ( + LOADPREC_DEFAULT = 2 + + LOADPREC_MAX = 9 + + SECDPREC_DEFAULT = 6 + + SECDPREC_MAX = 6 + + QUA_D byte = 3 + + QUA_DH byte = 4 + + QUA_DHM byte = 5 + + QUA_DHMS byte = 6 + + QUA_H byte = 7 + + QUA_HM byte = 8 + + QUA_HMS byte = 9 + + QUA_M byte = 10 + + QUA_MS byte = 11 + + QUA_S byte = 12 +) + +type DmIntervalDT struct { + _type byte + + leadScale int + + secScale int + + negative bool + + days int + + hours int + + minutes int + + seconds int + + fraction int + + scaleForSvr int + + Valid bool +} + +func (dt *DmIntervalDT) init() { + dt._type = QUA_D + dt.leadScale = 2 + dt.secScale = 6 + dt.negative = false + dt.days = 0 + dt.hours = 0 + dt.minutes = 0 + dt.seconds = 0 + dt.fraction = 0 + dt.scaleForSvr = 0 + dt.Valid = true +} + +func newDmIntervalDTByBytes(bytes []byte) *DmIntervalDT { + dt := new(DmIntervalDT) + dt.init() + + dt._type = bytes[21] + dt.scaleForSvr = int(Dm_build_1220.Dm_build_1322(bytes, 20)) + dt.leadScale = (dt.scaleForSvr >> 4) & 0x0000000F + dt.secScale = dt.scaleForSvr & 0x0000000F + + switch dt._type { + case QUA_D: + dt.days = int(Dm_build_1220.Dm_build_1322(bytes, 0)) + case QUA_DH: + dt.days = int(Dm_build_1220.Dm_build_1322(bytes, 0)) + dt.hours = int(Dm_build_1220.Dm_build_1322(bytes, 4)) + case QUA_DHM: + dt.days = int(Dm_build_1220.Dm_build_1322(bytes, 0)) + dt.hours = int(Dm_build_1220.Dm_build_1322(bytes, 4)) + dt.minutes = int(Dm_build_1220.Dm_build_1322(bytes, 8)) + case QUA_DHMS: + dt.days = int(Dm_build_1220.Dm_build_1322(bytes, 0)) + dt.hours = int(Dm_build_1220.Dm_build_1322(bytes, 4)) + dt.minutes = int(Dm_build_1220.Dm_build_1322(bytes, 8)) + dt.seconds = int(Dm_build_1220.Dm_build_1322(bytes, 12)) + dt.fraction = int(Dm_build_1220.Dm_build_1322(bytes, 16)) + case QUA_H: + dt.hours = int(Dm_build_1220.Dm_build_1322(bytes, 4)) + case QUA_HM: + dt.hours = int(Dm_build_1220.Dm_build_1322(bytes, 4)) + dt.minutes = int(Dm_build_1220.Dm_build_1322(bytes, 8)) + case QUA_HMS: + dt.hours = int(Dm_build_1220.Dm_build_1322(bytes, 4)) + dt.minutes = int(Dm_build_1220.Dm_build_1322(bytes, 8)) + dt.seconds = int(Dm_build_1220.Dm_build_1322(bytes, 12)) + dt.fraction = int(Dm_build_1220.Dm_build_1322(bytes, 16)) + case QUA_M: + dt.minutes = int(Dm_build_1220.Dm_build_1322(bytes, 8)) + case QUA_MS: + dt.minutes = int(Dm_build_1220.Dm_build_1322(bytes, 8)) + dt.seconds = int(Dm_build_1220.Dm_build_1322(bytes, 12)) + dt.fraction = int(Dm_build_1220.Dm_build_1322(bytes, 16)) + case QUA_S: + dt.seconds = int(Dm_build_1220.Dm_build_1322(bytes, 12)) + dt.fraction = int(Dm_build_1220.Dm_build_1322(bytes, 16)) + } + if dt.days < 0 { + dt.days = -dt.days + dt.negative = true + } + if dt.hours < 0 { + dt.hours = -dt.hours + dt.negative = true + } + if dt.minutes < 0 { + dt.minutes = -dt.minutes + dt.negative = true + } + if dt.seconds < 0 { + dt.seconds = -dt.seconds + dt.negative = true + } + if dt.fraction < 0 { + dt.fraction = -dt.fraction + dt.negative = true + } + + return dt +} + +func NewDmIntervalDTByString(str string) (dt *DmIntervalDT, err error) { + defer func() { + if p := recover(); p != nil { + err = ECGO_INVALID_TIME_INTERVAL.throw() + } + }() + dt = new(DmIntervalDT) + dt.init() + + if str == "" { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + + leadStr := strings.TrimSpace(strings.ToUpper(str)) + + if !(strings.Index(leadStr, "INTERVAL ") == 0) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + + leadStr = strings.TrimSpace(leadStr[strings.Index(leadStr, " "):]) + + endIndex := 0 + var valueStr string + + if endIndex = strings.Index(leadStr[1:], "'"); leadStr[0] == '\'' && endIndex != -1 { + endIndex += 1 + valueStr = strings.TrimSpace(leadStr[1:endIndex]) + valueStr = dt.checkSign(valueStr) + leadStr = strings.TrimSpace(leadStr[endIndex+1:]) + } + + if valueStr == "" { + leadStr = dt.checkSign(leadStr) + if endIndex = strings.Index(leadStr[1:], "'"); leadStr[0] != '\'' || endIndex == -1 { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + endIndex += 1 + valueStr = strings.TrimSpace(leadStr[1:endIndex]) + leadStr = strings.TrimSpace(leadStr[endIndex+1:]) + } + + strLeadPrec := "" + strSecPrec := "" + + leadPrecIndex := 0 + secPrecIndex := 0 + toIndex := 0 + + if leadPrecIndex = strings.Index(leadStr, "DAY"); leadPrecIndex != -1 { + toIndex = strings.Index(leadStr[leadPrecIndex:], "TO") + + if toIndex == -1 { + strLeadPrec = strings.TrimSpace(leadStr[leadPrecIndex:]) + if err := dt.setDay(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + toIndex += leadPrecIndex + strLeadPrec = strings.TrimSpace(leadStr[leadPrecIndex:toIndex]) + + if strings.Index(leadStr[toIndex:], "HOUR") != -1 { + if err := dt.setDayToHour(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else if strings.Index(leadStr[toIndex:], "MINUTE") != -1 { + if err := dt.setDayToMinute(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else if secPrecIndex = strings.Index(leadStr[toIndex:], "SECOND"); secPrecIndex != -1 { + secPrecIndex += toIndex + strSecPrec = leadStr[secPrecIndex:] + if err := dt.setDayToSecond(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } + + if err := dt.setPrecForSvr(leadStr, strLeadPrec, strSecPrec); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + return dt, nil + } + + if leadPrecIndex = strings.Index(leadStr, "HOUR"); leadPrecIndex != -1 { + toIndex = strings.Index(leadStr[leadPrecIndex:], "TO") + + if toIndex == -1 { + toIndex += leadPrecIndex + strLeadPrec = leadStr[leadPrecIndex:] + if err := dt.setHour(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + strLeadPrec = leadStr[leadPrecIndex:toIndex] + + if strings.Index(leadStr[toIndex:], "MINUTE") != -1 { + if err := dt.setHourToMinute(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else if secPrecIndex = strings.Index(leadStr[toIndex:], "SECOND"); secPrecIndex != -1 { + secPrecIndex += toIndex + strSecPrec = leadStr[secPrecIndex:] + if err := dt.setHourToSecond(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } + + if err := dt.setPrecForSvr(leadStr, strLeadPrec, strSecPrec); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + return dt, nil + } + + if leadPrecIndex = strings.Index(leadStr, "MINUTE"); leadPrecIndex != -1 { + toIndex = strings.Index(leadStr, "TO") + + if toIndex == -1 { + toIndex += leadPrecIndex + strLeadPrec = leadStr[leadPrecIndex:] + if err := dt.setMinute(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + strLeadPrec = leadStr[leadPrecIndex:toIndex] + + if secPrecIndex = strings.Index(leadStr[toIndex:], "SECOND"); secPrecIndex != -1 { + strSecPrec = leadStr[secPrecIndex:] + if err := dt.setMinuteToSecond(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } + + if err := dt.setPrecForSvr(leadStr, strLeadPrec, strSecPrec); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + return dt, nil + } + + if leadPrecIndex = strings.Index(leadStr, "SECOND"); leadPrecIndex != -1 { + if err := dt.setSecond(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + + leadStr = strings.TrimSpace(leadStr[leadPrecIndex:]) + + colonIndex := strings.Index(leadStr, ",") + if colonIndex != -1 { + strLeadPrec = strings.TrimSpace(leadStr[:colonIndex]) + ")" + strSecPrec = "(" + strings.TrimSpace(leadStr[:colonIndex+1]) + } + + if err := dt.setPrecForSvr(leadStr, strLeadPrec, strSecPrec); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + return dt, nil + } + + return nil, ECGO_INVALID_TIME_INTERVAL.throw() +} + +func (dt *DmIntervalDT) GetDay() int { + return dt.days +} + +func (dt *DmIntervalDT) GetHour() int { + return dt.hours +} + +func (dt *DmIntervalDT) GetMinute() int { + return dt.minutes +} + +func (dt *DmIntervalDT) GetSecond() int { + return dt.seconds +} + +func (dt *DmIntervalDT) GetMsec() int { + return dt.fraction +} + +func (dt *DmIntervalDT) GetDTType() byte { + return dt._type +} + +func (dt *DmIntervalDT) String() string { + if !dt.Valid { + return "" + } + var l, destLen int + var dStr, hStr, mStr, sStr, nStr string + interval := "INTERVAL " + + switch dt._type { + case QUA_D: + dStr := strconv.FormatInt(int64(float64(dt.days)), 10) + if dt.negative { + interval += "-" + } + + if len(dStr) < dt.leadScale { + l = len(dStr) + destLen = dt.leadScale + + for destLen > l { + dStr = "0" + dStr + destLen-- + } + } + + interval += "'" + dStr + "' DAY(" + strconv.FormatInt(int64(dt.leadScale), 10) + ")" + case QUA_DH: + dStr = strconv.FormatInt(int64(float64(dt.days)), 10) + hStr = strconv.FormatInt(int64(float64(dt.hours)), 10) + + if dt.negative { + interval += "-" + } + + if len(dStr) < dt.leadScale { + l = len(dStr) + destLen = dt.leadScale + + for destLen > l { + dStr = "0" + dStr + destLen-- + } + } + + if len(hStr) < 2 { + hStr = "0" + hStr + } + + interval += "'" + dStr + " " + hStr + "' DAY(" + strconv.FormatInt(int64(dt.leadScale), 10) + ") TO HOUR" + case QUA_DHM: + dStr = strconv.FormatInt(int64(float64(dt.days)), 10) + hStr = strconv.FormatInt(int64(float64(dt.hours)), 10) + mStr = strconv.FormatInt(int64(float64(dt.minutes)), 10) + + if dt.negative { + interval += "-" + } + + if len(dStr) < dt.leadScale { + l = len(dStr) + destLen = dt.leadScale + + for destLen > l { + dStr = "0" + dStr + destLen-- + } + } + if len(hStr) < 2 { + hStr = "0" + hStr + } + if len(mStr) < 2 { + mStr = "0" + mStr + } + interval += "'" + dStr + " " + hStr + ":" + mStr + "' DAY(" + strconv.FormatInt(int64(dt.leadScale), 10) + ") TO MINUTE" + case QUA_DHMS: + dStr = strconv.FormatInt(int64(float64(dt.days)), 10) + hStr = strconv.FormatInt(int64(float64(dt.hours)), 10) + mStr = strconv.FormatInt(int64(float64(dt.minutes)), 10) + sStr = strconv.FormatInt(int64(float64(dt.seconds)), 10) + nStr = dt.getMsecString() + if dt.negative { + interval += "-" + } + + if len(dStr) < dt.leadScale { + l = len(dStr) + destLen = dt.leadScale + + for destLen > l { + dStr = "0" + dStr + destLen-- + } + } + if len(hStr) < 2 { + hStr = "0" + hStr + } + if len(mStr) < 2 { + mStr = "0" + mStr + } + if len(sStr) < 2 { + sStr = "0" + sStr + } + interval += "'" + dStr + " " + hStr + ":" + mStr + ":" + sStr + if nStr != "" { + interval += "." + nStr + } + + interval += "' DAY(" + strconv.FormatInt(int64(dt.leadScale), 10) + ") TO SECOND(" + strconv.FormatInt(int64(dt.secScale), 10) + ")" + case QUA_H: + hStr = strconv.FormatInt(int64(float64(dt.hours)), 10) + if dt.negative { + interval += "-" + } + + if len(hStr) < dt.leadScale { + l = len(hStr) + destLen = dt.leadScale + + for destLen > l { + hStr = "0" + hStr + destLen-- + } + } + + interval += "'" + hStr + "' HOUR(" + strconv.FormatInt(int64(dt.leadScale), 10) + ")" + case QUA_HM: + hStr = strconv.FormatInt(int64(float64(dt.hours)), 10) + mStr = strconv.FormatInt(int64(float64(dt.minutes)), 10) + + if dt.negative { + interval += "-" + } + + if len(hStr) < dt.leadScale { + l = len(hStr) + destLen = dt.leadScale + + for destLen > l { + hStr = "0" + hStr + destLen-- + } + } + if len(mStr) < 2 { + mStr = "0" + mStr + } + + interval += "'" + hStr + ":" + mStr + "' HOUR(" + strconv.FormatInt(int64(dt.leadScale), 10) + ") TO MINUTE" + case QUA_HMS: + nStr = dt.getMsecString() + hStr = strconv.FormatInt(int64(float64(dt.hours)), 10) + mStr = strconv.FormatInt(int64(float64(dt.minutes)), 10) + sStr = strconv.FormatInt(int64(float64(dt.seconds)), 10) + + if dt.negative { + interval += "-" + } + + if len(hStr) < dt.leadScale { + l = len(hStr) + destLen = dt.leadScale + + for destLen > l { + hStr = "0" + hStr + destLen-- + } + } + if len(mStr) < 2 { + mStr = "0" + mStr + } + if len(sStr) < 2 { + sStr = "0" + sStr + } + + interval += "'" + hStr + ":" + mStr + ":" + sStr + if nStr != "" { + interval += "." + nStr + } + + interval += "' HOUR(" + strconv.FormatInt(int64(dt.leadScale), 10) + ") TO SECOND(" + strconv.FormatInt(int64(dt.secScale), 10) + ")" + + case QUA_M: + mStr = strconv.FormatInt(int64(float64(dt.minutes)), 10) + + if dt.negative { + interval += "-" + } + + if len(mStr) < dt.leadScale { + l = len(mStr) + destLen = dt.leadScale + + for destLen > l { + mStr = "0" + mStr + destLen-- + } + } + + interval += "'" + mStr + "' MINUTE(" + strconv.FormatInt(int64(dt.leadScale), 10) + ")" + case QUA_MS: + nStr = dt.getMsecString() + mStr = strconv.FormatInt(int64(float64(dt.minutes)), 10) + sStr = strconv.FormatInt(int64(float64(dt.seconds)), 10) + + if dt.negative { + interval += "-" + } + + if len(mStr) < dt.leadScale { + l = len(mStr) + destLen = dt.leadScale + + for destLen > l { + mStr = "0" + mStr + destLen-- + } + } + if len(sStr) < 2 { + sStr = "0" + sStr + } + interval += "'" + mStr + ":" + sStr + if nStr != "" { + interval += "." + nStr + } + + interval += "' MINUTE(" + strconv.FormatInt(int64(dt.leadScale), 10) + ") TO SECOND(" + strconv.FormatInt(int64(dt.secScale), 10) + ")" + case QUA_S: + nStr = dt.getMsecString() + sStr = strconv.FormatInt(int64(float64(dt.seconds)), 10) + + if dt.negative { + interval += "-" + } + + if len(sStr) < dt.leadScale { + l = len(sStr) + destLen = dt.leadScale + + for destLen > l { + sStr = "0" + sStr + destLen-- + } + } + + interval += "'" + sStr + + if nStr != "" { + interval += "." + nStr + } + + interval += "' SECOND(" + strconv.FormatInt(int64(dt.leadScale), 10) + ", " + strconv.FormatInt(int64(dt.secScale), 10) + ")" + + } + + return interval +} + +func (dest *DmIntervalDT) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmIntervalDT) + + (*dest).Valid = false + return nil + case *DmIntervalDT: + *dest = *src + return nil + case string: + ret, err := NewDmIntervalDTByString(src) + if err != nil { + return err + } + *dest = *ret + return nil + default: + return UNSUPPORTED_SCAN + } +} + +func (dt DmIntervalDT) Value() (driver.Value, error) { + if !dt.Valid { + return nil, nil + } + return dt, nil +} + +func (dt *DmIntervalDT) checkScale(leadScale int) (int, error) { + switch dt._type { + case QUA_D: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_DH: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + if int64(math.Abs(float64((dt.hours)))) > 23 { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_DHM: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + if int64(math.Abs(float64(dt.hours))) > 23 || int64(math.Abs(float64(dt.minutes))) > 59 { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_DHMS: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + if int64(math.Abs(float64(dt.hours))) > 23 || int64(math.Abs(float64(dt.minutes))) > 59 || + int64(math.Abs(float64(dt.seconds))) > 59 { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_H: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.hours))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.hours))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_HM: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.hours))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.hours))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + if int64(math.Abs(float64(dt.minutes))) > 59 { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_HMS: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.hours))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.hours))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + if int64(math.Abs(float64(dt.minutes))) > 59 || int64(math.Abs(float64(dt.seconds))) > 59 { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_M: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.minutes))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.minutes))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_MS: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.minutes))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.minutes))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + if int64(math.Abs(float64(dt.seconds))) > 59 { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + case QUA_S: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.minutes))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.minutes))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + } + + if leadScale > LOADPREC_MAX { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + return leadScale, nil +} + +func (dt *DmIntervalDT) parsePrec(leadStr string) (int, error) { + leftBtId := strings.Index(leadStr, "(") + rightBtId := strings.Index(leadStr, ")") + var prec int64 = -1 + + if rightBtId != -1 && leftBtId != -1 && rightBtId > leftBtId+1 { + strPrec := strings.TrimSpace(leadStr[leftBtId+1 : rightBtId]) + var err error + prec, err = strconv.ParseInt(strPrec, 10, 32) + if err != nil { + return -1, err + } + } + + return int(prec), nil +} + +func (dt *DmIntervalDT) setPrecForSvr(fullStr string, leadScale string, secScale string) error { + prec, err := dt.parsePrec(leadScale) + if err != nil { + return err + } + + prec, err = dt.checkScale(prec) + if err != nil { + return err + } + + if prec < LOADPREC_DEFAULT { + dt.leadScale = LOADPREC_DEFAULT + } else { + dt.leadScale = prec + } + + prec, err = dt.parsePrec(secScale) + if err != nil { + return err + } + + if prec >= 0 && prec < SECDPREC_MAX { + dt.secScale = prec + } else { + dt.secScale = SECDPREC_DEFAULT + } + + dt.scaleForSvr = int(dt._type<<8) + (dt.leadScale << 4) + dt.secScale + return nil +} + +func (dt *DmIntervalDT) checkSign(str string) string { + + if str[0] == '-' { + str = strings.TrimSpace(str[1:]) + dt.negative = true + } else if str[0] == '+' { + str = strings.TrimSpace(str[1:]) + dt.negative = false + } + + return str +} + +func (dt *DmIntervalDT) setDay(value string) error { + list := util.Split(value, " :.") + if len(list) > 1 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_D + i, err := strconv.ParseInt(value, 10, 32) + if err != nil { + return err + } + + if i < 0 { + dt.days = int(-i) + dt.negative = true + } else { + dt.days = int(i) + } + return nil +} + +func (dt *DmIntervalDT) setHour(value string) error { + list := util.Split(value, " :.") + if len(list) > 1 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_H + i, err := strconv.ParseInt(value, 10, 32) + if err != nil { + return err + } + + if i < 0 { + dt.hours = int(-i) + dt.negative = true + } else { + dt.hours = int(i) + } + return nil +} + +func (dt *DmIntervalDT) setMinute(value string) error { + list := util.Split(value, " :.") + if len(list) > 1 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_M + i, err := strconv.ParseInt(value, 10, 32) + if err != nil { + return err + } + + if i < 0 { + dt.minutes = int(-i) + dt.negative = true + } else { + dt.minutes = int(i) + } + return nil +} + +func (dt *DmIntervalDT) setSecond(value string) error { + list := util.Split(value, " :.") + if len(list) > 2 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_S + i, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + nano := 0 + if len(list) > 1 { + strNano := "0" + "." + list[1] + d_v, err := strconv.ParseFloat(strNano, 64) + if err != nil { + return err + } + nx := math.Pow10(dt.secScale) + nano = (int)(d_v * nx) + } + + if i < 0 { + dt.seconds = int(-i) + } else { + dt.seconds = int(i) + } + if nano < 0 { + dt.fraction = -nano + } else { + dt.fraction = nano + } + if i < 0 || nano < 0 { + dt.negative = true + } + return nil + +} + +func (dt *DmIntervalDT) setHourToSecond(value string) error { + list := util.Split(value, " :.") + if len(list) > 4 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_HMS + + h, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + m, err := strconv.ParseInt(list[1], 10, 32) + if err != nil { + return err + } + + s, err := strconv.ParseInt(list[2], 10, 32) + if err != nil { + return err + } + nano := 0 + if len(list) > 3 { + strNano := "0" + "." + list[3] + d_v, err := strconv.ParseFloat(strNano, 64) + if err != nil { + return err + } + nx := math.Pow10(dt.secScale) + nano = (int)(d_v * nx) + } + + if h < 0 { + dt.hours = int(-h) + } else { + dt.hours = int(h) + } + if m < 0 { + dt.minutes = int(-m) + } else { + dt.minutes = int(m) + } + if s < 0 { + dt.seconds = int(-s) + } else { + dt.seconds = int(s) + } + if nano < 0 { + dt.fraction = -nano + } else { + dt.fraction = nano + } + if h < 0 || m < 0 || s < 0 || nano < 0 { + dt.negative = true + } + return nil +} + +func (dt *DmIntervalDT) setHourToMinute(value string) error { + value = strings.TrimSpace(value) + list := util.Split(value, " :.") + if len(list) > 2 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_HM + + h, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + m, err := strconv.ParseInt(list[1], 10, 32) + if err != nil { + return err + } + + if h < 0 { + dt.hours = int(-h) + } else { + dt.hours = int(h) + } + if m < 0 { + dt.minutes = int(-m) + } else { + dt.minutes = int(m) + } + if h < 0 || m < 0 { + dt.negative = true + } + return nil +} + +func (dt *DmIntervalDT) setMinuteToSecond(value string) error { + list := util.Split(value, " :.") + if len(list) > 3 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_MS + + m, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + s, err := strconv.ParseInt(list[1], 10, 32) + if err != nil { + return err + } + + nano := 0 + if len(list) > 2 { + strNano := "0" + "." + list[2] + d_v, err := strconv.ParseFloat(strNano, 64) + if err != nil { + return err + } + + nx := math.Pow10(dt.secScale) + nano = (int)(d_v * nx) + } + + if m < 0 { + dt.minutes = int(-m) + } else { + dt.minutes = int(m) + } + if s < 0 { + dt.seconds = int(-s) + } else { + dt.seconds = int(s) + } + if nano < 0 { + dt.fraction = -nano + } else { + dt.fraction = nano + } + if m < 0 || s < 0 || nano < 0 { + dt.negative = true + } + return nil +} + +func (dt *DmIntervalDT) setDayToHour(value string) error { + list := util.Split(value, " :.") + if len(list) > 2 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_DH + + d, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + h, err := strconv.ParseInt(list[1], 10, 32) + if err != nil { + return err + } + + if d < 0 { + dt.days = int(-d) + } else { + dt.days = int(d) + } + if h < 0 { + dt.hours = int(-h) + } else { + dt.hours = int(h) + } + if d < 0 || h < 0 { + dt.negative = true + } + return nil +} + +func (dt *DmIntervalDT) setDayToMinute(value string) error { + list := util.Split(value, " :.") + if len(list) > 3 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_DHM + + d, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + h, err := strconv.ParseInt(list[1], 10, 32) + if err != nil { + return err + } + + m, err := strconv.ParseInt(list[2], 10, 32) + if err != nil { + return err + } + + if d < 0 { + dt.days = int(-d) + } else { + dt.days = int(d) + } + if h < 0 { + dt.hours = int(-h) + } else { + dt.hours = int(h) + } + if m < 0 { + dt.minutes = int(-m) + } else { + dt.minutes = int(m) + } + if d < 0 || h < 0 || m < 0 { + dt.negative = true + } + return nil +} + +func (dt *DmIntervalDT) setDayToSecond(value string) error { + list := util.Split(value, " :.") + if len(list) > 5 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_DHMS + + d, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + h, err := strconv.ParseInt(list[1], 10, 32) + if err != nil { + return err + } + + m, err := strconv.ParseInt(list[2], 10, 32) + if err != nil { + return err + } + + s, err := strconv.ParseInt(list[3], 10, 32) + if err != nil { + return err + } + + nano := 0 + if len(list) > 4 { + strNano := "0" + "." + list[4] + d_v, err := strconv.ParseFloat(strNano, 64) + if err != nil { + return err + } + + nx := math.Pow10(dt.secScale) + nano = (int)(d_v * nx) + } + + if d < 0 { + dt.days = int(-d) + } else { + dt.days = int(d) + } + if h < 0 { + dt.hours = int(-h) + } else { + dt.hours = int(h) + } + if m < 0 { + dt.minutes = int(-m) + } else { + dt.minutes = int(m) + } + if s < 0 { + dt.seconds = int(-s) + } else { + dt.seconds = int(s) + } + if nano < 0 { + dt.fraction = -nano + } else { + dt.fraction = nano + } + if d < 0 || h < 0 || m < 0 || s < 0 || nano < 0 { + dt.negative = true + } + return nil +} + +func (dt *DmIntervalDT) getMsecString() string { + nano := strconv.Itoa(dt.fraction) + + for i := 6 - len(nano); i > 0; i-- { + nano = "0" + nano + } + + if len(nano) > dt.secScale { + nano = nano[:dt.secScale] + } + + return nano +} + +func (dt *DmIntervalDT) encode(scale int) ([]byte, error) { + if scale == 0 { + scale = dt.scaleForSvr + } + day, hour, minute, second, f := dt.days, dt.hours, dt.minutes, dt.seconds, dt.fraction + if scale != dt.scaleForSvr { + convertDT, err := dt.convertTo(scale) + if err != nil { + return nil, err + } + day, hour, minute, second, f = convertDT.days, convertDT.hours, convertDT.minutes, convertDT.seconds, convertDT.fraction + } else { + loadPrec := (scale >> 4) & 0x0000000F + if _, err := dt.checkScale(loadPrec); err != nil { + return nil, err + } + } + + bytes := make([]byte, 24) + if dt.negative { + Dm_build_1220.Dm_build_1236(bytes, 0, int32(-day)) + Dm_build_1220.Dm_build_1236(bytes, 4, int32(-hour)) + Dm_build_1220.Dm_build_1236(bytes, 8, int32(-minute)) + Dm_build_1220.Dm_build_1236(bytes, 12, int32(-second)) + Dm_build_1220.Dm_build_1236(bytes, 16, int32(-f)) + Dm_build_1220.Dm_build_1236(bytes, 20, int32(scale)) + } else { + Dm_build_1220.Dm_build_1236(bytes, 0, int32(day)) + Dm_build_1220.Dm_build_1236(bytes, 4, int32(hour)) + Dm_build_1220.Dm_build_1236(bytes, 8, int32(minute)) + Dm_build_1220.Dm_build_1236(bytes, 12, int32(second)) + Dm_build_1220.Dm_build_1236(bytes, 16, int32(f)) + Dm_build_1220.Dm_build_1236(bytes, 20, int32(scale)) + } + return bytes, nil +} + +func (dt *DmIntervalDT) convertTo(scale int) (*DmIntervalDT, error) { + destType := (scale & 0x0000FF00) >> 8 + leadPrec := (scale >> 4) & 0x0000000F + secScale := scale & 0x0000000F + dayIndex := 0 + hourIndex := 1 + minuteIndex := 2 + secondIndex := 3 + fractionIndex := 4 + orgDT := make([]int, 5) + destDT := make([]int, 5) + + switch dt._type { + case QUA_D: + orgDT[dayIndex] = dt.days + case QUA_DH: + orgDT[dayIndex] = dt.days + orgDT[hourIndex] = dt.hours + case QUA_DHM: + orgDT[dayIndex] = dt.days + orgDT[hourIndex] = dt.hours + orgDT[minuteIndex] = dt.minutes + case QUA_DHMS: + orgDT[dayIndex] = dt.days + orgDT[hourIndex] = dt.hours + orgDT[minuteIndex] = dt.minutes + orgDT[secondIndex] = dt.seconds + orgDT[fractionIndex] = dt.fraction + case QUA_H: + orgDT[dayIndex] = dt.hours / 24 + orgDT[hourIndex] = dt.hours % 24 + case QUA_HM: + orgDT[dayIndex] = dt.hours / 24 + orgDT[hourIndex] = dt.hours % 24 + orgDT[minuteIndex] = dt.minutes + case QUA_HMS: + orgDT[dayIndex] = dt.hours / 24 + orgDT[hourIndex] = dt.hours % 24 + orgDT[minuteIndex] = dt.minutes + orgDT[secondIndex] = dt.seconds + orgDT[fractionIndex] = dt.fraction + case QUA_M: + orgDT[dayIndex] = dt.minutes / (24 * 60) + orgDT[hourIndex] = (dt.minutes % (24 * 60)) / 60 + orgDT[minuteIndex] = (dt.minutes % (24 * 60)) % 60 + case QUA_MS: + orgDT[dayIndex] = dt.minutes / (24 * 60) + orgDT[hourIndex] = (dt.minutes % (24 * 60)) / 60 + orgDT[minuteIndex] = (dt.minutes % (24 * 60)) % 60 + orgDT[secondIndex] = dt.seconds + orgDT[fractionIndex] = dt.fraction + case QUA_S: + orgDT[dayIndex] = dt.seconds / (24 * 60 * 60) + orgDT[hourIndex] = (dt.seconds % (24 * 60 * 60)) / (60 * 60) + orgDT[minuteIndex] = ((dt.seconds % (24 * 60 * 60)) % (60 * 60)) / 60 + orgDT[secondIndex] = ((dt.seconds % (24 * 60 * 60)) % (60 * 60)) % 60 + orgDT[fractionIndex] = dt.fraction + } + + switch byte(destType) { + case QUA_D: + destDT[dayIndex] = orgDT[dayIndex] + if orgDT[hourIndex] >= 12 { + incrementDay(QUA_D, destDT) + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[dayIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_DH: + destDT[dayIndex] = orgDT[dayIndex] + destDT[hourIndex] = orgDT[hourIndex] + if orgDT[minuteIndex] >= 30 { + incrementHour(QUA_DH, destDT) + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[dayIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_DHM: + destDT[dayIndex] = orgDT[dayIndex] + destDT[hourIndex] = orgDT[hourIndex] + destDT[minuteIndex] = orgDT[minuteIndex] + if orgDT[secondIndex] >= 30 { + incrementMinute(QUA_DHM, destDT) + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[dayIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_DHMS: + destDT[dayIndex] = orgDT[dayIndex] + destDT[hourIndex] = orgDT[hourIndex] + destDT[minuteIndex] = orgDT[minuteIndex] + destDT[secondIndex] = orgDT[secondIndex] + destDT[fractionIndex] = orgDT[fractionIndex] + dt.convertMSecond(QUA_DHMS, destDT, secScale) + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[dayIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_H: + destDT[hourIndex] = orgDT[dayIndex]*24 + orgDT[hourIndex] + if orgDT[minuteIndex] >= 30 { + incrementHour(QUA_H, destDT) + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[hourIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_HM: + destDT[hourIndex] = orgDT[dayIndex]*24 + orgDT[hourIndex] + destDT[minuteIndex] = orgDT[minuteIndex] + if orgDT[secondIndex] >= 30 { + incrementMinute(QUA_HM, destDT) + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[hourIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_HMS: + destDT[hourIndex] = orgDT[dayIndex]*24 + orgDT[hourIndex] + destDT[minuteIndex] = orgDT[minuteIndex] + destDT[secondIndex] = orgDT[secondIndex] + destDT[fractionIndex] = orgDT[fractionIndex] + dt.convertMSecond(QUA_HMS, destDT, secScale) + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[hourIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_M: + destDT[minuteIndex] = orgDT[dayIndex]*24*60 + orgDT[hourIndex]*60 + orgDT[minuteIndex] + if orgDT[secondIndex] >= 30 { + incrementMinute(QUA_M, destDT) + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[minuteIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_MS: + destDT[minuteIndex] = orgDT[dayIndex]*24*60 + orgDT[hourIndex]*60 + orgDT[minuteIndex] + destDT[secondIndex] = orgDT[secondIndex] + destDT[fractionIndex] = orgDT[fractionIndex] + dt.convertMSecond(QUA_MS, destDT, secScale) + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[minuteIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_S: + destDT[secondIndex] = orgDT[dayIndex]*24*60*60 + orgDT[hourIndex]*60*60 + orgDT[minuteIndex]*60 + orgDT[secondIndex] + destDT[fractionIndex] = orgDT[fractionIndex] + dt.convertMSecond(QUA_S, destDT, secScale) + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[secondIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + } + + return &DmIntervalDT{ + _type: byte(destType), + negative: dt.negative, + leadScale: (scale >> 4) & 0x0000000F, + secScale: scale & 0x0000000F, + scaleForSvr: scale, + days: destDT[dayIndex], + hours: destDT[hourIndex], + minutes: destDT[minuteIndex], + seconds: destDT[secondIndex], + fraction: destDT[fractionIndex], + Valid: true, + }, nil +} + +func (dt DmIntervalDT) convertMSecond(destType byte, destDT []int, destSecScale int) { + fractionIndex := 4 + orgFraction := destDT[fractionIndex] + if destSecScale == 0 || destSecScale < dt.secScale { + n := int(math.Pow(10, 6-float64(destSecScale)-1)) + f := orgFraction / n / 10 + + if (orgFraction/n)%10 >= 5 { + f++ + f = f * n * 10 + if f == 1000000 { + destDT[fractionIndex] = 0 + incrementSecond(destType, destDT) + return + } + } + destDT[fractionIndex] = f + } +} + +func incrementDay(destType byte, dt []int) { + dayIndex := 0 + dt[dayIndex]++ +} + +func incrementHour(destType byte, dt []int) { + hourIndex := 1 + dt[hourIndex]++ + if dt[hourIndex] == 24 && destType < QUA_H { + incrementDay(destType, dt) + dt[hourIndex] = 0 + } +} + +func incrementMinute(destType byte, dt []int) { + minuteIndex := 2 + dt[minuteIndex]++ + if dt[minuteIndex] == 60 && destType < QUA_M { + incrementHour(destType, dt) + dt[minuteIndex] = 0 + } +} + +func incrementSecond(destType byte, dt []int) { + secondIndex := 3 + dt[secondIndex]++ + if dt[secondIndex] == 60 && destType < QUA_S { + incrementMinute(destType, dt) + dt[secondIndex] = 0 + } +} + +func (dt *DmIntervalDT) checkValid() error { + if !dt.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} diff --git a/dmr/r.go b/dmr/r.go new file mode 100644 index 0000000..912e58d --- /dev/null +++ b/dmr/r.go @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "database/sql/driver" + "math" + "strconv" + "strings" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +const ( + QUA_Y = 0 + QUA_YM = 1 + QUA_MO = 2 +) + +type DmIntervalYM struct { + leadScale int + isLeadScaleSet bool + _type byte + years int + months int + scaleForSvr int + + Valid bool +} + +func newDmIntervalYM() *DmIntervalYM { + return &DmIntervalYM{ + Valid: true, + } +} + +func NewDmIntervalYMByString(str string) (ym *DmIntervalYM, err error) { + defer func() { + if p := recover(); p != nil { + err = ECGO_INVALID_TIME_INTERVAL.throw() + } + }() + ym = newDmIntervalYM() + ym.isLeadScaleSet = false + if err = ym.parseIntervYMString(strings.TrimSpace(str)); err != nil { + return nil, err + } + return ym, nil +} + +func newDmIntervalYMByBytes(bytes []byte) *DmIntervalYM { + ym := newDmIntervalYM() + + ym.scaleForSvr = int(Dm_build_1220.Dm_build_1322(bytes, 8)) + ym.leadScale = (ym.scaleForSvr >> 4) & 0x0000000F + ym._type = bytes[9] + switch ym._type { + case QUA_Y: + ym.years = int(Dm_build_1220.Dm_build_1322(bytes, 0)) + case QUA_YM: + ym.years = int(Dm_build_1220.Dm_build_1322(bytes, 0)) + ym.months = int(Dm_build_1220.Dm_build_1322(bytes, 4)) + case QUA_MO: + ym.months = int(Dm_build_1220.Dm_build_1322(bytes, 4)) + } + return ym +} + +func (ym *DmIntervalYM) GetYear() int { + return ym.years +} + +func (ym *DmIntervalYM) GetMonth() int { + return ym.months +} + +func (ym *DmIntervalYM) GetYMType() byte { + return ym._type +} + +func (ym *DmIntervalYM) String() string { + if !ym.Valid { + return "" + } + str := "INTERVAL " + var year, month string + var l int + var destLen int + + switch ym._type { + case QUA_Y: + year = strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10) + if ym.years < 0 { + str += "-" + } + + if ym.leadScale > len(year) { + l = len(year) + destLen = ym.leadScale + + for destLen > l { + year = "0" + year + destLen-- + } + } + + str += "'" + year + "' YEAR(" + strconv.FormatInt(int64(ym.leadScale), 10) + ")" + case QUA_YM: + year = strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10) + month = strconv.FormatInt(int64(math.Abs(float64(ym.months))), 10) + + if ym.years < 0 || ym.months < 0 { + str += "-" + } + + if ym.leadScale > len(year) { + l = len(year) + destLen = ym.leadScale + + for destLen > l { + year = "0" + year + destLen-- + } + } + + if len(month) < 2 { + month = "0" + month + } + + str += "'" + year + "-" + month + "' YEAR(" + strconv.FormatInt(int64(ym.leadScale), 10) + ") TO MONTH" + case QUA_MO: + + month = strconv.FormatInt(int64(math.Abs(float64(ym.months))), 10) + if ym.months < 0 { + str += "-" + } + + if ym.leadScale > len(month) { + l = len(month) + destLen = ym.leadScale + for destLen > l { + month = "0" + month + destLen-- + } + } + + str += "'" + month + "' MONTH(" + strconv.FormatInt(int64(ym.leadScale), 10) + ")" + } + return str +} + +func (dest *DmIntervalYM) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmIntervalYM) + + (*dest).Valid = false + return nil + case *DmIntervalYM: + *dest = *src + return nil + case string: + ret, err := NewDmIntervalYMByString(src) + if err != nil { + return err + } + *dest = *ret + return nil + default: + return UNSUPPORTED_SCAN + } +} + +func (ym DmIntervalYM) Value() (driver.Value, error) { + if !ym.Valid { + return nil, nil + } + return ym, nil +} + +func (ym *DmIntervalYM) parseIntervYMString(str string) error { + str = strings.ToUpper(str) + ret := strings.Split(str, " ") + l := len(ret) + if l < 3 || !util.StringUtil.EqualsIgnoreCase(ret[0], "INTERVAL") || !(strings.HasPrefix(ret[2], "YEAR") || strings.HasPrefix(ret[2], "MONTH")) { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + ym._type = QUA_YM + yearId := strings.Index(str, "YEAR") + monthId := strings.Index(str, "MONTH") + toId := strings.Index(str, "TO") + var err error + if toId == -1 { + if yearId != -1 && monthId == -1 { + ym._type = QUA_Y + ym.leadScale, err = ym.getLeadPrec(str, yearId) + if err != nil { + return err + } + } else if monthId != -1 && yearId == -1 { + ym._type = QUA_MO + ym.leadScale, err = ym.getLeadPrec(str, monthId) + if err != nil { + return err + } + } else { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + if yearId == -1 || monthId == -1 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + ym._type = QUA_YM + ym.leadScale, err = ym.getLeadPrec(str, yearId) + if err != nil { + return err + } + } + + ym.scaleForSvr = (int(ym._type) << 8) + (ym.leadScale << 4) + timeVals, err := ym.getTimeValue(ret[1], int(ym._type)) + if err != nil { + return err + } + ym.years = timeVals[0] + ym.months = timeVals[1] + return ym.checkScale(ym.leadScale) +} + +func (ym *DmIntervalYM) getLeadPrec(str string, startIndex int) (int, error) { + if ym.isLeadScaleSet { + return ym.leadScale, nil + } + + leftBtId := strings.Index(str[startIndex:], "(") + rightBtId := strings.Index(str[startIndex:], ")") + leadPrec := 0 + + if rightBtId == -1 && leftBtId == -1 { + leftBtId += startIndex + rightBtId += startIndex + l := strings.Index(str, "'") + var r int + var dataStr string + if l != -1 { + r = strings.Index(str[l+1:], "'") + if r != -1 { + r += l + 1 + } + } else { + r = -1 + } + + if r != -1 { + dataStr = strings.TrimSpace(str[l+1 : r]) + } else { + dataStr = "" + } + + if dataStr != "" { + sign := dataStr[0] + if sign == '+' || sign == '-' { + dataStr = strings.TrimSpace(dataStr[1:]) + } + end := strings.Index(dataStr, "-") + + if end != -1 { + dataStr = dataStr[:end] + } + + leadPrec = len(dataStr) + } else { + leadPrec = 2 + } + } else if rightBtId != -1 && leftBtId != -1 && rightBtId > leftBtId+1 { + leftBtId += startIndex + rightBtId += startIndex + strPrec := strings.TrimSpace(str[leftBtId+1 : rightBtId]) + temp, err := strconv.ParseInt(strPrec, 10, 32) + if err != nil { + return 0, err + } + + leadPrec = int(temp) + } else { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + return leadPrec, nil +} + +func (ym *DmIntervalYM) checkScale(prec int) error { + switch ym._type { + case QUA_Y: + if prec < len(strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10)) { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + case QUA_YM: + if prec < len(strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10)) { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + + if int64(math.Abs(float64(ym.months))) > 11 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_MO: + if prec < len(strconv.FormatInt(int64(math.Abs(float64(ym.months))), 10)) { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + } + return nil +} + +func (ym *DmIntervalYM) getTimeValue(subStr string, _type int) ([]int, error) { + hasQuate := false + if subStr[0] == '\'' && subStr[len(subStr)-1] == '\'' { + hasQuate = true + subStr = strings.TrimSpace(subStr[1 : len(subStr)-1]) + } + + negative := false + if strings.Index(subStr, "-") == 0 { + negative = true + subStr = subStr[1:] + } else if strings.Index(subStr, "+") == 0 { + negative = false + subStr = subStr[1:] + } + + if subStr[0] == '\'' && subStr[len(subStr)-1] == '\'' { + hasQuate = true + subStr = strings.TrimSpace(subStr[1 : len(subStr)-1]) + } + + if !hasQuate { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + + lastSignIndex := strings.LastIndex(subStr, "-") + + list := make([]string, 2) + if lastSignIndex == -1 || lastSignIndex == 0 { + list[0] = subStr + list[1] = "" + } else { + list[0] = subStr[0:lastSignIndex] + list[1] = subStr[lastSignIndex+1:] + } + + var yearVal, monthVal int64 + var err error + if ym._type == QUA_YM { + yearVal, err = strconv.ParseInt(list[0], 10, 32) + if err != nil { + return nil, err + } + + if util.StringUtil.EqualsIgnoreCase(list[1], "") { + monthVal = 0 + } else { + monthVal, err = strconv.ParseInt(list[1], 10, 32) + if err != nil { + return nil, err + } + } + + if negative { + yearVal *= -1 + monthVal *= -1 + } + + if yearVal > int64(math.Pow10(ym.leadScale))-1 || yearVal < 1-int64(math.Pow10(ym.leadScale)) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else if ym._type == QUA_Y { + yearVal, err = strconv.ParseInt(list[0], 10, 32) + if err != nil { + return nil, err + } + monthVal = 0 + + if negative { + yearVal *= -1 + } + + if yearVal > int64(math.Pow10(ym.leadScale))-1 || yearVal < 1-int64(math.Pow10(ym.leadScale)) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + yearVal = 0 + monthVal, err = strconv.ParseInt(list[0], 10, 32) + if err != nil { + return nil, err + } + if negative { + monthVal *= -1 + } + + if monthVal > int64(math.Pow10(ym.leadScale))-1 || monthVal < 1-int64(math.Pow10(ym.leadScale)) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } + + ret := make([]int, 2) + ret[0] = int(yearVal) + ret[1] = int(monthVal) + + return ret, nil +} + +func (ym *DmIntervalYM) encode(scale int) ([]byte, error) { + if scale == 0 { + scale = ym.scaleForSvr + } + year, month := ym.years, ym.months + if err := ym.checkScale(ym.leadScale); err != nil { + return nil, err + } + if scale != ym.scaleForSvr { + convertYM, err := ym.convertTo(scale) + if err != nil { + return nil, err + } + year = convertYM.years + month = convertYM.months + } else { + if err := ym.checkScale(ym.leadScale); err != nil { + return nil, err + } + } + + bytes := make([]byte, 12) + Dm_build_1220.Dm_build_1236(bytes, 0, int32(year)) + Dm_build_1220.Dm_build_1236(bytes, 4, int32(month)) + Dm_build_1220.Dm_build_1236(bytes, 8, int32(scale)) + return bytes, nil +} + +func (ym *DmIntervalYM) convertTo(scale int) (*DmIntervalYM, error) { + destType := (scale & 0x0000FF00) >> 8 + leadPrec := (scale >> 4) & 0x0000000F + totalMonths := ym.years*12 + ym.months + year := 0 + month := 0 + switch destType { + case QUA_Y: + year = totalMonths / 12 + + if totalMonths%12 >= 6 { + year++ + } else if totalMonths%12 <= -6 { + year-- + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(year))))) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + case QUA_YM: + year = totalMonths / 12 + month = totalMonths % 12 + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(year))))) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + case QUA_MO: + month = totalMonths + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(month))))) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } + return &DmIntervalYM{ + _type: byte(destType), + years: year, + months: month, + scaleForSvr: scale, + leadScale: (scale >> 4) & 0x0000000F, + Valid: true, + }, nil +} + +func (ym *DmIntervalYM) checkValid() error { + if !ym.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} diff --git a/dmr/s.go b/dmr/s.go new file mode 100644 index 0000000..b9f50bc --- /dev/null +++ b/dmr/s.go @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +type DmResult struct { + filterable + dmStmt *DmStatement + affectedRows int64 + insertId int64 +} + +func newDmResult(bs *DmStatement, execInfo *execRetInfo) *DmResult { + result := DmResult{} + result.resetFilterable(&bs.filterable) + result.dmStmt = bs + result.affectedRows = execInfo.updateCount + result.insertId = execInfo.lastInsertId + result.idGenerator = dmResultIDGenerator + + return &result +} + +/************************************************************* + ** PUBLIC METHODS AND FUNCTIONS + *************************************************************/ +func (r *DmResult) LastInsertId() (int64, error) { + //if err := r.dmStmt.checkClosed(); err != nil { + // return -1, err + //} + if len(r.filterChain.filters) == 0 { + return r.lastInsertId() + } + return r.filterChain.reset().DmResultLastInsertId(r) +} + +func (r *DmResult) RowsAffected() (int64, error) { + //if err := r.dmStmt.checkClosed(); err != nil { + // return -1, err + //} + if len(r.filterChain.filters) == 0 { + return r.rowsAffected() + } + return r.filterChain.reset().DmResultRowsAffected(r) +} + +func (result *DmResult) lastInsertId() (int64, error) { + return result.insertId, nil +} + +func (result *DmResult) rowsAffected() (int64, error) { + return result.affectedRows, nil +} diff --git a/dmr/security/zy.go b/dmr/security/zy.go new file mode 100644 index 0000000..5a1db64 --- /dev/null +++ b/dmr/security/zy.go @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +// This is a mirror of golang.org/x/crypto/internal/subtle. +package security + +import "unsafe" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && + uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} \ No newline at end of file diff --git a/dmr/security/zz.go b/dmr/security/zz.go new file mode 100644 index 0000000..45b2c1a --- /dev/null +++ b/dmr/security/zz.go @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +type Cipher interface { + Encrypt(plaintext []byte, genDigest bool) []byte + Decrypt(ciphertext []byte, checkDigest bool) ([]byte, error) +} diff --git a/dmr/security/zza.go b/dmr/security/zza.go new file mode 100644 index 0000000..92062ce --- /dev/null +++ b/dmr/security/zza.go @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import ( + "crypto/rand" + "errors" + "io" + "math/big" +) + +type dhGroup struct { + p *big.Int + g *big.Int +} + +func newDhGroup(prime, generator *big.Int) *dhGroup { + return &dhGroup{ + p: prime, + g: generator, + } +} + +func (dg *dhGroup) P() *big.Int { + p := new(big.Int) + p.Set(dg.p) + return p +} + +func (dg *dhGroup) G() *big.Int { + g := new(big.Int) + g.Set(dg.g) + return g +} + +// 生成本地公私钥 +func (dg *dhGroup) GeneratePrivateKey(randReader io.Reader) (key *DhKey, err error) { + if randReader == nil { + randReader = rand.Reader + } + // 0 < x < p + x, err := rand.Int(randReader, dg.p) + if err != nil { + return + } + zero := big.NewInt(0) + for x.Cmp(zero) == 0 { + x, err = rand.Int(randReader, dg.p) + if err != nil { + return + } + } + key = new(DhKey) + key.x = x + + // y = g ^ x mod p + key.y = new(big.Int).Exp(dg.g, x, dg.p) + key.group = dg + return +} + +func (dg *dhGroup) ComputeKey(pubkey *DhKey, privkey *DhKey) (kye *DhKey, err error) { + if dg.p == nil { + err = errors.New("DH: invalid group") + return + } + if pubkey.y == nil { + err = errors.New("DH: invalid public key") + return + } + if pubkey.y.Sign() <= 0 || pubkey.y.Cmp(dg.p) >= 0 { + err = errors.New("DH parameter out of bounds") + return + } + if privkey.x == nil { + err = errors.New("DH: invalid private key") + return + } + k := new(big.Int).Exp(pubkey.y, privkey.x, dg.p) + key := new(DhKey) + key.y = k + key.group = dg + return +} diff --git a/dmr/security/zzb.go b/dmr/security/zzb.go new file mode 100644 index 0000000..f9af994 --- /dev/null +++ b/dmr/security/zzb.go @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import "math/big" + +type DhKey struct { + x *big.Int + y *big.Int + group *dhGroup +} + +func newPublicKey(s []byte) *DhKey { + key := new(DhKey) + key.y = new(big.Int).SetBytes(s) + return key +} + +func (dk *DhKey) GetX() *big.Int { + x := new(big.Int) + x.Set(dk.x) + return x +} + +func (dk *DhKey) GetY() *big.Int { + y := new(big.Int) + y.Set(dk.y) + return y +} + +func (dk *DhKey) GetYBytes() []byte { + if dk.y == nil { + return nil + } + if dk.group != nil { + blen := (dk.group.p.BitLen() + 7) / 8 + ret := make([]byte, blen) + copyWithLeftPad(ret, dk.y.Bytes()) + return ret + } + return dk.y.Bytes() +} + +func (dk *DhKey) GetYString() string { + if dk.y == nil { + return "" + } + return dk.y.String() +} + +func (dk *DhKey) IsPrivateKey() bool { + return dk.x != nil +} + +func copyWithLeftPad(dest, src []byte) { + numPaddingBytes := len(dest) - len(src) + for i := 0; i < numPaddingBytes; i++ { + dest[i] = 0 + } + copy(dest[:numPaddingBytes], src) +} diff --git a/dmr/security/zzc.go b/dmr/security/zzc.go new file mode 100644 index 0000000..3841d68 --- /dev/null +++ b/dmr/security/zzc.go @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +// go官方没有实现ecb加密模式 +package security + +import ( + "crypto/cipher" +) + +type ecb struct { + b cipher.Block + blockSize int +} + +func newECB(b cipher.Block) *ecb { + return &ecb { + b: b, + blockSize: b.BlockSize(), + } +} + +type ecbEncrypter ecb + +func NewECBEncrypter(b cipher.Block) cipher.BlockMode { + return (*ecbEncrypter)(newECB(b)) +} + +func (x *ecbEncrypter) BlockSize() int { return x.blockSize } + +func (x *ecbEncrypter) CryptBlocks(dst, src []byte) { + if len(src)%x.blockSize != 0 { + panic("dm/security: input not full blocks") + } + if len(dst) < len(src) { + panic("dm/security: output smaller than input") + } + if InexactOverlap(dst[:len(src)], src) { + panic("dm/security: invalid buffer overlap") + } + for bs, be := 0, x.blockSize; bs < len(src); bs, be = bs + x.blockSize, be + x.blockSize { + x.b.Encrypt(dst[bs:be], src[bs:be]) + } +} + +type ecbDecrypter ecb + +func NewECBDecrypter(b cipher.Block) cipher.BlockMode { + return (*ecbDecrypter)(newECB(b)) +} + +func (x *ecbDecrypter) BlockSize() int { return x.blockSize } + +func (x *ecbDecrypter) CryptBlocks(dst, src []byte) { + if len(src)%x.blockSize != 0 { + panic("dm/security: input not full blocks") + } + if len(dst) < len(src) { + panic("dm/security: output smaller than input") + } + if InexactOverlap(dst[:len(src)], src) { + panic("dm/security: invalid buffer overlap") + } + for bs, be := 0, x.blockSize; bs < len(src); bs, be = bs + x.blockSize, be + x.blockSize { + x.b.Decrypt(dst[bs:be], src[bs:be]) + } +} diff --git a/dmr/security/zzd.go b/dmr/security/zzd.go new file mode 100644 index 0000000..bedbc54 --- /dev/null +++ b/dmr/security/zzd.go @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import ( + "math/big" +) + +const ( + DH_KEY_LENGTH int = 64 + /* 低7位用于保存分组加密算法中的工作模式 */ + WORK_MODE_MASK int = 0x007f + ECB_MODE int = 0x1 + CBC_MODE int = 0x2 + CFB_MODE int = 0x4 + OFB_MODE int = 0x8 + /* 高位保存加密算法 */ + ALGO_MASK int = 0xff80 + DES int = 0x0080 + DES3 int = 0x0100 + AES128 int = 0x0200 + AES192 int = 0x0400 + AES256 int = 0x0800 + RC4 int = 0x1000 + MD5 int = 0x1100 + + // 用户名密码加密算法 + DES_CFB int = 132 + // 消息加密摘要长度 + MD5_DIGEST_SIZE int = 16 + + MIN_EXTERNAL_CIPHER_ID int = 5000 +) + +var dhParaP = "C009D877BAF5FAF416B7F778E6115DCB90D65217DCC2F08A9DFCB5A192C593EBAB02929266B8DBFC2021039FDBD4B7FDE2B996E00008F57AE6EFB4ED3F17B6D3" +var dhParaG = "5" +var defaultIV = []byte{0x20, 0x21, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, + 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x20} +var p *big.Int +var g *big.Int + +func NewClientKeyPair() (key *DhKey, err error) { + p, _ = new(big.Int).SetString(dhParaP, 16) + g, _ = new(big.Int).SetString(dhParaG, 16) + dhGroup := newDhGroup(p, g) + key, err = dhGroup.GeneratePrivateKey(nil) + if err != nil { + return nil, err + } + return key, nil +} + +func ComputeSessionKey(clientPrivKey *DhKey, serverPubKey []byte) []byte { + serverKeyX := bytes2Bn(serverPubKey) + clientPrivKeyX := clientPrivKey.GetX() + sessionKeyBN := serverKeyX.Exp(serverKeyX, clientPrivKeyX, p) + return Bn2Bytes(sessionKeyBN, 0) +} + +func bytes2Bn(bnBytesSrc []byte) *big.Int { + if bnBytesSrc == nil { + return nil + } + if bnBytesSrc[0] == 0 { + return new(big.Int).SetBytes(bnBytesSrc) + } + validBytesCount := len(bnBytesSrc) + 1 + bnBytesTo := make([]byte, validBytesCount) + bnBytesTo[0] = 0 + copy(bnBytesTo[1:validBytesCount], bnBytesSrc) + return new(big.Int).SetBytes(bnBytesTo) +} + +func Bn2Bytes(bn *big.Int, bnLen int) []byte { + var bnBytesSrc, bnBytesTemp, bnBytesTo []byte + var leading_zero_count int + validBytesCount := 0 + if bn == nil { + return nil + } + bnBytesSrc = bn.Bytes() + + // 去除首位0 + if bnBytesSrc[0] != 0 { + bnBytesTemp = bnBytesSrc + validBytesCount = len(bnBytesTemp) + } else { + validBytesCount = len(bnBytesSrc) - 1 + bnBytesTemp = make([]byte, validBytesCount) + copy(bnBytesTemp, bnBytesSrc[1:validBytesCount+1]) + } + + if bnLen == 0 { + leading_zero_count = 0 + } else { + leading_zero_count = bnLen - validBytesCount + } + // 如果位数不足DH_KEY_LENGTH则在前面补0 + if leading_zero_count > 0 { + bnBytesTo = make([]byte, DH_KEY_LENGTH) + i := 0 + for i = 0; i < leading_zero_count; i++ { + bnBytesTo[i] = 0 + } + copy(bnBytesTo[i:i+validBytesCount], bnBytesTemp) + } else { + bnBytesTo = bnBytesTemp + } + return bnBytesTo +} diff --git a/dmr/security/zze.go b/dmr/security/zze.go new file mode 100644 index 0000000..4dcf7f5 --- /dev/null +++ b/dmr/security/zze.go @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/des" + "crypto/md5" + "crypto/rc4" + "errors" + "reflect" +) + +type SymmCipher struct { + encryptCipher interface{} //cipher.BlockMode | cipher.Stream + decryptCipher interface{} //cipher.BlockMode | cipher.Stream + key []byte + block cipher.Block // 分组加密算法 + algorithmType int + workMode int + needPadding bool +} + +func NewSymmCipher(algorithmID int, key []byte) (SymmCipher, error) { + var sc SymmCipher + var err error + sc.key = key + sc.algorithmType = algorithmID & ALGO_MASK + sc.workMode = algorithmID & WORK_MODE_MASK + switch sc.algorithmType { + case AES128: + if sc.block, err = aes.NewCipher(key[:16]); err != nil { + return sc, err + } + case AES192: + if sc.block, err = aes.NewCipher(key[:24]); err != nil { + return sc, err + } + case AES256: + if sc.block, err = aes.NewCipher(key[:32]); err != nil { + return sc, err + } + case DES: + if sc.block, err = des.NewCipher(key[:8]); err != nil { + return sc, err + } + case DES3: + var tripleDESKey []byte + tripleDESKey = append(tripleDESKey, key[:16]...) + tripleDESKey = append(tripleDESKey, key[:8]...) + if sc.block, err = des.NewTripleDESCipher(tripleDESKey); err != nil { + return sc, err + } + case RC4: + if sc.encryptCipher, err = rc4.NewCipher(key[:16]); err != nil { + return sc, err + } + if sc.decryptCipher, err = rc4.NewCipher(key[:16]); err != nil { + return sc, err + } + return sc, nil + default: + return sc, errors.New("invalidCipher") + } + blockSize := sc.block.BlockSize() + if sc.encryptCipher, err = sc.getEncrypter(sc.workMode, sc.block, defaultIV[:blockSize]); err != nil { + return sc, err + } + if sc.decryptCipher, err = sc.getDecrypter(sc.workMode, sc.block, defaultIV[:blockSize]); err != nil { + return sc, err + } + return sc, nil +} + +func (sc SymmCipher) Encrypt(plaintext []byte, genDigest bool) []byte { + // 执行过加密后,IV值变了,需要重新初始化encryptCipher对象(因为没有类似resetIV的方法) + if sc.algorithmType != RC4 { + sc.encryptCipher, _ = sc.getEncrypter(sc.workMode, sc.block, defaultIV[:sc.block.BlockSize()]) + } else { + sc.encryptCipher, _ = rc4.NewCipher(sc.key[:16]) + } + // 填充 + var paddingtext = make([]byte, len(plaintext)) + copy(paddingtext, plaintext) + if sc.needPadding { + paddingtext = pkcs5Padding(paddingtext) + } + + ret := make([]byte, len(paddingtext)) + + if v, ok := sc.encryptCipher.(cipher.Stream); ok { + v.XORKeyStream(ret, paddingtext) + } else if v, ok := sc.encryptCipher.(cipher.BlockMode); ok { + v.CryptBlocks(ret, paddingtext) + } + + // md5摘要 + if genDigest { + digest := md5.Sum(plaintext) + encrypt := ret + ret = make([]byte, len(encrypt)+len(digest)) + copy(ret[:len(encrypt)], encrypt) + copy(ret[len(encrypt):], digest[:]) + } + return ret +} + +func (sc SymmCipher) Decrypt(ciphertext []byte, checkDigest bool) ([]byte, error) { + // 执行过解密后,IV值变了,需要重新初始化decryptCipher对象(因为没有类似resetIV的方法) + if sc.algorithmType != RC4 { + sc.decryptCipher, _ = sc.getDecrypter(sc.workMode, sc.block, defaultIV[:sc.block.BlockSize()]) + } else { + sc.decryptCipher, _ = rc4.NewCipher(sc.key[:16]) + } + var ret []byte + if checkDigest { + var digest = ciphertext[len(ciphertext)-MD5_DIGEST_SIZE:] + ret = ciphertext[:len(ciphertext)-MD5_DIGEST_SIZE] + ret = sc.decrypt(ret) + var msgDigest = md5.Sum(ret) + if !reflect.DeepEqual(msgDigest[:], digest) { + return nil, errors.New("Decrypt failed/Digest not match\n") + } + } else { + ret = sc.decrypt(ciphertext) + } + return ret, nil +} + +func (sc SymmCipher) decrypt(ciphertext []byte) []byte { + ret := make([]byte, len(ciphertext)) + if v, ok := sc.decryptCipher.(cipher.Stream); ok { + v.XORKeyStream(ret, ciphertext) + } else if v, ok := sc.decryptCipher.(cipher.BlockMode); ok { + v.CryptBlocks(ret, ciphertext) + } + // 去除填充 + if sc.needPadding { + ret = pkcs5UnPadding(ret) + } + return ret +} + +func (sc *SymmCipher) getEncrypter(workMode int, block cipher.Block, iv []byte) (ret interface{}, err error) { + switch workMode { + case ECB_MODE: + ret = NewECBEncrypter(block) + sc.needPadding = true + case CBC_MODE: + ret = cipher.NewCBCEncrypter(block, iv) + sc.needPadding = true + case CFB_MODE: + ret = cipher.NewCFBEncrypter(block, iv) + sc.needPadding = false + case OFB_MODE: + ret = cipher.NewOFB(block, iv) + sc.needPadding = false + default: + err = errors.New("invalidCipherMode") + } + return +} + +func (sc *SymmCipher) getDecrypter(workMode int, block cipher.Block, iv []byte) (ret interface{}, err error) { + switch workMode { + case ECB_MODE: + ret = NewECBDecrypter(block) + sc.needPadding = true + case CBC_MODE: + ret = cipher.NewCBCDecrypter(block, iv) + sc.needPadding = true + case CFB_MODE: + ret = cipher.NewCFBDecrypter(block, iv) + sc.needPadding = false + case OFB_MODE: + ret = cipher.NewOFB(block, iv) + sc.needPadding = false + default: + err = errors.New("invalidCipherMode") + } + return +} + + +// 补码 +func pkcs77Padding(ciphertext []byte, blocksize int) []byte { + padding := blocksize - len(ciphertext)%blocksize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(ciphertext, padtext...) +} + +// 去码 +func pkcs7UnPadding(origData []byte) []byte { + length := len(origData) + unpadding := int(origData[length-1]) + return origData[:length-unpadding] +} + +// 补码 +func pkcs5Padding(ciphertext []byte) []byte { + return pkcs77Padding(ciphertext, 8) +} + +// 去码 +func pkcs5UnPadding(ciphertext []byte) []byte { + return pkcs7UnPadding(ciphertext) +} \ No newline at end of file diff --git a/dmr/security/zzf.go b/dmr/security/zzf.go new file mode 100644 index 0000000..8710712 --- /dev/null +++ b/dmr/security/zzf.go @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import ( + "crypto/md5" + "errors" + "fmt" + "reflect" + "unsafe" +) + +type ThirdPartCipher struct { + encryptType int // 外部加密算法id + encryptName string // 外部加密算法名称 + hashType int + key []byte + cipherCount int // 外部加密算法个数 + //innerId int // 外部加密算法内部id + blockSize int // 分组块大小 + khSize int // key/hash大小 +} + +func NewThirdPartCipher(encryptType int, key []byte, cipherPath string, hashType int) (ThirdPartCipher, error) { + var tpc = ThirdPartCipher{ + encryptType: encryptType, + key: key, + hashType: hashType, + cipherCount: -1, + } + var err error + err = initThirdPartCipher(cipherPath) + if err != nil { + return tpc, err + } + tpc.getCount() + tpc.getInfo() + return tpc, nil +} + +func (tpc *ThirdPartCipher) getCount() int { + if tpc.cipherCount == -1 { + tpc.cipherCount = cipherGetCount() + } + return tpc.cipherCount +} + +func (tpc *ThirdPartCipher) getInfo() { + var cipher_id, ty, blk_size, kh_size int + //var strptr, _ = syscall.UTF16PtrFromString(tpc.encryptName) + var strptr *uint16 = new(uint16) + for i := 1; i <= tpc.getCount(); i++ { + cipherGetInfo(uintptr(i), uintptr(unsafe.Pointer(&cipher_id)), uintptr(unsafe.Pointer(&strptr)), + uintptr(unsafe.Pointer(&ty)), uintptr(unsafe.Pointer(&blk_size)), uintptr(unsafe.Pointer(&kh_size))) + if tpc.encryptType == cipher_id { + tpc.blockSize = blk_size + tpc.khSize = kh_size + tpc.encryptName = string(uintptr2bytes(uintptr(unsafe.Pointer(strptr)))) + return + } + } + panic(fmt.Sprintf("ThirdPartyCipher: cipher id:%d not found", tpc.encryptType)) +} + +func (tpc ThirdPartCipher) Encrypt(plaintext []byte, genDigest bool) []byte { + var tmp_para uintptr + cipherEncryptInit(uintptr(tpc.encryptType), uintptr(unsafe.Pointer(&tpc.key[0])), uintptr(len(tpc.key)), tmp_para) + + ciphertextLen := cipherGetCipherTextSize(uintptr(tpc.encryptType), tmp_para, uintptr(len(plaintext))) + + ciphertext := make([]byte, ciphertextLen) + ret := cipherEncrypt(uintptr(tpc.encryptType), tmp_para, uintptr(unsafe.Pointer(&plaintext[0])), uintptr(len(plaintext)), + uintptr(unsafe.Pointer(&ciphertext[0])), uintptr(len(ciphertext))) + ciphertext = ciphertext[:ret] + + cipherClean(uintptr(tpc.encryptType), tmp_para) + // md5摘要 + if genDigest { + digest := md5.Sum(plaintext) + encrypt := ciphertext + ciphertext = make([]byte, len(encrypt)+len(digest)) + copy(ciphertext[:len(encrypt)], encrypt) + copy(ciphertext[len(encrypt):], digest[:]) + } + return ciphertext +} + +func (tpc ThirdPartCipher) Decrypt(ciphertext []byte, checkDigest bool) ([]byte, error) { + var ret []byte + if checkDigest { + var digest = ciphertext[len(ciphertext)-MD5_DIGEST_SIZE:] + ret = ciphertext[:len(ciphertext)-MD5_DIGEST_SIZE] + ret = tpc.decrypt(ret) + var msgDigest = md5.Sum(ret) + if !reflect.DeepEqual(msgDigest[:], digest) { + return nil, errors.New("Decrypt failed/Digest not match\n") + } + } else { + ret = tpc.decrypt(ciphertext) + } + return ret, nil +} + +func (tpc ThirdPartCipher) decrypt(ciphertext []byte) []byte { + var tmp_para uintptr + + cipherDecryptInit(uintptr(tpc.encryptType), uintptr(unsafe.Pointer(&tpc.key[0])), uintptr(len(tpc.key)), tmp_para) + + plaintext := make([]byte, len(ciphertext)) + ret := cipherDecrypt(uintptr(tpc.encryptType), tmp_para, uintptr(unsafe.Pointer(&ciphertext[0])), uintptr(len(ciphertext)), + uintptr(unsafe.Pointer(&plaintext[0])), uintptr(len(plaintext))) + plaintext = plaintext[:ret] + + cipherClean(uintptr(tpc.encryptType), tmp_para) + return plaintext +} + +func addBufSize(buf []byte, newCap int) []byte { + newBuf := make([]byte, newCap) + copy(newBuf, buf) + return newBuf +} + +func uintptr2bytes(p uintptr) []byte { + buf := make([]byte, 64) + i := 0 + for b := (*byte)(unsafe.Pointer(p)); *b != 0; i++ { + if i > cap(buf) { + buf = addBufSize(buf, i * 2) + } + buf[i] = *b + // byte占1字节 + p ++ + b = (*byte)(unsafe.Pointer(p)) + } + return buf[:i] +} diff --git a/dmr/security/zzg_darwin.go b/dmr/security/zzg_darwin.go new file mode 100644 index 0000000..835002e --- /dev/null +++ b/dmr/security/zzg_darwin.go @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import "plugin" + +var ( + dmCipherEncryptSo *plugin.Plugin + cipherGetCountProc plugin.Symbol + cipherGetInfoProc plugin.Symbol + cipherEncryptInitProc plugin.Symbol + cipherGetCipherTextSizeProc plugin.Symbol + cipherEncryptProc plugin.Symbol + cipherCleanupProc plugin.Symbol + cipherDecryptInitProc plugin.Symbol + cipherDecryptProc plugin.Symbol +) + +func initThirdPartCipher(cipherPath string) (err error) { + if dmCipherEncryptSo, err = plugin.Open(cipherPath); err != nil { + return err + } + if cipherGetCountProc, err = dmCipherEncryptSo.Lookup("cipher_get_count"); err != nil { + return err + } + if cipherGetInfoProc, err = dmCipherEncryptSo.Lookup("cipher_get_info"); err != nil { + return err + } + if cipherEncryptInitProc, err = dmCipherEncryptSo.Lookup("cipher_encrypt_init"); err != nil { + return err + } + if cipherGetCipherTextSizeProc, err = dmCipherEncryptSo.Lookup("cipher_get_cipher_text_size"); err != nil { + return err + } + if cipherEncryptProc, err = dmCipherEncryptSo.Lookup("cipher_encrypt"); err != nil { + return err + } + if cipherCleanupProc, err = dmCipherEncryptSo.Lookup("cipher_cleanup"); err != nil { + return err + } + if cipherDecryptInitProc, err = dmCipherEncryptSo.Lookup("cipher_decrypt_init"); err != nil { + return err + } + if cipherDecryptProc, err = dmCipherEncryptSo.Lookup("cipher_decrypt"); err != nil { + return err + } + return nil +} + +func cipherGetCount() int { + ret := cipherGetCountProc.(func() interface{})() + return ret.(int) +} + +func cipherGetInfo(seqno, cipherId, cipherName, _type, blkSize, khSIze uintptr) { + ret := cipherGetInfoProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(seqno, cipherId, cipherName, _type, blkSize, khSIze) + if ret.(int) == 0 { + panic("ThirdPartyCipher: call cipher_get_info failed") + } +} + +func cipherEncryptInit(cipherId, key, keySize, cipherPara uintptr) { + ret := cipherEncryptInitProc.(func(uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, key, keySize, cipherPara) + if ret.(int) == 0 { + panic("ThirdPartyCipher: call cipher_encrypt_init failed") + } +} + +func cipherGetCipherTextSize(cipherId, cipherPara, plainTextSize uintptr) uintptr { + ciphertextLen := cipherGetCipherTextSizeProc.(func(uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, plainTextSize) + return ciphertextLen.(uintptr) +} + +func cipherEncrypt(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize uintptr) uintptr { + ret := cipherEncryptProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize) + return ret.(uintptr) +} + +func cipherClean(cipherId, cipherPara uintptr) { + cipherEncryptProc.(func(uintptr, uintptr))(cipherId, cipherPara) +} + +func cipherDecryptInit(cipherId, key, keySize, cipherPara uintptr) { + ret := cipherDecryptInitProc.(func(uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, key, keySize, cipherPara) + if ret.(int) == 0 { + panic("ThirdPartyCipher: call cipher_decrypt_init failed") + } +} + +func cipherDecrypt(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize uintptr) uintptr { + ret := cipherDecryptProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize) + return ret.(uintptr) +} diff --git a/dmr/security/zzg_linux.go b/dmr/security/zzg_linux.go new file mode 100644 index 0000000..835002e --- /dev/null +++ b/dmr/security/zzg_linux.go @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import "plugin" + +var ( + dmCipherEncryptSo *plugin.Plugin + cipherGetCountProc plugin.Symbol + cipherGetInfoProc plugin.Symbol + cipherEncryptInitProc plugin.Symbol + cipherGetCipherTextSizeProc plugin.Symbol + cipherEncryptProc plugin.Symbol + cipherCleanupProc plugin.Symbol + cipherDecryptInitProc plugin.Symbol + cipherDecryptProc plugin.Symbol +) + +func initThirdPartCipher(cipherPath string) (err error) { + if dmCipherEncryptSo, err = plugin.Open(cipherPath); err != nil { + return err + } + if cipherGetCountProc, err = dmCipherEncryptSo.Lookup("cipher_get_count"); err != nil { + return err + } + if cipherGetInfoProc, err = dmCipherEncryptSo.Lookup("cipher_get_info"); err != nil { + return err + } + if cipherEncryptInitProc, err = dmCipherEncryptSo.Lookup("cipher_encrypt_init"); err != nil { + return err + } + if cipherGetCipherTextSizeProc, err = dmCipherEncryptSo.Lookup("cipher_get_cipher_text_size"); err != nil { + return err + } + if cipherEncryptProc, err = dmCipherEncryptSo.Lookup("cipher_encrypt"); err != nil { + return err + } + if cipherCleanupProc, err = dmCipherEncryptSo.Lookup("cipher_cleanup"); err != nil { + return err + } + if cipherDecryptInitProc, err = dmCipherEncryptSo.Lookup("cipher_decrypt_init"); err != nil { + return err + } + if cipherDecryptProc, err = dmCipherEncryptSo.Lookup("cipher_decrypt"); err != nil { + return err + } + return nil +} + +func cipherGetCount() int { + ret := cipherGetCountProc.(func() interface{})() + return ret.(int) +} + +func cipherGetInfo(seqno, cipherId, cipherName, _type, blkSize, khSIze uintptr) { + ret := cipherGetInfoProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(seqno, cipherId, cipherName, _type, blkSize, khSIze) + if ret.(int) == 0 { + panic("ThirdPartyCipher: call cipher_get_info failed") + } +} + +func cipherEncryptInit(cipherId, key, keySize, cipherPara uintptr) { + ret := cipherEncryptInitProc.(func(uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, key, keySize, cipherPara) + if ret.(int) == 0 { + panic("ThirdPartyCipher: call cipher_encrypt_init failed") + } +} + +func cipherGetCipherTextSize(cipherId, cipherPara, plainTextSize uintptr) uintptr { + ciphertextLen := cipherGetCipherTextSizeProc.(func(uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, plainTextSize) + return ciphertextLen.(uintptr) +} + +func cipherEncrypt(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize uintptr) uintptr { + ret := cipherEncryptProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize) + return ret.(uintptr) +} + +func cipherClean(cipherId, cipherPara uintptr) { + cipherEncryptProc.(func(uintptr, uintptr))(cipherId, cipherPara) +} + +func cipherDecryptInit(cipherId, key, keySize, cipherPara uintptr) { + ret := cipherDecryptInitProc.(func(uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, key, keySize, cipherPara) + if ret.(int) == 0 { + panic("ThirdPartyCipher: call cipher_decrypt_init failed") + } +} + +func cipherDecrypt(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize uintptr) uintptr { + ret := cipherDecryptProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize) + return ret.(uintptr) +} diff --git a/dmr/security/zzh_windows.go b/dmr/security/zzh_windows.go new file mode 100644 index 0000000..2fa6861 --- /dev/null +++ b/dmr/security/zzh_windows.go @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import ( + "syscall" +) + +var ( + dmCipherEncryptDLL *syscall.LazyDLL + cipherGetCountProc *syscall.LazyProc + cipherGetInfoProc *syscall.LazyProc + cipherEncryptInitProc *syscall.LazyProc + cipherGetCipherTextSizeProc *syscall.LazyProc + cipherEncryptProc *syscall.LazyProc + cipherCleanupProc *syscall.LazyProc + cipherDecryptInitProc *syscall.LazyProc + cipherDecryptProc *syscall.LazyProc +) + +func initThirdPartCipher(cipherPath string) error { + dmCipherEncryptDLL = syscall.NewLazyDLL(cipherPath) + if err := dmCipherEncryptDLL.Load(); err != nil { + return err + } + cipherGetCountProc = dmCipherEncryptDLL.NewProc("cipher_get_count") + cipherGetInfoProc = dmCipherEncryptDLL.NewProc("cipher_get_info") + cipherEncryptInitProc = dmCipherEncryptDLL.NewProc("cipher_encrypt_init") + cipherGetCipherTextSizeProc = dmCipherEncryptDLL.NewProc("cipher_get_cipher_text_size") + cipherEncryptProc = dmCipherEncryptDLL.NewProc("cipher_encrypt") + cipherCleanupProc = dmCipherEncryptDLL.NewProc("cipher_cleanup") + cipherDecryptInitProc = dmCipherEncryptDLL.NewProc("cipher_decrypt_init") + cipherDecryptProc = dmCipherEncryptDLL.NewProc("cipher_decrypt") + return nil +} + +func cipherGetCount() int { + ret, _, _ := cipherGetCountProc.Call() + return int(ret) +} + +func cipherGetInfo(seqno, cipherId, cipherName, _type, blkSize, khSIze uintptr) { + ret, _, _ := cipherGetInfoProc.Call(seqno, cipherId, cipherName, _type, blkSize, khSIze) + if ret == 0 { + panic("ThirdPartyCipher: call cipher_get_info failed") + } +} + +func cipherEncryptInit(cipherId, key, keySize, cipherPara uintptr) { + ret, _, _ := cipherEncryptInitProc.Call(cipherId, key, keySize, cipherPara) + if ret == 0 { + panic("ThirdPartyCipher: call cipher_encrypt_init failed") + } +} + +func cipherGetCipherTextSize(cipherId, cipherPara, plainTextSize uintptr) uintptr { + ciphertextLen, _, _ := cipherGetCipherTextSizeProc.Call(cipherId, cipherPara, plainTextSize) + return ciphertextLen +} + +func cipherEncrypt(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize uintptr) uintptr { + ret, _, _ := cipherEncryptProc.Call(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize) + return ret +} + +func cipherClean(cipherId, cipherPara uintptr) { + _, _, _ = cipherCleanupProc.Call(cipherId, cipherPara) +} + +func cipherDecryptInit(cipherId, key, keySize, cipherPara uintptr) { + ret, _, _ := cipherDecryptInitProc.Call(cipherId, key, keySize, cipherPara) + if ret == 0 { + panic("ThirdPartyCipher: call cipher_decrypt_init failed") + } +} + +func cipherDecrypt(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize uintptr) uintptr { + ret, _, _ := cipherDecryptProc.Call(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize) + return ret +} diff --git a/dmr/security/zzi.go b/dmr/security/zzi.go new file mode 100644 index 0000000..5b8b6f9 --- /dev/null +++ b/dmr/security/zzi.go @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import ( + "crypto/tls" + "errors" + "flag" + "net" + "os" +) + +var dmHome = flag.String("DM_HOME", "", "Where DMDB installed") + +func NewTLSFromTCP(conn *net.TCPConn, sslCertPath string, sslKeyPath string, user string) (*tls.Conn, error) { + if sslCertPath == "" && sslKeyPath == "" { + flag.Parse() + separator := string(os.PathSeparator) + if *dmHome != "" { + sslCertPath = *dmHome + separator + "bin" + separator + "client_ssl" + separator + + user + separator + "client-cert.pem" + sslKeyPath = *dmHome + separator + "bin" + separator + "client_ssl" + separator + + user + separator + "client-key.pem" + } else { + return nil, errors.New("sslCertPath and sslKeyPath can not be empty!") + } + } + cer, err := tls.LoadX509KeyPair(sslCertPath, sslKeyPath) + if err != nil { + return nil, err + } + conf := &tls.Config{ + InsecureSkipVerify: true, + Certificates: []tls.Certificate{cer}, + } + tlsConn := tls.Client(conn, conf) + if err := tlsConn.Handshake(); err != nil { + return nil, err + } + return tlsConn, nil +} \ No newline at end of file diff --git a/dmr/t.go b/dmr/t.go new file mode 100644 index 0000000..f602d86 --- /dev/null +++ b/dmr/t.go @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "database/sql/driver" + "io" + "reflect" + "strings" +) + +type DmRows struct { + filterable + CurrentRows *innerRows + finish func() +} + +func (r *DmRows) Columns() []string { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return nil + } + if len(r.filterChain.filters) == 0 { + return r.columns() + } + return r.filterChain.reset().DmRowsColumns(r) +} + +func (r *DmRows) Close() error { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return err + } + if len(r.filterChain.filters) == 0 { + return r.close() + } + return r.filterChain.reset().DmRowsClose(r) +} + +func (r *DmRows) Next(dest []driver.Value) error { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return err + } + if len(r.filterChain.filters) == 0 { + return r.next(dest) + } + return r.filterChain.reset().DmRowsNext(r, dest) +} + +func (r *DmRows) HasNextResultSet() bool { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return false + } + if len(r.filterChain.filters) == 0 { + return r.hasNextResultSet() + } + return r.filterChain.reset().DmRowsHasNextResultSet(r) +} + +func (r *DmRows) NextResultSet() error { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return err + } + if len(r.filterChain.filters) == 0 { + return r.nextResultSet() + } + return r.filterChain.reset().DmRowsNextResultSet(r) +} + +func (r *DmRows) ColumnTypeScanType(index int) reflect.Type { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return nil + } + if len(r.filterChain.filters) == 0 { + return r.columnTypeScanType(index) + } + return r.filterChain.reset().DmRowsColumnTypeScanType(r, index) +} + +func (r *DmRows) ColumnTypeDatabaseTypeName(index int) string { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return "" + } + if len(r.filterChain.filters) == 0 { + return r.columnTypeDatabaseTypeName(index) + } + return r.filterChain.reset().DmRowsColumnTypeDatabaseTypeName(r, index) +} + +func (r *DmRows) ColumnTypeLength(index int) (length int64, ok bool) { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return -1, false + } + if len(r.filterChain.filters) == 0 { + return r.columnTypeLength(index) + } + return r.filterChain.reset().DmRowsColumnTypeLength(r, index) +} + +func (r *DmRows) ColumnTypeNullable(index int) (nullable, ok bool) { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return false, false + } + if len(r.filterChain.filters) == 0 { + return r.columnTypeNullable(index) + } + return r.filterChain.reset().DmRowsColumnTypeNullable(r, index) +} + +func (r *DmRows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return -1, -1, false + } + if len(r.filterChain.filters) == 0 { + return r.columnTypePrecisionScale(index) + } + return r.filterChain.reset().DmRowsColumnTypePrecisionScale(r, index) +} + +func (rows *DmRows) columns() []string { + return rows.CurrentRows.Columns() +} + +func (rows *DmRows) close() error { + if f := rows.finish; f != nil { + f() + rows.finish = nil + } + return rows.CurrentRows.Close() +} + +func (rows *DmRows) next(dest []driver.Value) error { + return rows.CurrentRows.Next(dest) +} + +func (rows *DmRows) hasNextResultSet() bool { + return rows.CurrentRows.HasNextResultSet() +} + +func (rows *DmRows) nextResultSet() error { + return rows.CurrentRows.NextResultSet() +} + +func (rows *DmRows) columnTypeScanType(index int) reflect.Type { + return rows.CurrentRows.ColumnTypeScanType(index) +} + +func (rows *DmRows) columnTypeDatabaseTypeName(index int) string { + return rows.CurrentRows.ColumnTypeDatabaseTypeName(index) +} + +func (rows *DmRows) columnTypeLength(index int) (length int64, ok bool) { + return rows.CurrentRows.ColumnTypeLength(index) +} + +func (rows *DmRows) columnTypeNullable(index int) (nullable, ok bool) { + return rows.CurrentRows.ColumnTypeNullable(index) +} + +func (rows *DmRows) columnTypePrecisionScale(index int) (precision, scale int64, ok bool) { + return rows.CurrentRows.ColumnTypePrecisionScale(index) +} + +type innerRows struct { + dmStmt *DmStatement + + id int16 + + columns []column + + datas [][][]byte + + datasOffset int + + datasStartPos int64 + + currentPos int64 + + totalRowCount int64 + + fetchSize int + + sizeOfRow int + + isBdta bool + + nextExecInfo *execRetInfo + + next *innerRows + + dmRows *DmRows + + closed bool +} + +func (innerRows *innerRows) checkClosed() error { + if innerRows.closed { + return ECGO_RESULTSET_CLOSED.throw() + } + return nil +} + +func (innerRows *innerRows) Columns() []string { + err := innerRows.checkClosed() + if err != nil { + panic(err) + } + + columnNames := make([]string, len(innerRows.columns)) + nameCase := innerRows.dmStmt.dmConn.dmConnector.columnNameCase + + for i, column := range innerRows.columns { + if nameCase == COLUMN_NAME_NATURAL_CASE { + columnNames[i] = column.name + } else if nameCase == COLUMN_NAME_UPPER_CASE { + columnNames[i] = strings.ToUpper(column.name) + } else if nameCase == COLUMN_NAME_LOWER_CASE { + columnNames[i] = strings.ToLower(column.name) + } else { + columnNames[i] = column.name + } + } + + return columnNames +} + +func (innerRows *innerRows) Close() error { + if innerRows.closed { + return nil + } + + innerRows.closed = true + + if innerRows.dmStmt.innerUsed { + innerRows.dmStmt.close() + } else { + delete(innerRows.dmStmt.rsMap, innerRows.id) + } + + innerRows.dmStmt = nil + + return nil +} + +func (innerRows *innerRows) Next(dest []driver.Value) error { + err := innerRows.checkClosed() + if err != nil { + return err + } + + if innerRows.totalRowCount == 0 || innerRows.currentPos >= innerRows.totalRowCount { + return io.EOF + } + + if innerRows.currentPos+1 == innerRows.totalRowCount { + innerRows.currentPos++ + innerRows.datasOffset++ + return io.EOF + } + + if innerRows.currentPos+1 < innerRows.datasStartPos || innerRows.currentPos+1 >= innerRows.datasStartPos+int64(len(innerRows.datas)) { + if innerRows.fetchData(innerRows.currentPos + 1) { + innerRows.currentPos++ + err := innerRows.getRowData(dest) + if err != nil { + return err + } + } else { + innerRows.currentPos++ + innerRows.datasOffset++ + return io.EOF + } + } else { + innerRows.currentPos++ + innerRows.datasOffset++ + err := innerRows.getRowData(dest) + if err != nil { + return err + } + } + + return nil +} + +func (innerRows *innerRows) HasNextResultSet() bool { + err := innerRows.checkClosed() + if err != nil { + panic(err) + } + + if innerRows.nextExecInfo != nil { + return innerRows.nextExecInfo.hasResultSet + } + + innerRows.nextExecInfo, err = innerRows.dmStmt.dmConn.Access.Dm_build_449(innerRows.dmStmt, 0) + if err != nil { + panic(err) + } + + if innerRows.nextExecInfo.hasResultSet { + innerRows.next = newInnerRows(innerRows.id+1, innerRows.dmStmt, innerRows.nextExecInfo) + return true + } + + return false +} + +func (innerRows *innerRows) NextResultSet() error { + err := innerRows.checkClosed() + if err != nil { + return err + } + + if innerRows.nextExecInfo == nil { + innerRows.HasNextResultSet() + } + + if innerRows.next == nil { + return io.EOF + } + + innerRows.next.dmRows = innerRows.dmRows + innerRows.dmRows.CurrentRows = innerRows.next + return nil +} + +func (innerRows *innerRows) ColumnTypeScanType(index int) reflect.Type { + err := innerRows.checkClosed() + if err != nil { + panic(err) + } + column := innerRows.checkIndex(index) + return column.ScanType() +} + +func (innerRows *innerRows) ColumnTypeDatabaseTypeName(index int) string { + err := innerRows.checkClosed() + if err != nil { + panic(err) + } + column := innerRows.checkIndex(index) + return column.typeName +} + +func (innerRows *innerRows) ColumnTypeLength(index int) (length int64, ok bool) { + err := innerRows.checkClosed() + if err != nil { + panic(err) + } + column := innerRows.checkIndex(index) + return column.Length() +} + +func (innerRows *innerRows) ColumnTypeNullable(index int) (nullable, ok bool) { + err := innerRows.checkClosed() + if err != nil { + panic(err) + } + column := innerRows.checkIndex(index) + return column.nullable, true +} + +func (innerRows *innerRows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) { + err := innerRows.checkClosed() + if err != nil { + panic(err) + } + column := innerRows.checkIndex(index) + return column.PrecisionScale() +} + +func newDmRows(currentRows *innerRows) *DmRows { + dr := new(DmRows) + dr.resetFilterable(¤tRows.dmStmt.filterable) + dr.CurrentRows = currentRows + dr.idGenerator = dmRowsIDGenerator + currentRows.dmRows = dr + return dr +} + +func newInnerRows(id int16, stmt *DmStatement, execInfo *execRetInfo) *innerRows { + rows := new(innerRows) + rows.id = id + rows.dmStmt = stmt + rows.columns = stmt.columns + rows.datas = execInfo.rsDatas + rows.totalRowCount = execInfo.updateCount + rows.isBdta = execInfo.rsBdta + rows.fetchSize = stmt.fetchSize + + if len(execInfo.rsDatas) == 0 { + rows.sizeOfRow = 0 + } else { + rows.sizeOfRow = execInfo.rsSizeof / len(execInfo.rsDatas) + } + + rows.currentPos = -1 + rows.datasOffset = -1 + rows.datasStartPos = 0 + + rows.nextExecInfo = nil + rows.next = nil + + if rows.dmStmt.rsMap != nil { + rows.dmStmt.rsMap[rows.id] = rows + } + + if stmt.dmConn.dmConnector.enRsCache && execInfo.rsCacheOffset > 0 && + int64(len(execInfo.rsDatas)) == execInfo.updateCount { + rp.put(stmt, stmt.nativeSql, execInfo) + } + + return rows +} + +func newLocalInnerRows(stmt *DmStatement, columns []column, rsDatas [][][]byte) *innerRows { + rows := new(innerRows) + rows.id = 0 + rows.dmStmt = stmt + rows.fetchSize = stmt.fetchSize + + if columns == nil { + rows.columns = make([]column, 0) + } else { + rows.columns = columns + } + + if rsDatas == nil { + rows.datas = make([][][]byte, 0) + rows.totalRowCount = 0 + } else { + rows.datas = rsDatas + rows.totalRowCount = int64(len(rsDatas)) + } + + rows.isBdta = false + return rows +} + +func (innerRows *innerRows) checkIndex(index int) *column { + if index < 0 || index > len(innerRows.columns)-1 { + panic(ECGO_INVALID_SEQUENCE_NUMBER) + } + + return &innerRows.columns[index] +} + +func (innerRows *innerRows) fetchData(startPos int64) bool { + execInfo, err := innerRows.dmStmt.dmConn.Access.Dm_build_456(innerRows, startPos) + if err != nil { + panic(err) + } + + innerRows.totalRowCount = execInfo.updateCount + if execInfo.rsDatas != nil { + innerRows.datas = execInfo.rsDatas + innerRows.datasStartPos = startPos + innerRows.datasOffset = 0 + return true + } + + return false +} + +func (innerRows *innerRows) getRowData(dest []driver.Value) (err error) { + for i, column := range innerRows.columns { + + if i <= len(dest)-1 { + if column.colType == CURSOR { + var tmpExecInfo *execRetInfo + tmpExecInfo, err = innerRows.dmStmt.dmConn.Access.Dm_build_449(innerRows.dmStmt, 1) + if err != nil { + return err + } + + if tmpExecInfo.hasResultSet { + dest[i] = newDmRows(newInnerRows(innerRows.id+1, innerRows.dmStmt, tmpExecInfo)) + } else { + dest[i] = nil + } + continue + } + + dest[i], err = column.getColumnData(innerRows.datas[innerRows.datasOffset][i+1], innerRows.dmStmt.dmConn) + innerRows.columns[i].isBdta = innerRows.isBdta + if err != nil { + return err + } + } else { + return nil + } + } + + return nil +} + +func (innerRows *innerRows) getRowCount() int64 { + innerRows.checkClosed() + + if innerRows.totalRowCount == INT64_MAX { + return -1 + } + + return innerRows.totalRowCount +} diff --git a/dmr/u.go b/dmr/u.go new file mode 100644 index 0000000..df0599a --- /dev/null +++ b/dmr/u.go @@ -0,0 +1,1078 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "container/list" + "context" + "database/sql" + "database/sql/driver" + "fmt" + "io" + "math/big" + "reflect" + "strconv" + "strings" + "time" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +const ( + BIND_IN byte = 0x01 + + BIND_OUT byte = 0x10 +) + +var rp = newRsPool() + +type DmStatement struct { + filterable + + dmConn *DmConnection + rsMap map[int16]*innerRows + inUse bool + innerUsed bool + + innerExec bool + + id int32 + + cursorName string + + readBaseColName bool + + execInfo *execRetInfo + + resultSetType int + + resultSetConcurrency int + + resultSetHoldability int + + nativeSql string + + maxFieldSize int + + maxRows int64 + + escapeProcessing bool + + queryTimeout int32 + + fetchDirection int + + fetchSize int + + cursorUpdateRow int64 + + closeOnCompletion bool + + isBatch bool + + closed bool + + columns []column + + params []parameter + + paramCount int32 + + curRowBindIndicator []byte + + preExec bool +} + +type stmtPoolInfo struct { + id int32 + + cursorName string + + readBaseColName bool +} + +type rsPoolKey struct { + dbGuid string + currentSchema string + sql string + paramCount int +} + +func newRsPoolKey(stmt *DmStatement, sql string) rsPoolKey { + rpk := new(rsPoolKey) + rpk.dbGuid = stmt.dmConn.Guid + rpk.currentSchema = stmt.dmConn.Schema + rpk.paramCount = int(stmt.paramCount) + + rpk.sql = sql + return *rpk +} + +func (key rsPoolKey) equals(destKey rsPoolKey) bool { + return key.dbGuid == destKey.dbGuid && + key.currentSchema == destKey.currentSchema && + key.sql == destKey.sql && + key.paramCount == destKey.paramCount + +} + +type rsPoolValue struct { + m_lastChkTime int + m_TbIds []int32 + m_TbTss []int64 + execInfo *execRetInfo +} + +func newRsPoolValue(execInfo *execRetInfo) rsPoolValue { + rpv := new(rsPoolValue) + rpv.execInfo = execInfo + rpv.m_lastChkTime = time.Now().Nanosecond() + copy(rpv.m_TbIds, execInfo.tbIds) + copy(rpv.m_TbTss, execInfo.tbTss) + return *rpv +} + +func (rpv rsPoolValue) refreshed(conn *DmConnection) (bool, error) { + + if conn.dmConnector.rsRefreshFreq == 0 { + return false, nil + } + + if rpv.m_lastChkTime+conn.dmConnector.rsRefreshFreq*int(time.Second) > time.Now().Nanosecond() { + return false, nil + } + + tss, err := conn.Access.Dm_build_482(interface{}(rpv.m_TbIds).([]uint32)) + if err != nil { + return false, err + } + rpv.m_lastChkTime = time.Now().Nanosecond() + + var tbCount int + if tss != nil { + tbCount = len(tss) + } + + if tbCount != len(rpv.m_TbTss) { + return true, nil + } + + for i := 0; i < tbCount; i++ { + if rpv.m_TbTss[i] != tss[i] { + return true, nil + } + + } + return false, nil +} + +func (rpv rsPoolValue) getResultSet(stmt *DmStatement) *innerRows { + destDatas := rpv.execInfo.rsDatas + var totalRows int + if rpv.execInfo.rsDatas != nil { + totalRows = len(rpv.execInfo.rsDatas) + } + + if stmt.maxRows > 0 && stmt.maxRows < int64(totalRows) { + destDatas = make([][][]byte, stmt.maxRows) + copy(destDatas[:len(destDatas)], rpv.execInfo.rsDatas[:len(destDatas)]) + } + + rs := newLocalInnerRows(stmt, stmt.columns, destDatas) + rs.id = 1 + return rs +} + +func (rpv rsPoolValue) getDataLen() int { + return rpv.execInfo.rsSizeof +} + +type rsPool struct { + rsMap map[rsPoolKey]rsPoolValue + rsList *list.List + totalDataLen int +} + +func newRsPool() *rsPool { + rp := new(rsPool) + rp.rsMap = make(map[rsPoolKey]rsPoolValue, 100) + rp.rsList = list.New() + return rp +} + +func (rp *rsPool) removeInList(key rsPoolKey) { + for e := rp.rsList.Front(); e != nil && e.Value.(rsPoolKey).equals(key); e = e.Next() { + rp.rsList.Remove(e) + } +} + +func (rp *rsPool) put(stmt *DmStatement, sql string, execInfo *execRetInfo) { + var dataLen int + if execInfo != nil { + dataLen = execInfo.rsSizeof + } + + cacheSize := stmt.dmConn.dmConnector.rsCacheSize * 1024 * 1024 + + for rp.totalDataLen+dataLen > cacheSize { + if rp.totalDataLen == 0 { + return + } + + lk := rp.rsList.Back().Value.(rsPoolKey) + rp.totalDataLen -= rp.rsMap[lk].getDataLen() + rp.rsList.Remove(rp.rsList.Back()) + delete(rp.rsMap, rp.rsList.Back().Value.(rsPoolKey)) + } + + key := newRsPoolKey(stmt, sql) + value := newRsPoolValue(execInfo) + + if _, ok := rp.rsMap[key]; !ok { + rp.rsList.PushFront(key) + } else { + rp.removeInList(key) + rp.rsList.PushFront(key) + } + + rp.rsMap[key] = value + rp.totalDataLen += dataLen +} + +func (rp *rsPool) get(stmt *DmStatement, sql string) (*rsPoolValue, error) { + key := newRsPoolKey(stmt, sql) + + v, ok := rp.rsMap[key] + if ok { + b, err := v.refreshed(stmt.dmConn) + if err != nil { + return nil, err + } + + if b { + rp.removeInList(key) + delete(rp.rsMap, key) + return nil, nil + } + + rp.removeInList(key) + rp.rsList.PushFront(key) + return &v, nil + } else { + return nil, nil + } +} + +func (s *DmStatement) Close() error { + if s.closed { + return nil + } + if len(s.filterChain.filters) == 0 { + return s.close() + } + return s.filterChain.reset().DmStatementClose(s) +} + +func (s *DmStatement) NumInput() int { + if err := s.checkClosed(); err != nil { + return 0 + } + if len(s.filterChain.filters) == 0 { + return s.numInput() + } + return s.filterChain.reset().DmStatementNumInput(s) +} + +func (s *DmStatement) Exec(args []driver.Value) (driver.Result, error) { + if err := s.checkClosed(); err != nil { + return nil, err + } + if len(s.filterChain.filters) == 0 { + return s.exec(args) + } + return s.filterChain.reset().DmStatementExec(s, args) +} + +func (s *DmStatement) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { + if err := s.checkClosed(); err != nil { + return nil, err + } + if len(s.filterChain.filters) == 0 { + return s.execContext(ctx, args) + } + return s.filterChain.reset().DmStatementExecContext(s, ctx, args) +} + +func (s *DmStatement) Query(args []driver.Value) (driver.Rows, error) { + if err := s.checkClosed(); err != nil { + return nil, err + } + if len(s.filterChain.filters) == 0 { + return s.query(args) + } + return s.filterChain.reset().DmStatementQuery(s, args) +} + +func (s *DmStatement) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + if err := s.checkClosed(); err != nil { + return nil, err + } + if len(s.filterChain.filters) == 0 { + return s.queryContext(ctx, args) + } + return s.filterChain.reset().DmStatementQueryContext(s, ctx, args) +} + +func (s *DmStatement) CheckNamedValue(nv *driver.NamedValue) error { + if len(s.filterChain.filters) == 0 { + return s.checkNamedValue(nv) + } + return s.filterChain.reset().DmStatementCheckNamedValue(s, nv) +} + +func (st *DmStatement) prepare() error { + var err error + if st.dmConn.dmConnector.escapeProcess { + st.nativeSql, err = st.dmConn.escape(st.nativeSql, st.dmConn.dmConnector.keyWords) + if err != nil { + return err + } + } + + st.execInfo, err = st.dmConn.Access.Dm_build_407(st, Dm_build_685) + if err != nil { + return err + } + st.curRowBindIndicator = make([]byte, st.paramCount) + return nil +} + +func (stmt *DmStatement) close() error { + stmt.inUse = true + if stmt.dmConn.stmtPool != nil && len(stmt.dmConn.stmtPool) < stmt.dmConn.dmConnector.stmtPoolMaxSize { + stmt.pool() + return nil + } else { + return stmt.free() + } +} + +func (stmt *DmStatement) numInput() int { + return int(stmt.paramCount) +} + +func (stmt *DmStatement) checkNamedValue(nv *driver.NamedValue) error { + var err error + var cvt = converter{stmt.dmConn, false} + nv.Value, err = cvt.ConvertValue(nv.Value) + stmt.isBatch = cvt.isBatch + return err +} + +func (stmt *DmStatement) exec(args []driver.Value) (*DmResult, error) { + var err error + + stmt.inUse = true + if stmt.isBatch && len(args) > 0 { + var tmpArg []driver.Value + var arg driver.Value + for i := len(args) - 1; i >= 0; i-- { + if args[i] != nil { + arg = args[i] + break + } + } + for _, row := range arg.([][]interface{}) { + tmpArg = append(tmpArg, row) + } + err = stmt.executeBatch(tmpArg) + } else { + err = stmt.executeInner(args, Dm_build_687) + } + if err != nil { + return nil, err + } + return newDmResult(stmt, stmt.execInfo), nil +} + +func (stmt *DmStatement) execContext(ctx context.Context, args []driver.NamedValue) (*DmResult, error) { + stmt.inUse = true + dargs, err := namedValueToValue(stmt, args) + if err != nil { + return nil, err + } + + if err := stmt.dmConn.watchCancel(ctx); err != nil { + return nil, err + } + defer stmt.dmConn.finish() + + return stmt.exec(dargs) +} + +func (stmt *DmStatement) query(args []driver.Value) (*DmRows, error) { + var err error + stmt.inUse = true + err = stmt.executeInner(args, Dm_build_686) + if err != nil { + return nil, err + } + + return newDmRows(newInnerRows(0, stmt, stmt.execInfo)), nil +} + +func (stmt *DmStatement) queryContext(ctx context.Context, args []driver.NamedValue) (*DmRows, error) { + stmt.inUse = true + dargs, err := namedValueToValue(stmt, args) + if err != nil { + return nil, err + } + + if err := stmt.dmConn.watchCancel(ctx); err != nil { + return nil, err + } + + rows, err := stmt.query(dargs) + if err != nil { + stmt.dmConn.finish() + return nil, err + } + rows.finish = stmt.dmConn.finish + return rows, err +} + +func NewDmStmt(conn *DmConnection, sql string) (*DmStatement, error) { + var s *DmStatement + + if conn.stmtMap != nil && len(conn.stmtMap) > 0 { + for _, sv := range conn.stmtMap { + if !sv.inUse { + sv.inUse = true + sv.nativeSql = sql + s = sv + break + } + } + } + + if s == nil { + s = new(DmStatement) + s.resetFilterable(&conn.filterable) + s.objId = -1 + s.idGenerator = dmStmtIDGenerator + s.dmConn = conn + s.maxRows = int64(conn.dmConnector.maxRows) + s.nativeSql = sql + s.rsMap = make(map[int16]*innerRows) + s.inUse = true + s.isBatch = conn.isBatch + + if conn.stmtPool != nil && len(conn.stmtPool) > 0 { + len := len(conn.stmtPool) + spi := conn.stmtPool[0] + copy(conn.stmtPool, conn.stmtPool[1:]) + conn.stmtPool = conn.stmtPool[:len-1] + s.id = spi.id + s.cursorName = spi.cursorName + s.readBaseColName = spi.readBaseColName + } else { + err := conn.Access.Dm_build_389(s) + if err != nil { + return nil, err + } + } + conn.stmtMap[s.id] = s + } + + return s, nil + +} + +func (stmt *DmStatement) checkClosed() error { + if stmt.dmConn.closed.IsSet() { + return driver.ErrBadConn + } else if stmt.closed { + return ECGO_STATEMENT_HANDLE_CLOSED.throw() + } + + return nil +} + +func (stmt *DmStatement) pool() { + for _, rs := range stmt.rsMap { + rs.Close() + } + + stmt.dmConn.stmtPool = append(stmt.dmConn.stmtPool, stmtPoolInfo{stmt.id, stmt.cursorName, stmt.readBaseColName}) + delete(stmt.dmConn.stmtMap, stmt.id) + stmt.inUse = false + stmt.closed = true +} + +func (stmt *DmStatement) free() error { + for _, rs := range stmt.rsMap { + rs.Close() + } + + err := stmt.dmConn.Access.Dm_build_394(int32(stmt.id)) + if err != nil { + return err + } + delete(stmt.dmConn.stmtMap, stmt.id) + stmt.inUse = false + stmt.closed = true + return nil +} + +func encodeArgs(stmt *DmStatement, args []driver.Value) ([]interface{}, error) { + bytes := make([]interface{}, len(args), len(args)) + + var err error + + for i, arg := range args { + nextSwitch: + if stmt.params[i].colType == CURSOR { + if stmt.params[i].cursorStmt == nil { + stmt.params[i].cursorStmt = &DmStatement{dmConn: stmt.dmConn} + stmt.params[i].cursorStmt.resetFilterable(&stmt.dmConn.filterable) + err = stmt.params[i].cursorStmt.dmConn.Access.Dm_build_389(stmt.params[i].cursorStmt) + } + stmt.curRowBindIndicator[i] |= BIND_OUT + continue + } + if arg == nil { + if resetColType(stmt, i, NULL) { + bytes[i] = ParamDataEnum_Null + } + continue + } + + switch v := arg.(type) { + case bool: + if resetColType(stmt, i, BIT) { + bytes[i], err = G2DB.fromBool(v, stmt.params[i], stmt.dmConn) + } + case int8: + if resetColType(stmt, i, TINYINT) { + bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn) + } + case int16: + if resetColType(stmt, i, SMALLINT) { + bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn) + } + case int32: + if resetColType(stmt, i, INT) { + bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn) + } + case int64: + if resetColType(stmt, i, BIGINT) { + bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn) + } + case int: + if resetColType(stmt, i, BIGINT) { + bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn) + } + case uint8: + if resetColType(stmt, i, SMALLINT) { + bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn) + } + case uint16: + if resetColType(stmt, i, INT) { + bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn) + } + case uint32: + if resetColType(stmt, i, BIGINT) { + bytes[i], err = G2DB.fromInt64(int64(v), stmt.params[i], stmt.dmConn) + } + + case float32: + if resetColType(stmt, i, REAL) { + bytes[i], err = G2DB.fromFloat32(v, stmt.params[i], stmt.dmConn) + } + case float64: + if resetColType(stmt, i, DOUBLE) { + bytes[i], err = G2DB.fromFloat64(float64(v), stmt.params[i], stmt.dmConn) + } + case []byte: + if resetColType(stmt, i, VARBINARY) { + bytes[i], err = G2DB.fromBytes(v, stmt.params[i], stmt.dmConn) + } + case string: + + if v == "" && emptyStringToNil(stmt.params[i].colType) { + arg = nil + goto nextSwitch + } + if resetColType(stmt, i, VARCHAR) { + bytes[i], err = G2DB.fromString(v, stmt.params[i], stmt.dmConn) + } + case time.Time: + if resetColType(stmt, i, DATETIME_TZ) { + bytes[i], err = G2DB.fromTime(v, stmt.params[i], stmt.dmConn) + } + case DmTimestamp: + if resetColType(stmt, i, DATETIME_TZ) { + bytes[i], err = G2DB.fromTime(v.ToTime(), stmt.params[i], stmt.dmConn) + } + case DmIntervalDT: + if resetColType(stmt, i, INTERVAL_DT) { + bytes[i], err = G2DB.fromDmIntervalDT(v, stmt.params[i], stmt.dmConn) + } + case DmIntervalYM: + if resetColType(stmt, i, INTERVAL_YM) { + bytes[i], err = G2DB.fromDmdbIntervalYM(v, stmt.params[i], stmt.dmConn) + } + case DmDecimal: + if resetColType(stmt, i, DECIMAL) { + bytes[i], err = G2DB.fromDecimal(v, stmt.params[i], stmt.dmConn) + } + + case DmBlob: + if resetColType(stmt, i, BLOB) { + bytes[i], err = G2DB.fromBlob(DmBlob(v), stmt.params[i], stmt.dmConn) + if err != nil { + return nil, err + } + } + case DmClob: + if resetColType(stmt, i, CLOB) { + bytes[i], err = G2DB.fromClob(DmClob(v), stmt.params[i], stmt.dmConn) + if err != nil { + return nil, err + } + } + case DmArray: + if resetColType(stmt, i, ARRAY) { + da := &v + da, err = da.create(stmt.dmConn) + if err != nil { + return nil, err + } + + bytes[i], err = G2DB.fromArray(da, stmt.params[i], stmt.dmConn) + } + case DmStruct: + if resetColType(stmt, i, RECORD) { + ds := &v + ds, err = ds.create(stmt.dmConn) + if err != nil { + return nil, err + } + + bytes[i], err = G2DB.fromStruct(ds, stmt.params[i], stmt.dmConn) + } + case sql.Out: + arg = v.Dest + goto nextSwitch + + case *DmTimestamp: + if resetColType(stmt, i, DATETIME_TZ) { + bytes[i], err = G2DB.fromTime(v.ToTime(), stmt.params[i], stmt.dmConn) + } + case *DmIntervalDT: + if resetColType(stmt, i, INTERVAL_DT) { + bytes[i], err = G2DB.fromDmIntervalDT(*v, stmt.params[i], stmt.dmConn) + } + case *DmIntervalYM: + if resetColType(stmt, i, INTERVAL_YM) { + bytes[i], err = G2DB.fromDmdbIntervalYM(*v, stmt.params[i], stmt.dmConn) + } + case *DmDecimal: + if resetColType(stmt, i, DECIMAL) { + bytes[i], err = G2DB.fromDecimal(*v, stmt.params[i], stmt.dmConn) + } + case *DmBlob: + if resetColType(stmt, i, BLOB) { + bytes[i], err = G2DB.fromBlob(DmBlob(*v), stmt.params[i], stmt.dmConn) + } + case *DmClob: + if resetColType(stmt, i, CLOB) { + bytes[i], err = G2DB.fromClob(DmClob(*v), stmt.params[i], stmt.dmConn) + } + case *DmArray: + if resetColType(stmt, i, ARRAY) { + v, err = v.create(stmt.dmConn) + if err != nil { + return nil, err + } + + bytes[i], err = G2DB.fromArray(v, stmt.params[i], stmt.dmConn) + } + case *DmStruct: + if resetColType(stmt, i, RECORD) { + v, err = v.create(stmt.dmConn) + if err != nil { + return nil, err + } + + bytes[i], err = G2DB.fromStruct(v, stmt.params[i], stmt.dmConn) + } + case *driver.Rows: + if stmt.params[i].colType == CURSOR && !resetColType(stmt, i, CURSOR) && stmt.params[i].cursorStmt == nil { + stmt.params[i].cursorStmt = &DmStatement{dmConn: stmt.dmConn} + stmt.params[i].cursorStmt.resetFilterable(&stmt.dmConn.filterable) + err = stmt.params[i].cursorStmt.dmConn.Access.Dm_build_389(stmt.params[i].cursorStmt) + } + case io.Reader: + bytes[i], err = G2DB.fromReader(io.Reader(v), stmt.params[i], stmt.dmConn) + if err != nil { + return nil, err + } + default: + err = ECGO_UNSUPPORTED_INPARAM_TYPE.throw() + } + + if err != nil { + return nil, err + } + + } + + return bytes, nil +} + +type converter struct { + conn *DmConnection + isBatch bool +} +type decimalDecompose interface { + Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) +} + +func (c *converter) ConvertValue(v interface{}) (driver.Value, error) { + if driver.IsValue(v) { + return v, nil + } + + switch vr := v.(type) { + case driver.Valuer: + sv, err := callValuerValue(vr) + if err != nil { + return nil, err + } + + return sv, nil + + case decimalDecompose, DmDecimal, *DmDecimal, DmTimestamp, *DmTimestamp, DmIntervalDT, *DmIntervalDT, + DmIntervalYM, *DmIntervalYM, driver.Rows, *driver.Rows, DmArray, *DmArray, DmStruct, *DmStruct, sql.Out: + return vr, nil + case big.Int: + return NewDecimalFromBigInt(&vr) + case big.Float: + return NewDecimalFromBigFloat(&vr) + case DmClob: + + if vr.connection == nil { + vr.connection = c.conn + } + return vr, nil + case DmBlob: + + if vr.connection == nil { + vr.connection = c.conn + } + return vr, nil + case *DmBlob: + + if vr.connection == nil { + vr.connection = c.conn + } + return vr, nil + case io.Reader: + return vr, nil + } + + rv := reflect.ValueOf(v) + switch rv.Kind() { + case reflect.Ptr: + if rv.IsNil() { + return nil, nil + } else { + return c.ConvertValue(rv.Elem().Interface()) + } + case reflect.Int: + return rv.Int(), nil + case reflect.Int8: + return int8(rv.Int()), nil + case reflect.Int16: + return int16(rv.Int()), nil + case reflect.Int32: + return int32(rv.Int()), nil + case reflect.Int64: + return int64(rv.Int()), nil + case reflect.Uint8: + return uint8(rv.Uint()), nil + case reflect.Uint16: + return uint16(rv.Uint()), nil + case reflect.Uint32: + return uint32(rv.Uint()), nil + case reflect.Uint64, reflect.Uint: + u64 := rv.Uint() + if u64 >= 1<<63 { + bigInt := &big.Int{} + bigInt.SetString(strconv.FormatUint(u64, 10), 10) + return NewDecimalFromBigInt(bigInt) + } + return int64(u64), nil + case reflect.Float32: + return float32(rv.Float()), nil + case reflect.Float64: + return float64(rv.Float()), nil + case reflect.Bool: + return rv.Bool(), nil + case reflect.Slice: + ek := rv.Type().Elem().Kind() + if ek == reflect.Uint8 { + return rv.Bytes(), nil + } else if ek == reflect.Slice { + c.isBatch = true + return v, nil + } + return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek) + case reflect.String: + return rv.String(), nil + } + return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) +} + +var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() + +func callValuerValue(vr driver.Valuer) (v driver.Value, err error) { + if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr && + rv.IsNil() && + rv.Type().Elem().Implements(valuerReflectType) { + return nil, nil + } + return vr.Value() +} + +func namedValueToValue(stmt *DmStatement, named []driver.NamedValue) ([]driver.Value, error) { + + dargs := make([]driver.Value, stmt.paramCount) + for i, _ := range dargs { + found := false + for _, nv := range named { + if nv.Name != "" && strings.ToUpper(nv.Name) == strings.ToUpper(stmt.params[i].name) { + dargs[i] = nv.Value + found = true + break + } + } + + if !found && i < len(named) { + dargs[i] = named[i].Value + } + + } + return dargs, nil +} + +func (stmt *DmStatement) executeInner(args []driver.Value, executeType int16) (err error) { + + var bytes []interface{} + + if stmt.paramCount > 0 { + bytes, err = encodeArgs(stmt, args) + if err != nil { + return err + } + } + stmt.execInfo, err = stmt.dmConn.Access.Dm_build_439(stmt, bytes, false) + if err != nil { + return err + } + if stmt.execInfo.outParamDatas != nil { + for i, outParamData := range stmt.execInfo.outParamDatas { + if stmt.curRowBindIndicator[i]&BIND_OUT == BIND_OUT { + if outParamData == nil { + if arg, ok := args[i].(*driver.Rows); ok && stmt.params[i].colType == CURSOR { + var tmpExecInfo *execRetInfo + if tmpExecInfo, err = stmt.dmConn.Access.Dm_build_449(stmt.params[i].cursorStmt, 1); err != nil { + return err + } + if tmpExecInfo.hasResultSet { + *arg = newDmRows(newInnerRows(0, stmt.params[i].cursorStmt, tmpExecInfo)) + } else { + *arg = nil + } + } else { + args[i] = nil + } + continue + } + if args[i] == nil { + switch stmt.params[i].colType { + case BOOLEAN: + args[i], err = DB2G.toBool(outParamData, &stmt.params[i].column, stmt.dmConn) + case BIT: + if strings.ToLower(stmt.params[i].typeName) == "boolean" { + args[i], err = DB2G.toBool(outParamData, &stmt.params[i].column, stmt.dmConn) + } + + args[i], err = DB2G.toInt8(outParamData, &stmt.params[i].column, stmt.dmConn) + case TINYINT: + args[i], err = DB2G.toInt8(outParamData, &stmt.params[i].column, stmt.dmConn) + case SMALLINT: + args[i], err = DB2G.toInt16(outParamData, &stmt.params[i].column, stmt.dmConn) + case INT: + args[i], err = DB2G.toInt32(outParamData, &stmt.params[i].column, stmt.dmConn) + case BIGINT: + args[i], err = DB2G.toInt64(outParamData, &stmt.params[i].column, stmt.dmConn) + case REAL: + args[i], err = DB2G.toFloat32(outParamData, &stmt.params[i].column, stmt.dmConn) + case DOUBLE: + args[i], err = DB2G.toFloat64(outParamData, &stmt.params[i].column, stmt.dmConn) + case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ: + args[i], err = DB2G.toTime(outParamData, &stmt.params[i].column, stmt.dmConn) + case INTERVAL_DT: + args[i] = newDmIntervalDTByBytes(outParamData) + case INTERVAL_YM: + args[i] = newDmIntervalYMByBytes(outParamData) + case DECIMAL: + args[i], err = DB2G.toDmDecimal(outParamData, &stmt.params[i].column, stmt.dmConn) + case BINARY, VARBINARY: + args[i] = util.StringUtil.BytesToHexString(outParamData, false) + case BLOB: + args[i] = DB2G.toDmBlob(outParamData, &stmt.params[i].column, stmt.dmConn) + case CHAR, VARCHAR2, VARCHAR: + args[i] = DB2G.toString(outParamData, &stmt.params[i].column, stmt.dmConn) + case CLOB: + args[i] = DB2G.toDmClob(outParamData, stmt.dmConn, &stmt.params[i].column) + default: + err = ECGO_UNSUPPORTED_OUTPARAM_TYPE.throw() + } + } else { + nextSwitch: + switch v := args[i].(type) { + case sql.Out: + args[i] = v.Dest + goto nextSwitch + case string, *string: + args[i] = DB2G.toString(outParamData, &stmt.params[i].column, stmt.dmConn) + case []byte, *[]byte: + args[i], err = DB2G.toBytes(outParamData, &stmt.params[i].column, stmt.dmConn) + case bool, *bool: + args[i], err = DB2G.toBool(outParamData, &stmt.params[i].column, stmt.dmConn) + case int8, *int8: + args[i], err = DB2G.toInt8(outParamData, &stmt.params[i].column, stmt.dmConn) + case int16, *int16: + args[i], err = DB2G.toInt16(outParamData, &stmt.params[i].column, stmt.dmConn) + case int32, *int32: + args[i], err = DB2G.toInt32(outParamData, &stmt.params[i].column, stmt.dmConn) + case int64, *int64: + args[i], err = DB2G.toInt64(outParamData, &stmt.params[i].column, stmt.dmConn) + case uint8, *uint8: + args[i], err = DB2G.toByte(outParamData, &stmt.params[i].column, stmt.dmConn) + case uint16, *uint16: + args[i], err = DB2G.toUInt16(outParamData, &stmt.params[i].column, stmt.dmConn) + case uint32, *uint32: + args[i], err = DB2G.toUInt32(outParamData, &stmt.params[i].column, stmt.dmConn) + case uint64, *uint64: + args[i], err = DB2G.toUInt64(outParamData, &stmt.params[i].column, stmt.dmConn) + case int, *int: + args[i], err = DB2G.toInt(outParamData, &stmt.params[i].column, stmt.dmConn) + case uint, *uint: + args[i], err = DB2G.toUInt(outParamData, &stmt.params[i].column, stmt.dmConn) + case float32, *float32: + args[i], err = DB2G.toFloat32(outParamData, &stmt.params[i].column, stmt.dmConn) + case float64, *float64: + args[i], err = DB2G.toFloat64(outParamData, &stmt.params[i].column, stmt.dmConn) + case time.Time, *time.Time: + args[i], err = DB2G.toTime(outParamData, &stmt.params[i].column, stmt.dmConn) + case DmTimestamp, *DmTimestamp: + args[i] = newDmTimestampFromBytes(outParamData, stmt.params[i].column, stmt.dmConn) + case DmIntervalDT, *DmIntervalDT: + args[i] = newDmIntervalDTByBytes(outParamData) + case DmIntervalYM, *DmIntervalYM: + args[i] = newDmIntervalYMByBytes(outParamData) + case DmDecimal, *DmDecimal: + args[i], err = DB2G.toDmDecimal(outParamData, &stmt.params[i].column, stmt.dmConn) + case DmBlob, *DmBlob: + args[i] = DB2G.toDmBlob(outParamData, &stmt.params[i].column, stmt.dmConn) + case DmClob, *DmClob: + args[i] = DB2G.toDmClob(outParamData, stmt.dmConn, &stmt.params[i].column) + case *driver.Rows: + if stmt.params[i].colType == CURSOR { + var tmpExecInfo *execRetInfo + tmpExecInfo, err = stmt.dmConn.Access.Dm_build_449(stmt.params[i].cursorStmt, 1) + if err != nil { + return err + } + + if tmpExecInfo.hasResultSet { + *v = newDmRows(newInnerRows(0, stmt.params[i].cursorStmt, tmpExecInfo)) + } else { + *v = nil + } + } + case DmArray, *DmArray: + args[i], err = TypeDataSV.bytesToArray(outParamData, nil, stmt.params[i].typeDescriptor) + case DmStruct, *DmStruct: + args[i], err = TypeDataSV.bytesToRecord(outParamData, nil, stmt.params[i].typeDescriptor) + default: + err = ECGO_UNSUPPORTED_OUTPARAM_TYPE.throw() + } + } + } + } + } + + return err +} + +func (stmt *DmStatement) executeBatch(args []driver.Value) (err error) { + + var bytes [][]interface{} + + if stmt.execInfo.retSqlType == Dm_build_700 || stmt.execInfo.retSqlType == Dm_build_705 { + return ECGO_INVALID_SQL_TYPE.throw() + } + + if stmt.paramCount > 0 && args != nil && len(args) > 0 { + + if len(args) == 1 || stmt.dmConn.dmConnector.batchType == 2 || + (stmt.dmConn.dmConnector.batchNotOnCall && stmt.execInfo.retSqlType == Dm_build_701) { + return stmt.executeBatchByRow(args) + } else { + for _, arg := range args { + var newArg []driver.Value + for _, a := range arg.([]interface{}) { + newArg = append(newArg, a) + } + tmpBytes, err := encodeArgs(stmt, newArg) + if err != nil { + return err + } + bytes = append(bytes, tmpBytes) + } + stmt.execInfo, err = stmt.dmConn.Access.Dm_build_428(stmt, bytes, stmt.preExec) + } + } + return err +} + +func (stmt *DmStatement) executeBatchByRow(args []driver.Value) (err error) { + count := len(args) + stmt.execInfo = NewExceInfo() + stmt.execInfo.updateCounts = make([]int64, count) + var sqlErrBuilder strings.Builder + for i := 0; i < count; i++ { + tmpExecInfo, err := stmt.dmConn.Access.Dm_build_439(stmt, args[i].([]interface{}), stmt.preExec || i != 0) + if err == nil { + stmt.execInfo.union(tmpExecInfo, i, 1) + } else { + stmt.execInfo.updateCounts[i] = -1 + if stmt.dmConn.dmConnector.continueBatchOnError { + sqlErrBuilder.WriteString("row[" + strconv.Itoa(i) + "]:" + err.Error() + util.LINE_SEPARATOR) + } else { + return ECGO_BATCH_ERROR.addDetailln(err.Error()).throw() + } + } + } + if sqlErrBuilder.Len() > 0 { + return EC_BP_WITH_ERROR.addDetail(sqlErrBuilder.String()).throw() + } + return nil +} diff --git a/dmr/util/zzq.go b/dmr/util/zzq.go new file mode 100644 index 0000000..00660f2 --- /dev/null +++ b/dmr/util/zzq.go @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package util + +func Split(s string, sep string) []string { + var foot = make([]int, len(s)) // 足够的元素个数 + var count, sLen, sepLen = 0, len(s), len(sep) + for i := 0; i < sLen; i++ { + // 处理 s == “-9999-1" && seperators == "-"情况 + if i == 0 && sLen >= sepLen { + if s[0:sepLen] == sep { + i += sepLen - 1 + continue + } + } + for j := 0; j < sepLen; j++ { + if s[i] == sep[j] { + foot[count] = i + count++ + break + } + } + } + var ret = make([]string, count+1) + if count == 0 { + ret[0] = s + return ret + } + ret[0] = s[0:foot[0]] + for i := 1; i < count; i++ { + ret[i] = s[foot[i-1]+1 : foot[i]] + } + ret[count] = s[foot[count-1]+1:] + return ret +} diff --git a/dmr/util/zzr.go b/dmr/util/zzr.go new file mode 100644 index 0000000..78147cb --- /dev/null +++ b/dmr/util/zzr.go @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package util + +import ( + "go/build" + "os" + "runtime" + "strings" +) + +const ( + PathSeparator = string(os.PathSeparator) + PathListSeparator = string(os.PathListSeparator) +) + +var ( + goRoot = build.Default.GOROOT + goPath = build.Default.GOPATH //获取实际编译时的GOPATH值 +) + +type fileUtil struct { +} + +var FileUtil = &fileUtil{} + +func (fileUtil *fileUtil) Exists(path string) bool { + if _, err := os.Stat(path); !os.IsNotExist(err) { + return true + } + return false +} + +func (fileUtil *fileUtil) Search(relativePath string) (path string) { + if strings.Contains(runtime.GOOS, "windows") { + relativePath = strings.ReplaceAll(relativePath, "/", "\\") + } + + if fileUtil.Exists(goPath) { + for _, s := range strings.Split(goPath, PathListSeparator) { + path = s + PathSeparator + "src" + PathSeparator + relativePath + if fileUtil.Exists(path) { + return path + } + } + } + + if fileUtil.Exists(goPath) { + for _, s := range strings.Split(goPath, PathListSeparator) { + path = s + PathSeparator + "pkg" + PathSeparator + relativePath + if fileUtil.Exists(path) { + return path + } + } + } + + //if workDir, _ := os.Getwd(); fileUtil.Exists(workDir) { + // path = workDir + PathSeparator + "src" + PathSeparator + relativePath + // if fileUtil.Exists(path) { + // return path + // } + //} + + //if fileUtil.Exists(goRoot) { + // path = goRoot + PathSeparator + "src" + PathSeparator + relativePath + // if fileUtil.Exists(path) { + // return path + // } + //} + + return "" +} diff --git a/dmr/util/zzs.go b/dmr/util/zzs.go new file mode 100644 index 0000000..b01ae80 --- /dev/null +++ b/dmr/util/zzs.go @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package util + +const ( + LINE_SEPARATOR = "\n" +) + +func SliceEquals(src []byte, dest []byte) bool { + if len(src) != len(dest) { + return false + } + + for i, _ := range src { + if src[i] != dest[i] { + return false + } + } + + return true +} + +// 获取两个数的最大公约数,由调用者确保m、n>=0;如果m或n为0,返回1 +func GCD(m int32, n int32) int32 { + if m == 0 || n == 0 { + return 1 + } + r := m % n + m = n + n = r + if r == 0 { + return m + } else { + return GCD(m, n) + } +} + +// 返回切片中所有数的累加值 +func Sum(arr []int32) int32 { + var sum int32 = 0 + for _, i := range arr { + sum += i + } + return sum +} diff --git a/dmr/util/zzt.go b/dmr/util/zzt.go new file mode 100644 index 0000000..e652897 --- /dev/null +++ b/dmr/util/zzt.go @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package util + +import ( + "bytes" + "runtime" + "strings" + "time" + "unicode" +) + +type stringutil struct{} + +var StringUtil = &stringutil{} + +/*----------------------------------------------------*/ +func (StringUtil *stringutil) LineSeparator() string { + var lineSeparator string + if strings.Contains(runtime.GOOS, "windos") { + lineSeparator = "\r\n" + } else if strings.Contains(runtime.GOOS, "mac") { + lineSeparator = "\r" + } else { + lineSeparator = "\n" + } + + return lineSeparator +} + +func (StringUtil *stringutil) Equals(str1 string, str2 string) bool { + return str1 == str2 +} + +func (StringUtil *stringutil) EqualsIgnoreCase(str1 string, str2 string) bool { + return strings.ToUpper(str1) == strings.ToUpper(str2) +} + +func (StringUtil *stringutil) StartsWith(s string, subStr string) bool { + return strings.Index(s, subStr) == 0 +} + +func (StringUtil *stringutil) StartWithIgnoreCase(s string, subStr string) bool { + return strings.HasPrefix(strings.ToLower(s), strings.ToLower(subStr)) +} + +func (StringUtil *stringutil) EndsWith(s string, subStr string) bool { + return strings.LastIndex(s, subStr) == len(s)-1 +} + +func (StringUtil *stringutil) IsDigit(str string) bool { + if str == "" { + return false + } + sz := len(str) + for i := 0; i < sz; i++ { + if unicode.IsDigit(rune(str[i])) { + continue + } else { + return false + } + } + return true +} + +func (StringUtil *stringutil) FormatDir(dir string) string { + dir = strings.TrimSpace(dir) + if dir != "" { + if !StringUtil.EndsWith(dir, PathSeparator) { + dir += PathSeparator + } + } + return dir +} + +func (StringUtil *stringutil) HexStringToBytes(s string) []byte { + str := s + + bs := make([]byte, 0) + flag := false + + str = strings.TrimSpace(str) + if strings.Index(str, "0x") == 0 || strings.Index(str, "0X") == 0 { + str = str[2:] + } + + if len(str) == 0 { + return bs + } + + var bsChr []byte + l := len(str) + + if l%2 == 0 { + bsChr = []byte(str) + } else { + l += 1 + bsChr = make([]byte, l) + bsChr[0] = '0' + for i := 0; i < l-1; i++ { + bsChr[i+1] = str[i] + } + } + + bs = make([]byte, l/2) + + pos := 0 + for i := 0; i < len(bsChr); i += 2 { + bt := convertHex(bsChr[i]) + bt2 := convertHex(bsChr[i+1]) + if int(bt) == 0xff || int(bt2) == 0xff { + flag = true + break + } + + bs[pos] = byte(bt*16 + bt2) + pos++ + } + + if flag { + bs = ([]byte)(str) + } + + return bs +} + +func convertHex(chr byte) byte { + if chr >= '0' && chr <= '9' { + return chr - '0' + } else if chr >= 'a' && chr <= 'f' { + return chr - 'a' + 10 + } else if chr >= 'A' && chr <= 'F' { + return chr - 'A' + 10 + } else { + return 0xff + } +} + +func (StringUtil *stringutil) BytesToHexString(bs []byte, pre bool) string { + if bs == nil { + return "" + } + if len(bs) == 0 { + return "" + } + + hexDigits := "0123456789ABCDEF" + ret := new(strings.Builder) + for _, b := range bs { + ret.WriteByte(hexDigits[0x0F&(b>>4)]) + ret.WriteByte(hexDigits[0x0F&b]) + } + if pre { + return "0x" + ret.String() + } + return ret.String() +} + +func (StringUtil *stringutil) ProcessSingleQuoteOfName(name string) string { + return StringUtil.processQuoteOfName(name, "'") +} + +func (StringUtil *stringutil) ProcessDoubleQuoteOfName(name string) string { + return StringUtil.processQuoteOfName(name, "\"") +} + +func (StringUtil *stringutil) processQuoteOfName(name string, quote string) string { + if quote == "" || name == "" { + return name + } + + temp := name + result := bytes.NewBufferString("") + index := -1 + quetoLength := len(quote) + index = strings.Index(temp, quote) + for index != -1 { + result.WriteString(temp[:index+quetoLength]) + result.WriteString(quote) + temp = temp[index+quetoLength:] + index = strings.Index(temp, quote) + } + result.WriteString(temp) + return result.String() +} + +func (StringUtil *stringutil) FormatTime() string { + return time.Now().Format("2006-01-02 15:04:05") +} + +func (StringUtil *stringutil) SubstringBetween(str string, open string, close string) string { + if str == "" { + return "" + } + + iopen := -1 + if open != "" { + iopen = strings.Index(str, open) + } + + iclose := -1 + if close != "" { + iclose = strings.LastIndex(str, close) + } + + if iopen == -1 && iclose == -1 { + return "" + } else if iopen == -1 { + return str[0:iclose] + } else if iclose == -1 { + return str[iopen:] + } else { + return str[iopen:iclose] + } +} diff --git a/dmr/v.go b/dmr/v.go new file mode 100644 index 0000000..35bc373 --- /dev/null +++ b/dmr/v.go @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import "database/sql/driver" + +type DmStruct struct { + TypeData + m_strctDesc *StructDescriptor // 结构体的描述信息 + + m_attribs []TypeData // 各属性值 + + m_objCount int // 一个数组项中存在对象类型的个数(class、动态数组) + + m_strCount int // 一个数组项中存在字符串类型的个数 + + typeName string + + elements []interface{} + + // Valid为false代表DmArray数据在数据库中为NULL + Valid bool +} + +func newDmStruct(typeName string, elements []interface{}) *DmStruct { + ds := new(DmStruct) + ds.typeName = typeName + ds.elements = elements + ds.Valid = true + return ds +} + +func (ds *DmStruct) create(dc *DmConnection) (*DmStruct, error) { + desc, err := newStructDescriptor(ds.typeName, dc) + if err != nil { + return nil, err + } + return ds.createByStructDescriptor(desc, dc) +} + +func newDmStructByTypeData(atData []TypeData, desc *TypeDescriptor) *DmStruct { + ds := new(DmStruct) + ds.Valid = true + ds.initTypeData() + ds.m_strctDesc = newStructDescriptorByTypeDescriptor(desc) + ds.m_attribs = atData + return ds +} + +func (dest *DmStruct) Scan(src interface{}) error { + switch src := src.(type) { + case nil: + *dest = *new(DmStruct) + // 将Valid标志置false表示数据库中该列为NULL + (*dest).Valid = false + return nil + case *DmStruct: + *dest = *src + return nil + default: + return UNSUPPORTED_SCAN + } +} + +func (dt DmStruct) Value() (driver.Value, error) { + if !dt.Valid { + return nil, nil + } + return dt, nil +} + +func (ds *DmStruct) getAttribsTypeData() []TypeData { + return ds.m_attribs +} + +func (ds *DmStruct) createByStructDescriptor(desc *StructDescriptor, conn *DmConnection) (*DmStruct, error) { + ds.initTypeData() + + if nil == desc { + return nil, ECGO_INVALID_PARAMETER_VALUE.throw() + } + + ds.m_strctDesc = desc + if nil == ds.elements { + ds.m_attribs = make([]TypeData, desc.getSize()) + } else { + if desc.getSize() != len(ds.elements) && desc.getObjId() != 4 { + return nil, ECGO_STRUCT_MEM_NOT_MATCH.throw() + } + var err error + ds.m_attribs, err = TypeDataSV.toStruct(ds.elements, ds.m_strctDesc.m_typeDesc) + if err != nil { + return nil, err + } + } + + return ds, nil +} + +func (ds *DmStruct) getSQLTypeName() (string, error) { + return ds.m_strctDesc.m_typeDesc.getFulName() +} + +func (ds *DmStruct) getAttributes() ([]interface{}, error) { + return TypeDataSV.toJavaArrayByDmStruct(ds) +} + +func (ds *DmStruct) checkCol(col int) error { + if col < 1 || col > len(ds.m_attribs) { + return ECGO_INVALID_SEQUENCE_NUMBER.throw() + } + return nil +} + +// 获取指定索引的成员变量值,以TypeData的形式给出,col 1 based +func (ds *DmStruct) getAttrValue(col int) (*TypeData, error) { + err := ds.checkCol(col) + if err != nil { + return nil, err + } + return &ds.m_attribs[col-1], nil +} + +func (ds *DmStruct) checkValid() error { + if !ds.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} diff --git a/dmr/w.go b/dmr/w.go new file mode 100644 index 0000000..e730c1d --- /dev/null +++ b/dmr/w.go @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "database/sql/driver" + "strings" + "time" +) + +const ( + Seconds_1900_1970 = 2209017600 + + OFFSET_YEAR = 0 + + OFFSET_MONTH = 1 + + OFFSET_DAY = 2 + + OFFSET_HOUR = 3 + + OFFSET_MINUTE = 4 + + OFFSET_SECOND = 5 + + OFFSET_MILLISECOND = 6 + + OFFSET_TIMEZONE = 7 + + DT_LEN = 8 + + INVALID_VALUE = int(INT32_MIN) +) + +type DmTimestamp struct { + dt []int + dtype int + scale int + oracleFormatPattern string + oracleDateLanguage int + + // Valid为false代表DmArray数据在数据库中为NULL + Valid bool +} + +func newDmTimestampFromDt(dt []int, dtype int, scale int) *DmTimestamp { + dmts := new(DmTimestamp) + dmts.Valid = true + dmts.dt = dt + dmts.dtype = dtype + dmts.scale = scale + return dmts +} + +func newDmTimestampFromBytes(bytes []byte, column column, conn *DmConnection) *DmTimestamp { + dmts := new(DmTimestamp) + dmts.Valid = true + dmts.dt = decode(bytes, column.isBdta, int(column.colType), int(column.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + + if isLocalTimeZone(int(column.colType), int(column.scale)) { + dmts.scale = getLocalTimeZoneScale(int(column.colType), int(column.scale)) + } else { + dmts.scale = int(column.scale) + } + + dmts.dtype = int(column.colType) + dmts.scale = int(column.scale) + dmts.oracleDateLanguage = int(conn.OracleDateLanguage) + switch column.colType { + case DATE: + dmts.oracleFormatPattern = conn.FormatDate + case TIME: + dmts.oracleFormatPattern = conn.FormatTime + case TIME_TZ: + dmts.oracleFormatPattern = conn.FormatTimeTZ + case DATETIME: + dmts.oracleFormatPattern = conn.FormatTimestamp + case DATETIME_TZ: + dmts.oracleFormatPattern = conn.FormatTimestampTZ + } + return dmts +} + +func NewDmTimestampFromString(str string) (*DmTimestamp, error) { + dt := make([]int, DT_LEN) + dtype, err := toDTFromString(strings.TrimSpace(str), dt) + if err != nil { + return nil, err + } + + if dtype == DATE { + return newDmTimestampFromDt(dt, dtype, 0), nil + } + return newDmTimestampFromDt(dt, dtype, 6), nil +} + +func NewDmTimestampFromTime(time time.Time) *DmTimestamp { + dt := toDTFromTime(time) + return newDmTimestampFromDt(dt, DATETIME, 6) +} + +func (dmTimestamp *DmTimestamp) ToTime() time.Time { + return toTimeFromDT(dmTimestamp.dt, 0) +} + +// 获取年月日时分秒毫秒时区 +func (dmTimestamp *DmTimestamp) GetDt() []int { + return dmTimestamp.dt +} + +func (dmTimestamp *DmTimestamp) CompareTo(ts DmTimestamp) int { + if dmTimestamp.ToTime().Equal(ts.ToTime()) { + return 0 + } else if dmTimestamp.ToTime().Before(ts.ToTime()) { + return -1 + } else { + return 1 + } +} + +func (dmTimestamp *DmTimestamp) String() string { + if dmTimestamp.oracleFormatPattern != "" { + return dtToStringByOracleFormat(dmTimestamp.dt, dmTimestamp.oracleFormatPattern, dmTimestamp.oracleDateLanguage) + } + return dtToString(dmTimestamp.dt, dmTimestamp.dtype, dmTimestamp.scale) +} + +func (dest *DmTimestamp) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmTimestamp) + // 将Valid标志置false表示数据库中该列为NULL + (*dest).Valid = false + return nil + case *DmTimestamp: + *dest = *src + return nil + case time.Time: + ret := NewDmTimestampFromTime(src) + *dest = *ret + return nil + default: + return UNSUPPORTED_SCAN + } +} + +func (dmTimestamp DmTimestamp) Value() (driver.Value, error) { + if !dmTimestamp.Valid { + return nil, nil + } + return dmTimestamp, nil +} + +func (dmTimestamp *DmTimestamp) toBytes() ([]byte, error) { + return encode(dmTimestamp.dt, dmTimestamp.dtype, dmTimestamp.scale, dmTimestamp.dt[OFFSET_TIMEZONE]) +} + +/** + * 获取当前对象的年月日时分秒,如果原来没有decode会先decode; + */ +func (dmTimestamp *DmTimestamp) getDt() []int { + return dmTimestamp.dt +} + +func (dmTimestamp *DmTimestamp) getTime() int64 { + sec := toTimeFromDT(dmTimestamp.dt, 0).Unix() + return sec + int64(dmTimestamp.dt[OFFSET_MILLISECOND]) +} + +func (dmTimestamp *DmTimestamp) setTime(time int64) { + timeInMillis := (time / 1000) * 1000 + nanos := (int64)((time % 1000) * 1000000) + if nanos < 0 { + nanos = 1000000000 + nanos + timeInMillis = (((time / 1000) - 1) * 1000) + } + dmTimestamp.dt = toDTFromUnix(timeInMillis, nanos) +} + +func (dmTimestamp *DmTimestamp) setTimezone(tz int) error { + // DM中合法的时区取值范围为-12:59至+14:00 + if tz <= -13*60 || tz > 14*60 { + return ECGO_INVALID_DATETIME_FORMAT.throw() + } + dmTimestamp.dt[OFFSET_TIMEZONE] = tz + return nil +} + +func (dmTimestamp *DmTimestamp) getNano() int64 { + return int64(dmTimestamp.dt[OFFSET_MILLISECOND] * 1000) +} + +func (dmTimestamp *DmTimestamp) setNano(nano int64) { + dmTimestamp.dt[OFFSET_MILLISECOND] = (int)(nano / 1000) +} + +func (dmTimestamp *DmTimestamp) string() string { + if dmTimestamp.oracleFormatPattern != "" { + return dtToStringByOracleFormat(dmTimestamp.dt, dmTimestamp.oracleFormatPattern, dmTimestamp.oracleDateLanguage) + } + return dtToString(dmTimestamp.dt, dmTimestamp.dtype, dmTimestamp.scale) +} + +func (dmTimestamp *DmTimestamp) checkValid() error { + if !dmTimestamp.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} diff --git a/dmr/x.go b/dmr/x.go new file mode 100644 index 0000000..17edf20 --- /dev/null +++ b/dmr/x.go @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "context" + "strconv" + "strings" + "sync" + "time" +) + +const ( + STATUS_VALID_TIME = 20 * time.Second // ms + + // sort 值 + SORT_SERVER_MODE_INVALID = -1 // 不允许连接的模式 + + SORT_SERVER_NOT_ALIVE = -2 // 站点无法连接 + + SORT_UNKNOWN = INT32_MAX // 站点还未连接过,模式未知 + + SORT_NORMAL = 30 + + SORT_PRIMARY = 20 + + SORT_STANDBY = 10 + + // OPEN>MOUNT>SUSPEND + SORT_OPEN = 3 + + SORT_MOUNT = 2 + + SORT_SUSPEND = 1 +) + +type ep struct { + host string + port int32 + alive bool + statusRefreshTs int64 // 状态更新的时间点 + serverMode int32 + serverStatus int32 + dscControl bool + sort int32 + epSeqno int32 + epStatus int32 + lock sync.Mutex +} + +func newEP(host string, port int32) *ep { + ep := new(ep) + ep.host = host + ep.port = port + ep.serverMode = -1 + ep.serverStatus = -1 + ep.sort = SORT_UNKNOWN + return ep +} + +func (ep *ep) getSort(checkTime bool) int32 { + if checkTime { + if time.Now().UnixNano()-ep.statusRefreshTs < int64(STATUS_VALID_TIME) { + return ep.sort + } else { + return SORT_UNKNOWN + } + } + return ep.sort +} + +func (ep *ep) calcSort(loginMode int32) int32 { + var sort int32 = 0 + switch loginMode { + case LOGIN_MODE_PRIMARY_FIRST: + { + // 主机优先:PRIMARY>NORMAL>STANDBY + switch ep.serverMode { + case SERVER_MODE_NORMAL: + sort += SORT_NORMAL * 10 + case SERVER_MODE_PRIMARY: + sort += SORT_PRIMARY * 100 + case SERVER_MODE_STANDBY: + sort += SORT_STANDBY + } + } + case LOGIN_MODE_STANDBY_FIRST: + { + // STANDBY优先: STANDBY>PRIMARY>NORMAL + switch ep.serverMode { + case SERVER_MODE_NORMAL: + sort += SORT_NORMAL + case SERVER_MODE_PRIMARY: + sort += SORT_PRIMARY * 10 + case SERVER_MODE_STANDBY: + sort += SORT_STANDBY * 100 + } + } + case LOGIN_MODE_PRIMARY_ONLY: + if ep.serverMode != SERVER_MODE_PRIMARY { + return SORT_SERVER_MODE_INVALID + } + sort += SORT_PRIMARY + case LOGIN_MODE_STANDBY_ONLY: + if ep.serverMode != SERVER_MODE_STANDBY { + return SORT_SERVER_MODE_INVALID + } + sort += SORT_STANDBY + } + + switch ep.serverStatus { + case SERVER_STATUS_MOUNT: + sort += SORT_MOUNT + case SERVER_STATUS_OPEN: + sort += SORT_OPEN + case SERVER_STATUS_SUSPEND: + sort += SORT_SUSPEND + } + return sort +} + +func (ep *ep) refreshStatus(alive bool, conn *DmConnection) { + ep.lock.Lock() + defer ep.lock.Unlock() + ep.alive = alive + ep.statusRefreshTs = time.Now().UnixNano() + if alive { + ep.serverMode = conn.SvrMode + ep.serverStatus = conn.SvrStat + ep.dscControl = conn.dscControl + ep.sort = ep.calcSort(int32(conn.dmConnector.loginMode)) + } else { + ep.serverMode = -1 + ep.serverStatus = -1 + ep.dscControl = false + ep.sort = SORT_SERVER_NOT_ALIVE + } +} + +func (ep *ep) connect(connector *DmConnector) (*DmConnection, error) { + connector.host = ep.host + connector.port = ep.port + conn, err := connector.connectSingle(context.Background()) + if err != nil { + ep.refreshStatus(false, conn) + return nil, err + } + ep.refreshStatus(true, conn) + return conn, nil +} + +func (ep *ep) getServerStatusDesc(serverStatus int32) string { + ret := "" + switch ep.serverStatus { + case SERVER_STATUS_OPEN: + ret = "OPEN" + case SERVER_STATUS_MOUNT: + ret = "MOUNT" + case SERVER_STATUS_SUSPEND: + ret = "SUSPEND" + default: + ret = "UNKNOWN" + } + return ret +} + +func (ep *ep) getServerModeDesc(serverMode int32) string { + ret := "" + switch ep.serverMode { + case SERVER_MODE_NORMAL: + ret = "NORMAL" + case SERVER_MODE_PRIMARY: + ret = "PRIMARY" + case SERVER_MODE_STANDBY: + ret = "STANDBY" + default: + ret = "UNKNOWN" + } + return ret +} + +func (ep *ep) String() string { + dscControl := ")" + if ep.dscControl { + dscControl = ", DSC CONTROL)" + } + return strings.TrimSpace(ep.host) + ":" + strconv.Itoa(int(ep.port)) + + " (" + ep.getServerModeDesc(ep.serverMode) + ", " + ep.getServerStatusDesc(ep.serverStatus) + dscControl +} diff --git a/dmr/y.go b/dmr/y.go new file mode 100644 index 0000000..73e7155 --- /dev/null +++ b/dmr/y.go @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "bytes" + "math/rand" + "sync" + "time" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +/** + * dm_svc.conf中配置的服务名对应的一组实例, 以及相关属性和状态信息 + * + * 需求: + * 1. 连接均匀分布在各个节点上 + * 2. loginMode,loginStatus匹配 + * 3. 连接异常节点比较耗时,在DB列表中包含异常节点时异常连接尽量靠后,减少对建连接速度的影响 + * + * + * DB 连接顺序: + * 1. well distribution,每次连接都从列表的下一个节点开始 + * 2. 用DB sort值按从大到小排序,sort为一个四位数XXXX,个位--serverStatus,十位--serverMode,共 有三种模式,最优先的 *100, 次优先的*10 + */ +type epGroup struct { + name string + epList []*ep + props *Properties + epStartPos int32 // wellDistribute 起始位置 + lock sync.Mutex +} + +func newEPGroup(name string, serverList []*ep) *epGroup { + g := new(epGroup) + g.name = name + g.epList = serverList + if serverList == nil || len(serverList) == 0 { + g.epStartPos = -1 + } else { + // 保证进程间均衡,起始位置采用随机值 + g.epStartPos = rand.Int31n(int32(len(serverList))) - 1 + } + return g +} + +func (g *epGroup) connect(connector *DmConnector) (*DmConnection, error) { + var dbSelector = g.getEPSelector(connector) + var ex error = nil + // 如果配置了loginMode的主、备等优先策略,而未找到最高优先级的节点时持续循环switchtimes次,如果最终还是没有找到最高优先级则选择次优先级的 + // 如果只有一个节点,一轮即可决定是否连接;多个节点时保证switchTimes轮尝试,最后一轮决定用哪个节点(由于节点已经按照模式优先级排序,最后一轮理论上就是连第一个节点) + var cycleCount int32 + if len(g.epList) == 1 { + cycleCount = 1 + } else { + cycleCount = connector.switchTimes + 1 + } + for i := int32(0); i < cycleCount; i++ { + // 循环了一遍,如果没有符合要求的, 重新排序, 再尝试连接 + conn, err := g.traverseServerList(connector, dbSelector, i == 0, i == cycleCount-1) + if err != nil { + ex = err + time.Sleep(time.Duration(connector.switchInterval) * time.Millisecond) + continue + } + return conn, nil + } + return nil, ex +} + +func (g *epGroup) getEPSelector(connector *DmConnector) *epSelector { + if connector.epSelector == TYPE_HEAD_FIRST { + return newEPSelector(g.epList) + } else { + serverCount := int32(len(g.epList)) + sortEPs := make([]*ep, serverCount) + g.lock.Lock() + defer g.lock.Unlock() + g.epStartPos = (g.epStartPos + 1) % serverCount + for i := int32(0); i < serverCount; i++ { + sortEPs[i] = g.epList[(i+g.epStartPos)%serverCount] + } + return newEPSelector(sortEPs) + } +} + +/** +* 从指定编号开始,遍历一遍服务名中的ip列表,只连接指定类型(主机或备机)的ip +* @param servers +* @param checkTime +* +* @exception +* DBError.ECJDBC_INVALID_SERVER_MODE 有站点的模式不匹配 +* DBError.ECJDBC_COMMUNITION_ERROR 所有站点都连不上 + */ +func (g *epGroup) traverseServerList(connector *DmConnector, epSelector *epSelector, first bool, last bool) (*DmConnection, error) { + epList := epSelector.sortDBList(first) + errorMsg := bytes.NewBufferString("") + var ex error = nil // 第一个错误 + for _, server := range epList { + conn, err := server.connect(connector) + if err != nil { + if ex == nil { + ex = err + } + errorMsg.WriteString("[") + errorMsg.WriteString(server.String()) + errorMsg.WriteString("]") + errorMsg.WriteString(err.Error()) + errorMsg.WriteString(util.StringUtil.LineSeparator()) + continue + } + valid, err := epSelector.checkServerMode(conn, last) + if err != nil { + if ex == nil { + ex = err + } + errorMsg.WriteString("[") + errorMsg.WriteString(server.String()) + errorMsg.WriteString("]") + errorMsg.WriteString(err.Error()) + errorMsg.WriteString(util.StringUtil.LineSeparator()) + continue + } + if !valid { + conn.close() + err = ECGO_INVALID_SERVER_MODE.throw() + if ex == nil { + ex = err + } + errorMsg.WriteString("[") + errorMsg.WriteString(server.String()) + errorMsg.WriteString("]") + errorMsg.WriteString(err.Error()) + errorMsg.WriteString(util.StringUtil.LineSeparator()) + continue + } + return conn, nil + } + if ex != nil { + return nil, ex + } + return nil, ECGO_COMMUNITION_ERROR.addDetail(errorMsg.String()).throw() +} diff --git a/dmr/z.go b/dmr/z.go new file mode 100644 index 0000000..377fba1 --- /dev/null +++ b/dmr/z.go @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import "sort" + +const ( + TYPE_WELL_DISTRIBUTE = 0 + TYPE_HEAD_FIRST = 1 +) + +type epSelector struct { + dbs []*ep +} + +func newEPSelector(dbs []*ep) *epSelector { + return &epSelector{dbs} +} + +func (s *epSelector) sortDBList(first bool) []*ep { + if !first { + // 按sort从大到小排序,相同sort值顺序不变 + sort.Slice(s.dbs, func(i, j int) bool { + return s.dbs[i].getSort(first) > s.dbs[j].getSort(first) + }) + } + return s.dbs +} + +func (s *epSelector) checkServerMode(conn *DmConnection, last bool) (bool, error) { + // 只连dsc control节点 + if conn.dmConnector.loginDscCtrl && !conn.dscControl { + conn.close() + return false, ECGO_INVALID_SERVER_MODE.throw() + } + // 模式不匹配, 这里使用的是连接之前的sort,连接之后server的状态可能发生改变sort也可能改变 + if conn.dmConnector.loginStatus > 0 && int(conn.SvrStat) != conn.dmConnector.loginStatus { + conn.close() + return false, ECGO_INVALID_SERVER_MODE.throw() + } + if last { + switch conn.dmConnector.loginMode { + case LOGIN_MODE_PRIMARY_ONLY: + return conn.SvrMode == SERVER_MODE_PRIMARY, nil + case LOGIN_MODE_STANDBY_ONLY: + return conn.SvrMode == SERVER_MODE_STANDBY, nil + default: + return true, nil + } + } + switch conn.dmConnector.loginMode { + case LOGIN_MODE_NORMAL_FIRST: + return conn.SvrMode == SERVER_MODE_NORMAL, nil + case LOGIN_MODE_PRIMARY_FIRST, LOGIN_MODE_PRIMARY_ONLY: + return conn.SvrMode == SERVER_MODE_PRIMARY, nil + case LOGIN_MODE_STANDBY_FIRST, LOGIN_MODE_STANDBY_ONLY: + return conn.SvrMode == SERVER_MODE_STANDBY, nil + default: + break + } + return false, nil +} diff --git a/dmr/za.go b/dmr/za.go new file mode 100644 index 0000000..040612c --- /dev/null +++ b/dmr/za.go @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "bytes" + "fmt" + "runtime" + + "github.com/nfjBill/gorm-driver-dm/dmr/i18n" +) + +// 驱动级错误 +var ( + DSN_INVALID_SCHEMA = newDmError(9001, "error.dsn.invalidSchema") + UNSUPPORTED_SCAN = newDmError(9002, "error.unsupported.scan") + INVALID_PARAMETER_NUMBER = newDmError(9003, "error.invalidParameterNumber") + THIRD_PART_CIPHER_INIT_FAILED = newDmError(9004, "error.initThirdPartCipherFailed") + ECGO_NOT_QUERY_SQL = newDmError(9005, "error.notQuerySQL") + ECGO_NOT_EXEC_SQL = newDmError(9006, "error.notExecSQL") + ECGO_UNKOWN_NETWORK = newDmError(9007, "error.unkownNetWork") + ECGO_INVALID_CONN = newDmError(9008, "error.invalidConn") + ECGO_UNSUPPORTED_INPARAM_TYPE = newDmError(9009, "error.unsupportedInparamType") + ECGO_UNSUPPORTED_OUTPARAM_TYPE = newDmError(9010, "error.unsupportedOutparamType") + ECGO_STORE_IN_NIL_POINTER = newDmError(9011, "error.storeInNilPointer") + ECGO_IS_NULL = newDmError(9012, "error.isNull") +) + +var ( + ECGO_CONNECTION_SWITCH_FAILED = newDmError(20001, "error.connectionSwitchFailed") + ECGO_CONNECTION_SWITCHED = newDmError(20000, "error.connectionSwitched") + ECGO_COMMUNITION_ERROR = newDmError(6001, "error.communicationError") + ECGO_MSG_CHECK_ERROR = newDmError(6002, "error.msgCheckError") + ECGO_INVALID_TIME_INTERVAL = newDmError(6005, "error.invalidTimeInterval") + ECGO_UNSUPPORTED_TYPE = newDmError(6006, "error.unsupportedType") + ECGO_DATA_CONVERTION_ERROR = newDmError(6007, "error.dataConvertionError") + ECGO_INVALID_SQL_TYPE = newDmError(6009, "error.invalidSqlType") + ECGO_INVALID_DATETIME_FORMAT = newDmError(6015, "error.invalidDateTimeFormat") + ECGO_INVALID_COLUMN_TYPE = newDmError(6016, "error.invalidColumnType") + ECGO_RESULTSET_IS_READ_ONLY = newDmError(6029, "error.resultsetInReadOnlyStatus") + ECGO_INVALID_SEQUENCE_NUMBER = newDmError(6032, "error.invalidSequenceNumber") + ECGO_RESULTSET_CLOSED = newDmError(6034, "errorResultSetColsed") + ECGO_STATEMENT_HANDLE_CLOSED = newDmError(6035, "errorStatementHandleClosed") + ECGO_INVALID_PARAMETER_VALUE = newDmError(6036, "error.invalidParamterValue") + ECGO_INVALID_TRAN_ISOLATION = newDmError(6038, "error.invalidTranIsolation") + ECGO_COMMIT_IN_AUTOCOMMIT_MODE = newDmError(6039, "errorCommitInAutoCommitMode") + ECGO_ROLLBACK_IN_AUTOCOMMIT_MODE = newDmError(6040, "errorRollbackInAutoCommitMode") + ECGO_INVALID_LENGTH_OR_OFFSET = newDmError(6057, "error.invalidLenOrOffset") + ECGO_INTERVAL_OVERFLOW = newDmError(6066, "error.intervalValueOverflow") + ECGO_INVALID_BFILE_STR = newDmError(6067, "error.invalidBFile") + ECGO_INVALID_HEX = newDmError(6068, "error.invalidHex") + ECGO_INVALID_CIPHER = newDmError(6069, "error.invalidCipher") + ECGO_OSAUTH_ERROR = newDmError(6073, "error.osauthError") + ECGO_ERROR_SERVER_VERSION = newDmError(6074, "error.serverVersion") + ECGO_USERNAME_TOO_LONG = newDmError(6075, "error.usernameTooLong") + ECGO_PASSWORD_TOO_LONG = newDmError(6076, "error.passwordTooLong") + ECGO_INVALID_COMPLEX_TYPE_NAME = newDmError(6079, "error.invalidComplexTypeName") + ECGO_STRUCT_MEM_NOT_MATCH = newDmError(6080, "error.structMemNotMatch") + ECGO_INVALID_OBJ_BLOB = newDmError(6081, "error.invalidObjBlob") + ECGO_INVALID_ARRAY_LEN = newDmError(6082, "error.invalidArrayLen") + ECGO_INVALID_SERVER_MODE = newDmError(6091, "error.invalidServerMode") + ECGO_DATA_TOO_LONG = newDmError(6092, "error.dataTooLong") + ECGO_BATCH_ERROR = newDmError(6093, "error.batchError") + ECGO_MSG_TOO_LONG = newDmError(6101, "error.msgTooLong") + ECGO_INVALID_DATETIME_VALUE = newDmError(6103, "error.invalidDateTimeValue") + + ECGO_INIT_SSL_FAILED = newDmError(20002, "error.SSLInitFailed") + ECGO_LOB_FREED = newDmError(20003, "error.LobDataHasFreed") + ECGO_FATAL_ERROR = newDmError(20004, "error.fatalError") +) + +//Svr Msg Err +var ( + ECGO_DATA_OVERFLOW = newDmError(-6102, "error.dataOverflow") + ECGO_DATETIME_OVERFLOW = newDmError(-6112, "error.datetimeOverflow") + EC_RN_EXCEED_ROWSET_SIZE = newDmError(-7036, "") + EC_BP_WITH_ERROR = newDmError(121, "warning.bpWithErr") +) + +type DmError struct { + ErrCode int32 + ErrText string + stack []uintptr + detail string +} + +func newDmError(errCode int32, errText string) *DmError { + de := new(DmError) + de.ErrCode = errCode + de.ErrText = errText + de.stack = nil + de.detail = "" + return de +} + +func (dmError *DmError) throw() *DmError { + var pcs [32]uintptr + n := runtime.Callers(2, pcs[:]) + dmError.stack = pcs[0:n] + return dmError +} + +func (dmError *DmError) FormatStack() string { + if dmError == nil || dmError.stack == nil { + return "" + } + buffer := bytes.NewBuffer(nil) + index := 1 + space := " " + for _, p := range dmError.stack { + if fn := runtime.FuncForPC(p - 1); fn != nil { + file, line := fn.FileLine(p - 1) + buffer.WriteString(fmt.Sprintf(" %d).%s%s\n \t%s:%d\n", index, space, fn.Name(), file, line)) + index++ + } + } + return buffer.String() +} + +func (dmError *DmError) Error() string { + return fmt.Sprintf("Error %d: %s", dmError.ErrCode, i18n.Get(dmError.ErrText, Locale)) + dmError.detail + "\n" + "stack info:\n" + dmError.FormatStack() +} + +// 扩充ErrText +func (dmError *DmError) addDetail(detail string) *DmError { + dmError.detail = detail + return dmError +} +func (dmError *DmError) addDetailln(detail string) *DmError { + return dmError.addDetail("\n" + detail) +} diff --git a/dmr/zb.go b/dmr/zb.go new file mode 100644 index 0000000..35ce362 --- /dev/null +++ b/dmr/zb.go @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +const ( + IGNORE_TARGET_LENGTH int32 = -1 + + IGNORE_TARGET_SCALE int32 = -1 + + IGNORE_TARGET_TYPE = INT32_MIN + + TYPE_FLAG_UNKNOWN byte = 0 // 未知类型 + + TYPE_FLAG_EXACT byte = 1 // 精确类型 + + TYPE_FLAG_RECOMMEND byte = 2 // 推荐类型 + + IO_TYPE_IN byte = 0 + + IO_TYPE_OUT byte = 1 + + IO_TYPE_INOUT byte = 2 +) + +type execRetInfo struct { + // param + outParamDatas [][]byte + + // rs + hasResultSet bool + + rsDatas [][][]byte + + rsSizeof int // 结果集数据占用多少空间,(消息中结果集起始位置到 rsCacheOffset + // 的空间大小,这和实际的rsDatas占用空间大小有一定出入,这里粗略估算,用于结果集缓存时的空间管理) + + rsCacheOffset int32 // 缓存信息,在响应消息体中的偏移,0表示不存在,仅结果集缓存中可以用 + + rsBdta bool + + rsUpdatable bool + + rsRowIds []int64 + + // rs cache + tbIds []int32 + + tbTss []int64 + + // print + printLen int32 + + printMsg string + + // explain + explain string + + // 影响行数 + updateCount int64 // Insert/Update/Delet影响行数, select结果集的总行数 + + updateCounts []int64 // 批量影响行数 + + // 键 + rowid int64 + + lastInsertId int64 + + // other + retSqlType int16 // 执行返回的语句类型 + + execId int32 +} + +type column struct { + typeName string + + colType int32 + + prec int32 + + scale int32 + + name string + + tableName string + + schemaName string + + nullable bool + + identity bool + + readonly bool // 是否只读 + + baseName string + + // lob info + lob bool + + lobTabId int32 + + lobColId int16 + + // 用于描述ARRAY、STRUCT类型的特有描述信息 + typeDescriptor *TypeDescriptor + + isBdta bool +} + +type parameter struct { + column + + typeFlag byte + + ioType byte + + outJType int32 + + outScale int32 + + outObjectName string + + cursorStmt *DmStatement +} + +func (column *column) InitColumn() *column { + column.typeName = "" + + column.colType = 0 + + column.prec = 0 + + column.scale = 0 + + column.name = "" + + column.tableName = "" + + column.schemaName = "" + + column.nullable = false + + column.identity = false + + column.readonly = false + + column.baseName = "" + + // lob info + column.lob = false + + column.lobTabId = 0 + + column.lobColId = 0 + + // 用于描述ARRAY、STRUCT类型的特有描述信息 + column.typeDescriptor = nil + + column.isBdta = false + + return column +} + +func (parameter *parameter) InitParameter() *parameter { + parameter.InitColumn() + + parameter.typeFlag = TYPE_FLAG_UNKNOWN + + parameter.ioType = IO_TYPE_IN + + parameter.outJType = IGNORE_TARGET_TYPE + + parameter.outScale = IGNORE_TARGET_SCALE + + parameter.outObjectName = "" + + parameter.cursorStmt = nil + + return parameter +} + +func (execInfo *execRetInfo) union(other *execRetInfo, startRow int, count int) { + if count == 1 { + execInfo.updateCounts[startRow] = other.updateCount + } else if execInfo.updateCounts != nil { + copy(execInfo.updateCounts[startRow:startRow+count], other.updateCounts[0:count]) + } + if execInfo.outParamDatas != nil { + execInfo.outParamDatas = append(execInfo.outParamDatas, other.outParamDatas...) + } +} + +func NewExceInfo() *execRetInfo { + + execInfo := execRetInfo{} + + execInfo.outParamDatas = nil + + execInfo.hasResultSet = false + + execInfo.rsDatas = nil + + execInfo.rsSizeof = 0 + + execInfo.rsCacheOffset = 0 + + execInfo.rsBdta = false + + execInfo.rsUpdatable = false + + execInfo.rsRowIds = nil + + execInfo.tbIds = nil + + execInfo.tbTss = nil + + execInfo.printLen = 0 + + execInfo.printMsg = "" + + execInfo.explain = "" + + execInfo.updateCount = 0 + + execInfo.updateCounts = nil + + execInfo.rowid = -1 + + execInfo.lastInsertId = 0 + // other + execInfo.retSqlType = -1 // 执行返回的语句类型 + + execInfo.execId = 0 + + return &execInfo +} diff --git a/dmr/zc.go b/dmr/zc.go new file mode 100644 index 0000000..ec3a6ed --- /dev/null +++ b/dmr/zc.go @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "context" + "database/sql/driver" + "reflect" + "sync" + "sync/atomic" + "time" +) + +type filter interface { + DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error) + DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error) + + DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error) + DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver + + DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error) + DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) + DmConnectionCommit(filterChain *filterChain, c *DmConnection) error + DmConnectionRollback(filterChain *filterChain, c *DmConnection) error + DmConnectionClose(filterChain *filterChain, c *DmConnection) error + DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error + DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error) + DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) + DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error) + DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) + DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error) + DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error) + DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error + DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error + + DmStatementClose(filterChain *filterChain, s *DmStatement) error + DmStatementNumInput(filterChain *filterChain, s *DmStatement) int + DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error) + DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) + DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error) + DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) + DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error + + DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error) + DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error) + + DmRowsColumns(filterChain *filterChain, r *DmRows) []string + DmRowsClose(filterChain *filterChain, r *DmRows) error + DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error + DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool + DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error + DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type + DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string + DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) + DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) + DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) +} + +type IDGenerator int64 + +var dmDriverIDGenerator = new(IDGenerator) +var dmConntorIDGenerator = new(IDGenerator) +var dmConnIDGenerator = new(IDGenerator) +var dmStmtIDGenerator = new(IDGenerator) +var dmResultIDGenerator = new(IDGenerator) +var dmRowsIDGenerator = new(IDGenerator) + +func (g *IDGenerator) incrementAndGet() int64 { + return atomic.AddInt64((*int64)(g), 1) +} + +type RWSiteEnum int + +const ( + PRIMARY RWSiteEnum = iota + STANDBY + ANYSITE +) + +var ( + goMapMu sync.RWMutex + goMap = make(map[string]goRun, 2) +) + +type filterable struct { + filterChain *filterChain + rwInfo *rwInfo + logInfo *logInfo + recoverInfo *recoverInfo + statInfo *statInfo + objId int64 + idGenerator *IDGenerator +} + +func runLog() { + goMapMu.Lock() + _, ok := goMap["log"] + if !ok { + goMap["log"] = &logWriter{ + flushQueue: make(chan []byte, LogFlushQueueSize), + date: time.Now().Format("2006-01-02"), + logFile: nil, + flushFreq: LogFlushFreq, + filePath: LogDir, + filePrefix: "dm_go", + buffer: Dm_build_1503(), + } + go goMap["log"].doRun() + } + goMapMu.Unlock() +} + +func runStat() { + goMapMu.Lock() + _, ok := goMap["stat"] + if !ok { + goMap["stat"] = newStatFlusher() + go goMap["stat"].doRun() + } + goMapMu.Unlock() +} + +func (f *filterable) createFilterChain(bc *DmConnector, props *Properties) { + var filters = make([]filter, 0, 5) + + if bc != nil { + if LogLevel != LOG_OFF { + filters = append(filters, &logFilter{}) + f.logInfo = &logInfo{logRecord: new(LogRecord)} + runLog() + } + + if StatEnable { + filters = append(filters, &statFilter{}) + f.statInfo = newStatInfo() + goStatMu.Lock() + if goStat == nil { + goStat = newGoStat(1000) + } + goStatMu.Unlock() + runStat() + } + + if bc.doSwitch != DO_SWITCH_OFF { + filters = append(filters, &reconnectFilter{}) + } + + if bc.rwSeparate { + filters = append(filters, &rwFilter{}) + f.rwInfo = newRwInfo() + } + } else if props != nil { + if ParseLogLevel(props) != LOG_OFF { + filters = append(filters, &logFilter{}) + f.logInfo = &logInfo{logRecord: new(LogRecord)} + runLog() + } + + if props.GetBool("statEnable", StatEnable) { + filters = append(filters, &statFilter{}) + f.statInfo = newStatInfo() + goStatMu.Lock() + if goStat == nil { + goStat = newGoStat(1000) + } + goStatMu.Unlock() + runStat() + } + + if props.GetInt(DoSwitchKey, int(DO_SWITCH_OFF), 0, 2) != int(DO_SWITCH_OFF) { + filters = append(filters, &reconnectFilter{}) + f.recoverInfo = newRecoverInfo() + } + + if props.GetBool("rwSeparate", false) { + filters = append(filters, &rwFilter{}) + f.rwInfo = newRwInfo() + } + } + + f.filterChain = newFilterChain(filters) +} + +func (f *filterable) resetFilterable(src *filterable) { + f.filterChain = src.filterChain + f.logInfo = src.logInfo + f.rwInfo = src.rwInfo + f.statInfo = src.statInfo +} + +func (f filterable) getID() int64 { + if f.objId < 0 { + f.objId = f.idGenerator.incrementAndGet() + } + return f.objId +} + +type logInfo struct { + logRecord *LogRecord + lastExecuteStartNano time.Time +} + +type rwInfo struct { + distribute RWSiteEnum + + rwCounter *rwCounter + + connStandby *DmConnection + + connCurrent *DmConnection + + tryRecoverTs int64 + + stmtStandby *DmStatement + + stmtCurrent *DmStatement + + readOnly bool +} + +func newRwInfo() *rwInfo { + rwInfo := new(rwInfo) + rwInfo.distribute = PRIMARY + rwInfo.readOnly = true + return rwInfo +} + +func (rwi *rwInfo) cleanup() { + rwi.distribute = PRIMARY + rwi.rwCounter = nil + rwi.connStandby = nil + rwi.connCurrent = nil + rwi.stmtStandby = nil + rwi.stmtCurrent = nil +} + +func (rwi *rwInfo) toPrimary() RWSiteEnum { + if rwi.distribute != PRIMARY { + + rwi.rwCounter.countPrimary() + } + rwi.distribute = PRIMARY + return rwi.distribute +} + +func (rwi *rwInfo) toAny() RWSiteEnum { + + rwi.distribute = rwi.rwCounter.count(ANYSITE, rwi.connStandby) + return rwi.distribute +} + +type recoverInfo struct { + checkEpRecoverTs int64 +} + +func newRecoverInfo() *recoverInfo { + recoverInfo := new(recoverInfo) + recoverInfo.checkEpRecoverTs = 0 + return recoverInfo +} + +type statInfo struct { + constructNano int64 + + connStat *connectionStat + + lastExecuteStartNano int64 + + lastExecuteTimeNano int64 + + lastExecuteType ExecuteTypeEnum + + firstResultSet bool + + lastExecuteSql string + + sqlStat *sqlStat + + sql string + + cursorIndex int + + closeCount int + + readStringLength int64 + + readBytesLength int64 + + openInputStreamCount int + + openReaderCount int +} + +var ( + goStatMu sync.RWMutex + goStat *GoStat +) + +func newStatInfo() *statInfo { + si := new(statInfo) + return si +} +func (si *statInfo) init(conn *DmConnection) { + si.connStat = goStat.createConnStat(conn) +} + +func (si *statInfo) setConstructNano() { + si.constructNano = time.Now().UnixNano() +} + +func (si *statInfo) getConstructNano() int64 { + return si.constructNano +} + +func (si *statInfo) getConnStat() *connectionStat { + return si.connStat +} + +func (si *statInfo) getLastExecuteStartNano() int64 { + return si.lastExecuteStartNano +} + +func (si *statInfo) setLastExecuteStartNano(lastExecuteStartNano int64) { + si.lastExecuteStartNano = lastExecuteStartNano +} + +func (si *statInfo) getLastExecuteTimeNano() int64 { + return si.lastExecuteTimeNano +} + +func (si *statInfo) setLastExecuteTimeNano(lastExecuteTimeNano int64) { + si.lastExecuteTimeNano = lastExecuteTimeNano +} + +func (si *statInfo) getLastExecuteType() ExecuteTypeEnum { + return si.lastExecuteType +} + +func (si *statInfo) setLastExecuteType(lastExecuteType ExecuteTypeEnum) { + si.lastExecuteType = lastExecuteType +} + +func (si *statInfo) isFirstResultSet() bool { + return si.firstResultSet +} + +func (si *statInfo) setFirstResultSet(firstResultSet bool) { + si.firstResultSet = firstResultSet +} + +func (si *statInfo) getLastExecuteSql() string { + return si.lastExecuteSql +} + +func (si *statInfo) setLastExecuteSql(lastExecuteSql string) { + si.lastExecuteSql = lastExecuteSql +} + +func (si *statInfo) getSqlStat() *sqlStat { + return si.sqlStat +} + +func (si *statInfo) setSqlStat(sqlStat *sqlStat) { + si.sqlStat = sqlStat +} + +func (si *statInfo) setConnStat(connStat *connectionStat) { + si.connStat = connStat +} + +func (si *statInfo) setConstructNanoWithConstructNano(constructNano int64) { + si.constructNano = constructNano +} + +func (si *statInfo) afterExecute(nanoSpan int64) { + si.lastExecuteTimeNano = nanoSpan +} + +func (si *statInfo) beforeExecute() { + si.lastExecuteStartNano = time.Now().UnixNano() +} + +func (si *statInfo) getSql() string { + return si.sql +} + +func (si *statInfo) setSql(sql string) { + si.sql = sql +} + +func (si *statInfo) getCursorIndex() int { + return si.cursorIndex +} + +func (si *statInfo) setCursorIndex(cursorIndex int) { + si.cursorIndex = cursorIndex +} + +func (si *statInfo) getCloseCount() int { + return si.closeCount +} + +func (si *statInfo) setCloseCount(closeCount int) { + si.closeCount = closeCount +} + +func (si *statInfo) getReadStringLength() int64 { + return si.readStringLength +} + +func (si *statInfo) setReadStringLength(readStringLength int64) { + si.readStringLength = readStringLength +} + +func (si *statInfo) getReadBytesLength() int64 { + return si.readBytesLength +} + +func (si *statInfo) setReadBytesLength(readBytesLength int64) { + si.readBytesLength = readBytesLength +} + +func (si *statInfo) getOpenInputStreamCount() int { + return si.openInputStreamCount +} + +func (si *statInfo) setOpenInputStreamCount(openInputStreamCount int) { + si.openInputStreamCount = openInputStreamCount +} + +func (si *statInfo) getOpenReaderCount() int { + return si.openReaderCount +} + +func (si *statInfo) setOpenReaderCount(openReaderCount int) { + si.openReaderCount = openReaderCount +} + +func (si *statInfo) incrementCloseCount() { + si.closeCount++ +} diff --git a/dmr/zd.go b/dmr/zd.go new file mode 100644 index 0000000..4201579 --- /dev/null +++ b/dmr/zd.go @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "context" + "database/sql/driver" + "reflect" +) + +type filterChain struct { + filters []filter + fpos int +} + +func newFilterChain(filters []filter) *filterChain { + fc := new(filterChain) + fc.filters = filters + fc.fpos = 0 + return fc +} + +func (filterChain *filterChain) reset() *filterChain { + filterChain.fpos = 0 + return filterChain +} + +func (filterChain *filterChain) DmDriverOpen(d *DmDriver, dsn string) (*DmConnection, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmDriverOpen(filterChain, d, dsn) + } + + return d.open(dsn) +} + +func (filterChain *filterChain) DmDriverOpenConnector(d *DmDriver, dsn string) (*DmConnector, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmDriverOpenConnector(filterChain, d, dsn) + } + + return d.openConnector(dsn) +} + +//DmConnector +func (filterChain *filterChain) DmConnectorConnect(c *DmConnector, ctx context.Context) (*DmConnection, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectorConnect(filterChain, c, ctx) + } + + return c.connect(ctx) +} + +func (filterChain *filterChain) DmConnectorDriver(c *DmConnector) *DmDriver { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectorDriver(filterChain, c) + } + + return c.driver() +} + +//DmConnection +func (filterChain *filterChain) DmConnectionBegin(c *DmConnection) (*DmConnection, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionBegin(filterChain, c) + } + + return c.begin() +} +func (filterChain *filterChain) DmConnectionBeginTx(c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionBeginTx(filterChain, c, ctx, opts) + } + + return c.beginTx(ctx, opts) +} + +func (filterChain *filterChain) DmConnectionCommit(c *DmConnection) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionCommit(filterChain, c) + } + + return c.commit() +} + +func (filterChain *filterChain) DmConnectionRollback(c *DmConnection) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionRollback(filterChain, c) + } + + return c.rollback() +} + +func (filterChain *filterChain) DmConnectionClose(c *DmConnection) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionClose(filterChain, c) + } + + return c.close() +} + +func (filterChain *filterChain) DmConnectionPing(c *DmConnection, ctx context.Context) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionPing(filterChain, c, ctx) + } + + return c.ping(ctx) +} + +func (filterChain *filterChain) DmConnectionExec(c *DmConnection, query string, args []driver.Value) (*DmResult, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionExec(filterChain, c, query, args) + } + + return c.exec(query, args) +} + +func (filterChain *filterChain) DmConnectionExecContext(c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionExecContext(filterChain, c, ctx, query, args) + } + + return c.execContext(ctx, query, args) +} + +func (filterChain *filterChain) DmConnectionQuery(c *DmConnection, query string, args []driver.Value) (*DmRows, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionQuery(filterChain, c, query, args) + } + + return c.query(query, args) +} + +func (filterChain *filterChain) DmConnectionQueryContext(c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionQueryContext(filterChain, c, ctx, query, args) + } + + return c.queryContext(ctx, query, args) +} + +func (filterChain *filterChain) DmConnectionPrepare(c *DmConnection, query string) (*DmStatement, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionPrepare(filterChain, c, query) + } + + return c.prepare(query) +} + +func (filterChain *filterChain) DmConnectionPrepareContext(c *DmConnection, ctx context.Context, query string) (*DmStatement, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionPrepareContext(filterChain, c, ctx, query) + } + + return c.prepareContext(ctx, query) +} + +func (filterChain *filterChain) DmConnectionResetSession(c *DmConnection, ctx context.Context) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionResetSession(filterChain, c, ctx) + } + + return c.resetSession(ctx) +} + +func (filterChain *filterChain) DmConnectionCheckNamedValue(c *DmConnection, nv *driver.NamedValue) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionCheckNamedValue(filterChain, c, nv) + } + + return c.checkNamedValue(nv) +} + +//DmStatement +func (filterChain *filterChain) DmStatementClose(s *DmStatement) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementClose(filterChain, s) + } + + return s.close() +} + +func (filterChain *filterChain) DmStatementNumInput(s *DmStatement) int { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementNumInput(filterChain, s) + } + + return s.numInput() +} + +func (filterChain *filterChain) DmStatementExec(s *DmStatement, args []driver.Value) (*DmResult, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementExec(filterChain, s, args) + } + + return s.exec(args) +} + +func (filterChain *filterChain) DmStatementExecContext(s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementExecContext(filterChain, s, ctx, args) + } + + return s.execContext(ctx, args) +} + +func (filterChain *filterChain) DmStatementQuery(s *DmStatement, args []driver.Value) (*DmRows, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementQuery(filterChain, s, args) + } + + return s.query(args) +} + +func (filterChain *filterChain) DmStatementQueryContext(s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementQueryContext(filterChain, s, ctx, args) + } + + return s.queryContext(ctx, args) +} + +func (filterChain *filterChain) DmStatementCheckNamedValue(s *DmStatement, nv *driver.NamedValue) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementCheckNamedValue(filterChain, s, nv) + } + + return s.checkNamedValue(nv) +} + +//DmResult +func (filterChain *filterChain) DmResultLastInsertId(r *DmResult) (int64, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmResultLastInsertId(filterChain, r) + } + + return r.lastInsertId() +} + +func (filterChain *filterChain) DmResultRowsAffected(r *DmResult) (int64, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmResultRowsAffected(filterChain, r) + } + + return r.rowsAffected() +} + +//DmRows +func (filterChain *filterChain) DmRowsColumns(r *DmRows) []string { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsColumns(filterChain, r) + } + + return r.columns() +} + +func (filterChain *filterChain) DmRowsClose(r *DmRows) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsClose(filterChain, r) + } + + return r.close() +} + +func (filterChain *filterChain) DmRowsNext(r *DmRows, dest []driver.Value) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsNext(filterChain, r, dest) + } + + return r.next(dest) +} + +func (filterChain *filterChain) DmRowsHasNextResultSet(r *DmRows) bool { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsHasNextResultSet(filterChain, r) + } + + return r.hasNextResultSet() +} + +func (filterChain *filterChain) DmRowsNextResultSet(r *DmRows) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsNextResultSet(filterChain, r) + } + + return r.nextResultSet() +} + +func (filterChain *filterChain) DmRowsColumnTypeScanType(r *DmRows, index int) reflect.Type { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsColumnTypeScanType(filterChain, r, index) + } + + return r.columnTypeScanType(index) +} + +func (filterChain *filterChain) DmRowsColumnTypeDatabaseTypeName(r *DmRows, index int) string { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsColumnTypeDatabaseTypeName(filterChain, r, index) + } + + return r.columnTypeDatabaseTypeName(index) +} + +func (filterChain *filterChain) DmRowsColumnTypeLength(r *DmRows, index int) (length int64, ok bool) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsColumnTypeLength(filterChain, r, index) + } + + return r.columnTypeLength(index) +} + +func (filterChain *filterChain) DmRowsColumnTypeNullable(r *DmRows, index int) (nullable, ok bool) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsColumnTypeNullable(filterChain, r, index) + } + + return r.columnTypeNullable(index) +} + +func (filterChain *filterChain) DmRowsColumnTypePrecisionScale(r *DmRows, index int) (precision, scale int64, ok bool) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsColumnTypePrecisionScale(filterChain, r, index) + } + + return r.columnTypePrecisionScale(index) +} diff --git a/dmr/ze.go b/dmr/ze.go new file mode 100644 index 0000000..7bb1bb1 --- /dev/null +++ b/dmr/ze.go @@ -0,0 +1,871 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "context" + "database/sql/driver" + "reflect" + "strconv" + "time" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +type logFilter struct{} + +func (filter *logFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (ret *DmConnection, err error) { + var logRecord = d.logInfo.logRecord + logRecord.Set(d, "open", dsn) + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmDriverOpen(d, dsn) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (ret *DmConnector, err error) { + var logRecord = d.logInfo.logRecord + logRecord.Set(d, "openConnector", dsn) + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmDriverOpenConnector(d, dsn) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (ret *DmConnection, err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "connect") + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmConnectorConnect(c, ctx) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) (ret *DmDriver) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "dmr") + defer func() { + filter.doLog(logRecord) + }() + ret = filterChain.DmConnectorDriver(c) + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (ret *DmConnection, err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "begin") + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmConnectionBegin(c) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (ret *DmConnection, err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "beginTx", opts) + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmConnectionBeginTx(c, ctx, opts) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) (err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "commit") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmConnectionCommit(c) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) (err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "rollback") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmConnectionRollback(c) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) (err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "close") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmConnectionClose(c) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) (err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "ping") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmConnectionPing(c, ctx) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (ret *DmResult, err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "executeByStmt", query, args) + defer func() { + filter.executeAfter(c.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(query) + filter.executeBefore(c.logInfo) + ret, err = filterChain.DmConnectionExec(c, query, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (ret *DmResult, err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "executeCtx", query, args) + defer func() { + filter.executeAfter(c.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(query) + filter.executeBefore(c.logInfo) + ret, err = filterChain.DmConnectionExecContext(c, ctx, query, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (ret *DmRows, err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "query", query, args) + defer func() { + filter.executeAfter(c.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(query) + filter.executeBefore(c.logInfo) + ret, err = filterChain.DmConnectionQuery(c, query, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (ret *DmRows, err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "queryCtx", query, args) + defer func() { + filter.executeAfter(c.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(query) + filter.executeBefore(c.logInfo) + ret, err = filterChain.DmConnectionQueryContext(c, ctx, query, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (ret *DmStatement, err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "prepareStatement", query) + defer func() { + filter.doLog(logRecord) + }() + logRecord.SetSql(query) + ret, err = filterChain.DmConnectionPrepare(c, query) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (ret *DmStatement, err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "prepareStatementCtx", query) + defer func() { + filter.doLog(logRecord) + }() + logRecord.SetSql(query) + ret, err = filterChain.DmConnectionPrepareContext(c, ctx, query) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) (err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "resetSession") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmConnectionResetSession(c, ctx) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) (err error) { + var logRecord = c.logInfo.logRecord + logRecord.Set(c, "checkNamedValue", nv) + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmConnectionCheckNamedValue(c, nv) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) (err error) { + var logRecord = s.logInfo.logRecord + logRecord.Set(s, "close") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmStatementClose(s) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) (ret int) { + var logRecord = s.logInfo.logRecord + logRecord.Set(s, "numInput") + defer func() { + filter.doLog(logRecord) + }() + ret = filterChain.DmStatementNumInput(s) + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (ret *DmResult, err error) { + var logRecord = s.logInfo.logRecord + logRecord.Set(s, "executeByStmt", args) + defer func() { + filter.executeAfter(s.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(s.nativeSql) + filter.executeBefore(s.logInfo) + ret, err = filterChain.DmStatementExec(s, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (ret *DmResult, err error) { + var logRecord = s.logInfo.logRecord + logRecord.Set(s, "executeCtx", args) + defer func() { + filter.executeAfter(s.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(s.nativeSql) + filter.executeBefore(s.logInfo) + ret, err = filterChain.DmStatementExecContext(s, ctx, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (ret *DmRows, err error) { + var logRecord = s.logInfo.logRecord + logRecord.Set(s, "query", args) + defer func() { + filter.executeAfter(s.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(s.nativeSql) + filter.executeBefore(s.logInfo) + ret, err = filterChain.DmStatementQuery(s, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (ret *DmRows, err error) { + var logRecord = s.logInfo.logRecord + logRecord.Set(s, "queryCtx", args) + defer func() { + filter.executeAfter(s.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(s.nativeSql) + filter.executeBefore(s.logInfo) + ret, err = filterChain.DmStatementQueryContext(s, ctx, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) (err error) { + var logRecord = s.logInfo.logRecord + logRecord.Set(s, "checkNamedValue", nv) + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmStatementCheckNamedValue(s, nv) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (ret int64, err error) { + var logRecord = r.logInfo.logRecord + logRecord.Set(r, "lastInsertId") + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmResultLastInsertId(r) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (ret int64, err error) { + var logRecord = r.logInfo.logRecord + logRecord.Set(r, "rowsAffected") + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmResultRowsAffected(r) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) (ret []string) { + var logRecord = r.logInfo.logRecord + logRecord.Set(r, "columns") + defer func() { + filter.doLog(logRecord) + }() + ret = filterChain.DmRowsColumns(r) + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmRowsClose(filterChain *filterChain, r *DmRows) (err error) { + var logRecord = r.logInfo.logRecord + logRecord.Set(r, "close") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmRowsClose(r) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) (err error) { + var logRecord = r.logInfo.logRecord + logRecord.Set(r, "next", dest) + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmRowsNext(r, dest) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) (ret bool) { + var logRecord = r.logInfo.logRecord + logRecord.Set(r, "hasNextResultSet") + defer func() { + filter.doLog(logRecord) + }() + ret = filterChain.DmRowsHasNextResultSet(r) + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) (err error) { + var logRecord = r.logInfo.logRecord + logRecord.Set(r, "nextResultSet") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmRowsNextResultSet(r) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) (ret reflect.Type) { + var logRecord = r.logInfo.logRecord + logRecord.Set(r, "columnTypeScanType", index) + defer func() { + filter.doLog(logRecord) + }() + ret = filterChain.DmRowsColumnTypeScanType(r, index) + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) (ret string) { + var logRecord = r.logInfo.logRecord + logRecord.Set(r, "columnTypeDatabaseTypeName", index) + defer func() { + filter.doLog(logRecord) + }() + ret = filterChain.DmRowsColumnTypeDatabaseTypeName(r, index) + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) { + var logRecord = r.logInfo.logRecord + logRecord.Set(r, "columnTypeLength", index) + defer func() { + filter.doLog(logRecord) + }() + length, ok = filterChain.DmRowsColumnTypeLength(r, index) + if ok { + logRecord.SetReturnValue(length) + } else { + logRecord.SetReturnValue(-1) + } + return +} + +func (filter *logFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) { + var logRecord = r.logInfo.logRecord + logRecord.Set(r, "columnTypeNullable", index) + defer func() { + filter.doLog(logRecord) + }() + nullable, ok = filterChain.DmRowsColumnTypeNullable(r, index) + if ok { + logRecord.SetReturnValue(nullable) + } else { + logRecord.SetReturnValue(false) + } + return +} + +func (filter *logFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) { + var logRecord = r.logInfo.logRecord + logRecord.Set(r, "columnTypePrecisionScale", index) + defer func() { + filter.doLog(logRecord) + }() + precision, scale, ok = filterChain.DmRowsColumnTypePrecisionScale(r, index) + if ok { + logRecord.SetReturnValue(strconv.FormatInt(precision, 10) + "&" + strconv.FormatInt(scale, 10)) + } else { + logRecord.SetReturnValue("-1&-1") + } + return +} + +func (filter *logFilter) executeBefore(logInfo *logInfo) { + if LogFilterLogger.IsSqlEnabled() { + logInfo.lastExecuteStartNano = time.Now() + } +} + +func (filter *logFilter) executeAfter(logInfo *logInfo, record *LogRecord) { + if LogFilterLogger.IsSqlEnabled() { + record.SetUsedTime(time.Since(logInfo.lastExecuteStartNano)) + } +} + +func (filter *logFilter) doLog(record *LogRecord) { + + if record == nil { + return + } + if record.GetError() != nil { + LogFilterLogger.ErrorWithErr(record.ToString(), record.GetError()) + } else if record.GetSql() != "" && LogFilterLogger.IsSqlEnabled() { + LogFilterLogger.Sql(record.ToString()) + } else { + LogFilterLogger.Info(record.ToString()) + } +} + +/************************************************************************************************************/ +type Logger struct { +} + +var LogFilterLogger = &Logger{} +var ConnLogger = &Logger{} +var AccessLogger = &Logger{} + +func (logger Logger) IsDebugEnabled() bool { + return LogLevel >= LOG_DEBUG +} +func (logger Logger) IsErrorEnabled() bool { + return LogLevel >= LOG_ERROR +} +func (logger Logger) IsInfoEnabled() bool { + return LogLevel >= LOG_INFO +} +func (logger Logger) IsWarnEnabled() bool { + return LogLevel >= LOG_WARN +} +func (logger Logger) IsSqlEnabled() bool { + return LogLevel >= LOG_SQL +} +func (logger Logger) Debug(msg string) { + if logger.IsDebugEnabled() { + logger.println(logger.formatHead("DEBUG") + msg) + } +} +func (logger Logger) DebugWithErr(msg string, err error) { + if logger.IsDebugEnabled() { + if e, ok := err.(*DmError); ok { + logger.println(logger.formatHead("DEBUG") + msg + util.LINE_SEPARATOR + e.FormatStack()) + } else { + logger.println(logger.formatHead("DEBUG") + msg + util.LINE_SEPARATOR + err.Error()) + } + } +} +func (logger Logger) Info(msg string) { + if logger.IsInfoEnabled() { + logger.println(logger.formatHead("INFO ") + msg) + } +} +func (logger Logger) Sql(msg string) { + if logger.IsSqlEnabled() { + logger.println(logger.formatHead("SQL ") + msg) + } +} +func (logger Logger) Warn(msg string) { + if logger.IsWarnEnabled() { + logger.println(logger.formatHead("WARN ") + msg) + } +} +func (logger Logger) ErrorWithErr(msg string, err error) { + if e, ok := err.(*DmError); ok { + logger.println(logger.formatHead("ERROR") + msg + util.LINE_SEPARATOR + e.FormatStack()) + } else { + logger.println(logger.formatHead("ERROR") + msg + util.LINE_SEPARATOR + err.Error()) + } +} + +//TODO: 获取goroutine objId +func (logger Logger) formatHead(head string) string { + // return "[" + head + " - " + StringUtil.formatTime() + "] tid:" + Thread.currentThread().getId(); + return "[" + head + " - " + util.StringUtil.FormatTime() + "]" +} +func (logger Logger) println(msg string) { + goMap["log"].(*logWriter).WriteLine(msg) +} + +/*************************************************************************************************/ +func formatSource(source interface{}) string { + if source == nil { + return "" + } + var str string + switch src := source.(type) { + case string: + str += src + case *DmDriver: + str += formatDriver(src) + case *DmConnector: + str += formatContor(src) + case *DmConnection: + str += formatConn(src) + case *DmStatement: + str += formatConn(src.dmConn) + ", " + str += formatStmt(src) + case *DmResult: + str += formatConn(src.dmStmt.dmConn) + ", " + str += formatStmt(src.dmStmt) + ", " + str += formatRs(src) + case *DmRows: + str += formatConn(src.CurrentRows.dmStmt.dmConn) + ", " + str += formatStmt(src.CurrentRows.dmStmt) + ", " + str += formatRows(src) + default: + str += reflect.TypeOf(src).String() + "@" + reflect.ValueOf(src).Addr().String() + } + return str +} + +func formatDriver(driver *DmDriver) string { + if driver != nil && driver.logInfo != nil { + return "dmr-" + strconv.FormatInt(driver.getID(), 10) + } + return "dmr-nil" +} + +func formatContor(contor *DmConnector) string { + if contor != nil && contor.logInfo != nil { + return "contor-" + strconv.FormatInt(contor.getID(), 10) + } + return "contor-nil" +} + +func formatConn(conn *DmConnection) string { + if conn != nil && conn.logInfo != nil { + return "conn-" + strconv.FormatInt(conn.getID(), 10) + } + return "conn-nil" +} + +func formatStmt(stmt *DmStatement) string { + if stmt != nil && stmt.logInfo != nil { + return "stmt-" + strconv.FormatInt(stmt.getID(), 10) + } + return "stmt-nil" +} + +func formatRs(result *DmResult) string { + if result != nil && result.logInfo != nil { + return "rs-" + strconv.FormatInt(result.getID(), 10) + } + return "rs-nil" +} + +func formatRows(rows *DmRows) string { + if rows != nil && rows.logInfo != nil { + return "rows-" + strconv.FormatInt(rows.getID(), 10) + } + return "rows-nil" +} + +func formatTrace(source string, method string, returnValue interface{}, params ...interface{}) string { + var str string + if source != "" { + str += "{ " + source + " } " + } + str += method + "(" + var paramStartIndex = 0 + if params != nil && len(params) > paramStartIndex { + for i := paramStartIndex; i < len(params); i++ { + if i != paramStartIndex { + str += ", " + } + if params[i] != nil { + str += reflect.TypeOf(params[i]).String() + } else { + str += "nil" + } + } + } + str += ")" + if returnValue != nil { + str += ": " + formatReturn(returnValue) + } + str += "; " + if params != nil && len(params) > paramStartIndex { + str += "[PARAMS]: " + for i := paramStartIndex; i < len(params); i++ { + if i != 0 { + str += ", " + } + if s, ok := params[i].(string); ok { + str += "\"" + s + "\"" + } else { + str += reflect.ValueOf(params[i]).String() + } + } + str += "; " + } + return str +} + +func formatReturn(returnObj interface{}) string { + var str string + switch o := returnObj.(type) { + case *DmConnection: + str = formatConn(o) + sessID := o.SessionID + if sessID != -1 { + str += ", sessionID-0x" + strconv.FormatInt(sessID, 16) + } + case *DmStatement: + str = formatStmt(o) + str += ", handle-" + strconv.Itoa(int(o.id)) + case *DmResult: + str = formatRs(o) + case *DmRows: + str = formatRows(o) + case string: + str = `"` + o + `"` + case nullData: + str = "nil" + default: + str = "unknown" + } + return str +} + +func formatUsedTime(duration time.Duration) string { + return "[USED TIME]: " + duration.String() +} + +/************************************************************************************************************/ + +type nullData struct{} + +var null = nullData{} + +type LogRecord struct { + source string + method string + params []interface{} + returnValue interface{} + e error + usedTime time.Duration + sql string +} + +func (record *LogRecord) Set(source interface{}, method string, params ...interface{}) { + record.source = formatSource(source) + record.method = method + record.params = params +} + +func (record *LogRecord) SetReturnValue(retValue interface{}) { + if retValue == nil { + record.returnValue = null + } else { + record.returnValue = retValue + } +} + +func (record *LogRecord) GetReturnValue() interface{} { + return record.returnValue +} + +func (record *LogRecord) SetSql(sql string) { + record.sql = sql +} + +func (record *LogRecord) GetSql() string { + return record.sql +} + +func (record *LogRecord) SetUsedTime(usedTime time.Duration) { + record.usedTime = usedTime +} + +func (record *LogRecord) GetUsedTime() time.Duration { + return record.usedTime +} + +func (record *LogRecord) SetError(err error) { + record.e = err +} + +func (record *LogRecord) GetError() error { + return record.e +} + +func (record *LogRecord) ToString() string { + var str string + str += formatTrace(record.source, record.method, record.returnValue, record.params...) + if record.usedTime > 0 { + str += formatUsedTime(record.usedTime) + } + return str +} diff --git a/dmr/zf.go b/dmr/zf.go new file mode 100644 index 0000000..bad6c81 --- /dev/null +++ b/dmr/zf.go @@ -0,0 +1,497 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "context" + "database/sql/driver" + "io" + "reflect" + "time" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +const SQL_GET_DSC_EP_SITE = "SELECT " + + "dsc.ep_seqno, " + + "(CASE mal.MAL_INST_HOST WHEN '' THEN mal.MAL_HOST ELSE mal.MAL_INST_HOST END) as ep_host, " + + "dcr.EP_PORT, " + + "dsc.EP_STATUS " + + "FROM V$DSC_EP_INFO dsc " + + "LEFT join V$DM_MAL_INI mal " + + "on dsc.EP_NAME = mal.MAL_INST_NAME " + + "LEFT join (SELECT grp.GROUP_TYPE GROUP_TYPE, ep.* FROM SYS.\"V$DCR_GROUP\" grp, SYS.\"V$DCR_EP\" ep where grp.GROUP_NAME = ep.GROUP_NAME) dcr " + + "on dsc.EP_NAME = dcr.EP_NAME and GROUP_TYPE = 'DB' order by dsc.ep_seqno asc;" + +type reconnectFilter struct { +} + +// 一定抛错 +func (rf *reconnectFilter) autoReconnect(connection *DmConnection, err error) error { + if dmErr, ok := err.(*DmError); ok { + if dmErr.ErrCode == ECGO_COMMUNITION_ERROR.ErrCode { + return rf.reconnect(connection, dmErr.Error()) + } + } + return err +} + +// 一定抛错 +func (rf *reconnectFilter) reconnect(connection *DmConnection, reason string) error { + // 读写分离,重连需要处理备机 + var err error + if connection.dmConnector.rwSeparate { + err = RWUtil.reconnect(connection) + } else { + err = connection.reconnect() + } + + if err != nil { + return ECGO_CONNECTION_SWITCH_FAILED.addDetailln(reason).throw() + } + + // 重连成功 + return ECGO_CONNECTION_SWITCHED.addDetailln(reason).throw() +} + +func (rf *reconnectFilter) loadDscEpSites(conn *DmConnection) []*ep { + stmt, rs, err := conn.driverQuery(SQL_GET_DSC_EP_SITE) + if err != nil { + return nil + } + defer func() { + rs.close() + stmt.close() + }() + epList := make([]*ep, 0) + dest := make([]driver.Value, 4) + for err = rs.next(dest); err != io.EOF; err = rs.next(dest) { + ep := newEP(dest[1].(string), dest[2].(int32)) + ep.epSeqno = dest[0].(int32) + if util.StringUtil.EqualsIgnoreCase(dest[3].(string), "OK") { + ep.epStatus = EP_STATUS_OK + } else { + ep.epStatus = EP_STATUS_ERROR + } + epList = append(epList, ep) + } + return epList +} + +func (rf *reconnectFilter) checkAndRecover(conn *DmConnection) error { + if conn.dmConnector.doSwitch != DO_SWITCH_WHEN_EP_RECOVER { + return nil + } + // check trx finish + if !conn.trxFinish { + return nil + } + var curIndex = conn.getIndexOnEPGroup() + if curIndex == 0 || (time.Now().UnixNano()/1000000-conn.recoverInfo.checkEpRecoverTs) < int64(conn.dmConnector.switchInterval) { + return nil + } + // check db recover + var dscEps []*ep + if conn.dmConnector.cluster == CLUSTER_TYPE_DSC { + dscEps = rf.loadDscEpSites(conn) + } + if dscEps == nil || len(dscEps) == 0 { + return nil + } + var recover = false + for _, okEp := range dscEps { + if okEp.epStatus != EP_STATUS_OK { + continue + } + for i := int32(0); i < curIndex; i++ { + ep := conn.dmConnector.group.epList[i] + if okEp.host == ep.host && okEp.port == ep.port { + recover = true + break + } + } + if recover { + break + } + } + + conn.recoverInfo.checkEpRecoverTs = time.Now().UnixNano() / 1000000 + if !recover { + return nil + } + // do reconnect + return conn.reconnect() +} + +//DmDriver +func (rf *reconnectFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error) { + return filterChain.DmDriverOpen(d, dsn) +} + +func (rf *reconnectFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error) { + return filterChain.DmDriverOpenConnector(d, dsn) +} + +//DmConnector +func (rf *reconnectFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error) { + return filterChain.DmConnectorConnect(c, ctx) +} + +func (rf *reconnectFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver { + return filterChain.DmConnectorDriver(c) +} + +//DmConnection +func (rf *reconnectFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error) { + dc, err := filterChain.DmConnectionBegin(c) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + return dc, err +} + +func (rf *reconnectFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) { + dc, err := filterChain.DmConnectionBeginTx(c, ctx, opts) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + return dc, err +} + +func (rf *reconnectFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) error { + if err := filterChain.DmConnectionCommit(c); err != nil { + return rf.autoReconnect(c, err) + } + if err := rf.checkAndRecover(c); err != nil { + return rf.autoReconnect(c, err) + } + return nil +} + +func (rf *reconnectFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) error { + err := filterChain.DmConnectionRollback(c) + if err != nil { + err = rf.autoReconnect(c, err) + } + + return err +} + +func (rf *reconnectFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) error { + err := filterChain.DmConnectionClose(c) + if err != nil { + err = rf.autoReconnect(c, err) + } + + return err +} + +func (rf *reconnectFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error { + err := filterChain.DmConnectionPing(c, ctx) + if err != nil { + err = rf.autoReconnect(c, err) + } + + return err +} + +func (rf *reconnectFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error) { + if err := rf.checkAndRecover(c); err != nil { + return nil, rf.autoReconnect(c, err) + } + dr, err := filterChain.DmConnectionExec(c, query, args) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) { + if err := rf.checkAndRecover(c); err != nil { + return nil, rf.autoReconnect(c, err) + } + dr, err := filterChain.DmConnectionExecContext(c, ctx, query, args) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error) { + if err := rf.checkAndRecover(c); err != nil { + return nil, rf.autoReconnect(c, err) + } + dr, err := filterChain.DmConnectionQuery(c, query, args) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) { + if err := rf.checkAndRecover(c); err != nil { + return nil, rf.autoReconnect(c, err) + } + dr, err := filterChain.DmConnectionQueryContext(c, ctx, query, args) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error) { + ds, err := filterChain.DmConnectionPrepare(c, query) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + + return ds, err +} + +func (rf *reconnectFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error) { + ds, err := filterChain.DmConnectionPrepareContext(c, ctx, query) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + + return ds, err +} + +func (rf *reconnectFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error { + err := filterChain.DmConnectionResetSession(c, ctx) + if err != nil { + err = rf.autoReconnect(c, err) + } + + return err +} + +func (rf *reconnectFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error { + err := filterChain.DmConnectionCheckNamedValue(c, nv) + if err != nil { + err = rf.autoReconnect(c, err) + } + + return err +} + +//DmStatement +func (rf *reconnectFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) error { + err := filterChain.DmStatementClose(s) + if err != nil { + err = rf.autoReconnect(s.dmConn, err) + } + + return err +} + +func (rf *reconnectFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) int { + var ret int + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(s.dmConn, err.(error)) + ret = 0 + } + }() + ret = filterChain.DmStatementNumInput(s) + return ret +} + +func (rf *reconnectFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error) { + if err := rf.checkAndRecover(s.dmConn); err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + dr, err := filterChain.DmStatementExec(s, args) + if err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) { + if err := rf.checkAndRecover(s.dmConn); err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + dr, err := filterChain.DmStatementExecContext(s, ctx, args) + if err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error) { + if err := rf.checkAndRecover(s.dmConn); err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + dr, err := filterChain.DmStatementQuery(s, args) + if err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) { + if err := rf.checkAndRecover(s.dmConn); err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + dr, err := filterChain.DmStatementQueryContext(s, ctx, args) + if err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error { + err := filterChain.DmStatementCheckNamedValue(s, nv) + if err != nil { + err = rf.autoReconnect(s.dmConn, err) + } + + return err +} + +//DmResult +func (rf *reconnectFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error) { + i, err := filterChain.DmResultLastInsertId(r) + if err != nil { + err = rf.autoReconnect(r.dmStmt.dmConn, err) + return 0, err + } + + return i, err +} + +func (rf *reconnectFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error) { + i, err := filterChain.DmResultRowsAffected(r) + if err != nil { + err = rf.autoReconnect(r.dmStmt.dmConn, err) + return 0, err + } + + return i, err +} + +//DmRows +func (rf *reconnectFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) []string { + var ret []string + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + ret = nil + } + }() + ret = filterChain.DmRowsColumns(r) + return ret +} + +func (rf *reconnectFilter) DmRowsClose(filterChain *filterChain, r *DmRows) error { + err := filterChain.DmRowsClose(r) + if err != nil { + err = rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err) + } + + return err +} + +func (rf *reconnectFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error { + err := filterChain.DmRowsNext(r, dest) + if err != nil { + err = rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err) + } + + return err +} + +func (rf *reconnectFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool { + var ret bool + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + ret = false + } + }() + ret = filterChain.DmRowsHasNextResultSet(r) + return ret +} + +func (rf *reconnectFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error { + err := filterChain.DmRowsNextResultSet(r) + if err != nil { + err = rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err) + } + + return err +} + +func (rf *reconnectFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type { + var ret reflect.Type + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + ret = scanTypeUnknown + } + }() + ret = filterChain.DmRowsColumnTypeScanType(r, index) + return ret +} + +func (rf *reconnectFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string { + var ret string + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + ret = "" + } + }() + ret = filterChain.DmRowsColumnTypeDatabaseTypeName(r, index) + return ret +} + +func (rf *reconnectFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) { + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + length, ok = 0, false + } + }() + return filterChain.DmRowsColumnTypeLength(r, index) +} + +func (rf *reconnectFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) { + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + nullable, ok = false, false + } + }() + return filterChain.DmRowsColumnTypeNullable(r, index) +} + +func (rf *reconnectFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) { + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + precision, scale, ok = 0, 0, false + } + }() + return filterChain.DmRowsColumnTypePrecisionScale(r, index) +} diff --git a/dmr/zg.go b/dmr/zg.go new file mode 100644 index 0000000..a65db20 --- /dev/null +++ b/dmr/zg.go @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "context" + "database/sql/driver" + "reflect" +) + +type rwFilter struct { +} + +//DmDriver +func (rwf *rwFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error) { + return filterChain.DmDriverOpen(d, dsn) +} + +func (rwf *rwFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error) { + return filterChain.DmDriverOpenConnector(d, dsn) +} + +//DmConnector +func (rwf *rwFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error) { + return RWUtil.connect(c, ctx) +} + +func (rwf *rwFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver { + return filterChain.DmConnectorDriver(c) +} + +//DmConnection +func (rwf *rwFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error) { + if RWUtil.isStandbyAlive(c) { + _, err := c.rwInfo.connStandby.begin() + if err != nil { + RWUtil.afterExceptionOnStandby(c, err) + } + } + + return filterChain.DmConnectionBegin(c) +} + +func (rwf *rwFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) { + if RWUtil.isStandbyAlive(c) { + _, err := c.rwInfo.connStandby.beginTx(ctx, opts) + if err != nil { + RWUtil.afterExceptionOnStandby(c, err) + } + } + + return filterChain.DmConnectionBeginTx(c, ctx, opts) +} + +func (rwf *rwFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) error { + if RWUtil.isStandbyAlive(c) { + err := c.rwInfo.connStandby.commit() + if err != nil { + RWUtil.afterExceptionOnStandby(c, err) + } + } + + return filterChain.DmConnectionCommit(c) +} + +func (rwf *rwFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) error { + if RWUtil.isStandbyAlive(c) { + err := c.rwInfo.connStandby.rollback() + if err != nil { + RWUtil.afterExceptionOnStandby(c, err) + } + } + + return filterChain.DmConnectionRollback(c) +} + +func (rwf *rwFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) error { + if RWUtil.isStandbyAlive(c) { + err := c.rwInfo.connStandby.close() + if err != nil { + RWUtil.afterExceptionOnStandby(c, err) + } + } + + return filterChain.DmConnectionClose(c) +} + +func (rwf *rwFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error { + return filterChain.DmConnectionPing(c, ctx) +} + +func (rwf *rwFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error) { + ret, err := RWUtil.executeByConn(c, query, func() (interface{}, error) { + return c.rwInfo.connCurrent.exec(query, args) + }, func(otherConn *DmConnection) (interface{}, error) { + return otherConn.exec(query, args) + }) + if err != nil { + return nil, err + } + return ret.(*DmResult), nil +} + +func (rwf *rwFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) { + ret, err := RWUtil.executeByConn(c, query, func() (interface{}, error) { + return c.rwInfo.connCurrent.execContext(ctx, query, args) + }, func(otherConn *DmConnection) (interface{}, error) { + return otherConn.execContext(ctx, query, args) + }) + if err != nil { + return nil, err + } + return ret.(*DmResult), nil +} + +func (rwf *rwFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error) { + ret, err := RWUtil.executeByConn(c, query, func() (interface{}, error) { + return c.rwInfo.connCurrent.query(query, args) + }, func(otherConn *DmConnection) (interface{}, error) { + return otherConn.query(query, args) + }) + if err != nil { + return nil, err + } + return ret.(*DmRows), nil +} + +func (rwf *rwFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) { + ret, err := RWUtil.executeByConn(c, query, func() (interface{}, error) { + return c.rwInfo.connCurrent.queryContext(ctx, query, args) + }, func(otherConn *DmConnection) (interface{}, error) { + return otherConn.queryContext(ctx, query, args) + }) + if err != nil { + return nil, err + } + return ret.(*DmRows), nil +} + +func (rwf *rwFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error) { + stmt, err := c.prepare(query) + if err != nil { + return nil, err + } + stmt.rwInfo.stmtCurrent = stmt + stmt.rwInfo.readOnly = RWUtil.checkReadonlyByStmt(stmt) + if RWUtil.isCreateStandbyStmt(stmt) { + stmt.rwInfo.stmtStandby, err = c.rwInfo.connStandby.prepare(query) + if err == nil { + stmt.rwInfo.stmtCurrent = stmt.rwInfo.stmtStandby + } else { + RWUtil.afterExceptionOnStandby(c, err) + } + } + return stmt, nil +} + +func (rwf *rwFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error) { + stmt, err := c.prepareContext(ctx, query) + if err != nil { + return nil, err + } + stmt.rwInfo.stmtCurrent = stmt + stmt.rwInfo.readOnly = RWUtil.checkReadonlyByStmt(stmt) + if RWUtil.isCreateStandbyStmt(stmt) { + stmt.rwInfo.stmtStandby, err = c.rwInfo.connStandby.prepareContext(ctx, query) + if err == nil { + stmt.rwInfo.stmtCurrent = stmt.rwInfo.stmtStandby + } else { + RWUtil.afterExceptionOnStandby(c, err) + } + } + return stmt, nil +} + +func (rwf *rwFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error { + if RWUtil.isStandbyAlive(c) { + err := c.rwInfo.connStandby.resetSession(ctx) + if err != nil { + RWUtil.afterExceptionOnStandby(c, err) + } + } + + return filterChain.DmConnectionResetSession(c, ctx) +} + +func (rwf *rwFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error { + return filterChain.DmConnectionCheckNamedValue(c, nv) +} + +//DmStatement +func (rwf *rwFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) error { + if RWUtil.isStandbyStatementValid(s) { + err := s.rwInfo.stmtStandby.close() + if err != nil { + RWUtil.afterExceptionOnStandby(s.dmConn, err) + } + } + + return filterChain.DmStatementClose(s) +} + +func (rwf *rwFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) int { + return filterChain.DmStatementNumInput(s) +} + +func (rwf *rwFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error) { + ret, err := RWUtil.executeByStmt(s, func() (interface{}, error) { + return s.rwInfo.stmtCurrent.exec(args) + }, func(otherStmt *DmStatement) (interface{}, error) { + return otherStmt.exec(args) + }) + if err != nil { + return nil, err + } + return ret.(*DmResult), nil +} + +func (rwf *rwFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) { + ret, err := RWUtil.executeByStmt(s, func() (interface{}, error) { + return s.rwInfo.stmtCurrent.execContext(ctx, args) + }, func(otherStmt *DmStatement) (interface{}, error) { + return otherStmt.execContext(ctx, args) + }) + if err != nil { + return nil, err + } + return ret.(*DmResult), nil +} + +func (rwf *rwFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error) { + ret, err := RWUtil.executeByStmt(s, func() (interface{}, error) { + return s.rwInfo.stmtCurrent.query(args) + }, func(otherStmt *DmStatement) (interface{}, error) { + return otherStmt.query(args) + }) + if err != nil { + return nil, err + } + return ret.(*DmRows), nil +} + +func (rwf *rwFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) { + ret, err := RWUtil.executeByStmt(s, func() (interface{}, error) { + return s.rwInfo.stmtCurrent.queryContext(ctx, args) + }, func(otherStmt *DmStatement) (interface{}, error) { + return otherStmt.queryContext(ctx, args) + }) + if err != nil { + return nil, err + } + return ret.(*DmRows), nil +} + +func (rwf *rwFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error { + return filterChain.DmStatementCheckNamedValue(s, nv) +} + +//DmResult +func (rwf *rwFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error) { + return filterChain.DmResultLastInsertId(r) +} + +func (rwf *rwFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error) { + return filterChain.DmResultRowsAffected(r) +} + +//DmRows +func (rwf *rwFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) []string { + return filterChain.DmRowsColumns(r) +} + +func (rwf *rwFilter) DmRowsClose(filterChain *filterChain, r *DmRows) error { + return filterChain.DmRowsClose(r) +} + +func (rwf *rwFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error { + return filterChain.DmRowsNext(r, dest) +} + +func (rwf *rwFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool { + return filterChain.DmRowsHasNextResultSet(r) +} + +func (rwf *rwFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error { + return filterChain.DmRowsNextResultSet(r) +} + +func (rwf *rwFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type { + return filterChain.DmRowsColumnTypeScanType(r, index) +} + +func (rwf *rwFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string { + return filterChain.DmRowsColumnTypeDatabaseTypeName(r, index) +} + +func (rwf *rwFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) { + return filterChain.DmRowsColumnTypeLength(r, index) +} + +func (rwf *rwFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) { + return filterChain.DmRowsColumnTypeNullable(r, index) +} + +func (rwf *rwFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) { + return filterChain.DmRowsColumnTypePrecisionScale(r, index) +} diff --git a/dmr/zh.go b/dmr/zh.go new file mode 100644 index 0000000..7afeaeb --- /dev/null +++ b/dmr/zh.go @@ -0,0 +1,607 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "bytes" + "context" + "database/sql/driver" + "fmt" + "reflect" + "time" +) + +type statFilter struct { +} + +//DmDriver +func (sf *statFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error) { + conn, err := filterChain.DmDriverOpen(d, dsn) + if err != nil { + return nil, err + } + conn.statInfo.init(conn) + conn.statInfo.setConstructNano() + conn.statInfo.getConnStat().incrementConn() + return conn, nil +} + +func (sf *statFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error) { + return filterChain.DmDriverOpenConnector(d, dsn) +} + +//DmConnector +func (sf *statFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error) { + conn, err := filterChain.DmConnectorConnect(c, ctx) + if err != nil { + return nil, err + } + conn.statInfo.init(conn) + conn.statInfo.setConstructNano() + conn.statInfo.getConnStat().incrementConn() + return conn, nil +} + +func (sf *statFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver { + return filterChain.DmConnectorDriver(c) +} + +//DmConnection +func (sf *statFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error) { + return filterChain.DmConnectionBegin(c) +} + +func (sf *statFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) { + return filterChain.DmConnectionBeginTx(c, ctx, opts) +} + +func (sf *statFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) error { + err := filterChain.DmConnectionCommit(c) + if err != nil { + return err + } + c.statInfo.getConnStat().incrementCommitCount() + return nil +} + +func (sf *statFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) error { + err := filterChain.DmConnectionRollback(c) + if err != nil { + return err + } + c.statInfo.getConnStat().incrementRollbackCount() + return nil +} + +func (sf *statFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) error { + if !c.closed.IsSet() { + c.statInfo.getConnStat().decrementStmtByActiveStmtCount(int64(getActiveStmtCount(c))) + c.statInfo.getConnStat().decrementConn() + } + + return filterChain.DmConnectionClose(c) +} + +func (sf *statFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error { + return c.ping(ctx) +} + +func (sf *statFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error) { + connExecBefore(c, query) + dr, err := filterChain.DmConnectionExec(c, query, args) + if err != nil { + connExecuteErrorAfter(c, args, err) + return nil, err + } + connExecAfter(c, query, args, int(dr.affectedRows)) + return dr, nil +} + +func (sf *statFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) { + connExecBefore(c, query) + dr, err := filterChain.DmConnectionExecContext(c, ctx, query, args) + if err != nil { + connExecuteErrorAfter(c, args, err) + return nil, err + } + connExecAfter(c, query, args, int(dr.affectedRows)) + return dr, nil +} + +func (sf *statFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error) { + connQueryBefore(c, query) + dr, err := filterChain.DmConnectionQuery(c, query, args) + if err != nil { + connExecuteErrorAfter(c, args, err) + return nil, err + } + connQueryAfter(c, query, args, dr) + return dr, nil +} + +func (sf *statFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) { + connQueryBefore(c, query) + dr, err := filterChain.DmConnectionQueryContext(c, ctx, query, args) + if err != nil { + connExecuteErrorAfter(c, args, err) + return nil, err + } + connQueryAfter(c, query, args, dr) + return dr, nil +} + +func (sf *statFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error) { + stmt, err := filterChain.DmConnectionPrepare(c, query) + if err != nil { + return nil, err + } + statementCreateAfter(c, stmt) + return stmt, nil +} + +func (sf *statFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error) { + stmt, err := filterChain.DmConnectionPrepareContext(c, ctx, query) + if err != nil { + return nil, err + } + statementCreateAfter(c, stmt) + return stmt, nil +} + +func (sf *statFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error { + return filterChain.DmConnectionResetSession(c, ctx) +} + +func (sf *statFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error { + return filterChain.DmConnectionCheckNamedValue(c, nv) +} + +//DmStatement +func (sf *statFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) error { + if !s.closed { + statementCloseBefore(s) + } + return filterChain.DmStatementClose(s) +} + +func (sf *statFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) int { + return filterChain.DmStatementNumInput(s) +} + +func (sf *statFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error) { + stmtExecBefore(s) + dr, err := filterChain.DmStatementExec(s, args) + if err != nil { + statementExecuteErrorAfter(s, args, err) + return nil, err + } + stmtExecAfter(s, args, int(dr.affectedRows)) + return dr, nil +} + +func (sf *statFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) { + stmtExecBefore(s) + dr, err := filterChain.DmStatementExecContext(s, ctx, args) + if err != nil { + statementExecuteErrorAfter(s, args, err) + return nil, err + } + stmtExecAfter(s, args, int(dr.affectedRows)) + return dr, nil +} + +func (sf *statFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error) { + stmtQueryBefore(s) + dr, err := filterChain.DmStatementQuery(s, args) + if err != nil { + statementExecuteErrorAfter(s, args, err) + return nil, err + } + stmtQueryAfter(s, args, dr) + return dr, nil +} + +func (sf *statFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) { + stmtQueryBefore(s) + dr, err := filterChain.DmStatementQueryContext(s, ctx, args) + if err != nil { + statementExecuteErrorAfter(s, args, err) + return nil, err + } + stmtQueryAfter(s, args, dr) + return dr, nil +} + +func (sf *statFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error { + return filterChain.DmStatementCheckNamedValue(s, nv) +} + +//DmResult +func (sf *statFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error) { + return filterChain.DmResultLastInsertId(r) +} + +func (sf *statFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error) { + return filterChain.DmResultRowsAffected(r) +} + +//DmRows +func (sf *statFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) []string { + return filterChain.DmRowsColumns(r) +} + +func (sf *statFilter) DmRowsClose(filterChain *filterChain, r *DmRows) error { + if !r.CurrentRows.closed { + resultSetCloseBefore(r) + } + return filterChain.DmRowsClose(r) +} + +func (sf *statFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error { + return filterChain.DmRowsNext(r, dest) +} + +func (sf *statFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool { + return filterChain.DmRowsHasNextResultSet(r) +} + +func (sf *statFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error { + return filterChain.DmRowsNextResultSet(r) +} + +func (sf *statFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type { + return filterChain.DmRowsColumnTypeScanType(r, index) +} + +func (sf *statFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string { + return filterChain.DmRowsColumnTypeDatabaseTypeName(r, index) +} + +func (sf *statFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) { + return filterChain.DmRowsColumnTypeLength(r, index) +} + +func (sf *statFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) { + return filterChain.DmRowsColumnTypeNullable(r, index) +} + +func (sf *statFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) { + return filterChain.DmRowsColumnTypePrecisionScale(r, index) +} + +func getActiveStmtCount(conn *DmConnection) int { + if conn.stmtMap == nil { + return 0 + } else { + return len(conn.stmtMap) + } +} + +func statementCreateAfter(conn *DmConnection, stmt *DmStatement) { + stmt.statInfo.setConstructNano() + conn.statInfo.getConnStat().incrementStmt() +} + +func connExecBefore(conn *DmConnection, sql string) { + conn.statInfo.setLastExecuteSql(sql) + conn.statInfo.setFirstResultSet(false) + conn.statInfo.setLastExecuteType(ExecuteUpdate) + internalBeforeConnExecute(conn, sql) +} + +func connExecAfter(conn *DmConnection, sql string, args interface{}, updateCount int) { + internalAfterConnExecute(conn, args, updateCount) +} + +func connQueryBefore(conn *DmConnection, sql string) { + conn.statInfo.setLastExecuteSql(sql) + conn.statInfo.setFirstResultSet(true) + conn.statInfo.setLastExecuteType(ExecuteQuery) + internalBeforeConnExecute(conn, sql) +} + +func connQueryAfter(conn *DmConnection, sql string, args interface{}, resultSet *DmRows) { + if resultSet != nil { + connResultSetCreateAfter(resultSet, conn) + } + internalAfterConnExecute(conn, args, 0) +} + +func stmtExecBefore(stmt *DmStatement) { + stmt.statInfo.setLastExecuteSql(stmt.nativeSql) + stmt.statInfo.setFirstResultSet(false) + stmt.statInfo.setLastExecuteType(ExecuteUpdate) + internalBeforeStatementExecute(stmt, stmt.nativeSql) +} + +func stmtExecAfter(stmt *DmStatement, args interface{}, updateCount int) { + internalAfterStatementExecute(stmt, args, updateCount) +} + +func stmtQueryBefore(stmt *DmStatement) { + stmt.statInfo.setLastExecuteSql(stmt.nativeSql) + stmt.statInfo.setFirstResultSet(true) + stmt.statInfo.setLastExecuteType(ExecuteQuery) + internalBeforeStatementExecute(stmt, stmt.nativeSql) +} + +func stmtQueryAfter(stmt *DmStatement, args interface{}, resultSet *DmRows) { + if resultSet != nil { + stmtResultSetCreateAfter(resultSet, stmt) + } + internalAfterStatementExecute(stmt, args, 0) +} + +func internalBeforeConnExecute(conn *DmConnection, sql string) { + connStat := conn.statInfo.getConnStat() + connStat.incrementExecuteCount() + conn.statInfo.beforeExecute() + + sqlStat := conn.statInfo.getSqlStat() + if sqlStat == nil || sqlStat.Removed == 1 || !(sqlStat.Sql == sql) { + sqlStat = connStat.createSqlStat(sql) + conn.statInfo.setSqlStat(sqlStat) + } + + inTransaction := false + inTransaction = !conn.autoCommit + + if sqlStat != nil { + sqlStat.ExecuteLastStartTime = time.Now().UnixNano() + sqlStat.incrementRunningCount() + + if inTransaction { + sqlStat.incrementInTransactionCount() + } + } +} + +func internalAfterConnExecute(conn *DmConnection, args interface{}, updateCount int) { + nowNano := time.Now().UnixNano() + nanos := nowNano - conn.statInfo.getLastExecuteStartNano() + + conn.statInfo.afterExecute(nanos) + + sqlStat := conn.statInfo.getSqlStat() + + if sqlStat != nil { + sqlStat.incrementExecuteSuccessCount() + + sqlStat.decrementRunningCount() + + parameters := buildSlowParameters(args) + + sqlStat.addExecuteTimeAndResultHoldTimeHistogramRecord(conn.statInfo.getLastExecuteType(), conn.statInfo.isFirstResultSet(), + nanos, parameters) + + if !conn.statInfo.isFirstResultSet() && + conn.statInfo.getLastExecuteType() == ExecuteUpdate { + if updateCount < 0 { + updateCount = 0 + } + sqlStat.addUpdateCount(int64(updateCount)) + } + } + +} + +func internalBeforeStatementExecute(stmt *DmStatement, sql string) { + connStat := stmt.dmConn.statInfo.getConnStat() + connStat.incrementExecuteCount() + stmt.statInfo.beforeExecute() + + sqlStat := stmt.statInfo.getSqlStat() + if sqlStat == nil || sqlStat.Removed == 1 || !(sqlStat.Sql == sql) { + sqlStat = connStat.createSqlStat(sql) + stmt.statInfo.setSqlStat(sqlStat) + } + + inTransaction := false + inTransaction = !stmt.dmConn.autoCommit + + if sqlStat != nil { + sqlStat.ExecuteLastStartTime = time.Now().UnixNano() + sqlStat.incrementRunningCount() + + if inTransaction { + sqlStat.incrementInTransactionCount() + } + } +} + +func internalAfterStatementExecute(stmt *DmStatement, args interface{}, updateCount int) { + nowNano := time.Now().UnixNano() + nanos := nowNano - stmt.statInfo.getLastExecuteStartNano() + + stmt.statInfo.afterExecute(nanos) + + sqlStat := stmt.statInfo.getSqlStat() + + if sqlStat != nil { + sqlStat.incrementExecuteSuccessCount() + + sqlStat.decrementRunningCount() + + parameters := "" + if stmt.paramCount > 0 { + parameters = buildStmtSlowParameters(stmt, args) + } + sqlStat.addExecuteTimeAndResultHoldTimeHistogramRecord(stmt.statInfo.getLastExecuteType(), stmt.statInfo.isFirstResultSet(), + nanos, parameters) + + if (!stmt.statInfo.isFirstResultSet()) && + stmt.statInfo.getLastExecuteType() == ExecuteUpdate { + updateCount := stmt.execInfo.updateCount + if updateCount < 0 { + updateCount = 0 + } + sqlStat.addUpdateCount(updateCount) + } + + } + +} + +func buildSlowParameters(args interface{}) string { + switch v := args.(type) { + case []driver.Value: + sb := bytes.NewBufferString("") + for i := 0; i < len(v); i++ { + if i != 0 { + sb.WriteString(",") + } else { + sb.WriteString("[") + } + + sb.WriteString(fmt.Sprint(v[i])) + } + + if len(v) > 0 { + sb.WriteString("]") + } + return sb.String() + case []driver.NamedValue: + sb := bytes.NewBufferString("") + for i := 0; i < len(v); i++ { + if i != 0 { + sb.WriteString(",") + } else { + sb.WriteString("[") + } + + sb.WriteString(fmt.Sprint(v[i])) + } + if len(v) > 0 { + sb.WriteString("]") + } + return sb.String() + default: + return "" + } +} + +func buildStmtSlowParameters(stmt *DmStatement, args interface{}) string { + switch v := args.(type) { + case []driver.Value: + sb := bytes.NewBufferString("") + for i := 0; i < int(stmt.paramCount); i++ { + if i != 0 { + sb.WriteString(",") + } else { + sb.WriteString("[") + } + + sb.WriteString(fmt.Sprint(v[i])) + } + if len(v) > 0 { + sb.WriteString("]") + } + return sb.String() + case []driver.NamedValue: + sb := bytes.NewBufferString("") + for i := 0; i < int(stmt.paramCount); i++ { + if i != 0 { + sb.WriteString(",") + } else { + sb.WriteString("[") + } + + sb.WriteString(fmt.Sprint(v[i])) + } + if len(v) > 0 { + sb.WriteString("]") + } + return sb.String() + default: + return "" + } +} + +func connExecuteErrorAfter(conn *DmConnection, args interface{}, err error) { + nanos := time.Now().UnixNano() - conn.statInfo.getLastExecuteStartNano() + conn.statInfo.getConnStat().incrementErrorCount() + conn.statInfo.afterExecute(nanos) + + // SQL + sqlStat := conn.statInfo.getSqlStat() + if sqlStat != nil { + sqlStat.decrementRunningCount() + sqlStat.error(err) + parameters := buildSlowParameters(args) + sqlStat.addExecuteTimeAndResultHoldTimeHistogramRecord(conn.statInfo.getLastExecuteType(), conn.statInfo.isFirstResultSet(), + nanos, parameters) + } + +} + +func statementExecuteErrorAfter(stmt *DmStatement, args interface{}, err error) { + nanos := time.Now().UnixNano() - stmt.statInfo.getLastExecuteStartNano() + stmt.dmConn.statInfo.getConnStat().incrementErrorCount() + stmt.statInfo.afterExecute(nanos) + + // SQL + sqlStat := stmt.statInfo.getSqlStat() + if sqlStat != nil { + sqlStat.decrementRunningCount() + sqlStat.error(err) + parameters := "" + if stmt.paramCount > 0 { + parameters = buildStmtSlowParameters(stmt, args) + } + sqlStat.addExecuteTimeAndResultHoldTimeHistogramRecord(stmt.statInfo.getLastExecuteType(), stmt.statInfo.isFirstResultSet(), + nanos, parameters) + } + +} + +func statementCloseBefore(stmt *DmStatement) { + stmt.dmConn.statInfo.getConnStat().decrementStmt() +} + +func connResultSetCreateAfter(dmdbResultSet *DmRows, conn *DmConnection) { + dmdbResultSet.statInfo.setSql(conn.statInfo.getLastExecuteSql()) + dmdbResultSet.statInfo.setSqlStat(conn.statInfo.getSqlStat()) + dmdbResultSet.statInfo.setConstructNano() +} + +func stmtResultSetCreateAfter(dmdbResultSet *DmRows, stmt *DmStatement) { + dmdbResultSet.statInfo.setSql(stmt.statInfo.getLastExecuteSql()) + dmdbResultSet.statInfo.setSqlStat(stmt.statInfo.getSqlStat()) + dmdbResultSet.statInfo.setConstructNano() +} + +func resultSetCloseBefore(resultSet *DmRows) { + nanos := time.Now().UnixNano() - resultSet.statInfo.getConstructNano() + fetchRowCount := getFetchedRows(resultSet) + sqlStat := resultSet.statInfo.getSqlStat() + if sqlStat != nil && resultSet.statInfo.getCloseCount() == 0 { + sqlStat.addFetchRowCount(fetchRowCount) + stmtExecuteNano := resultSet.statInfo.getLastExecuteTimeNano() + sqlStat.addResultSetHoldTimeNano2(stmtExecuteNano, nanos) + if resultSet.statInfo.getReadStringLength() > 0 { + sqlStat.addStringReadLength(resultSet.statInfo.getReadStringLength()) + } + if resultSet.statInfo.getReadBytesLength() > 0 { + sqlStat.addReadBytesLength(resultSet.statInfo.getReadBytesLength()) + } + if resultSet.statInfo.getOpenInputStreamCount() > 0 { + sqlStat.addInputStreamOpenCount(int64(resultSet.statInfo.getOpenInputStreamCount())) + } + if resultSet.statInfo.getOpenReaderCount() > 0 { + sqlStat.addReaderOpenCount(int64(resultSet.statInfo.getOpenReaderCount())) + } + } + + resultSet.statInfo.incrementCloseCount() +} + +func getFetchedRows(rs *DmRows) int64 { + if rs.CurrentRows.currentPos >= rs.CurrentRows.totalRowCount { + return rs.CurrentRows.totalRowCount + } else { + return rs.CurrentRows.currentPos + 1 + } +} diff --git a/dmr/zi.go b/dmr/zi.go new file mode 100644 index 0000000..cb217fd --- /dev/null +++ b/dmr/zi.go @@ -0,0 +1,1015 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "bytes" + "io" + "math/big" + "strconv" + "strings" + "time" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +var G2DB g2db + +type g2db struct { +} + +func (G2DB g2db) checkTinyint(val interface{}) error { + switch v := val.(type) { + case float64: + if v < float64(INT8_MIN) || v > float64(INT8_MAX) { + return ECGO_DATA_OVERFLOW.throw() + } + case DmDecimal: + if v.ToBigInt().Cmp(big.NewInt(int64(INT8_MIN))) < 0 || + v.ToBigInt().Cmp(big.NewInt(int64(INT8_MAX))) > 0 { + return ECGO_DATA_OVERFLOW.throw() + } + } + return nil +} + +func (G2DB g2db) checkSmallint(val interface{}) error { + switch v := val.(type) { + case float64: + if v < float64(INT16_MIN) || v > float64(INT16_MAX) { + return ECGO_DATA_OVERFLOW.throw() + } + case DmDecimal: + if v.ToBigInt().Cmp(big.NewInt(int64(INT16_MIN))) < 0 || + v.ToBigInt().Cmp(big.NewInt(int64(INT16_MAX))) > 0 { + return ECGO_DATA_OVERFLOW.throw() + } + } + return nil +} + +func (G2DB g2db) checkInt(val interface{}) error { + switch v := val.(type) { + case float64: + if v < float64(INT32_MIN) || v > float64(INT32_MAX) { + return ECGO_DATA_OVERFLOW.throw() + } + case DmDecimal: + if v.ToBigInt().Cmp(big.NewInt(int64(INT32_MIN))) < 0 || + v.ToBigInt().Cmp(big.NewInt(int64(INT32_MAX))) > 0 { + return ECGO_DATA_OVERFLOW.throw() + } + } + return nil +} + +func (G2DB g2db) checkBigint(val interface{}) error { + switch v := val.(type) { + case float64: + if v < float64(INT64_MIN) || v > float64(INT64_MAX) { + return ECGO_DATA_OVERFLOW.throw() + } + case DmDecimal: + if v.ToBigInt().Cmp(big.NewInt(INT64_MIN)) < 0 || + v.ToBigInt().Cmp(big.NewInt(INT64_MAX)) > 0 { + return ECGO_DATA_OVERFLOW.throw() + } + } + return nil +} + +func (G2DB g2db) checkReal(val interface{}) error { + switch v := val.(type) { + case float64: + if v < float64(FLOAT32_MIN) || v > float64(FLOAT32_MAX) { + return ECGO_DATA_OVERFLOW.throw() + } + case DmDecimal: + if v.ToBigFloat().Cmp(big.NewFloat(float64(FLOAT32_MIN))) < 0 || + v.ToBigFloat().Cmp(big.NewFloat(float64(FLOAT32_MAX))) > 0 { + return ECGO_DATA_OVERFLOW.throw() + } + } + return nil +} + +func (G2DB g2db) fromBool(val bool, param parameter, conn *DmConnection) ([]byte, error) { + switch param.colType { + case BOOLEAN, BIT, TINYINT, SMALLINT, INT, BIGINT, REAL, DOUBLE, DECIMAL, CHAR, + VARCHAR2, VARCHAR, CLOB: + if val { + return G2DB.fromInt64(1, param, conn) + } else { + return G2DB.fromInt64(0, param, conn) + } + case BINARY, VARBINARY, BLOB: + if val { + return Dm_build_1220.Dm_build_1398(byte(1)), nil + } else { + return Dm_build_1220.Dm_build_1398(byte(0)), nil + } + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) fromInt64(val int64, param parameter, conn *DmConnection) ([]byte, error) { + + switch param.colType { + case BOOLEAN, BIT: + if val == 0 { + return Dm_build_1220.Dm_build_1398(byte(0)), nil + } + + return Dm_build_1220.Dm_build_1398(byte(1)), nil + + case TINYINT: + err := G2DB.checkTinyint(float64(val)) + + if err != nil { + return nil, err + } + + return Dm_build_1220.Dm_build_1398(byte(val)), nil + case SMALLINT: + err := G2DB.checkSmallint(float64(val)) + + if err != nil { + return nil, err + } + + return Dm_build_1220.Dm_build_1401(int16(val)), nil + case INT: + err := G2DB.checkInt(float64(val)) + + if err != nil { + return nil, err + } + + return Dm_build_1220.Dm_build_1404(int32(val)), nil + case BIGINT: + err := G2DB.checkBigint(float64(val)) + + if err != nil { + return nil, err + } + + return Dm_build_1220.Dm_build_1407(int64(val)), nil + case REAL: + err := G2DB.checkReal(float64(val)) + + if err != nil { + return nil, err + } + + return Dm_build_1220.Dm_build_1410(float32(val)), nil + case DOUBLE: + return Dm_build_1220.Dm_build_1413(float64(val)), nil + case DECIMAL: + d, err := newDecimal(big.NewInt(val), int(param.prec), int(param.scale)) + if err != nil { + return nil, err + } + return d.encodeDecimal() + case CHAR, VARCHAR2, VARCHAR, CLOB: + return Dm_build_1220.Dm_build_1433(strconv.FormatInt(val, 10), conn.getServerEncoding(), conn), nil + case BINARY, VARBINARY, BLOB: + return G2DB.ToBinary(val, int(param.prec)), nil + case DATE, TIME, DATETIME: + if err := G2DB.checkInt(float64(val)); err != nil { + return nil, err + } + return encodeByDateNumber(val, int(param.colType), int(param.scale), int(conn.dmConnector.localTimezone), conn.DbTimezone) + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) ToBinary(x int64, prec int) []byte { + b := make([]byte, 8) + b[7] = byte(x) + b[6] = byte(x >> 8) + b[5] = byte(x >> 16) + b[4] = byte(x >> 24) + b[3] = byte(x >> 32) + b[2] = byte(x >> 40) + b[1] = byte(x >> 48) + b[0] = byte(x >> 56) + + if prec > 0 && prec < len(b) { + dest := make([]byte, prec) + copy(dest, b[len(b)-prec:]) + return dest + } + return b +} + +func (G2DB g2db) fromFloat32(val float32, param parameter, conn *DmConnection) ([]byte, error) { + switch param.colType { + case BOOLEAN, BIT: + if val == 0.0 { + return Dm_build_1220.Dm_build_1398(0), nil + } + return Dm_build_1220.Dm_build_1398(1), nil + case TINYINT: + if err := G2DB.checkTinyint(float64(val)); err != nil { + return nil, err + } + return Dm_build_1220.Dm_build_1398(byte(val)), nil + case SMALLINT: + if err := G2DB.checkSmallint(float64(val)); err != nil { + return nil, err + } + return Dm_build_1220.Dm_build_1401(int16(val)), nil + case INT: + if err := G2DB.checkInt(float64(val)); err != nil { + return nil, err + } + return Dm_build_1220.Dm_build_1404(int32(val)), nil + case BIGINT: + if err := G2DB.checkBigint(float64(val)); err != nil { + return nil, err + } + return Dm_build_1220.Dm_build_1407(int64(val)), nil + case REAL: + if err := G2DB.checkReal(float64(val)); err != nil { + return nil, err + } + return Dm_build_1220.Dm_build_1410(val), nil + case DOUBLE: + return Dm_build_1220.Dm_build_1413(float64(val)), nil + case DECIMAL: + d, err := newDecimal(big.NewFloat(float64(val)), int(param.prec), int(param.scale)) + if err != nil { + return nil, err + } + return d.encodeDecimal() + case CHAR, VARCHAR2, VARCHAR, CLOB: + return Dm_build_1220.Dm_build_1433(strconv.FormatFloat(float64(val), 'f', -1, 32), conn.getServerEncoding(), conn), nil + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) fromFloat64(val float64, param parameter, conn *DmConnection) ([]byte, error) { + + switch param.colType { + case BOOLEAN, BIT: + if val == 0.0 { + return Dm_build_1220.Dm_build_1398(0), nil + } + return Dm_build_1220.Dm_build_1398(1), nil + + case TINYINT: + err := G2DB.checkTinyint(val) + + if err != nil { + return nil, err + } + + return Dm_build_1220.Dm_build_1398(byte(val)), nil + case SMALLINT: + err := G2DB.checkSmallint(val) + + if err != nil { + return nil, err + } + + return Dm_build_1220.Dm_build_1401(int16(val)), nil + case INT: + err := G2DB.checkInt(val) + + if err != nil { + return nil, err + } + + return Dm_build_1220.Dm_build_1404(int32(val)), nil + case BIGINT: + err := G2DB.checkBigint(val) + + if err != nil { + return nil, err + } + + return Dm_build_1220.Dm_build_1407(int64(val)), nil + case REAL: + err := G2DB.checkReal(val) + + if err != nil { + return nil, err + } + + return Dm_build_1220.Dm_build_1410(float32(val)), nil + case DOUBLE: + return Dm_build_1220.Dm_build_1413(float64(val)), nil + case DECIMAL: + d, err := newDecimal(big.NewFloat(val), int(param.prec), int(param.scale)) + if err != nil { + return nil, err + } + return d.encodeDecimal() + case CHAR, VARCHAR2, VARCHAR, CLOB: + return Dm_build_1220.Dm_build_1433(strconv.FormatFloat(val, 'f', -1, 64), conn.getServerEncoding(), conn), nil + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) fromBytes(val []byte, param parameter, conn *DmConnection) (interface{}, error) { + switch param.colType { + case CHAR, VARCHAR2, VARCHAR: + return G2DB.toVarchar(val) + case CLOB: + b, err := G2DB.toVarchar(val) + if err != nil { + return nil, err + } + return G2DB.changeOffRowData(param, b, conn.getServerEncoding()) + case BINARY, VARBINARY: + return val, nil + case BLOB: + return G2DB.bytes2Blob(val, param, conn) + case ARRAY, CLASS, PLTYPE_RECORD, SARRAY: + if param.typeDescriptor == nil { + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return TypeDataSV.objBlobToBytes(val, param.typeDescriptor) + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) toVarchar(bsArr []byte) ([]byte, error) { + if bsArr == nil || len(bsArr) == 0 { + return make([]byte, 0), nil + } + + realLen := len(bsArr) * 2 + bsRet := make([]byte, realLen) + for i := 0; i < len(bsArr); i++ { + bsTemp, err := G2DB.toChar(bsArr[i]) + if err != nil { + return nil, err + } + + bsRet[i*2] = bsTemp[0] + bsRet[i*2+1] = bsTemp[1] + } + + return bsRet, nil +} + +func (G2DB g2db) toChar(bt byte) ([]byte, error) { + bytes := make([]byte, 2) + var err error + + bytes[0], err = G2DB.getCharByNumVal((bt >> 4) & 0x0F) + if err != nil { + return nil, err + } + + bytes[1], err = G2DB.getCharByNumVal(bt & 0x0F) + if err != nil { + return nil, err + } + + return bytes, nil +} + +func (G2DB g2db) getCharByNumVal(val byte) (byte, error) { + if val >= 0 && val <= 9 { + return (byte)(val + '0'), nil + } + + if val >= 0x0a && val <= 0x0F { + return (byte)(val + 'A' - 0x0a), nil + } + return 0, ECGO_INVALID_HEX.throw() +} + +func (G2DB g2db) fromString(val string, param parameter, conn *DmConnection) (interface{}, error) { + switch param.colType { + case BOOLEAN, BIT: + ret, err := G2DB.toBool(val) + if err != nil { + return nil, err + } + + if ret { + return Dm_build_1220.Dm_build_1398(byte(1)), nil + } else { + return Dm_build_1220.Dm_build_1398(byte(0)), nil + } + + case TINYINT, SMALLINT, INT, BIGINT: + f, ok := new(big.Float).SetString(val) + if !ok { + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + if f.Sign() < 0 { + f.Sub(f, big.NewFloat(0.5)) + } else { + f.Add(f, big.NewFloat(0.5)) + } + z, _ := f.Int(nil) + return G2DB.fromBigInt(z, param, conn) + case REAL, DOUBLE, DECIMAL: + f, ok := new(big.Float).SetString(val) + if ok { + return G2DB.fromBigFloat(f, param, conn) + } else { + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + + case CHAR, VARCHAR2, VARCHAR: + if isBFile(int(param.colType), int(param.prec), int(param.scale)) && !checkBFileStr(val) { + return nil, ECGO_INVALID_BFILE_STR.throw() + } + return Dm_build_1220.Dm_build_1433(val, conn.getServerEncoding(), conn), nil + case CLOB: + return G2DB.string2Clob(val, param, conn) + case BINARY, VARBINARY: + return util.StringUtil.HexStringToBytes(val), nil + case BLOB: + return G2DB.bytes2Blob(util.StringUtil.HexStringToBytes(val), param, conn) + case DATE: + if conn.FormatDate != "" { + dt, err := parse(val, conn.FormatDate, int(conn.OracleDateLanguage)) + if err != nil { + return nil, err + } + + return encode(dt, int(param.colType), int(param.scale), int(conn.dmConnector.localTimezone)) + } + + return encodeByString(val, int(param.colType), int(param.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + case TIME: + if conn.FormatTime != "" { + dt, err := parse(val, conn.FormatTime, int(conn.OracleDateLanguage)) + if err != nil { + return nil, err + } + + return encode(dt, int(param.colType), int(param.scale), int(conn.dmConnector.localTimezone)) + } + + return encodeByString(val, int(param.colType), int(param.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + case DATETIME: + if conn.FormatTimestamp != "" { + dt, err := parse(val, conn.FormatTimestamp, int(conn.OracleDateLanguage)) + if err != nil { + return nil, err + } + + return encode(dt, int(param.colType), int(param.scale), int(conn.dmConnector.localTimezone)) + } + + return encodeByString(val, int(param.colType), int(param.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + case TIME_TZ: + dt, err := parse(val, conn.FormatTimeTZ, int(conn.OracleDateLanguage)) + if err != nil { + return nil, err + } + + if conn.FormatTimeTZ != "" { + return encode(dt, int(param.colType), int(param.scale), int(conn.dmConnector.localTimezone)) + } + + return encodeByString(val, int(param.colType), int(param.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + case DATETIME_TZ: + if conn.FormatTimestampTZ != "" { + dt, err := parse(val, conn.FormatTimestampTZ, int(conn.OracleDateLanguage)) + if err != nil { + return nil, err + } + + return encode(dt, int(param.colType), int(param.scale), int(conn.dmConnector.localTimezone)) + } + + return encodeByString(val, int(param.colType), int(param.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + case INTERVAL_DT: + dt, err := NewDmIntervalDTByString(val) + if err != nil { + return nil, err + } + return dt.encode(int(param.scale)) + + case INTERVAL_YM: + ym, err := NewDmIntervalYMByString(val) + if err != nil { + return nil, err + } + return ym.encode(int(param.scale)) + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) toBool(str string) (bool, error) { + str = strings.TrimSpace(str) + if util.StringUtil.Equals(str, "0") { + return false, nil + } else if util.StringUtil.Equals(str, "1") { + return true, nil + } + + return strings.ToLower(str) == "true", nil +} + +func (G2DB g2db) fromBigInt(val *big.Int, param parameter, conn *DmConnection) ([]byte, error) { + var ret []byte + switch param.colType { + case BOOLEAN, BIT: + if val.Sign() == 0 { + ret = Dm_build_1220.Dm_build_1398(0) + } else { + ret = Dm_build_1220.Dm_build_1398(1) + } + case TINYINT: + err := G2DB.checkTinyint(float64(val.Int64())) + + if err != nil { + return nil, err + } + + ret = Dm_build_1220.Dm_build_1398(byte(val.Int64())) + case SMALLINT: + err := G2DB.checkSmallint(float64(val.Int64())) + + if err != nil { + return nil, err + } + + ret = Dm_build_1220.Dm_build_1401(int16(val.Int64())) + case INT: + err := G2DB.checkInt(float64(val.Int64())) + + if err != nil { + return nil, err + } + + ret = Dm_build_1220.Dm_build_1404(int32(val.Int64())) + case BIGINT: + err := G2DB.checkBigint(float64(val.Int64())) + + if err != nil { + return nil, err + } + + ret = Dm_build_1220.Dm_build_1407(val.Int64()) + case REAL: + err := G2DB.checkReal(float64(val.Int64())) + + if err != nil { + return nil, err + } + + ret = Dm_build_1220.Dm_build_1410(float32(val.Int64())) + case DOUBLE: + ret = Dm_build_1220.Dm_build_1413(float64(val.Int64())) + case DECIMAL, BINARY, VARBINARY, BLOB: + d, err := newDecimal(val, int(param.prec), int(param.scale)) + if err != nil { + return nil, err + } + ret, err = d.encodeDecimal() + if err != nil { + return nil, err + } + case CHAR, VARCHAR2, VARCHAR, CLOB: + ret = Dm_build_1220.Dm_build_1433(val.String(), conn.getServerEncoding(), conn) + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, nil +} + +func (G2DB g2db) fromBigFloat(val *big.Float, param parameter, conn *DmConnection) ([]byte, error) { + var ret []byte + switch param.colType { + case BOOLEAN, BIT: + if val.Sign() == 0 { + ret = Dm_build_1220.Dm_build_1398(0) + } else { + ret = Dm_build_1220.Dm_build_1398(1) + } + case TINYINT: + f, _ := val.Float64() + + err := G2DB.checkTinyint(f) + + if err != nil { + return nil, err + } + + ret = Dm_build_1220.Dm_build_1398(byte(f)) + case SMALLINT: + f, _ := val.Float64() + + err := G2DB.checkSmallint(f) + + if err != nil { + return nil, err + } + + ret = Dm_build_1220.Dm_build_1401(int16(f)) + case INT: + f, _ := val.Float64() + + err := G2DB.checkInt(f) + + if err != nil { + return nil, err + } + + ret = Dm_build_1220.Dm_build_1404(int32(f)) + case BIGINT: + f, _ := val.Float64() + + err := G2DB.checkBigint(f) + + if err != nil { + return nil, err + } + + ret = Dm_build_1220.Dm_build_1407(int64(f)) + case REAL: + f, _ := val.Float64() + + err := G2DB.checkReal(f) + + if err != nil { + return nil, err + } + + ret = Dm_build_1220.Dm_build_1410(float32(f)) + case DOUBLE: + f, _ := val.Float64() + ret = Dm_build_1220.Dm_build_1413(f) + case DECIMAL: + d, err := newDecimal(val, int(param.prec), int(param.scale)) + if err != nil { + return nil, err + } + ret, err = d.encodeDecimal() + if err != nil { + return nil, err + } + case CHAR, VARCHAR2, VARCHAR, CLOB: + ret = Dm_build_1220.Dm_build_1433(val.Text('f', int(param.scale)), conn.getServerEncoding(), conn) + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, nil +} + +func (G2DB g2db) fromDecimal(val DmDecimal, param parameter, conn *DmConnection) ([]byte, error) { + var ret []byte + switch param.colType { + case BOOLEAN, BIT: + if val.Sign() == 0 { + ret = Dm_build_1220.Dm_build_1398(0) + } else { + ret = Dm_build_1220.Dm_build_1398(1) + } + case TINYINT: + if err := G2DB.checkTinyint(val); err != nil { + return nil, err + } + ret = Dm_build_1220.Dm_build_1398(byte(val.ToBigInt().Int64())) + case SMALLINT: + if err := G2DB.checkSmallint(val); err != nil { + return nil, err + } + ret = Dm_build_1220.Dm_build_1401(int16(val.ToBigInt().Int64())) + case INT: + if err := G2DB.checkInt(val); err != nil { + return nil, err + } + ret = Dm_build_1220.Dm_build_1404(int32(val.ToBigInt().Int64())) + case BIGINT: + if err := G2DB.checkBigint(val); err != nil { + return nil, err + } + ret = Dm_build_1220.Dm_build_1407(int64(val.ToBigInt().Int64())) + case REAL: + if err := G2DB.checkReal(val); err != nil { + return nil, err + } + f, _ := val.ToBigFloat().Float32() + ret = Dm_build_1220.Dm_build_1410(f) + case DOUBLE: + f, _ := val.ToBigFloat().Float64() + ret = Dm_build_1220.Dm_build_1413(f) + case DECIMAL: + var err error + ret, err = val.encodeDecimal() + if err != nil { + return nil, err + } + case CHAR, VARCHAR2, VARCHAR, CLOB: + ret = Dm_build_1220.Dm_build_1433(val.ToBigFloat().Text('f', -1), conn.getServerEncoding(), conn) + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, nil +} + +func (G2DB g2db) fromTime(val time.Time, param parameter, conn *DmConnection) ([]byte, error) { + + switch param.colType { + case DATE, DATETIME, DATETIME_TZ, TIME, TIME_TZ: + return encodeByTime(val, int(param.colType), int(param.scale), int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + case CHAR, VARCHAR2, VARCHAR, CLOB: + return Dm_build_1220.Dm_build_1433(val.Format("2006-01-02 15:04:05.999999999 -07:00"), conn.getServerEncoding(), conn), nil + } + + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) fromDmIntervalDT(val DmIntervalDT, param parameter, conn *DmConnection) ([]byte, error) { + switch param.colType { + case CHAR, VARCHAR2, VARCHAR, CLOB: + return Dm_build_1220.Dm_build_1433(val.String(), conn.getServerEncoding(), conn), nil + case INTERVAL_DT: + return val.encode(int(param.scale)) + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } +} + +func (G2DB g2db) fromDmdbIntervalYM(val DmIntervalYM, param parameter, conn *DmConnection) ([]byte, error) { + + switch param.colType { + case CHAR, VARCHAR, VARCHAR2, CLOB: + return Dm_build_1220.Dm_build_1433(val.String(), conn.getServerEncoding(), conn), nil + case INTERVAL_YM: + return val.encode(int(param.scale)) + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } +} + +func (G2DB g2db) fromBlob(val DmBlob, param parameter, conn *DmConnection) (interface{}, error) { + var ret interface{} + switch param.colType { + case BINARY, VARBINARY: + len, err := val.GetLength() + if err != nil { + return nil, err + } + ret, err = val.getBytes(1, int32(len)) + if err != nil { + return nil, err + } + case BLOB: + var err error + ret, err = G2DB.blob2Blob(val, param, conn) + if err != nil { + return nil, err + } + case ARRAY, CLASS, PLTYPE_RECORD, SARRAY: + + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, nil +} + +func (G2DB g2db) fromClob(val DmClob, param parameter, conn *DmConnection) (interface{}, error) { + var ret interface{} + switch param.colType { + case CHAR, VARCHAR, VARCHAR2: + var len int64 + var s string + var err error + len, err = val.GetLength() + if err != nil { + return nil, err + } + s, err = val.getSubString(1, int32(len)) + if err != nil { + return nil, err + } + ret = []byte(s) + case CLOB: + var err error + ret, err = G2DB.clob2Clob(val, param, conn) + if err != nil { + return nil, err + } + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, nil +} + +func (G2DB g2db) fromReader(val io.Reader, param parameter, conn *DmConnection) (interface{}, error) { + var ret interface{} + switch param.colType { + case CHAR, VARCHAR2, VARCHAR: + var bytesBuf = new(bytes.Buffer) + if _, err := bytesBuf.ReadFrom(val); err != nil { + return nil, err + } + return Dm_build_1220.Dm_build_1433(string(bytesBuf.Bytes()), conn.getServerEncoding(), conn), nil + case BINARY, VARBINARY: + var bytesBuf = new(bytes.Buffer) + if _, err := bytesBuf.ReadFrom(val); err != nil { + return nil, err + } + return util.StringUtil.HexStringToBytes(string(bytesBuf.Bytes())), nil + case BLOB, CLOB: + var binder = newOffRowReaderBinder(val, conn.getServerEncoding()) + if binder.offRow { + ret = binder + } else { + ret = binder.readAll() + } + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, nil +} + +func (G2DB g2db) string2Clob(val string, param parameter, conn *DmConnection) (interface{}, error) { + return G2DB.changeOffRowData(param, Dm_build_1220.Dm_build_1433(val, conn.getServerEncoding(), conn), conn.getServerEncoding()) +} + +func (G2DB g2db) bytes2Blob(val []byte, param parameter, conn *DmConnection) (interface{}, error) { + return G2DB.changeOffRowData(param, val, conn.getServerEncoding()) +} + +func (G2DB g2db) clob2Clob(val DmClob, param parameter, conn *DmConnection) (interface{}, error) { + var clobLen int64 + var err error + if clobLen, err = val.GetLength(); err != nil { + return nil, err + } + if G2DB.isOffRow(param.colType, clobLen) { + return newOffRowClobBinder(val, conn.getServerEncoding()), nil + } else { + var length int64 + var str string + if length, err = val.GetLength(); err != nil { + return nil, err + } + if str, err = val.getSubString(1, int32(length)); err != nil { + return nil, err + } + return Dm_build_1220.Dm_build_1433(str, conn.getServerEncoding(), conn), nil + } +} + +func (G2DB g2db) blob2Blob(val DmBlob, param parameter, conn *DmConnection) (interface{}, error) { + var clobLen int64 + var err error + if clobLen, err = val.GetLength(); err != nil { + return nil, err + } + if G2DB.isOffRow(param.colType, clobLen) { + return newOffRowBlobBinder(val, conn.getServerEncoding()), nil + } else { + var length int64 + if length, err = val.GetLength(); err != nil { + return nil, err + } + return val.getBytes(1, int32(length)) + } +} + +func (G2DB g2db) changeOffRowData(paramDesc parameter, paramData []byte, encoding string) (interface{}, error) { + if G2DB.isOffRow(paramDesc.colType, int64(len(paramData))) { + return newOffRowBytesBinder(paramData, encoding), nil + } else { + return paramData, nil + } +} + +func (G2DB g2db) isOffRow(dtype int32, length int64) bool { + return (dtype == BLOB || dtype == CLOB) && length > Dm_build_714 +} + +func (G2DB g2db) fromObject(mem interface{}, param parameter, conn *DmConnection) ([]byte, error) { + switch v := mem.(type) { + case bool: + return G2DB.fromBool(v, param, conn) + case rune: + val, err := G2DB.fromString(string(v), param, conn) + return val.([]byte), err + case string: + val, err := G2DB.fromString(v, param, conn) + return val.([]byte), err + case byte: + return G2DB.fromInt64(int64(v), param, conn) + case int: + return G2DB.fromInt64(int64(v), param, conn) + case int16: + return G2DB.fromInt64(int64(v), param, conn) + case int64: + return G2DB.fromInt64(v, param, conn) + case float32: + return G2DB.fromFloat64(float64(v), param, conn) + case float64: + return G2DB.fromFloat64(v, param, conn) + case time.Time: + return G2DB.fromTime(v, param, conn) + case DmDecimal: + return G2DB.fromDecimal(v, param, conn) + case DmIntervalDT: + return G2DB.fromDmIntervalDT(v, param, conn) + case DmIntervalYM: + return G2DB.fromDmdbIntervalYM(v, param, conn) + case DmBlob: + length, _ := v.GetLength() + return v.getBytes(1, int32(length)) + case DmClob: + length, _ := v.GetLength() + str, err := v.getSubString(1, int32(length)) + if err != nil { + return nil, err + } + return Dm_build_1220.Dm_build_1433(str, conn.getServerEncoding(), conn), nil + default: + return nil, ECGO_UNSUPPORTED_TYPE.throw() + } + +} + +func (G2DB g2db) toInt32(val int32) []byte { + bytes := make([]byte, 4) + Dm_build_1220.Dm_build_1236(bytes, 0, val) + return bytes +} + +func (G2DB g2db) toInt64(val int64) []byte { + bytes := make([]byte, 8) + Dm_build_1220.Dm_build_1241(bytes, 0, val) + return bytes +} + +func (G2DB g2db) toFloat32(val float32) []byte { + bytes := make([]byte, 4) + Dm_build_1220.Dm_build_1246(bytes, 0, val) + return bytes +} + +func (G2DB g2db) toFloat64(val float64) []byte { + bytes := make([]byte, 8) + Dm_build_1220.Dm_build_1251(bytes, 0, val) + return bytes +} + +func (G2DB g2db) toDecimal(val string, prec int, scale int) ([]byte, error) { + d, err := decodeDecimal([]byte(val), prec, scale) + if err != nil { + return nil, err + } + return d.encodeDecimal() +} + +func (G2DB g2db) fromArray(x *DmArray, param parameter, connection *DmConnection) (interface{}, error) { + var ret interface{} + var err error + switch param.colType { + case SARRAY: + ret, err = TypeDataSV.sarrayToBytes(x, param.typeDescriptor) + case CLASS, ARRAY: + ret, err = TypeDataSV.arrayToBytes(x, param.typeDescriptor) + case BLOB: + ret, err = TypeDataSV.toBytesFromDmArray(x, param.typeDescriptor) + if err == nil { + ret, err = G2DB.bytes2Blob(ret.([]byte), param, connection) + } + default: + err = ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, err +} + +func (G2DB g2db) fromStruct(x *DmStruct, param parameter, connection *DmConnection) (interface{}, error) { + var ret interface{} + var err error + switch param.colType { + case CLASS: + ret, err = TypeDataSV.structToBytes(x, param.typeDescriptor) + case PLTYPE_RECORD: + ret, err = TypeDataSV.recordToBytes(x, param.typeDescriptor) + case BLOB: + ret, err = TypeDataSV.toBytesFromDmStruct(x, param.typeDescriptor) + if err == nil { + ret, err = G2DB.bytes2Blob(ret.([]byte), param, connection) + } + + default: + err = ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, err +} + +func checkBFileStr(s string) bool { + strs := strings.Split(strings.TrimSpace(s), ":") + if len(strs) != 2 { + return false + } + if len(strs[0]) > 128 || len(strs[1]) > 256 { + return false + } + return true +} diff --git a/dmr/zn.go b/dmr/zn.go new file mode 100644 index 0000000..4b8654d --- /dev/null +++ b/dmr/zn.go @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +const ( + LOB_FLAG_BYTE = 0 + LOB_FLAG_CHAR = 1 + + LOB_IN_ROW = 0x1 + LOB_OFF_ROW = 0x2 + + NBLOB_HEAD_IN_ROW_FLAG = 0 + NBLOB_HEAD_BLOBID = NBLOB_HEAD_IN_ROW_FLAG + BYTE_SIZE + NBLOB_HEAD_BLOB_LEN = NBLOB_HEAD_BLOBID + DDWORD_SIZE + + NBLOB_HEAD_OUTROW_GROUPID = NBLOB_HEAD_BLOB_LEN + ULINT_SIZE + NBLOB_HEAD_OUTROW_FILEID = NBLOB_HEAD_OUTROW_GROUPID + USINT_SIZE + NBLOB_HEAD_OUTROW_PAGENO = NBLOB_HEAD_OUTROW_FILEID + USINT_SIZE + + NBLOB_EX_HEAD_TABLE_ID = NBLOB_HEAD_OUTROW_PAGENO + ULINT_SIZE + NBLOB_EX_HEAD_COL_ID = NBLOB_EX_HEAD_TABLE_ID + ULINT_SIZE + NBLOB_EX_HEAD_ROW_ID = NBLOB_EX_HEAD_COL_ID + USINT_SIZE + NBLOB_EX_HEAD_FPA_GRPID = NBLOB_EX_HEAD_ROW_ID + LINT64_SIZE + NBLOB_EX_HEAD_FPA_FILEID = NBLOB_EX_HEAD_FPA_GRPID + USINT_SIZE + NBLOB_EX_HEAD_FPA_PAGENO = NBLOB_EX_HEAD_FPA_FILEID + USINT_SIZE + NBLOB_EX_HEAD_SIZE = NBLOB_EX_HEAD_FPA_PAGENO + ULINT_SIZE + + NBLOB_OUTROW_HEAD_SIZE = NBLOB_HEAD_OUTROW_PAGENO + ULINT_SIZE + + NBLOB_INROW_HEAD_SIZE = NBLOB_HEAD_BLOB_LEN + ULINT_SIZE +) + +type lob struct { + blobId int64 + inRow bool + + groupId int16 + fileId int16 + pageNo int32 + tabId int32 + colId int16 + rowId int64 + exGroupId int16 + exFileId int16 + exPageNo int32 + + curFileId int16 + curPageNo int32 + curPageOffset int16 + totalOffset int32 + readOver bool + + connection *DmConnection + local bool + updateable bool + lobFlag int8 + length int64 + compatibleOracle bool + fetchAll bool + freed bool + modify bool + + Valid bool +} + +func (lob *lob) GetLength() (int64, error) { + var err error + if err = lob.checkValid(); err != nil { + return -1, err + } + if err = lob.checkFreed(); err != nil { + return -1, err + } + if lob.length == -1 { + + if lob.length, err = lob.connection.Access.dm_build_491(lob); err != nil { + return -1, err + } + } + return lob.length, nil +} + +func (lob *lob) resetCurrentInfo() { + lob.curFileId = lob.fileId + lob.curPageNo = lob.pageNo + lob.totalOffset = 0 + lob.curPageOffset = 0 +} + +func (lob *lob) getLengthFromHead(head []byte) int64 { + return int64(Dm_build_1220.Dm_build_1322(head, NBLOB_HEAD_BLOB_LEN)) +} + +func (lob *lob) canOptimized(connection *DmConnection) bool { + return !(lob.inRow || lob.fetchAll || lob.local || connection != lob.connection) +} + +func (lob *lob) buildCtlData() (bytes []byte) { + if lob.connection.NewLobFlag { + bytes = make([]byte, NBLOB_EX_HEAD_SIZE, NBLOB_EX_HEAD_SIZE) + } else { + bytes = make([]byte, NBLOB_OUTROW_HEAD_SIZE, NBLOB_OUTROW_HEAD_SIZE) + } + Dm_build_1220.Dm_build_1221(bytes, NBLOB_HEAD_IN_ROW_FLAG, LOB_OFF_ROW) + Dm_build_1220.Dm_build_1241(bytes, NBLOB_HEAD_BLOBID, lob.blobId) + Dm_build_1220.Dm_build_1236(bytes, NBLOB_HEAD_BLOB_LEN, -1) + + Dm_build_1220.Dm_build_1231(bytes, NBLOB_HEAD_OUTROW_GROUPID, lob.groupId) + Dm_build_1220.Dm_build_1231(bytes, NBLOB_HEAD_OUTROW_FILEID, lob.fileId) + Dm_build_1220.Dm_build_1236(bytes, NBLOB_HEAD_OUTROW_PAGENO, lob.pageNo) + + if lob.connection.NewLobFlag { + Dm_build_1220.Dm_build_1236(bytes, NBLOB_EX_HEAD_TABLE_ID, lob.tabId) + Dm_build_1220.Dm_build_1231(bytes, NBLOB_EX_HEAD_COL_ID, lob.colId) + Dm_build_1220.Dm_build_1241(bytes, NBLOB_EX_HEAD_ROW_ID, lob.rowId) + Dm_build_1220.Dm_build_1231(bytes, NBLOB_EX_HEAD_FPA_GRPID, lob.exGroupId) + Dm_build_1220.Dm_build_1231(bytes, NBLOB_EX_HEAD_FPA_FILEID, lob.exFileId) + Dm_build_1220.Dm_build_1236(bytes, NBLOB_EX_HEAD_FPA_PAGENO, lob.exPageNo) + } + return +} + +func (lob *lob) checkFreed() (err error) { + if lob.freed { + err = ECGO_LOB_FREED.throw() + } + return +} + +func (lob *lob) checkValid() error { + if !lob.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} diff --git a/dmr/zo.go b/dmr/zo.go new file mode 100644 index 0000000..98f0861 --- /dev/null +++ b/dmr/zo.go @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +const ( + ParamDataEnum_Null = 0 + /** + * 只有大字段才有行内数据、行外数据的概念 + */ + ParamDataEnum_OFF_ROW = 1 +) + +type lobCtl struct { + value []byte +} diff --git a/dmr/zp.go b/dmr/zp.go new file mode 100644 index 0000000..223566b --- /dev/null +++ b/dmr/zp.go @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "os" + "strconv" + "strings" + "time" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +const ( + MAX_FILE_SIZE = 100 * 1024 * 1024 + FLUSH_SIZE = 32 * 1024 +) + +type goRun interface { + doRun() +} + +type logWriter struct { + flushQueue chan []byte + date string + logFile *os.File + flushFreq int + filePath string + filePrefix string + buffer *Dm_build_1499 +} + +func (lw *logWriter) doRun() { + defer func() { + lw.beforeExit() + lw.closeCurrentFile() + }() + + i := 0 + for { + var ibytes []byte + + select { + case ibytes = <-lw.flushQueue: + if LogLevel != LOG_OFF { + if i == LogFlushQueueSize { + lw.doFlush(lw.buffer) + i = 0 + } else { + lw.buffer.Dm_build_1525(ibytes, 0, len(ibytes)) + i++ + } + } + case <-time.After(time.Duration(LogFlushFreq) * time.Millisecond): + if LogLevel != LOG_OFF && lw.buffer.Dm_build_1504() > 0 { + lw.doFlush(lw.buffer) + i = 0 + } + + } + + } +} + +func (lw *logWriter) doFlush(buffer *Dm_build_1499) { + if lw.needCreateNewFile() { + lw.closeCurrentFile() + lw.logFile = lw.createNewFile() + } + buffer.Dm_build_1519(lw.logFile, buffer.Dm_build_1504()) +} +func (lw *logWriter) closeCurrentFile() { + if lw.logFile != nil { + lw.logFile.Close() + lw.logFile = nil + } +} +func (lw *logWriter) createNewFile() *os.File { + lw.date = time.Now().Format("2006-01-02") + fileName := lw.filePrefix + "_" + lw.date + "_" + strconv.Itoa(time.Now().Nanosecond()) + ".log" + lw.filePath = LogDir + if len(lw.filePath) > 0 { + if _, err := os.Stat(lw.filePath); err != nil { + os.MkdirAll(lw.filePath, 0755) + } + if _, err := os.Stat(lw.filePath + fileName); err != nil { + logFile, err := os.Create(lw.filePath + fileName) + if err != nil { + panic(err) + } + return logFile + } + } + return nil +} +func (lw *logWriter) needCreateNewFile() bool { + now := time.Now().Format("2006-01-02") + fileInfo, err := lw.logFile.Stat() + return now != lw.date || err != nil || lw.logFile == nil || fileInfo.Size() > int64(MAX_FILE_SIZE) +} +func (lw *logWriter) beforeExit() { + close(lw.flushQueue) + var ibytes []byte + for ibytes = <-lw.flushQueue; ibytes != nil; ibytes = <-lw.flushQueue { + lw.buffer.Dm_build_1525(ibytes, 0, len(ibytes)) + if lw.buffer.Dm_build_1504() >= LogBufferSize { + lw.doFlush(lw.buffer) + } + } + if lw.buffer.Dm_build_1504() > 0 { + lw.doFlush(lw.buffer) + } +} + +func (lw *logWriter) WriteLine(msg string) { + var b = []byte(strings.TrimSpace(msg) + util.LINE_SEPARATOR) + lw.flushQueue <- b +} diff --git a/dmr/zq.go b/dmr/zq.go new file mode 100644 index 0000000..08691ee --- /dev/null +++ b/dmr/zq.go @@ -0,0 +1,2762 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "os" + "strconv" + "strings" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +const ( + Dm_build_597 = "7.6.0.0" + + Dm_build_598 = "7.0.0.9" + + Dm_build_599 = "8.0.0.73" + + Dm_build_600 = "7.1.2.128" + + Dm_build_601 = "7.1.5.144" + + Dm_build_602 = "7.1.6.123" + + Dm_build_603 = 2 + + Dm_build_604 = 32768 - 128 + + Dm_build_605 = 0x20000000 + + Dm_build_606 int16 = 1 + + Dm_build_607 int16 = 2 + + Dm_build_608 int16 = 3 + + Dm_build_609 int16 = 4 + + Dm_build_610 int16 = 5 + + Dm_build_611 int16 = 6 + + Dm_build_612 int16 = 7 + + Dm_build_613 int16 = 8 + + Dm_build_614 int16 = 9 + + Dm_build_615 int16 = 13 + + Dm_build_616 int16 = 14 + + Dm_build_617 int16 = 15 + + Dm_build_618 int16 = 17 + + Dm_build_619 int16 = 21 + + Dm_build_620 int16 = 24 + + Dm_build_621 int16 = 27 + + Dm_build_622 int16 = 29 + + Dm_build_623 int16 = 30 + + Dm_build_624 int16 = 31 + + Dm_build_625 int16 = 32 + + Dm_build_626 int16 = 44 + + Dm_build_627 int16 = 52 + + Dm_build_628 int16 = 60 + + Dm_build_629 int16 = 71 + + Dm_build_630 int16 = 90 + + Dm_build_631 int16 = 91 + + Dm_build_632 int16 = 200 + + Dm_build_633 = 64 + + Dm_build_634 = 20 + + Dm_build_635 = 0 + + Dm_build_636 = 4 + + Dm_build_637 = 6 + + Dm_build_638 = 10 + + Dm_build_639 = 14 + + Dm_build_640 = 18 + + Dm_build_641 = 19 + + Dm_build_642 = 128 + + Dm_build_643 = 256 + + Dm_build_644 = 0xffff + + Dm_build_645 int32 = 2 + + Dm_build_646 int32 = 5 + + Dm_build_647 = -1 + + Dm_build_648 uint16 = 0xFFFE + + Dm_build_649 uint16 = uint16(Dm_build_648 - 3) + + Dm_build_650 uint16 = Dm_build_648 + + Dm_build_651 int32 = 0xFFFF + + Dm_build_652 int32 = 0x80 + + Dm_build_653 byte = 0x60 + + Dm_build_654 uint16 = uint16(Dm_build_650) + + Dm_build_655 uint16 = uint16(Dm_build_651) + + Dm_build_656 int16 = 0x00 + + Dm_build_657 int16 = 0x03 + + Dm_build_658 int32 = 0x80 + + Dm_build_659 byte = 0 + + Dm_build_660 byte = 1 + + Dm_build_661 byte = 2 + + Dm_build_662 byte = 3 + + Dm_build_663 byte = 4 + + Dm_build_664 byte = Dm_build_659 + + Dm_build_665 int = 10 + + Dm_build_666 int32 = 32 + + Dm_build_667 int32 = 65536 + + Dm_build_668 byte = 0 + + Dm_build_669 byte = 1 + + Dm_build_670 int32 = 0x00000000 + + Dm_build_671 int32 = 0x00000020 + + Dm_build_672 int32 = 0x00000040 + + Dm_build_673 int32 = 0x00000FFF + + Dm_build_674 int32 = 0 + + Dm_build_675 int32 = 1 + + Dm_build_676 int32 = 2 + + Dm_build_677 int32 = 3 + + Dm_build_678 = 8192 + + Dm_build_679 = 1 + + Dm_build_680 = 2 + + Dm_build_681 = 0 + + Dm_build_682 = 0 + + Dm_build_683 = 1 + + Dm_build_684 = -1 + + Dm_build_685 int16 = 0 + + Dm_build_686 int16 = 1 + + Dm_build_687 int16 = 2 + + Dm_build_688 int16 = 3 + + Dm_build_689 int16 = 4 + + Dm_build_690 int16 = 127 + + Dm_build_691 int16 = Dm_build_690 + 20 + + Dm_build_692 int16 = Dm_build_690 + 21 + + Dm_build_693 int16 = Dm_build_690 + 22 + + Dm_build_694 int16 = Dm_build_690 + 24 + + Dm_build_695 int16 = Dm_build_690 + 25 + + Dm_build_696 int16 = Dm_build_690 + 26 + + Dm_build_697 int16 = Dm_build_690 + 30 + + Dm_build_698 int16 = Dm_build_690 + 31 + + Dm_build_699 int16 = Dm_build_690 + 32 + + Dm_build_700 int16 = Dm_build_690 + 33 + + Dm_build_701 int16 = Dm_build_690 + 35 + + Dm_build_702 int16 = Dm_build_690 + 38 + + Dm_build_703 int16 = Dm_build_690 + 39 + + Dm_build_704 int16 = Dm_build_690 + 51 + + Dm_build_705 int16 = Dm_build_690 + 71 + + Dm_build_706 int16 = Dm_build_690 + 124 + + Dm_build_707 int16 = Dm_build_690 + 125 + + Dm_build_708 int16 = Dm_build_690 + 126 + + Dm_build_709 int16 = Dm_build_690 + 127 + + Dm_build_710 int16 = Dm_build_690 + 128 + + Dm_build_711 int16 = Dm_build_690 + 129 + + Dm_build_712 byte = 0 + + Dm_build_713 byte = 2 + + Dm_build_714 = 2048 + + Dm_build_715 = -1 + + Dm_build_716 = 0 + + Dm_build_717 = 16000 + + Dm_build_718 = 32000 + + Dm_build_719 = 0x00000000 + + Dm_build_720 = 0x00000020 + + Dm_build_721 = 0x00000040 + + Dm_build_722 = 0x00000FFF + + Dm_build_723 = 4 +) + +var Dm_build_724 = [8][256]uint32{ + + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, + 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, + 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, + 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, + 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, + 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, + 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, + 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, + 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, + 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, + 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, + 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, + 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, + 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, + 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, + 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, + 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, + 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, + 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, + 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, + 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, + 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, + 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, + 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, + 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, + 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, + 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, + 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, + 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, + 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, + 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, + 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, + 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, + 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, + 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}, + + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, 0x7d77f445, 0x565aa786, + 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, + 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, + 0x61ef4192, 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, + 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, 0xf1e8e1a6, + 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, + 0x7670fd69, 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, + 0xc65d07b2, 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, 0x73f379ff, + 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, 0xe9627e44, 0xc24f2d87, + 0xdb541cc6, 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2, 0x38a0c50d, + 0x21bbf44c, 0x0a96a78f, 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, + 0x77e153ca, 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, 0x4054b5de, + 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b, 0x65fd6ba7, + 0x7ce65ae6, 0x57cb0925, 0x4ed03864, 0x0191aea3, 0x188a9fe2, 0x33a7cc21, + 0x2abcfd60, 0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, + 0xd05315ea, 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, 0xe7e6f3fe, + 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, 0x9a9107bb, 0xb1bc5478, + 0xa8a76539, 0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, + 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, + 0xd8774180, 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, + 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, 0xddf4c516, + 0xc4eff457, 0xefc2a794, 0xf6d996d5, 0xae07bce9, 0xb71c8da8, 0x9c31de6b, + 0x852aef2a, 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, + 0x7fc507a0, 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, 0x80a96bbc, + 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, 0x350715f1, 0x1e2a4632, + 0x07317773, 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277, 0xcbfad74e, + 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, + 0x84bb4189, 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, 0xb30ea79d, + 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8, 0x49e14f17, + 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, + 0x06a0d9d0, 0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, + 0x230907a9, 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, 0x14bce1bd, + 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, 0x69cb15f8, 0x42e6463b, + 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, 0xb809aeb1, + 0xa1129ff0, 0x8a3fcc33, 0x9324fd72}, + + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, + 0x054f1685, 0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, 0x091af964, + 0x08d89353, 0x0a9e2d0a, 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, + 0x1e601d29, 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, 0x16b88e7a, + 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, 0x3f44ee3c, + 0x3e86840b, 0x3cc03a52, 0x3d025065, 0x365e1758, 0x379c7d6f, 0x35dac336, + 0x3418a901, 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, + 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, 0x2d711cf4, + 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, 0x7158e7f7, 0x731e59ae, + 0x72dc3399, 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45, 0x7e89dc78, + 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, + 0x7bc6cafd, 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, 0x612bab66, + 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d, 0x48d7cb20, + 0x4915a117, 0x4b531f4e, 0x4a917579, 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, + 0x4d98dda5, 0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, + 0x400f5873, 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, 0x5ae239e8, + 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, 0x5c29fb03, 0x5e6f455a, + 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, + 0xe7fed96b, 0xe5b86732, 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, + 0xed60f461, 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, + 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, 0xf4094194, + 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, 0xd9785d60, 0xd8ba3757, 0xdafc890e, + 0xdb3ee339, 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, + 0xd6a966ef, 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, 0xc25756cc, + 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, + 0xc90b11f1, 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d, 0x91af9640, + 0x906dfc77, 0x922b422e, 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, + 0x94e080c5, 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, 0x8e0de15e, + 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5, 0x839a6488, + 0x82580ebf, 0x801eb0e6, 0x81dcdad1, 0x8493cc54, 0x8551a663, 0x8717183a, + 0x86d5720d, 0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, + 0xaf29124b, 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, 0xb5c473d0, + 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, + 0xb08b6555, 0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, 0xbcde8ab4, + 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed}, + + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, 0x37def032, 0x256b5fdc, + 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, 0x4ad6bfb8, + 0xf26ad8dd, 0xe0df7733, 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, + 0x42acf871, 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, 0xb0c620ac, + 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, 0x2f503869, + 0x97ec5f0c, 0x8559f0e2, 0x3de59787, 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, + 0x7733283f, 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, + 0x48979fc4, 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, 0xbafd4719, + 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, 0x23a83f58, 0x311d90b6, + 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084, 0x5ea070d2, + 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, + 0xc377486b, 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, 0xa4b0efc6, + 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4, 0x3b26f703, + 0x839a9066, 0x912f3f88, 0x299358ed, 0xb4446054, 0x0cf80731, 0x1e4da8df, + 0xa6f1cfba, 0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, + 0xc94c2fde, 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, 0xae8b8873, + 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, 0x99557841, 0x8be0d7af, + 0x335cb0ca, 0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, 0x623b216c, + 0xda874609, 0xc832e9e7, 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, + 0x3a58313a, 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, 0x982bbe78, + 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, 0xf7965e1c, + 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, 0x4d6b1905, 0xf5d77e60, 0xe762d18e, + 0x5fdeb6eb, 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, + 0x3063568f, 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, 0x9210d9cd, + 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, 0x607a0110, 0x72cfaefe, + 0xca73c99b, 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc, 0x764dee06, + 0xcef18963, 0xdc44268d, 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, + 0xeb9ad6bf, 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, 0x8c5d7112, + 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120, 0xe3e09176, + 0x5b5cf613, 0x49e959fd, 0xf1553e98, 0x6c820621, 0xd43e6144, 0xc68bceaa, + 0x7e37a9cf, 0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, + 0xe1a1b10a, 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, 0x866616a7, + 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, 0xb1b8e695, 0xa30d497b, + 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, + 0x740cce7a, 0x66b96194, 0xde0506f1}, + + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, 0xc8e08f70, 0x8f40f5a0, + 0xb220dc10, 0x30704bc1, 0x0d106271, 0x4ab018a1, 0x77d03111, 0xc5f0ed01, + 0xf890c4b1, 0xbf30be61, 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, + 0x2740ed52, 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, 0xdfd029e3, + 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, 0x866155d4, 0x344189c4, + 0x0921a074, 0x4e81daa4, 0x73e1f314, 0xf1b164c5, 0xccd14d75, 0x8b7137a5, + 0xb6111e15, 0x0431c205, 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, + 0x9c419136, 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, 0x64d15587, + 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, 0x659371f9, 0x22330b29, + 0x1f532299, 0xad73fe89, 0x9013d739, 0xd7b3ade9, 0xead38459, 0x68831388, + 0x55e33a38, 0x124340e8, 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, + 0xdaa3cf98, 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, 0x72a3d76a, + 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, 0xba43581a, 0x9932774d, + 0xa4525efd, 0xe3f2242d, 0xde920d9d, 0x6cb2d18d, 0x51d2f83d, 0x167282ed, + 0x2b12ab5d, 0xa9423c8c, 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, + 0x61a2b3fc, 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, 0xc9a2ab0e, + 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, 0x0142247e, 0x46e25eae, + 0x7b82771e, 0xb1e6b092, 0x8c869922, 0xcb26e3f2, 0xf646ca42, 0x44661652, + 0x79063fe2, 0x3ea64532, 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, + 0xc6368183, 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, 0x5e46d2b0, + 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, 0xa6d61601, 0x14f6ca11, + 0x2996e3a1, 0x6e369971, 0x5356b0c1, 0x70279f96, 0x4d47b626, 0x0ae7ccf6, + 0x3787e546, 0x85a73956, 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, + 0x7d37fde7, 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, 0xe547aed4, + 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, 0x1dd76a65, 0x5a7710b5, + 0x67173905, 0xd537e515, 0xe857cca5, 0xaff7b675, 0x92979fc5, 0xe915e8db, + 0xd475c16b, 0x93d5bbbb, 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, + 0x5b3534cb, 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, 0xf3352c39, + 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, 0x3bd5a349, 0xb9853498, + 0x84e51d28, 0xc34567f8, 0xfe254e48, 0x4c059258, 0x7165bbe8, 0x36c5c138, + 0x0ba5e888, 0x28d4c7df, 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, + 0xe03448af, 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, 0x4834505d, + 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, 0x80d4df2d, 0xc774a5fd, + 0xfa148c4d, 0x78441b9c, 0x4524322c, 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, + 0xb0a494ec, 0xf704ee3c, 0xca64c78c}, + + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, 0x50cd91b3, 0xd659e31d, + 0x1d0530b8, 0xec53826d, 0x270f51c8, 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, + 0xbc9e13de, 0x3a0a6170, 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, + 0x85427035, 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, 0x39dc63eb, + 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, 0x81387798, 0x9c3d4720, + 0x57619485, 0xd1f5e62b, 0x1aa9358e, 0xebff875b, 0x20a354fe, 0xa6372650, + 0x6d6bf5f5, 0x706ec54d, 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, + 0xcf26d408, 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, 0x73b8c7d6, + 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, 0xc404d9c9, 0x4290ab67, + 0x89cc78c2, 0x94c9487a, 0x5f959bdf, 0xd901e971, 0x125d3ad4, 0xe30b8801, + 0x28575ba4, 0xaec3290a, 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, + 0xfe0eb8b9, 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, 0xad152b91, + 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, 0xfdd8ba22, 0x08f40f5a, + 0xc3a8dcff, 0x453cae51, 0x8e607df4, 0x93654d4c, 0x58399ee9, 0xdeadec47, + 0x15f13fe2, 0xe4a78d37, 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, + 0xb46a1c84, 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, 0xe7718fac, + 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, 0xb7bc1e1f, 0x31286cb1, + 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, 0x5378b5d3, 0x98246676, 0x852156ce, + 0x4e7d856b, 0xc8e9f7c5, 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, + 0x7477e41b, 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, 0xcb3ff55e, + 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, 0x77a1e680, 0x6aa4d638, + 0xa1f8059d, 0x276c7733, 0xec30a496, 0x191c11ee, 0xd240c24b, 0x54d4b0e5, + 0x9f886340, 0x828d53f8, 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, + 0x3e134026, 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, 0x815b5163, + 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, 0x3dc542bd, 0xbb513013, + 0x700de3b6, 0x6d08d30e, 0xa65400ab, 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, + 0xdab4cd11, 0x5c20bfbf, 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, + 0x0ced2e0c, 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, 0x5ff6bd24, + 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, 0x0f3b2c97, 0xfe6d9e42, + 0x35314de7, 0xb3a53f49, 0x78f9ecec, 0x65fcdc54, 0xaea00ff1, 0x28347d5f, + 0xe368aefa, 0x16441b82, 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, + 0x46898a31, 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, 0x15921919, + 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, 0x455f88aa, 0xc3cbfa04, + 0x089729a1, 0xf9c19b74, 0x329d48d1, 0xb4093a7f, 0x7f55e9da, 0x6250d962, + 0xa90c0ac7, 0x2f987869, 0xe4c4abcc}, + + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, 0x52382fa7, 0x63d0353a, + 0xc5a73e8e, 0x33ef4e67, 0x959845d3, 0xa4705f4e, 0x020754fa, 0xc7a06a74, + 0x61d761c0, 0x503f7b5d, 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, + 0x56368653, 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, 0x37e1e793, + 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, 0xfe552301, 0x3bf21d8f, + 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, + 0xcdba6d66, 0x081d53e8, 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, + 0x0e14aee6, 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, 0x6fc3cf26, + 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, 0xe27c7ecd, 0xd3946450, + 0x75e36fe4, 0xb044516a, 0x16335ade, 0x27db4043, 0x81ac4bf7, 0x77e43b1e, + 0xd19330aa, 0xe07b2a37, 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, + 0xb2430590, 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, 0x87a5b6f9, + 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, 0xd59d995e, 0x8bb64ce5, + 0x2dc14751, 0x1c295dcc, 0xba5e5678, 0x7ff968f6, 0xd98e6342, 0xe86679df, + 0x4e11726b, 0xb8590282, 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, + 0xea612d25, 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, 0xdf879e4c, + 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, 0x8dbfb1eb, 0xbc57ab76, + 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, + 0xda2ec555, 0xebc6dfc8, 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, + 0x8a11be08, 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, 0x8c184306, + 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, 0xedcf22c6, 0x28681c48, + 0x8e1f17fc, 0xbff70d61, 0x198006d5, 0x47abd36e, 0xe1dcd8da, 0xd034c247, + 0x7643c9f3, 0xb3e4f77d, 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, + 0xd23396bd, 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, 0xd43a6bb3, + 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, 0xb5ed0a73, 0x840510ee, + 0x22721b5a, 0xe7d525d4, 0x41a22e60, 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, + 0x6a6a943f, 0x5b828ea2, 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, + 0x09baa105, 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, 0x3c5c126c, + 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, 0x6e643dcb, 0x982c4d22, + 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, 0x6c636931, 0xca146285, 0xfbfc7818, + 0x5d8b73ac, 0x03a0a617, 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, + 0x519889b0, 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, 0x647e3ad9, + 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, 0x3646157e, 0x07ae0fe3, + 0xa1d90457, 0x579174be, 0xf1e67f0a, 0xc00e6597, 0x66796e23, 0xa3de50ad, + 0x05a95b19, 0x34414184, 0x92364a30}, + + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, 0x48e00e64, 0xc66f0987, + 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, 0x91c01cc8, 0x5d6a1c56, 0x57af154f, + 0x9b0515d1, 0x158a1232, 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, + 0xf23436c8, 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, 0x69312319, + 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, 0x77f965b5, 0x7d3c6cac, + 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, 0x2a9379e3, 0xe639797d, 0x68b67e9e, + 0xa41c7e00, 0xaed97719, 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, + 0x496753e3, 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, 0xd2624632, + 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, 0xe537c273, 0x6bb8c590, + 0xa712c50e, 0xadd7cc17, 0x617dcc89, 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, + 0x36d2d9c6, 0xb85dde25, 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, + 0xf0bdd041, 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, 0xc4e6ef0e, + 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, 0x8c06e16a, 0xd0eba0bb, + 0x1c41a025, 0x92cea7c6, 0x5e64a758, 0x54a1ae41, 0x980baedf, 0x1684a93c, + 0xda2ea9a2, 0x030ebb0e, 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, + 0x4beeb56a, 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, 0x7fb58a25, + 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, 0x37558441, 0xb9da83a2, + 0x7570833c, 0x533b85da, 0x9f918544, 0x111e82a7, 0xddb48239, 0xd7718b20, + 0x1bdb8bbe, 0x95548c5d, 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, + 0x0e51998c, 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, 0xe9efbd76, + 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, 0x72eaa8a7, 0x782fa1be, + 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, 0xaa4de78c, 0x66e7e712, 0xe868e0f1, + 0x24c2e06f, 0x2e07e976, 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, + 0xb502fca7, 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, 0x52bcd85d, + 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, 0xc9b9cd8c, 0x4736ca6f, + 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, 0xc37cc495, 0x0fd6c40b, 0x7aa64737, + 0xb60c47a9, 0x3883404a, 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, + 0x70634e2e, 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, 0x44387161, + 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, 0x0cd87f05, 0xd5f86da9, + 0x19526d37, 0x97dd6ad4, 0x5b776a4a, 0x51b26353, 0x9d1863cd, 0x1397642e, + 0xdf3d64b0, 0x83d02561, 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, + 0xcb302b05, 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, 0xff6b144a, + 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, 0xb78b1a2e, 0x39041dcd, + 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, 0x6eab0882, 0xa201081c, 0xa8c40105, + 0x646e019b, 0xeae10678, 0x264b06e6}} + +type dm_build_725 interface { + dm_build_726() + dm_build_727() error + dm_build_728() + dm_build_729(imsg dm_build_725) error + dm_build_730() error + dm_build_731() (interface{}, error) + dm_build_732() + dm_build_733(imsg dm_build_725) (interface{}, error) + dm_build_734() + dm_build_735() error + dm_build_736() byte + dm_build_737(buffer *Dm_build_0, startOff int32, endOff int32) uint32 + dm_build_738() int32 + dm_build_739(length int32) + dm_build_740() int16 +} + +type dm_build_741 struct { + dm_build_742 *dm_build_332 + + dm_build_743 int16 + + dm_build_744 int32 + + dm_build_745 *DmStatement +} + +func (dm_build_747 *dm_build_741) dm_build_746(dm_build_748 *dm_build_332, dm_build_749 int16) *dm_build_741 { + dm_build_747.dm_build_742 = dm_build_748 + dm_build_747.dm_build_743 = dm_build_749 + return dm_build_747 +} + +func (dm_build_751 *dm_build_741) dm_build_750(dm_build_752 *dm_build_332, dm_build_753 int16, dm_build_754 *DmStatement) *dm_build_741 { + dm_build_751.dm_build_746(dm_build_752, dm_build_753).dm_build_745 = dm_build_754 + return dm_build_751 +} + +func dm_build_755(dm_build_756 *dm_build_332, dm_build_757 int16) *dm_build_741 { + return new(dm_build_741).dm_build_746(dm_build_756, dm_build_757) +} + +func dm_build_758(dm_build_759 *dm_build_332, dm_build_760 int16, dm_build_761 *DmStatement) *dm_build_741 { + return new(dm_build_741).dm_build_750(dm_build_759, dm_build_760, dm_build_761) +} + +func (dm_build_763 *dm_build_741) dm_build_726() { + dm_build_763.dm_build_742.dm_build_335.Dm_build_14(0) + dm_build_763.dm_build_742.dm_build_335.Dm_build_25(Dm_build_633, true, true) +} + +func (dm_build_765 *dm_build_741) dm_build_727() error { + return nil +} + +func (dm_build_767 *dm_build_741) dm_build_728() { + if dm_build_767.dm_build_745 == nil { + dm_build_767.dm_build_742.dm_build_335.Dm_build_191(Dm_build_635, 0) + } else { + dm_build_767.dm_build_742.dm_build_335.Dm_build_191(Dm_build_635, dm_build_767.dm_build_745.id) + } + + dm_build_767.dm_build_742.dm_build_335.Dm_build_187(Dm_build_636, dm_build_767.dm_build_743) + dm_build_767.dm_build_742.dm_build_335.Dm_build_191(Dm_build_637, int32(dm_build_767.dm_build_742.dm_build_335.Dm_build_12()-Dm_build_633)) +} + +func (dm_build_769 *dm_build_741) dm_build_730() error { + dm_build_769.dm_build_742.dm_build_335.Dm_build_17(0) + dm_build_769.dm_build_742.dm_build_335.Dm_build_25(Dm_build_633, false, true) + return dm_build_769.dm_build_774() +} + +func (dm_build_771 *dm_build_741) dm_build_731() (interface{}, error) { + return nil, nil +} + +func (dm_build_773 *dm_build_741) dm_build_732() { +} + +func (dm_build_775 *dm_build_741) dm_build_774() error { + dm_build_775.dm_build_744 = dm_build_775.dm_build_742.dm_build_335.Dm_build_269(Dm_build_638) + if dm_build_775.dm_build_744 < 0 && dm_build_775.dm_build_744 != EC_RN_EXCEED_ROWSET_SIZE.ErrCode { + return (&DmError{dm_build_775.dm_build_744, dm_build_775.dm_build_776(), nil, ""}).throw() + } else if dm_build_775.dm_build_744 > 0 { + + } else if dm_build_775.dm_build_743 == Dm_build_632 || dm_build_775.dm_build_743 == Dm_build_606 { + dm_build_775.dm_build_776() + } + + return nil +} + +func (dm_build_777 *dm_build_741) dm_build_776() string { + + dm_build_778 := dm_build_777.dm_build_742.dm_build_336.getServerEncoding() + + if dm_build_778 != "" && dm_build_778 == ENCODING_EUCKR && Locale != LANGUAGE_EN { + dm_build_778 = ENCODING_GB18030 + } + + dm_build_777.dm_build_742.dm_build_335.Dm_build_25(int(dm_build_777.dm_build_742.dm_build_335.Dm_build_125()), false, true) + + dm_build_777.dm_build_742.dm_build_335.Dm_build_25(int(dm_build_777.dm_build_742.dm_build_335.Dm_build_125()), false, true) + + dm_build_777.dm_build_742.dm_build_335.Dm_build_25(int(dm_build_777.dm_build_742.dm_build_335.Dm_build_125()), false, true) + + return dm_build_777.dm_build_742.dm_build_335.Dm_build_167(dm_build_778, dm_build_777.dm_build_742.dm_build_336) +} + +func (dm_build_780 *dm_build_741) dm_build_729(dm_build_781 dm_build_725) (dm_build_782 error) { + dm_build_781.dm_build_726() + if dm_build_782 = dm_build_781.dm_build_727(); dm_build_782 != nil { + return dm_build_782 + } + dm_build_781.dm_build_728() + return nil +} + +func (dm_build_784 *dm_build_741) dm_build_733(dm_build_785 dm_build_725) (dm_build_786 interface{}, dm_build_787 error) { + dm_build_787 = dm_build_785.dm_build_730() + if dm_build_787 != nil { + return nil, dm_build_787 + } + dm_build_786, dm_build_787 = dm_build_785.dm_build_731() + if dm_build_787 != nil { + return nil, dm_build_787 + } + dm_build_785.dm_build_732() + return dm_build_786, nil +} + +func (dm_build_789 *dm_build_741) dm_build_734() { + if dm_build_789.dm_build_742.dm_build_341 { + + var orgLen = dm_build_789.dm_build_738() + + dm_build_789.dm_build_739(orgLen + Dm_build_723) + var crc = dm_build_789.dm_build_737(dm_build_789.dm_build_742.dm_build_335, 0, Dm_build_633+orgLen) + dm_build_789.dm_build_742.dm_build_335.Dm_build_63(crc) + } else { + dm_build_789.dm_build_742.dm_build_335.Dm_build_183(Dm_build_641, dm_build_789.dm_build_736()) + } +} + +func (dm_build_791 *dm_build_741) dm_build_735() error { + if dm_build_791.dm_build_742.dm_build_341 { + + var bodyLen = dm_build_791.dm_build_738() - Dm_build_723 + var msgLen = Dm_build_633 + bodyLen + var recv = dm_build_791.dm_build_742.dm_build_335.Dm_build_287(int(msgLen)) + var calc = dm_build_791.dm_build_737(dm_build_791.dm_build_742.dm_build_335, 0, msgLen) + if recv != calc { + return ECGO_MSG_CHECK_ERROR.throw() + } + + dm_build_791.dm_build_739(bodyLen) + dm_build_791.dm_build_742.dm_build_335.Dm_build_14(int(msgLen)) + return nil + } else { + var recv = dm_build_791.dm_build_742.dm_build_335.Dm_build_263(Dm_build_641) + var calc = dm_build_791.dm_build_736() + if recv != calc { + return ECGO_MSG_CHECK_ERROR.throw() + } + return nil + } +} + +func (dm_build_793 *dm_build_741) dm_build_736() byte { + dm_build_794 := dm_build_793.dm_build_742.dm_build_335.Dm_build_263(0) + + for i := 1; i < Dm_build_641; i++ { + dm_build_794 ^= dm_build_793.dm_build_742.dm_build_335.Dm_build_263(i) + } + + return dm_build_794 +} + +func (dm_build_796 *dm_build_741) dm_build_737(dm_build_797 *Dm_build_0, dm_build_798 int32, dm_build_799 int32) uint32 { + + var dm_build_800 uint32 = 0xFFFFFFFF + var dm_build_801 = dm_build_798 + var dm_build_802 = dm_build_799 - dm_build_798 + var dm_build_803, dm_build_804 uint32 + + for dm_build_802 >= 8 { + dm_build_803 = dm_build_797.Dm_build_287(int(dm_build_801)) ^ dm_build_800 + dm_build_801 += ULINT_SIZE + + dm_build_804 = dm_build_797.Dm_build_287(int(dm_build_801)) + dm_build_801 += ULINT_SIZE + + dm_build_800 = Dm_build_724[7][dm_build_803&0xFF] ^ Dm_build_724[6][(dm_build_803>>8)&0xFF] ^ + Dm_build_724[5][(dm_build_803>>16)&0xFF] ^ Dm_build_724[4][(dm_build_803>>24)&0xFF] ^ + Dm_build_724[3][dm_build_804&0xFF] ^ Dm_build_724[2][(dm_build_804>>8)&0xFF] ^ + Dm_build_724[1][(dm_build_804>>16)&0xFF] ^ Dm_build_724[0][(dm_build_804>>24)&0xFF] + dm_build_802 -= 8 + } + + for dm_build_802 > 0 { + dm_build_800 = ((dm_build_800 >> 8) & 0x00FFFFFF) ^ Dm_build_724[0][(dm_build_800&0xFF)^uint32(dm_build_797.Dm_build_281(int(dm_build_801)))] + dm_build_801++ + dm_build_802-- + } + return ^dm_build_800 +} + +func (dm_build_806 *dm_build_741) dm_build_738() int32 { + return dm_build_806.dm_build_742.dm_build_335.Dm_build_269(Dm_build_637) +} + +func (dm_build_808 *dm_build_741) dm_build_739(dm_build_809 int32) { + dm_build_808.dm_build_742.dm_build_335.Dm_build_191(Dm_build_637, dm_build_809) +} + +func (dm_build_811 *dm_build_741) dm_build_740() int16 { + return dm_build_811.dm_build_743 +} + +type dm_build_812 struct { + dm_build_741 +} + +func dm_build_813(dm_build_814 *dm_build_332) *dm_build_812 { + dm_build_815 := new(dm_build_812) + dm_build_815.dm_build_746(dm_build_814, Dm_build_613) + return dm_build_815 +} + +type dm_build_816 struct { + dm_build_741 + dm_build_817 string +} + +func dm_build_818(dm_build_819 *dm_build_332, dm_build_820 *DmStatement, dm_build_821 string) *dm_build_816 { + dm_build_822 := new(dm_build_816) + dm_build_822.dm_build_750(dm_build_819, Dm_build_621, dm_build_820) + dm_build_822.dm_build_817 = dm_build_821 + dm_build_822.dm_build_745.cursorName = dm_build_821 + return dm_build_822 +} + +func (dm_build_824 *dm_build_816) dm_build_727() error { + dm_build_824.dm_build_742.dm_build_335.Dm_build_113(dm_build_824.dm_build_817, dm_build_824.dm_build_742.dm_build_336.getServerEncoding(), dm_build_824.dm_build_742.dm_build_336) + dm_build_824.dm_build_742.dm_build_335.Dm_build_51(1) + return nil +} + +type Dm_build_825 struct { + dm_build_841 + dm_build_826 []OptParameter +} + +func dm_build_827(dm_build_828 *dm_build_332, dm_build_829 *DmStatement, dm_build_830 []OptParameter) *Dm_build_825 { + dm_build_831 := new(Dm_build_825) + dm_build_831.dm_build_750(dm_build_828, Dm_build_631, dm_build_829) + dm_build_831.dm_build_826 = dm_build_830 + return dm_build_831 +} + +func (dm_build_833 *Dm_build_825) dm_build_727() error { + dm_build_834 := len(dm_build_833.dm_build_826) + + dm_build_833.dm_build_855(int32(dm_build_834), 1) + + dm_build_833.dm_build_742.dm_build_335.Dm_build_113(dm_build_833.dm_build_745.nativeSql, dm_build_833.dm_build_745.dmConn.getServerEncoding(), dm_build_833.dm_build_745.dmConn) + + for _, param := range dm_build_833.dm_build_826 { + dm_build_833.dm_build_742.dm_build_335.Dm_build_43(param.ioType) + dm_build_833.dm_build_742.dm_build_335.Dm_build_51(int32(param.tp)) + dm_build_833.dm_build_742.dm_build_335.Dm_build_51(int32(param.prec)) + dm_build_833.dm_build_742.dm_build_335.Dm_build_51(int32(param.scale)) + } + + for _, param := range dm_build_833.dm_build_826 { + if param.bytes == nil { + dm_build_833.dm_build_742.dm_build_335.Dm_build_59(Dm_build_650) + } else { + dm_build_833.dm_build_742.dm_build_335.Dm_build_89(param.bytes[:len(param.bytes)]) + } + } + return nil +} + +func (dm_build_836 *Dm_build_825) dm_build_731() (interface{}, error) { + return dm_build_836.dm_build_841.dm_build_731() +} + +const ( + Dm_build_837 int = 0x01 + + Dm_build_838 int = 0x02 + + Dm_build_839 int = 0x04 + + Dm_build_840 int = 0x08 +) + +type dm_build_841 struct { + dm_build_741 + dm_build_842 [][]interface{} + dm_build_843 []parameter + dm_build_844 bool +} + +func dm_build_845(dm_build_846 *dm_build_332, dm_build_847 int16, dm_build_848 *DmStatement) *dm_build_841 { + dm_build_849 := new(dm_build_841) + dm_build_849.dm_build_750(dm_build_846, dm_build_847, dm_build_848) + dm_build_849.dm_build_844 = true + return dm_build_849 +} + +func dm_build_850(dm_build_851 *dm_build_332, dm_build_852 *DmStatement, dm_build_853 [][]interface{}) *dm_build_841 { + dm_build_854 := new(dm_build_841) + + if dm_build_851.dm_build_336.Execute2 { + dm_build_854.dm_build_750(dm_build_851, Dm_build_615, dm_build_852) + } else { + dm_build_854.dm_build_750(dm_build_851, Dm_build_611, dm_build_852) + } + + dm_build_854.dm_build_843 = dm_build_852.params + dm_build_854.dm_build_842 = dm_build_853 + dm_build_854.dm_build_844 = true + return dm_build_854 +} + +func (dm_build_856 *dm_build_841) dm_build_855(dm_build_857 int32, dm_build_858 int64) { + + dm_build_859 := Dm_build_634 + + if dm_build_856.dm_build_742.dm_build_336.autoCommit { + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_183(dm_build_859, 1) + } else { + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_183(dm_build_859, 0) + } + + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_211(dm_build_859, uint16(dm_build_857)) + + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_183(dm_build_859, 1) + + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_195(dm_build_859, dm_build_858) + + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_195(dm_build_859, dm_build_856.dm_build_745.cursorUpdateRow) + + if dm_build_856.dm_build_745.maxRows <= 0 || dm_build_856.dm_build_745.dmConn.dmConnector.enRsCache { + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_195(dm_build_859, INT64_MAX) + } else { + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_195(dm_build_859, dm_build_856.dm_build_745.maxRows) + } + + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_183(dm_build_859, 1) + + if dm_build_856.dm_build_742.dm_build_336.dmConnector.continueBatchOnError { + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_183(dm_build_859, 1) + } else { + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_183(dm_build_859, 0) + } + + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_183(dm_build_859, 0) + + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_183(dm_build_859, 0) + + if dm_build_856.dm_build_745.queryTimeout == 0 { + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_191(dm_build_859, -1) + } else { + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_191(dm_build_859, dm_build_856.dm_build_745.queryTimeout) + } + + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_191(dm_build_859, dm_build_856.dm_build_742.dm_build_336.dmConnector.batchAllowMaxErrors) + + if dm_build_856.dm_build_745.innerExec { + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_183(dm_build_859, 1) + } else { + dm_build_859 += dm_build_856.dm_build_742.dm_build_335.Dm_build_183(dm_build_859, 0) + } +} + +func (dm_build_861 *dm_build_841) dm_build_727() error { + var dm_build_862 int32 + var dm_build_863 int64 + + if dm_build_861.dm_build_843 != nil { + dm_build_862 = int32(len(dm_build_861.dm_build_843)) + } else { + dm_build_862 = 0 + } + + if dm_build_861.dm_build_842 != nil { + dm_build_863 = int64(len(dm_build_861.dm_build_842)) + } else { + dm_build_863 = 0 + } + + dm_build_861.dm_build_855(dm_build_862, dm_build_863) + + if dm_build_862 > 0 { + err := dm_build_861.dm_build_864(dm_build_861.dm_build_843) + if err != nil { + return err + } + if dm_build_861.dm_build_842 != nil && len(dm_build_861.dm_build_842) > 0 { + for _, paramObject := range dm_build_861.dm_build_842 { + if err := dm_build_861.dm_build_867(paramObject); err != nil { + return err + } + } + } + } + + return nil +} + +func (dm_build_865 *dm_build_841) dm_build_864(dm_build_866 []parameter) error { + for _, param := range dm_build_866 { + + if param.colType == CURSOR && param.ioType == IO_TYPE_OUT { + dm_build_865.dm_build_742.dm_build_335.Dm_build_43(IO_TYPE_INOUT) + } else { + dm_build_865.dm_build_742.dm_build_335.Dm_build_43(param.ioType) + } + + dm_build_865.dm_build_742.dm_build_335.Dm_build_51(param.colType) + + lprec := param.prec + lscale := param.scale + typeDesc := param.typeDescriptor + switch param.colType { + case ARRAY, SARRAY: + tmp, err := getPackArraySize(typeDesc) + if err != nil { + return err + } + lprec = int32(tmp) + case PLTYPE_RECORD: + tmp, err := getPackRecordSize(typeDesc) + if err != nil { + return err + } + lprec = int32(tmp) + case CLASS: + tmp, err := getPackClassSize(typeDesc) + if err != nil { + return err + } + lprec = int32(tmp) + case BLOB: + if isComplexType(int(param.colType), int(param.scale)) { + lprec = int32(typeDesc.getObjId()) + if lprec == 4 { + lprec = int32(typeDesc.getOuterId()) + } + } + } + + dm_build_865.dm_build_742.dm_build_335.Dm_build_51(lprec) + + dm_build_865.dm_build_742.dm_build_335.Dm_build_51(lscale) + + switch param.colType { + case ARRAY, SARRAY: + err := packArray(typeDesc, dm_build_865.dm_build_742.dm_build_335) + if err != nil { + return err + } + + case PLTYPE_RECORD: + err := packRecord(typeDesc, dm_build_865.dm_build_742.dm_build_335) + if err != nil { + return err + } + + case CLASS: + err := packClass(typeDesc, dm_build_865.dm_build_742.dm_build_335) + if err != nil { + return err + } + + } + } + + return nil +} + +func (dm_build_868 *dm_build_841) dm_build_867(dm_build_869 []interface{}) error { + for i := 0; i < len(dm_build_868.dm_build_843); i++ { + + if dm_build_868.dm_build_843[i].colType == CURSOR { + dm_build_868.dm_build_742.dm_build_335.Dm_build_47(ULINT_SIZE) + dm_build_868.dm_build_742.dm_build_335.Dm_build_51(dm_build_868.dm_build_843[i].cursorStmt.id) + continue + } + + if dm_build_868.dm_build_843[i].ioType == IO_TYPE_OUT { + continue + } + + switch dm_build_869[i].(type) { + case []byte: + if dataBytes, ok := dm_build_869[i].([]byte); ok { + if len(dataBytes) > Dm_build_644 { + return ECGO_DATA_TOO_LONG.throw() + } + dm_build_868.dm_build_742.dm_build_335.Dm_build_89(dataBytes) + } + case int: + if dm_build_869[i] == ParamDataEnum_Null { + dm_build_868.dm_build_742.dm_build_335.Dm_build_59(Dm_build_650) + } else if dm_build_869[i] == ParamDataEnum_OFF_ROW { + dm_build_868.dm_build_742.dm_build_335.Dm_build_47(0) + } + case lobCtl: + dm_build_868.dm_build_742.dm_build_335.Dm_build_59(uint16(Dm_build_649)) + dm_build_868.dm_build_742.dm_build_335.Dm_build_79(dm_build_869[i].(lobCtl).value) + default: + panic("Bind param data failed by invalid param data type: ") + } + } + + return nil +} + +func (dm_build_871 *dm_build_841) dm_build_731() (interface{}, error) { + dm_build_872 := execRetInfo{} + dm_build_873 := dm_build_871.dm_build_745.dmConn + + dm_build_874 := Dm_build_634 + + dm_build_872.retSqlType = dm_build_871.dm_build_742.dm_build_335.Dm_build_266(dm_build_874) + dm_build_874 += USINT_SIZE + + dm_build_875 := dm_build_871.dm_build_742.dm_build_335.Dm_build_266(dm_build_874) + dm_build_874 += USINT_SIZE + + dm_build_872.updateCount = dm_build_871.dm_build_742.dm_build_335.Dm_build_272(dm_build_874) + dm_build_874 += DDWORD_SIZE + + dm_build_876 := dm_build_871.dm_build_742.dm_build_335.Dm_build_284(dm_build_874) + dm_build_874 += USINT_SIZE + + dm_build_872.rsUpdatable = dm_build_871.dm_build_742.dm_build_335.Dm_build_263(dm_build_874) != 0 + dm_build_874 += BYTE_SIZE + + dm_build_877 := dm_build_871.dm_build_742.dm_build_335.Dm_build_266(dm_build_874) + dm_build_874 += ULINT_SIZE + + dm_build_872.printLen = dm_build_871.dm_build_742.dm_build_335.Dm_build_269(dm_build_874) + dm_build_874 += ULINT_SIZE + + var dm_build_878 int16 = -1 + if dm_build_872.retSqlType == Dm_build_700 || dm_build_872.retSqlType == Dm_build_701 { + dm_build_872.rowid = 0 + + dm_build_872.rsBdta = dm_build_871.dm_build_742.dm_build_335.Dm_build_263(dm_build_874) == Dm_build_713 + dm_build_874 += BYTE_SIZE + + dm_build_878 = dm_build_871.dm_build_742.dm_build_335.Dm_build_266(dm_build_874) + dm_build_874 += USINT_SIZE + dm_build_874 += 5 + } else { + dm_build_872.rowid = dm_build_871.dm_build_742.dm_build_335.Dm_build_272(dm_build_874) + dm_build_874 += DDWORD_SIZE + } + + dm_build_872.execId = dm_build_871.dm_build_742.dm_build_335.Dm_build_269(dm_build_874) + dm_build_874 += ULINT_SIZE + + dm_build_872.rsCacheOffset = dm_build_871.dm_build_742.dm_build_335.Dm_build_269(dm_build_874) + dm_build_874 += ULINT_SIZE + + dm_build_879 := dm_build_871.dm_build_742.dm_build_335.Dm_build_263(dm_build_874) + dm_build_874 += BYTE_SIZE + dm_build_880 := (dm_build_879 & 0x01) == 0x01 + dm_build_881 := (dm_build_879 & 0x02) == 0x02 + + dm_build_873.TrxStatus = dm_build_871.dm_build_742.dm_build_335.Dm_build_269(dm_build_874) + dm_build_873.setTrxFinish(dm_build_873.TrxStatus) + dm_build_874 += ULINT_SIZE + + if dm_build_872.printLen > 0 { + bytes := dm_build_871.dm_build_742.dm_build_335.Dm_build_146(int(dm_build_872.printLen)) + dm_build_872.printMsg = Dm_build_1220.Dm_build_1377(bytes, 0, len(bytes), dm_build_873.getServerEncoding(), dm_build_873) + } + + if dm_build_876 > 0 { + dm_build_872.outParamDatas = dm_build_871.dm_build_882(int(dm_build_876)) + } + + switch dm_build_872.retSqlType { + case Dm_build_702: + dm_build_873.dmConnector.localTimezone = dm_build_871.dm_build_742.dm_build_335.Dm_build_122() + case Dm_build_700: + dm_build_872.hasResultSet = true + if dm_build_875 > 0 { + dm_build_871.dm_build_745.columns = dm_build_871.dm_build_891(int(dm_build_875), dm_build_872.rsBdta) + } + dm_build_871.dm_build_901(&dm_build_872, len(dm_build_871.dm_build_745.columns), int(dm_build_877), int(dm_build_878)) + case Dm_build_701: + if dm_build_875 > 0 || dm_build_877 > 0 { + dm_build_872.hasResultSet = true + } + if dm_build_875 > 0 { + dm_build_871.dm_build_745.columns = dm_build_871.dm_build_891(int(dm_build_875), dm_build_872.rsBdta) + } + dm_build_871.dm_build_901(&dm_build_872, len(dm_build_871.dm_build_745.columns), int(dm_build_877), int(dm_build_878)) + case Dm_build_703: + dm_build_873.IsoLevel = int32(dm_build_871.dm_build_742.dm_build_335.Dm_build_122()) + dm_build_873.ReadOnly = dm_build_871.dm_build_742.dm_build_335.Dm_build_119() == 1 + case Dm_build_696: + dm_build_873.Schema = dm_build_871.dm_build_742.dm_build_335.Dm_build_167(dm_build_873.getServerEncoding(), dm_build_873) + case Dm_build_693: + dm_build_872.explain = dm_build_871.dm_build_742.dm_build_335.Dm_build_167(dm_build_873.getServerEncoding(), dm_build_873) + + case Dm_build_697, Dm_build_699, Dm_build_698: + if dm_build_880 { + + counts := dm_build_871.dm_build_742.dm_build_335.Dm_build_125() + rowCounts := make([]int64, counts) + for i := 0; i < int(counts); i++ { + rowCounts[i] = dm_build_871.dm_build_742.dm_build_335.Dm_build_128() + } + dm_build_872.updateCounts = rowCounts + } + + if dm_build_881 { + rows := dm_build_871.dm_build_742.dm_build_335.Dm_build_125() + + var lastInsertId int64 + for i := 0; i < int(rows); i++ { + lastInsertId = dm_build_871.dm_build_742.dm_build_335.Dm_build_128() + } + dm_build_872.lastInsertId = lastInsertId + + } else if dm_build_872.updateCount == 1 { + dm_build_872.lastInsertId = dm_build_872.rowid + } + + if dm_build_871.dm_build_744 == EC_BP_WITH_ERROR.ErrCode { + dm_build_871.dm_build_907(dm_build_872.updateCounts) + } + case Dm_build_706: + len := dm_build_871.dm_build_742.dm_build_335.Dm_build_137() + dm_build_873.FormatDate = dm_build_871.dm_build_742.dm_build_335.Dm_build_162(int(len), dm_build_873.getServerEncoding(), dm_build_873) + case Dm_build_708: + + len := dm_build_871.dm_build_742.dm_build_335.Dm_build_137() + dm_build_873.FormatTimestamp = dm_build_871.dm_build_742.dm_build_335.Dm_build_162(int(len), dm_build_873.getServerEncoding(), dm_build_873) + case Dm_build_709: + + len := dm_build_871.dm_build_742.dm_build_335.Dm_build_137() + dm_build_873.FormatTimestampTZ = dm_build_871.dm_build_742.dm_build_335.Dm_build_162(int(len), dm_build_873.getServerEncoding(), dm_build_873) + case Dm_build_707: + len := dm_build_871.dm_build_742.dm_build_335.Dm_build_137() + dm_build_873.FormatTime = dm_build_871.dm_build_742.dm_build_335.Dm_build_162(int(len), dm_build_873.getServerEncoding(), dm_build_873) + case Dm_build_710: + len := dm_build_871.dm_build_742.dm_build_335.Dm_build_137() + dm_build_873.FormatTimeTZ = dm_build_871.dm_build_742.dm_build_335.Dm_build_162(int(len), dm_build_873.getServerEncoding(), dm_build_873) + case Dm_build_711: + dm_build_873.OracleDateLanguage = dm_build_871.dm_build_742.dm_build_335.Dm_build_137() + } + + return &dm_build_872, nil +} + +func (dm_build_883 *dm_build_841) dm_build_882(dm_build_884 int) [][]byte { + dm_build_885 := make([]int, dm_build_884) + + dm_build_886 := 0 + for i := 0; i < len(dm_build_883.dm_build_843); i++ { + if dm_build_883.dm_build_843[i].ioType == IO_TYPE_INOUT || dm_build_883.dm_build_843[i].ioType == IO_TYPE_OUT { + dm_build_885[dm_build_886] = i + dm_build_886++ + } + } + + dm_build_887 := make([][]byte, len(dm_build_883.dm_build_843)) + var dm_build_888 int32 + var dm_build_889 bool + var dm_build_890 []byte = nil + for i := 0; i < dm_build_884; i++ { + dm_build_889 = false + dm_build_888 = int32(dm_build_883.dm_build_742.dm_build_335.Dm_build_140()) + + if dm_build_888 == int32(Dm_build_650) { + dm_build_888 = 0 + dm_build_889 = true + } else if dm_build_888 == int32(Dm_build_651) { + dm_build_888 = dm_build_883.dm_build_742.dm_build_335.Dm_build_125() + } + + if dm_build_889 { + dm_build_887[dm_build_885[i]] = nil + } else { + dm_build_890 = dm_build_883.dm_build_742.dm_build_335.Dm_build_146(int(dm_build_888)) + dm_build_887[dm_build_885[i]] = dm_build_890 + } + } + + return dm_build_887 +} + +func (dm_build_892 *dm_build_841) dm_build_891(dm_build_893 int, dm_build_894 bool) []column { + dm_build_895 := dm_build_892.dm_build_742.dm_build_336.getServerEncoding() + var dm_build_896, dm_build_897, dm_build_898, dm_build_899 int16 + dm_build_900 := make([]column, dm_build_893) + for i := 0; i < dm_build_893; i++ { + dm_build_900[i].InitColumn() + + dm_build_900[i].colType = dm_build_892.dm_build_742.dm_build_335.Dm_build_125() + + dm_build_900[i].prec = dm_build_892.dm_build_742.dm_build_335.Dm_build_125() + + dm_build_900[i].scale = dm_build_892.dm_build_742.dm_build_335.Dm_build_125() + + dm_build_900[i].nullable = dm_build_892.dm_build_742.dm_build_335.Dm_build_125() != 0 + + itemFlag := dm_build_892.dm_build_742.dm_build_335.Dm_build_122() + dm_build_900[i].lob = int(itemFlag)&Dm_build_838 != 0 + dm_build_900[i].identity = int(itemFlag)&Dm_build_837 != 0 + dm_build_900[i].readonly = int(itemFlag)&Dm_build_839 != 0 + + dm_build_892.dm_build_742.dm_build_335.Dm_build_25(4, false, true) + + dm_build_892.dm_build_742.dm_build_335.Dm_build_25(2, false, true) + + dm_build_896 = dm_build_892.dm_build_742.dm_build_335.Dm_build_122() + + dm_build_897 = dm_build_892.dm_build_742.dm_build_335.Dm_build_122() + + dm_build_898 = dm_build_892.dm_build_742.dm_build_335.Dm_build_122() + + dm_build_899 = dm_build_892.dm_build_742.dm_build_335.Dm_build_122() + dm_build_900[i].name = dm_build_892.dm_build_742.dm_build_335.Dm_build_162(int(dm_build_896), dm_build_895, dm_build_892.dm_build_742.dm_build_336) + dm_build_900[i].typeName = dm_build_892.dm_build_742.dm_build_335.Dm_build_162(int(dm_build_897), dm_build_895, dm_build_892.dm_build_742.dm_build_336) + dm_build_900[i].tableName = dm_build_892.dm_build_742.dm_build_335.Dm_build_162(int(dm_build_898), dm_build_895, dm_build_892.dm_build_742.dm_build_336) + dm_build_900[i].schemaName = dm_build_892.dm_build_742.dm_build_335.Dm_build_162(int(dm_build_899), dm_build_895, dm_build_892.dm_build_742.dm_build_336) + + if dm_build_892.dm_build_745.readBaseColName { + dm_build_900[i].baseName = dm_build_892.dm_build_742.dm_build_335.Dm_build_175(dm_build_895, dm_build_892.dm_build_742.dm_build_336) + } + + if dm_build_900[i].lob { + dm_build_900[i].lobTabId = dm_build_892.dm_build_742.dm_build_335.Dm_build_125() + dm_build_900[i].lobColId = dm_build_892.dm_build_742.dm_build_335.Dm_build_122() + } + + } + + for i := 0; i < dm_build_893; i++ { + + if isComplexType(int(dm_build_900[i].colType), int(dm_build_900[i].scale)) { + strDesc := newTypeDescriptor(dm_build_892.dm_build_742.dm_build_336) + strDesc.unpack(dm_build_892.dm_build_742.dm_build_335) + dm_build_900[i].typeDescriptor = strDesc + } + } + + return dm_build_900 +} + +func (dm_build_902 *dm_build_841) dm_build_901(dm_build_903 *execRetInfo, dm_build_904 int, dm_build_905 int, dm_build_906 int) { + if dm_build_905 > 0 { + startOffset := dm_build_902.dm_build_742.dm_build_335.Dm_build_20() + if dm_build_903.rsBdta { + dm_build_903.rsDatas = dm_build_902.dm_build_920(dm_build_902.dm_build_745.columns, dm_build_906) + } else { + datas := make([][][]byte, dm_build_905) + + for i := 0; i < dm_build_905; i++ { + + datas[i] = make([][]byte, dm_build_904+1) + + dm_build_902.dm_build_742.dm_build_335.Dm_build_25(2, false, true) + + datas[i][0] = dm_build_902.dm_build_742.dm_build_335.Dm_build_146(LINT64_SIZE) + + dm_build_902.dm_build_742.dm_build_335.Dm_build_25(2*dm_build_904, false, true) + + for j := 1; j < dm_build_904+1; j++ { + + colLen := dm_build_902.dm_build_742.dm_build_335.Dm_build_140() + if colLen == Dm_build_654 { + datas[i][j] = nil + } else if colLen != Dm_build_655 { + datas[i][j] = dm_build_902.dm_build_742.dm_build_335.Dm_build_146(int(colLen)) + } else { + datas[i][j] = dm_build_902.dm_build_742.dm_build_335.Dm_build_150() + } + } + } + + dm_build_903.rsDatas = datas + } + dm_build_903.rsSizeof = dm_build_902.dm_build_742.dm_build_335.Dm_build_20() - startOffset + } + + if dm_build_903.rsCacheOffset > 0 { + tbCount := dm_build_902.dm_build_742.dm_build_335.Dm_build_122() + + ids := make([]int32, tbCount) + tss := make([]int64, tbCount) + + for i := 0; i < int(tbCount); i++ { + ids[i] = dm_build_902.dm_build_742.dm_build_335.Dm_build_125() + tss[i] = dm_build_902.dm_build_742.dm_build_335.Dm_build_128() + } + + dm_build_903.tbIds = ids[:] + dm_build_903.tbTss = tss[:] + } +} + +func (dm_build_908 *dm_build_841) dm_build_907(dm_build_909 []int64) error { + + dm_build_908.dm_build_742.dm_build_335.Dm_build_25(4, false, true) + + dm_build_910 := dm_build_908.dm_build_742.dm_build_335.Dm_build_125() + + dm_build_911 := make([]string, 0, 8) + for i := 0; i < int(dm_build_910); i++ { + irow := dm_build_908.dm_build_742.dm_build_335.Dm_build_125() + + dm_build_909[irow] = -3 + + code := dm_build_908.dm_build_742.dm_build_335.Dm_build_125() + + errStr := dm_build_908.dm_build_742.dm_build_335.Dm_build_175(dm_build_908.dm_build_742.dm_build_336.getServerEncoding(), dm_build_908.dm_build_742.dm_build_336) + + dm_build_911 = append(dm_build_911, "row["+strconv.Itoa(int(irow))+"]:"+strconv.Itoa(int(code))+", "+errStr) + } + + if len(dm_build_911) > 0 { + builder := &strings.Builder{} + for _, str := range dm_build_911 { + builder.WriteString(util.LINE_SEPARATOR) + builder.WriteString(str) + } + EC_BP_WITH_ERROR.ErrText += builder.String() + return EC_BP_WITH_ERROR.throw() + } + return nil +} + +const ( + Dm_build_912 = 0 + + Dm_build_913 = Dm_build_912 + ULINT_SIZE + + Dm_build_914 = Dm_build_913 + USINT_SIZE + + Dm_build_915 = Dm_build_914 + ULINT_SIZE + + Dm_build_916 = Dm_build_915 + ULINT_SIZE + + Dm_build_917 = Dm_build_916 + BYTE_SIZE + + Dm_build_918 = -2 + + Dm_build_919 = -3 +) + +func (dm_build_921 *dm_build_841) dm_build_920(dm_build_922 []column, dm_build_923 int) [][][]byte { + + dm_build_924 := dm_build_921.dm_build_742.dm_build_335.Dm_build_143() + + dm_build_925 := dm_build_921.dm_build_742.dm_build_335.Dm_build_140() + + var dm_build_926 bool + + if dm_build_923 >= 0 && int(dm_build_925) == len(dm_build_922)+1 { + dm_build_926 = true + } else { + dm_build_926 = false + } + + dm_build_921.dm_build_742.dm_build_335.Dm_build_25(ULINT_SIZE, false, true) + + dm_build_921.dm_build_742.dm_build_335.Dm_build_25(ULINT_SIZE, false, true) + + dm_build_921.dm_build_742.dm_build_335.Dm_build_25(BYTE_SIZE, false, true) + + dm_build_927 := make([]uint16, dm_build_925) + for icol := 0; icol < int(dm_build_925); icol++ { + dm_build_927[icol] = dm_build_921.dm_build_742.dm_build_335.Dm_build_140() + } + + dm_build_928 := make([]uint32, dm_build_925) + dm_build_929 := make([][][]byte, dm_build_924) + + for i := uint32(0); i < dm_build_924; i++ { + dm_build_929[i] = make([][]byte, len(dm_build_922)+1) + } + + for icol := 0; icol < int(dm_build_925); icol++ { + dm_build_928[icol] = dm_build_921.dm_build_742.dm_build_335.Dm_build_143() + } + + for icol := 0; icol < int(dm_build_925); icol++ { + + dataCol := icol + 1 + if dm_build_926 && icol == dm_build_923 { + dataCol = 0 + } else if dm_build_926 && icol > dm_build_923 { + dataCol = icol + } + + allNotNull := dm_build_921.dm_build_742.dm_build_335.Dm_build_125() == 1 + var isNull []bool = nil + if !allNotNull { + isNull = make([]bool, dm_build_924) + for irow := uint32(0); irow < dm_build_924; irow++ { + isNull[irow] = dm_build_921.dm_build_742.dm_build_335.Dm_build_119() == 0 + } + } + + for irow := uint32(0); irow < dm_build_924; irow++ { + if allNotNull || !isNull[irow] { + dm_build_929[irow][dataCol] = dm_build_921.dm_build_930(int(dm_build_927[icol])) + } + } + } + + if !dm_build_926 && dm_build_923 >= 0 { + for irow := uint32(0); irow < dm_build_924; irow++ { + dm_build_929[irow][0] = dm_build_929[irow][dm_build_923+1] + } + } + + return dm_build_929 +} + +func (dm_build_931 *dm_build_841) dm_build_930(dm_build_932 int) []byte { + + dm_build_933 := dm_build_931.dm_build_936(dm_build_932) + + dm_build_934 := int32(0) + if dm_build_933 == Dm_build_918 { + dm_build_934 = dm_build_931.dm_build_742.dm_build_335.Dm_build_125() + dm_build_933 = int(dm_build_931.dm_build_742.dm_build_335.Dm_build_125()) + } else if dm_build_933 == Dm_build_919 { + dm_build_933 = int(dm_build_931.dm_build_742.dm_build_335.Dm_build_125()) + } + + dm_build_935 := dm_build_931.dm_build_742.dm_build_335.Dm_build_146(dm_build_933 + int(dm_build_934)) + if dm_build_934 == 0 { + return dm_build_935 + } + + for i := dm_build_933; i < len(dm_build_935); i++ { + dm_build_935[i] = ' ' + } + return dm_build_935 +} + +func (dm_build_937 *dm_build_841) dm_build_936(dm_build_938 int) int { + + dm_build_939 := 0 + switch dm_build_938 { + case INT: + case BIT: + case TINYINT: + case SMALLINT: + case BOOLEAN: + case NULL: + dm_build_939 = 4 + + case BIGINT: + + dm_build_939 = 8 + + case CHAR: + case VARCHAR2: + case VARCHAR: + case BINARY: + case VARBINARY: + case BLOB: + case CLOB: + dm_build_939 = Dm_build_918 + + case DECIMAL: + dm_build_939 = Dm_build_919 + + case REAL: + dm_build_939 = 4 + + case DOUBLE: + dm_build_939 = 8 + + case DATE: + case TIME: + case DATETIME: + case TIME_TZ: + case DATETIME_TZ: + dm_build_939 = 12 + + case INTERVAL_YM: + dm_build_939 = 12 + + case INTERVAL_DT: + dm_build_939 = 24 + + default: + panic(ECGO_INVALID_COLUMN_TYPE) + } + return dm_build_939 +} + +const ( + Dm_build_940 = Dm_build_634 + + Dm_build_941 = Dm_build_940 + DDWORD_SIZE + + Dm_build_942 = Dm_build_941 + LINT64_SIZE + + Dm_build_943 = Dm_build_942 + USINT_SIZE + + Dm_build_944 = Dm_build_634 + + Dm_build_945 = Dm_build_944 + DDWORD_SIZE +) + +type dm_build_946 struct { + dm_build_841 + dm_build_947 *innerRows + dm_build_948 int64 + dm_build_949 int64 +} + +func dm_build_950(dm_build_951 *dm_build_332, dm_build_952 *innerRows, dm_build_953 int64, dm_build_954 int64) *dm_build_946 { + dm_build_955 := new(dm_build_946) + dm_build_955.dm_build_750(dm_build_951, Dm_build_612, dm_build_952.dmStmt) + dm_build_955.dm_build_947 = dm_build_952 + dm_build_955.dm_build_948 = dm_build_953 + dm_build_955.dm_build_949 = dm_build_954 + return dm_build_955 +} + +func (dm_build_957 *dm_build_946) dm_build_727() error { + + dm_build_957.dm_build_742.dm_build_335.Dm_build_195(Dm_build_940, dm_build_957.dm_build_948) + + dm_build_957.dm_build_742.dm_build_335.Dm_build_195(Dm_build_941, dm_build_957.dm_build_949) + + dm_build_957.dm_build_742.dm_build_335.Dm_build_187(Dm_build_942, dm_build_957.dm_build_947.id) + + dm_build_958 := dm_build_957.dm_build_947.dmStmt.dmConn.dmConnector.bufPrefetch + var dm_build_959 int32 + if dm_build_957.dm_build_947.sizeOfRow != 0 && dm_build_957.dm_build_947.fetchSize != 0 { + if dm_build_957.dm_build_947.sizeOfRow*dm_build_957.dm_build_947.fetchSize > int(INT32_MAX) { + dm_build_959 = INT32_MAX + } else { + dm_build_959 = int32(dm_build_957.dm_build_947.sizeOfRow * dm_build_957.dm_build_947.fetchSize) + } + + if dm_build_959 < Dm_build_666 { + dm_build_958 = int(Dm_build_666) + } else if dm_build_959 > Dm_build_667 { + dm_build_958 = int(Dm_build_667) + } else { + dm_build_958 = int(dm_build_959) + } + + dm_build_957.dm_build_742.dm_build_335.Dm_build_191(Dm_build_943, int32(dm_build_958)) + } + + return nil +} + +func (dm_build_961 *dm_build_946) dm_build_731() (interface{}, error) { + dm_build_962 := execRetInfo{} + dm_build_962.rsBdta = dm_build_961.dm_build_947.isBdta + + dm_build_962.updateCount = dm_build_961.dm_build_742.dm_build_335.Dm_build_272(Dm_build_944) + dm_build_963 := dm_build_961.dm_build_742.dm_build_335.Dm_build_269(Dm_build_945) + + dm_build_961.dm_build_901(&dm_build_962, len(dm_build_961.dm_build_947.columns), int(dm_build_963), -1) + + return &dm_build_962, nil +} + +type dm_build_964 struct { + dm_build_741 + dm_build_965 *lob + dm_build_966 int + dm_build_967 int +} + +func dm_build_968(dm_build_969 *dm_build_332, dm_build_970 *lob, dm_build_971 int, dm_build_972 int) *dm_build_964 { + dm_build_973 := new(dm_build_964) + dm_build_973.dm_build_746(dm_build_969, Dm_build_625) + dm_build_973.dm_build_965 = dm_build_970 + dm_build_973.dm_build_966 = dm_build_971 + dm_build_973.dm_build_967 = dm_build_972 + return dm_build_973 +} + +func (dm_build_975 *dm_build_964) dm_build_727() error { + + dm_build_975.dm_build_742.dm_build_335.Dm_build_43(byte(dm_build_975.dm_build_965.lobFlag)) + + dm_build_975.dm_build_742.dm_build_335.Dm_build_51(dm_build_975.dm_build_965.tabId) + + dm_build_975.dm_build_742.dm_build_335.Dm_build_47(dm_build_975.dm_build_965.colId) + + dm_build_975.dm_build_742.dm_build_335.Dm_build_67(uint64(dm_build_975.dm_build_965.blobId)) + + dm_build_975.dm_build_742.dm_build_335.Dm_build_47(dm_build_975.dm_build_965.groupId) + + dm_build_975.dm_build_742.dm_build_335.Dm_build_47(dm_build_975.dm_build_965.fileId) + + dm_build_975.dm_build_742.dm_build_335.Dm_build_51(dm_build_975.dm_build_965.pageNo) + + dm_build_975.dm_build_742.dm_build_335.Dm_build_47(dm_build_975.dm_build_965.curFileId) + + dm_build_975.dm_build_742.dm_build_335.Dm_build_51(dm_build_975.dm_build_965.curPageNo) + + dm_build_975.dm_build_742.dm_build_335.Dm_build_51(dm_build_975.dm_build_965.totalOffset) + + dm_build_975.dm_build_742.dm_build_335.Dm_build_51(int32(dm_build_975.dm_build_966)) + + dm_build_975.dm_build_742.dm_build_335.Dm_build_51(int32(dm_build_975.dm_build_967)) + + if dm_build_975.dm_build_742.dm_build_336.NewLobFlag { + dm_build_975.dm_build_742.dm_build_335.Dm_build_67(uint64(dm_build_975.dm_build_965.rowId)) + dm_build_975.dm_build_742.dm_build_335.Dm_build_47(dm_build_975.dm_build_965.exGroupId) + dm_build_975.dm_build_742.dm_build_335.Dm_build_47(dm_build_975.dm_build_965.exFileId) + dm_build_975.dm_build_742.dm_build_335.Dm_build_51(dm_build_975.dm_build_965.exPageNo) + } + + return nil +} + +func (dm_build_977 *dm_build_964) dm_build_731() (interface{}, error) { + + dm_build_977.dm_build_965.readOver = dm_build_977.dm_build_742.dm_build_335.Dm_build_119() == 1 + var dm_build_978 = dm_build_977.dm_build_742.dm_build_335.Dm_build_143() + if dm_build_978 <= 0 { + return []byte(nil), nil + } + dm_build_977.dm_build_965.curFileId = dm_build_977.dm_build_742.dm_build_335.Dm_build_122() + dm_build_977.dm_build_965.curPageNo = dm_build_977.dm_build_742.dm_build_335.Dm_build_125() + dm_build_977.dm_build_965.totalOffset = dm_build_977.dm_build_742.dm_build_335.Dm_build_125() + + return dm_build_977.dm_build_742.dm_build_335.Dm_build_156(int(dm_build_978)), nil +} + +type dm_build_979 struct { + dm_build_741 + dm_build_980 *lob +} + +func dm_build_981(dm_build_982 *dm_build_332, dm_build_983 *lob) *dm_build_979 { + dm_build_984 := new(dm_build_979) + dm_build_984.dm_build_746(dm_build_982, Dm_build_622) + dm_build_984.dm_build_980 = dm_build_983 + return dm_build_984 +} + +func (dm_build_986 *dm_build_979) dm_build_727() error { + + dm_build_986.dm_build_742.dm_build_335.Dm_build_43(byte(dm_build_986.dm_build_980.lobFlag)) + + dm_build_986.dm_build_742.dm_build_335.Dm_build_67(uint64(dm_build_986.dm_build_980.blobId)) + + dm_build_986.dm_build_742.dm_build_335.Dm_build_47(dm_build_986.dm_build_980.groupId) + + dm_build_986.dm_build_742.dm_build_335.Dm_build_47(dm_build_986.dm_build_980.fileId) + + dm_build_986.dm_build_742.dm_build_335.Dm_build_51(dm_build_986.dm_build_980.pageNo) + + if dm_build_986.dm_build_742.dm_build_336.NewLobFlag { + dm_build_986.dm_build_742.dm_build_335.Dm_build_51(dm_build_986.dm_build_980.tabId) + dm_build_986.dm_build_742.dm_build_335.Dm_build_47(dm_build_986.dm_build_980.colId) + dm_build_986.dm_build_742.dm_build_335.Dm_build_67(uint64(dm_build_986.dm_build_980.rowId)) + + dm_build_986.dm_build_742.dm_build_335.Dm_build_47(dm_build_986.dm_build_980.exGroupId) + dm_build_986.dm_build_742.dm_build_335.Dm_build_47(dm_build_986.dm_build_980.exFileId) + dm_build_986.dm_build_742.dm_build_335.Dm_build_51(dm_build_986.dm_build_980.exPageNo) + } + + return nil +} + +func (dm_build_988 *dm_build_979) dm_build_731() (interface{}, error) { + + if dm_build_988.dm_build_742.dm_build_335.Dm_build_22(false) == 8 { + return dm_build_988.dm_build_742.dm_build_335.Dm_build_128(), nil + } else { + return int64(dm_build_988.dm_build_742.dm_build_335.Dm_build_143()), nil + } +} + +type dm_build_989 struct { + dm_build_741 + dm_build_990 *lob + dm_build_991 int +} + +func dm_build_992(dm_build_993 *dm_build_332, dm_build_994 *lob, dm_build_995 int) *dm_build_989 { + dm_build_996 := new(dm_build_989) + dm_build_996.dm_build_746(dm_build_993, Dm_build_624) + dm_build_996.dm_build_990 = dm_build_994 + dm_build_996.dm_build_991 = dm_build_995 + return dm_build_996 +} + +func (dm_build_998 *dm_build_989) dm_build_727() error { + + dm_build_998.dm_build_742.dm_build_335.Dm_build_43(byte(dm_build_998.dm_build_990.lobFlag)) + + dm_build_998.dm_build_742.dm_build_335.Dm_build_67(uint64(dm_build_998.dm_build_990.blobId)) + + dm_build_998.dm_build_742.dm_build_335.Dm_build_47(dm_build_998.dm_build_990.groupId) + + dm_build_998.dm_build_742.dm_build_335.Dm_build_47(dm_build_998.dm_build_990.fileId) + + dm_build_998.dm_build_742.dm_build_335.Dm_build_51(dm_build_998.dm_build_990.pageNo) + + dm_build_998.dm_build_742.dm_build_335.Dm_build_51(dm_build_998.dm_build_990.tabId) + dm_build_998.dm_build_742.dm_build_335.Dm_build_47(dm_build_998.dm_build_990.colId) + dm_build_998.dm_build_742.dm_build_335.Dm_build_67(uint64(dm_build_998.dm_build_990.rowId)) + dm_build_998.dm_build_742.dm_build_335.Dm_build_79(Dm_build_1220.Dm_build_1422(uint32(dm_build_998.dm_build_991))) + + if dm_build_998.dm_build_742.dm_build_336.NewLobFlag { + dm_build_998.dm_build_742.dm_build_335.Dm_build_47(dm_build_998.dm_build_990.exGroupId) + dm_build_998.dm_build_742.dm_build_335.Dm_build_47(dm_build_998.dm_build_990.exFileId) + dm_build_998.dm_build_742.dm_build_335.Dm_build_51(dm_build_998.dm_build_990.exPageNo) + } + return nil +} + +func (dm_build_1000 *dm_build_989) dm_build_731() (interface{}, error) { + + dm_build_1001 := dm_build_1000.dm_build_742.dm_build_335.Dm_build_143() + dm_build_1000.dm_build_990.blobId = dm_build_1000.dm_build_742.dm_build_335.Dm_build_128() + dm_build_1000.dm_build_990.resetCurrentInfo() + return int64(dm_build_1001), nil +} + +const ( + Dm_build_1002 = Dm_build_634 + + Dm_build_1003 = Dm_build_1002 + ULINT_SIZE + + Dm_build_1004 = Dm_build_1003 + ULINT_SIZE + + Dm_build_1005 = Dm_build_1004 + ULINT_SIZE + + Dm_build_1006 = Dm_build_1005 + BYTE_SIZE + + Dm_build_1007 = Dm_build_1006 + USINT_SIZE + + Dm_build_1008 = Dm_build_1007 + ULINT_SIZE + + Dm_build_1009 = Dm_build_1008 + BYTE_SIZE + + Dm_build_1010 = Dm_build_1009 + BYTE_SIZE + + Dm_build_1011 = Dm_build_1010 + BYTE_SIZE + + Dm_build_1012 = Dm_build_634 + + Dm_build_1013 = Dm_build_1012 + ULINT_SIZE + + Dm_build_1014 = Dm_build_1013 + ULINT_SIZE + + Dm_build_1015 = Dm_build_1014 + BYTE_SIZE + + Dm_build_1016 = Dm_build_1015 + ULINT_SIZE + + Dm_build_1017 = Dm_build_1016 + BYTE_SIZE + + Dm_build_1018 = Dm_build_1017 + BYTE_SIZE + + Dm_build_1019 = Dm_build_1018 + USINT_SIZE + + Dm_build_1020 = Dm_build_1019 + USINT_SIZE + + Dm_build_1021 = Dm_build_1020 + BYTE_SIZE + + Dm_build_1022 = Dm_build_1021 + USINT_SIZE + + Dm_build_1023 = Dm_build_1022 + BYTE_SIZE + + Dm_build_1024 = Dm_build_1023 + BYTE_SIZE + + Dm_build_1025 = Dm_build_1024 + ULINT_SIZE + + Dm_build_1026 = Dm_build_1025 + USINT_SIZE +) + +type dm_build_1027 struct { + dm_build_741 + + dm_build_1028 *DmConnection + + dm_build_1029 bool +} + +func dm_build_1030(dm_build_1031 *dm_build_332) *dm_build_1027 { + dm_build_1032 := new(dm_build_1027) + dm_build_1032.dm_build_746(dm_build_1031, Dm_build_606) + dm_build_1032.dm_build_1028 = dm_build_1031.dm_build_336 + return dm_build_1032 +} + +func (dm_build_1034 *dm_build_1027) dm_build_727() error { + + if dm_build_1034.dm_build_1028.dmConnector.newClientType { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_191(Dm_build_1002, Dm_build_646) + } else { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_191(Dm_build_1002, Dm_build_645) + } + + dm_build_1034.dm_build_742.dm_build_335.Dm_build_191(Dm_build_1003, g2dbIsoLevel(dm_build_1034.dm_build_1028.IsoLevel)) + dm_build_1034.dm_build_742.dm_build_335.Dm_build_191(Dm_build_1004, int32(Locale)) + dm_build_1034.dm_build_742.dm_build_335.Dm_build_187(Dm_build_1006, dm_build_1034.dm_build_1028.dmConnector.localTimezone) + + if dm_build_1034.dm_build_1028.ReadOnly { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1005, Dm_build_669) + } else { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1005, Dm_build_668) + } + + dm_build_1034.dm_build_742.dm_build_335.Dm_build_191(Dm_build_1007, int32(dm_build_1034.dm_build_1028.dmConnector.sessionTimeout)) + + if dm_build_1034.dm_build_1028.dmConnector.mppLocal { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1008, 1) + } else { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1008, 0) + } + + if dm_build_1034.dm_build_1028.dmConnector.rwSeparate { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1009, 1) + } else { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1009, 0) + } + + if dm_build_1034.dm_build_1028.NewLobFlag { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1010, 1) + } else { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1010, 0) + } + + dm_build_1034.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1011, dm_build_1034.dm_build_1028.dmConnector.osAuthType) + + dm_build_1035 := dm_build_1034.dm_build_1028.getServerEncoding() + + if dm_build_1034.dm_build_742.dm_build_342 != "" { + + } + + dm_build_1036 := Dm_build_1220.Dm_build_1433(dm_build_1034.dm_build_1028.dmConnector.user, dm_build_1035, dm_build_1034.dm_build_742.dm_build_336) + dm_build_1037 := Dm_build_1220.Dm_build_1433(dm_build_1034.dm_build_1028.dmConnector.password, dm_build_1035, dm_build_1034.dm_build_742.dm_build_336) + if len(dm_build_1036) > Dm_build_642 { + return ECGO_USERNAME_TOO_LONG.throw() + } + if len(dm_build_1037) > Dm_build_642 { + return ECGO_PASSWORD_TOO_LONG.throw() + } + + if dm_build_1034.dm_build_742.dm_build_338 && dm_build_1034.dm_build_1028.dmConnector.loginCertificate != "" { + + } else if dm_build_1034.dm_build_742.dm_build_338 { + dm_build_1036 = dm_build_1034.dm_build_742.dm_build_337.Encrypt(dm_build_1036, false) + dm_build_1037 = dm_build_1034.dm_build_742.dm_build_337.Encrypt(dm_build_1037, false) + } + + dm_build_1034.dm_build_742.dm_build_335.Dm_build_83(dm_build_1036) + dm_build_1034.dm_build_742.dm_build_335.Dm_build_83(dm_build_1037) + + dm_build_1034.dm_build_742.dm_build_335.Dm_build_95(dm_build_1034.dm_build_1028.dmConnector.appName, dm_build_1035, dm_build_1034.dm_build_742.dm_build_336) + dm_build_1034.dm_build_742.dm_build_335.Dm_build_95(dm_build_1034.dm_build_1028.dmConnector.osName, dm_build_1035, dm_build_1034.dm_build_742.dm_build_336) + + if hostName, err := os.Hostname(); err != nil { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_95(hostName, dm_build_1035, dm_build_1034.dm_build_742.dm_build_336) + } else { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_95("", dm_build_1035, dm_build_1034.dm_build_742.dm_build_336) + } + + if dm_build_1034.dm_build_1028.dmConnector.rwStandby { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_43(1) + } else { + dm_build_1034.dm_build_742.dm_build_335.Dm_build_43(0) + } + + return nil +} + +func (dm_build_1039 *dm_build_1027) dm_build_731() (interface{}, error) { + + dm_build_1039.dm_build_1028.MaxRowSize = dm_build_1039.dm_build_742.dm_build_335.Dm_build_269(Dm_build_1012) + dm_build_1039.dm_build_1028.DDLAutoCommit = dm_build_1039.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1014) == 1 + dm_build_1039.dm_build_1028.IsoLevel = dm_build_1039.dm_build_742.dm_build_335.Dm_build_269(Dm_build_1015) + dm_build_1039.dm_build_1028.dmConnector.caseSensitive = dm_build_1039.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1016) == 1 + dm_build_1039.dm_build_1028.BackslashEscape = dm_build_1039.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1017) == 1 + dm_build_1039.dm_build_1028.SvrStat = int32(dm_build_1039.dm_build_742.dm_build_335.Dm_build_266(Dm_build_1019)) + dm_build_1039.dm_build_1028.SvrMode = int32(dm_build_1039.dm_build_742.dm_build_335.Dm_build_266(Dm_build_1018)) + dm_build_1039.dm_build_1028.ConstParaOpt = dm_build_1039.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1020) == 1 + dm_build_1039.dm_build_1028.DbTimezone = dm_build_1039.dm_build_742.dm_build_335.Dm_build_266(Dm_build_1021) + dm_build_1039.dm_build_1028.NewLobFlag = dm_build_1039.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1023) == 1 + + if dm_build_1039.dm_build_1028.dmConnector.bufPrefetch == 0 { + dm_build_1039.dm_build_1028.dmConnector.bufPrefetch = int(dm_build_1039.dm_build_742.dm_build_335.Dm_build_269(Dm_build_1024)) + } + + dm_build_1039.dm_build_1028.LifeTimeRemainder = dm_build_1039.dm_build_742.dm_build_335.Dm_build_266(Dm_build_1025) + dm_build_1039.dm_build_1028.dscControl = dm_build_1039.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1026) == 1 + + dm_build_1040 := dm_build_1039.dm_build_1028.getServerEncoding() + + dm_build_1039.dm_build_1028.InstanceName = dm_build_1039.dm_build_742.dm_build_335.Dm_build_167(dm_build_1040, dm_build_1039.dm_build_742.dm_build_336) + + var dm_build_1041 = dm_build_1039.dm_build_742.dm_build_335.Dm_build_125() + if dm_build_1041 == 0 && dm_build_1039.dm_build_1028.MsgVersion > 0 { + dm_build_1039.dm_build_1028.Schema = strings.ToUpper(dm_build_1039.dm_build_1028.dmConnector.user) + } else { + dm_build_1039.dm_build_1028.Schema = dm_build_1039.dm_build_742.dm_build_335.Dm_build_162(int(dm_build_1041), dm_build_1040, dm_build_1039.dm_build_742.dm_build_336) + } + + dm_build_1039.dm_build_1028.LastLoginIP = dm_build_1039.dm_build_742.dm_build_335.Dm_build_167(dm_build_1040, dm_build_1039.dm_build_742.dm_build_336) + dm_build_1039.dm_build_1028.LastLoginTime = dm_build_1039.dm_build_742.dm_build_335.Dm_build_167(dm_build_1040, dm_build_1039.dm_build_742.dm_build_336) + dm_build_1039.dm_build_1028.FailedAttempts = dm_build_1039.dm_build_742.dm_build_335.Dm_build_125() + dm_build_1039.dm_build_1028.LoginWarningID = dm_build_1039.dm_build_742.dm_build_335.Dm_build_125() + dm_build_1039.dm_build_1028.GraceTimeRemainder = dm_build_1039.dm_build_742.dm_build_335.Dm_build_125() + dm_build_1039.dm_build_1028.Guid = dm_build_1039.dm_build_742.dm_build_335.Dm_build_167(dm_build_1040, dm_build_1039.dm_build_742.dm_build_336) + dm_build_1039.dm_build_1028.DbName = dm_build_1039.dm_build_742.dm_build_335.Dm_build_167(dm_build_1040, dm_build_1039.dm_build_742.dm_build_336) + + if dm_build_1039.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1022) == 1 { + dm_build_1039.dm_build_1028.StandbyHost = dm_build_1039.dm_build_742.dm_build_335.Dm_build_167(dm_build_1040, dm_build_1039.dm_build_742.dm_build_336) + dm_build_1039.dm_build_1028.StandbyPort = dm_build_1039.dm_build_742.dm_build_335.Dm_build_125() + dm_build_1039.dm_build_1028.StandbyCount = int32(dm_build_1039.dm_build_742.dm_build_335.Dm_build_140()) + } + + if dm_build_1039.dm_build_742.dm_build_335.Dm_build_22(false) > 0 { + dm_build_1039.dm_build_1028.SessionID = dm_build_1039.dm_build_742.dm_build_335.Dm_build_128() + } + + if dm_build_1039.dm_build_742.dm_build_335.Dm_build_22(false) > 0 { + if dm_build_1039.dm_build_742.dm_build_335.Dm_build_119() == 1 { + + dm_build_1039.dm_build_1028.FormatDate = "DD-MON-YY" + + dm_build_1039.dm_build_1028.FormatTime = "HH12.MI.SS.FF6 AM" + + dm_build_1039.dm_build_1028.FormatTimestamp = "DD-MON-YY HH12.MI.SS.FF6 AM" + + dm_build_1039.dm_build_1028.FormatTimestampTZ = "DD-MON-YY HH12.MI.SS.FF6 AM +TZH:TZM" + + dm_build_1039.dm_build_1028.FormatTimeTZ = "HH12.MI.SS.FF6 AM +TZH:TZM" + } + } + + if dm_build_1039.dm_build_742.dm_build_335.Dm_build_22(false) > 0 { + + format := dm_build_1039.dm_build_742.dm_build_335.Dm_build_171(dm_build_1040, dm_build_1039.dm_build_742.dm_build_336) + if format != "" { + dm_build_1039.dm_build_1028.FormatDate = format + } + format = dm_build_1039.dm_build_742.dm_build_335.Dm_build_171(dm_build_1040, dm_build_1039.dm_build_742.dm_build_336) + if format != "" { + dm_build_1039.dm_build_1028.FormatTime = format + } + format = dm_build_1039.dm_build_742.dm_build_335.Dm_build_171(dm_build_1040, dm_build_1039.dm_build_742.dm_build_336) + if format != "" { + dm_build_1039.dm_build_1028.FormatTimestamp = format + } + format = dm_build_1039.dm_build_742.dm_build_335.Dm_build_171(dm_build_1040, dm_build_1039.dm_build_742.dm_build_336) + if format != "" { + dm_build_1039.dm_build_1028.FormatTimestampTZ = format + } + format = dm_build_1039.dm_build_742.dm_build_335.Dm_build_171(dm_build_1040, dm_build_1039.dm_build_742.dm_build_336) + if format != "" { + dm_build_1039.dm_build_1028.FormatTimeTZ = format + } + } + + return nil, nil +} + +const ( + Dm_build_1042 = Dm_build_634 +) + +type dm_build_1043 struct { + dm_build_841 + dm_build_1044 int16 +} + +func dm_build_1045(dm_build_1046 *dm_build_332, dm_build_1047 *DmStatement, dm_build_1048 int16) *dm_build_1043 { + dm_build_1049 := new(dm_build_1043) + dm_build_1049.dm_build_750(dm_build_1046, Dm_build_626, dm_build_1047) + dm_build_1049.dm_build_1044 = dm_build_1048 + return dm_build_1049 +} + +func (dm_build_1051 *dm_build_1043) dm_build_727() error { + dm_build_1051.dm_build_742.dm_build_335.Dm_build_187(Dm_build_1042, dm_build_1051.dm_build_1044) + return nil +} + +func (dm_build_1053 *dm_build_1043) dm_build_731() (interface{}, error) { + return dm_build_1053.dm_build_841.dm_build_731() +} + +const ( + Dm_build_1054 = Dm_build_634 + Dm_build_1055 = Dm_build_1054 + USINT_SIZE +) + +type dm_build_1056 struct { + dm_build_841 + dm_build_1057 []parameter +} + +func dm_build_1058(dm_build_1059 *dm_build_332, dm_build_1060 *DmStatement, dm_build_1061 []parameter) *dm_build_1056 { + dm_build_1062 := new(dm_build_1056) + dm_build_1062.dm_build_750(dm_build_1059, Dm_build_630, dm_build_1060) + dm_build_1062.dm_build_1057 = dm_build_1061 + return dm_build_1062 +} + +func (dm_build_1064 *dm_build_1056) dm_build_727() error { + + if dm_build_1064.dm_build_1057 == nil { + dm_build_1064.dm_build_742.dm_build_335.Dm_build_187(Dm_build_1054, 0) + } else { + dm_build_1064.dm_build_742.dm_build_335.Dm_build_187(Dm_build_1054, int16(len(dm_build_1064.dm_build_1057))) + } + + dm_build_1064.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1055, 0) + + return dm_build_1064.dm_build_864(dm_build_1064.dm_build_1057) +} + +type dm_build_1065 struct { + dm_build_841 + dm_build_1066 bool + dm_build_1067 int16 +} + +func dm_build_1068(dm_build_1069 *dm_build_332, dm_build_1070 *DmStatement, dm_build_1071 bool, dm_build_1072 int16) *dm_build_1065 { + dm_build_1073 := new(dm_build_1065) + dm_build_1073.dm_build_750(dm_build_1069, Dm_build_610, dm_build_1070) + dm_build_1073.dm_build_1066 = dm_build_1071 + dm_build_1073.dm_build_1067 = dm_build_1072 + return dm_build_1073 +} + +func (dm_build_1075 *dm_build_1065) dm_build_727() error { + + dm_build_1076 := Dm_build_634 + + if dm_build_1075.dm_build_742.dm_build_336.autoCommit { + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 1) + } else { + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 0) + } + + if dm_build_1075.dm_build_1066 { + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 1) + } else { + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 0) + } + + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 0) + + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 1) + + if dm_build_1075.dm_build_742.dm_build_336.CompatibleOracle() { + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 0) + } else { + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 1) + } + + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_187(dm_build_1076, dm_build_1075.dm_build_1067) + + if dm_build_1075.dm_build_745.maxRows <= 0 || dm_build_1075.dm_build_742.dm_build_336.dmConnector.enRsCache { + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_195(dm_build_1076, INT64_MAX) + } else { + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_195(dm_build_1076, dm_build_1075.dm_build_745.maxRows) + } + + if dm_build_1075.dm_build_742.dm_build_336.dmConnector.isBdtaRS { + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, Dm_build_713) + } else { + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, Dm_build_712) + } + + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_187(dm_build_1076, 0) + + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 1) + + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 0) + + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 0) + + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_191(dm_build_1076, dm_build_1075.dm_build_745.queryTimeout) + + if dm_build_1075.dm_build_745.innerExec { + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 1) + } else { + dm_build_1076 += dm_build_1075.dm_build_742.dm_build_335.Dm_build_183(dm_build_1076, 0) + } + + dm_build_1075.dm_build_742.dm_build_335.Dm_build_113(dm_build_1075.dm_build_745.nativeSql, dm_build_1075.dm_build_742.dm_build_336.getServerEncoding(), dm_build_1075.dm_build_742.dm_build_336) + + return nil +} + +func (dm_build_1078 *dm_build_1065) dm_build_731() (interface{}, error) { + + if dm_build_1078.dm_build_1066 { + return dm_build_1078.dm_build_841.dm_build_731() + } + + dm_build_1079 := NewExceInfo() + dm_build_1080 := Dm_build_634 + + dm_build_1079.retSqlType = dm_build_1078.dm_build_742.dm_build_335.Dm_build_266(dm_build_1080) + dm_build_1080 += USINT_SIZE + + dm_build_1081 := dm_build_1078.dm_build_742.dm_build_335.Dm_build_284(dm_build_1080) + dm_build_1080 += USINT_SIZE + + dm_build_1082 := dm_build_1078.dm_build_742.dm_build_335.Dm_build_266(dm_build_1080) + dm_build_1080 += USINT_SIZE + + dm_build_1078.dm_build_742.dm_build_335.Dm_build_272(dm_build_1080) + dm_build_1080 += DDWORD_SIZE + + dm_build_1078.dm_build_742.dm_build_336.TrxStatus = dm_build_1078.dm_build_742.dm_build_335.Dm_build_269(dm_build_1080) + dm_build_1080 += ULINT_SIZE + + if dm_build_1081 > 0 { + dm_build_1078.dm_build_745.params = dm_build_1078.dm_build_1083(int(dm_build_1081)) + dm_build_1078.dm_build_745.paramCount = int32(dm_build_1081) + } else { + dm_build_1078.dm_build_745.params = make([]parameter, 0) + dm_build_1078.dm_build_745.paramCount = 0 + } + + if dm_build_1082 > 0 { + dm_build_1078.dm_build_745.columns = dm_build_1078.dm_build_891(int(dm_build_1082), dm_build_1079.rsBdta) + } else { + dm_build_1078.dm_build_745.columns = make([]column, 0) + } + + return dm_build_1079, nil +} + +func (dm_build_1084 *dm_build_1065) dm_build_1083(dm_build_1085 int) []parameter { + + var dm_build_1086, dm_build_1087, dm_build_1088, dm_build_1089 int16 + + dm_build_1090 := make([]parameter, dm_build_1085) + for i := 0; i < dm_build_1085; i++ { + + dm_build_1090[i].InitParameter() + + dm_build_1090[i].colType = dm_build_1084.dm_build_742.dm_build_335.Dm_build_125() + + dm_build_1090[i].prec = dm_build_1084.dm_build_742.dm_build_335.Dm_build_125() + + dm_build_1090[i].scale = dm_build_1084.dm_build_742.dm_build_335.Dm_build_125() + + dm_build_1090[i].nullable = dm_build_1084.dm_build_742.dm_build_335.Dm_build_125() != 0 + + itemFlag := dm_build_1084.dm_build_742.dm_build_335.Dm_build_122() + + if int(itemFlag)&Dm_build_840 != 0 { + dm_build_1090[i].typeFlag = TYPE_FLAG_RECOMMEND + } else { + dm_build_1090[i].typeFlag = TYPE_FLAG_EXACT + } + + dm_build_1090[i].lob = int(itemFlag)&Dm_build_838 != 0 + + dm_build_1084.dm_build_742.dm_build_335.Dm_build_125() + + dm_build_1090[i].ioType = byte(dm_build_1084.dm_build_742.dm_build_335.Dm_build_122()) + + dm_build_1086 = dm_build_1084.dm_build_742.dm_build_335.Dm_build_122() + + dm_build_1087 = dm_build_1084.dm_build_742.dm_build_335.Dm_build_122() + + dm_build_1088 = dm_build_1084.dm_build_742.dm_build_335.Dm_build_122() + + dm_build_1089 = dm_build_1084.dm_build_742.dm_build_335.Dm_build_122() + dm_build_1090[i].name = dm_build_1084.dm_build_742.dm_build_335.Dm_build_162(int(dm_build_1086), dm_build_1084.dm_build_742.dm_build_336.getServerEncoding(), dm_build_1084.dm_build_742.dm_build_336) + dm_build_1090[i].typeName = dm_build_1084.dm_build_742.dm_build_335.Dm_build_162(int(dm_build_1087), dm_build_1084.dm_build_742.dm_build_336.getServerEncoding(), dm_build_1084.dm_build_742.dm_build_336) + dm_build_1090[i].tableName = dm_build_1084.dm_build_742.dm_build_335.Dm_build_162(int(dm_build_1088), dm_build_1084.dm_build_742.dm_build_336.getServerEncoding(), dm_build_1084.dm_build_742.dm_build_336) + dm_build_1090[i].schemaName = dm_build_1084.dm_build_742.dm_build_335.Dm_build_162(int(dm_build_1089), dm_build_1084.dm_build_742.dm_build_336.getServerEncoding(), dm_build_1084.dm_build_742.dm_build_336) + + if dm_build_1090[i].lob { + dm_build_1090[i].lobTabId = dm_build_1084.dm_build_742.dm_build_335.Dm_build_125() + dm_build_1090[i].lobColId = dm_build_1084.dm_build_742.dm_build_335.Dm_build_122() + } + } + + for i := 0; i < dm_build_1085; i++ { + + if isComplexType(int(dm_build_1090[i].colType), int(dm_build_1090[i].scale)) { + + strDesc := newTypeDescriptor(dm_build_1084.dm_build_742.dm_build_336) + strDesc.unpack(dm_build_1084.dm_build_742.dm_build_335) + dm_build_1090[i].typeDescriptor = strDesc + } + } + + return dm_build_1090 +} + +const ( + Dm_build_1091 = Dm_build_634 +) + +type dm_build_1092 struct { + dm_build_741 + dm_build_1093 int16 + dm_build_1094 *Dm_build_1499 + dm_build_1095 int32 +} + +func dm_build_1096(dm_build_1097 *dm_build_332, dm_build_1098 *DmStatement, dm_build_1099 int16, dm_build_1100 *Dm_build_1499, dm_build_1101 int32) *dm_build_1092 { + dm_build_1102 := new(dm_build_1092) + dm_build_1102.dm_build_750(dm_build_1097, Dm_build_616, dm_build_1098) + dm_build_1102.dm_build_1093 = dm_build_1099 + dm_build_1102.dm_build_1094 = dm_build_1100 + dm_build_1102.dm_build_1095 = dm_build_1101 + return dm_build_1102 +} + +func (dm_build_1104 *dm_build_1092) dm_build_727() error { + dm_build_1104.dm_build_742.dm_build_335.Dm_build_187(Dm_build_1091, dm_build_1104.dm_build_1093) + + dm_build_1104.dm_build_742.dm_build_335.Dm_build_51(dm_build_1104.dm_build_1095) + + if dm_build_1104.dm_build_742.dm_build_336.NewLobFlag { + dm_build_1104.dm_build_742.dm_build_335.Dm_build_51(-1) + } + dm_build_1104.dm_build_1094.Dm_build_1506(dm_build_1104.dm_build_742.dm_build_335, int(dm_build_1104.dm_build_1095)) + return nil +} + +type dm_build_1105 struct { + dm_build_741 +} + +func dm_build_1106(dm_build_1107 *dm_build_332) *dm_build_1105 { + dm_build_1108 := new(dm_build_1105) + dm_build_1108.dm_build_746(dm_build_1107, Dm_build_614) + return dm_build_1108 +} + +type dm_build_1109 struct { + dm_build_741 + dm_build_1110 int32 +} + +func dm_build_1111(dm_build_1112 *dm_build_332, dm_build_1113 int32) *dm_build_1109 { + dm_build_1114 := new(dm_build_1109) + dm_build_1114.dm_build_746(dm_build_1112, Dm_build_627) + dm_build_1114.dm_build_1110 = dm_build_1113 + return dm_build_1114 +} + +func (dm_build_1116 *dm_build_1109) dm_build_727() error { + + dm_build_1117 := Dm_build_634 + dm_build_1117 += dm_build_1116.dm_build_742.dm_build_335.Dm_build_191(dm_build_1117, g2dbIsoLevel(dm_build_1116.dm_build_1110)) + return nil +} + +type dm_build_1118 struct { + dm_build_741 + dm_build_1119 *lob + dm_build_1120 byte + dm_build_1121 int + dm_build_1122 []byte + dm_build_1123 int + dm_build_1124 int +} + +func dm_build_1125(dm_build_1126 *dm_build_332, dm_build_1127 *lob, dm_build_1128 byte, dm_build_1129 int, dm_build_1130 []byte, + dm_build_1131 int, dm_build_1132 int) *dm_build_1118 { + dm_build_1133 := new(dm_build_1118) + dm_build_1133.dm_build_746(dm_build_1126, Dm_build_623) + dm_build_1133.dm_build_1119 = dm_build_1127 + dm_build_1133.dm_build_1120 = dm_build_1128 + dm_build_1133.dm_build_1121 = dm_build_1129 + dm_build_1133.dm_build_1122 = dm_build_1130 + dm_build_1133.dm_build_1123 = dm_build_1131 + dm_build_1133.dm_build_1124 = dm_build_1132 + return dm_build_1133 +} + +func (dm_build_1135 *dm_build_1118) dm_build_727() error { + + dm_build_1135.dm_build_742.dm_build_335.Dm_build_43(byte(dm_build_1135.dm_build_1119.lobFlag)) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_43(dm_build_1135.dm_build_1120) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_67(uint64(dm_build_1135.dm_build_1119.blobId)) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_47(dm_build_1135.dm_build_1119.groupId) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_47(dm_build_1135.dm_build_1119.fileId) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_51(dm_build_1135.dm_build_1119.pageNo) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_47(dm_build_1135.dm_build_1119.curFileId) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_51(dm_build_1135.dm_build_1119.curPageNo) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_51(dm_build_1135.dm_build_1119.totalOffset) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_51(dm_build_1135.dm_build_1119.tabId) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_47(dm_build_1135.dm_build_1119.colId) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_67(uint64(dm_build_1135.dm_build_1119.rowId)) + + dm_build_1135.dm_build_742.dm_build_335.Dm_build_51(int32(dm_build_1135.dm_build_1121)) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_51(int32(dm_build_1135.dm_build_1124)) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_79(dm_build_1135.dm_build_1122) + + if dm_build_1135.dm_build_742.dm_build_336.NewLobFlag { + dm_build_1135.dm_build_742.dm_build_335.Dm_build_47(dm_build_1135.dm_build_1119.exGroupId) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_47(dm_build_1135.dm_build_1119.exFileId) + dm_build_1135.dm_build_742.dm_build_335.Dm_build_51(dm_build_1135.dm_build_1119.exPageNo) + } + return nil +} + +func (dm_build_1137 *dm_build_1118) dm_build_731() (interface{}, error) { + + var dm_build_1138 = dm_build_1137.dm_build_742.dm_build_335.Dm_build_125() + dm_build_1137.dm_build_1119.blobId = dm_build_1137.dm_build_742.dm_build_335.Dm_build_128() + dm_build_1137.dm_build_1119.fileId = dm_build_1137.dm_build_742.dm_build_335.Dm_build_122() + dm_build_1137.dm_build_1119.pageNo = dm_build_1137.dm_build_742.dm_build_335.Dm_build_125() + dm_build_1137.dm_build_1119.curFileId = dm_build_1137.dm_build_742.dm_build_335.Dm_build_122() + dm_build_1137.dm_build_1119.curPageNo = dm_build_1137.dm_build_742.dm_build_335.Dm_build_125() + dm_build_1137.dm_build_1119.totalOffset = dm_build_1137.dm_build_742.dm_build_335.Dm_build_125() + return dm_build_1138, nil +} + +const ( + Dm_build_1139 = Dm_build_634 + + Dm_build_1140 = Dm_build_1139 + ULINT_SIZE + + Dm_build_1141 = Dm_build_1140 + ULINT_SIZE + + Dm_build_1142 = Dm_build_1141 + BYTE_SIZE + + Dm_build_1143 = Dm_build_1142 + BYTE_SIZE + + Dm_build_1144 = Dm_build_1143 + BYTE_SIZE + + Dm_build_1145 = Dm_build_1144 + BYTE_SIZE + + Dm_build_1146 = Dm_build_1145 + BYTE_SIZE + + Dm_build_1147 = Dm_build_1146 + BYTE_SIZE + + Dm_build_1148 = Dm_build_1147 + BYTE_SIZE + + Dm_build_1149 = Dm_build_634 + + Dm_build_1150 = Dm_build_1149 + ULINT_SIZE + + Dm_build_1151 = Dm_build_1150 + ULINT_SIZE + + Dm_build_1152 = Dm_build_1151 + ULINT_SIZE + + Dm_build_1153 = Dm_build_1152 + ULINT_SIZE + + Dm_build_1154 = Dm_build_1153 + ULINT_SIZE + + Dm_build_1155 = Dm_build_1154 + BYTE_SIZE + + Dm_build_1156 = Dm_build_1155 + BYTE_SIZE + + Dm_build_1157 = Dm_build_1156 + BYTE_SIZE + + Dm_build_1158 = Dm_build_1157 + BYTE_SIZE + + Dm_build_1159 = Dm_build_1158 + BYTE_SIZE + + Dm_build_1160 = Dm_build_1159 + USINT_SIZE + + Dm_build_1161 = Dm_build_1160 + BYTE_SIZE +) + +type dm_build_1162 struct { + dm_build_741 + dm_build_1163 *DmConnection + dm_build_1164 int + Dm_build_1165 int32 + Dm_build_1166 []byte + dm_build_1167 byte +} + +func dm_build_1168(dm_build_1169 *dm_build_332) *dm_build_1162 { + dm_build_1170 := new(dm_build_1162) + dm_build_1170.dm_build_746(dm_build_1169, Dm_build_632) + dm_build_1170.dm_build_1163 = dm_build_1169.dm_build_336 + return dm_build_1170 +} + +func dm_build_1171(dm_build_1172 string, dm_build_1173 string) int { + dm_build_1174 := strings.Split(dm_build_1172, ".") + dm_build_1175 := strings.Split(dm_build_1173, ".") + + for i, serStr := range dm_build_1174 { + ser, _ := strconv.ParseInt(serStr, 10, 32) + global, _ := strconv.ParseInt(dm_build_1175[i], 10, 32) + if ser < global { + return -1 + } else if ser == global { + continue + } else { + return 1 + } + } + + return 0 +} + +func (dm_build_1177 *dm_build_1162) dm_build_727() error { + + dm_build_1177.dm_build_742.dm_build_335.Dm_build_191(Dm_build_1139, int32(0)) + dm_build_1177.dm_build_742.dm_build_335.Dm_build_191(Dm_build_1140, int32(dm_build_1177.dm_build_1163.dmConnector.compress)) + + if dm_build_1177.dm_build_1163.dmConnector.loginEncrypt { + dm_build_1177.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1142, 2) + dm_build_1177.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1141, 1) + } else { + dm_build_1177.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1142, 0) + dm_build_1177.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1141, 0) + } + + if dm_build_1177.dm_build_1163.dmConnector.isBdtaRS { + dm_build_1177.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1143, Dm_build_713) + } else { + dm_build_1177.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1143, Dm_build_712) + } + + dm_build_1177.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1144, byte(dm_build_1177.dm_build_1163.dmConnector.compressID)) + + if dm_build_1177.dm_build_1163.dmConnector.loginCertificate != "" { + dm_build_1177.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1145, 1) + } else { + dm_build_1177.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1145, 0) + } + + dm_build_1177.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1146, 0) + dm_build_1177.dm_build_742.dm_build_335.Dm_build_183(Dm_build_1147, 1) + dm_build_1177.dm_build_742.dm_build_335.Dm_build_211(Dm_build_1148, uint16(dm_build_1177.dm_build_1163.MsgVersion)) + + dm_build_1178 := dm_build_1177.dm_build_1163.getServerEncoding() + dm_build_1177.dm_build_742.dm_build_335.Dm_build_95(Dm_build_597, dm_build_1178, dm_build_1177.dm_build_742.dm_build_336) + + var dm_build_1179 byte + if dm_build_1177.dm_build_1163.dmConnector.uKeyName != "" { + dm_build_1179 = 1 + } else { + dm_build_1179 = 0 + } + + dm_build_1177.dm_build_742.dm_build_335.Dm_build_43(0) + + if dm_build_1179 == 1 { + + } + + if dm_build_1177.dm_build_1163.dmConnector.loginEncrypt { + clientPubKey, err := dm_build_1177.dm_build_742.dm_build_577() + if err != nil { + return err + } + dm_build_1177.dm_build_742.dm_build_335.Dm_build_83(clientPubKey) + } + + return nil +} + +func (dm_build_1181 *dm_build_1162) dm_build_730() error { + dm_build_1181.dm_build_742.dm_build_335.Dm_build_17(0) + dm_build_1181.dm_build_742.dm_build_335.Dm_build_25(Dm_build_633, false, true) + return nil +} + +func (dm_build_1183 *dm_build_1162) dm_build_731() (interface{}, error) { + + dm_build_1183.dm_build_1163.sslEncrypt = int(dm_build_1183.dm_build_742.dm_build_335.Dm_build_269(Dm_build_1149)) + dm_build_1183.dm_build_1163.GlobalServerSeries = int(dm_build_1183.dm_build_742.dm_build_335.Dm_build_269(Dm_build_1150)) + + switch dm_build_1183.dm_build_742.dm_build_335.Dm_build_269(Dm_build_1151) { + case 1: + dm_build_1183.dm_build_1163.serverEncoding = ENCODING_UTF8 + case 2: + dm_build_1183.dm_build_1163.serverEncoding = ENCODING_EUCKR + default: + dm_build_1183.dm_build_1163.serverEncoding = ENCODING_GB18030 + } + + dm_build_1183.dm_build_1163.dmConnector.compress = int(dm_build_1183.dm_build_742.dm_build_335.Dm_build_269(Dm_build_1152)) + dm_build_1184 := dm_build_1183.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1154) + dm_build_1185 := dm_build_1183.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1155) + dm_build_1183.dm_build_1163.dmConnector.isBdtaRS = dm_build_1183.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1156) > 0 + dm_build_1183.dm_build_1163.dmConnector.compressID = int8(dm_build_1183.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1157)) + + dm_build_1183.dm_build_742.dm_build_341 = dm_build_1183.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1159) == 1 + dm_build_1183.dm_build_1163.dmConnector.newClientType = dm_build_1183.dm_build_742.dm_build_335.Dm_build_263(Dm_build_1160) == 1 + dm_build_1183.dm_build_1163.MsgVersion = int32(dm_build_1183.dm_build_742.dm_build_335.Dm_build_284(Dm_build_1161)) + + dm_build_1186 := dm_build_1183.dm_build_774() + if dm_build_1186 != nil { + return nil, dm_build_1186 + } + + dm_build_1187 := dm_build_1183.dm_build_742.dm_build_335.Dm_build_167(dm_build_1183.dm_build_1163.getServerEncoding(), dm_build_1183.dm_build_742.dm_build_336) + if dm_build_1171(dm_build_1187, Dm_build_598) < 0 { + return nil, ECGO_ERROR_SERVER_VERSION.throw() + } + + dm_build_1183.dm_build_1163.ServerVersion = dm_build_1187 + dm_build_1183.dm_build_1163.Malini2 = dm_build_1171(dm_build_1187, Dm_build_599) > 0 + dm_build_1183.dm_build_1163.Execute2 = dm_build_1171(dm_build_1187, Dm_build_600) > 0 + dm_build_1183.dm_build_1163.LobEmptyCompOrcl = dm_build_1171(dm_build_1187, Dm_build_601) > 0 + + if dm_build_1183.dm_build_742.dm_build_336.dmConnector.uKeyName != "" { + dm_build_1183.dm_build_1167 = 1 + } else { + dm_build_1183.dm_build_1167 = 0 + } + + if dm_build_1183.dm_build_1167 == 1 { + dm_build_1183.dm_build_742.dm_build_342 = dm_build_1183.dm_build_742.dm_build_335.Dm_build_162(16, dm_build_1183.dm_build_1163.getServerEncoding(), dm_build_1183.dm_build_742.dm_build_336) + } + + dm_build_1183.dm_build_1164 = -1 + dm_build_1188 := false + dm_build_1189 := false + dm_build_1183.Dm_build_1165 = -1 + if dm_build_1185 > 0 { + dm_build_1183.dm_build_1164 = int(dm_build_1183.dm_build_742.dm_build_335.Dm_build_125()) + } + + if dm_build_1184 > 0 { + + if dm_build_1183.dm_build_1164 == -1 { + dm_build_1188 = true + } else { + dm_build_1189 = true + } + + dm_build_1183.Dm_build_1166 = dm_build_1183.dm_build_742.dm_build_335.Dm_build_150() + } + + if dm_build_1185 == 2 { + dm_build_1183.Dm_build_1165 = dm_build_1183.dm_build_742.dm_build_335.Dm_build_125() + } + dm_build_1183.dm_build_742.dm_build_338 = dm_build_1188 + dm_build_1183.dm_build_742.dm_build_339 = dm_build_1189 + + return nil, nil +} + +type dm_build_1190 struct { + dm_build_741 +} + +func dm_build_1191(dm_build_1192 *dm_build_332, dm_build_1193 *DmStatement) *dm_build_1190 { + dm_build_1194 := new(dm_build_1190) + dm_build_1194.dm_build_750(dm_build_1192, Dm_build_608, dm_build_1193) + return dm_build_1194 +} + +func (dm_build_1196 *dm_build_1190) dm_build_727() error { + + dm_build_1196.dm_build_742.dm_build_335.Dm_build_183(Dm_build_634, 1) + return nil +} + +func (dm_build_1198 *dm_build_1190) dm_build_731() (interface{}, error) { + + dm_build_1198.dm_build_745.id = dm_build_1198.dm_build_742.dm_build_335.Dm_build_269(Dm_build_635) + + dm_build_1198.dm_build_745.readBaseColName = dm_build_1198.dm_build_742.dm_build_335.Dm_build_263(Dm_build_634) == 1 + return nil, nil +} + +type dm_build_1199 struct { + dm_build_741 + dm_build_1200 int32 +} + +func dm_build_1201(dm_build_1202 *dm_build_332, dm_build_1203 int32) *dm_build_1199 { + dm_build_1204 := new(dm_build_1199) + dm_build_1204.dm_build_746(dm_build_1202, Dm_build_609) + dm_build_1204.dm_build_1200 = dm_build_1203 + return dm_build_1204 +} + +func (dm_build_1206 *dm_build_1199) dm_build_728() { + dm_build_1206.dm_build_741.dm_build_728() + dm_build_1206.dm_build_742.dm_build_335.Dm_build_191(Dm_build_635, dm_build_1206.dm_build_1200) +} + +type dm_build_1207 struct { + dm_build_741 + dm_build_1208 []uint32 +} + +func dm_build_1209(dm_build_1210 *dm_build_332, dm_build_1211 []uint32) *dm_build_1207 { + dm_build_1212 := new(dm_build_1207) + dm_build_1212.dm_build_746(dm_build_1210, Dm_build_629) + dm_build_1212.dm_build_1208 = dm_build_1211 + return dm_build_1212 +} + +func (dm_build_1214 *dm_build_1207) dm_build_727() error { + + dm_build_1214.dm_build_742.dm_build_335.Dm_build_211(Dm_build_634, uint16(len(dm_build_1214.dm_build_1208))) + + for _, tableID := range dm_build_1214.dm_build_1208 { + dm_build_1214.dm_build_742.dm_build_335.Dm_build_63(uint32(tableID)) + } + + return nil +} + +func (dm_build_1216 *dm_build_1207) dm_build_731() (interface{}, error) { + dm_build_1217 := dm_build_1216.dm_build_742.dm_build_335.Dm_build_284(Dm_build_634) + if dm_build_1217 <= 0 { + return nil, nil + } + + dm_build_1218 := make([]int64, dm_build_1217) + for i := 0; i < int(dm_build_1217); i++ { + dm_build_1218[i] = dm_build_1216.dm_build_742.dm_build_335.Dm_build_128() + } + + return dm_build_1218, nil +} diff --git a/dmr/zr.go b/dmr/zr.go new file mode 100644 index 0000000..2dccf4e --- /dev/null +++ b/dmr/zr.go @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "io" +) + +const ( + READ_LEN = Dm_build_717 +) + +type iOffRowBinder interface { + read(buf *Dm_build_1499) + isReadOver() bool + getObj() interface{} +} + +type offRowBinder struct { + obj interface{} + encoding string + readOver bool + buffer *Dm_build_1499 + position int32 + offRow bool + targetLength int64 +} + +func newOffRowBinder(obj interface{}, encoding string, targetLength int64) *offRowBinder { + return &offRowBinder{ + obj: obj, + encoding: encoding, + targetLength: targetLength, + readOver: false, + buffer: Dm_build_1503(), + position: 0, + } +} + +type offRowBytesBinder struct { + *offRowBinder +} + +func newOffRowBytesBinder(obj []byte, encoding string) *offRowBytesBinder { + var binder = &offRowBytesBinder{ + newOffRowBinder(obj, encoding, int64(IGNORE_TARGET_LENGTH)), + } + binder.read(binder.buffer) + binder.offRow = binder.buffer.Dm_build_1504() > Dm_build_714 + return binder +} + +func (b *offRowBytesBinder) read(buf *Dm_build_1499) { + if b.buffer.Dm_build_1504() > 0 { + buf.Dm_build_1536(b.buffer) + } else if !b.readOver { + var obj = b.obj.([]byte) + buf.Dm_build_1525(obj, 0, len(obj)) + b.readOver = true + } +} + +func (b *offRowBytesBinder) isReadOver() bool { + return b.readOver +} + +func (b *offRowBytesBinder) getObj() interface{} { + return b.obj +} + +type offRowBlobBinder struct { + *offRowBinder +} + +func newOffRowBlobBinder(blob DmBlob, encoding string) *offRowBlobBinder { + var binder = &offRowBlobBinder{ + newOffRowBinder(blob, encoding, int64(IGNORE_TARGET_LENGTH)), + } + binder.read(binder.buffer) + binder.offRow = binder.buffer.Dm_build_1504() > Dm_build_714 + return binder +} + +func (b *offRowBlobBinder) read(buf *Dm_build_1499) { + if b.buffer.Dm_build_1504() > 0 { + buf.Dm_build_1536(b.buffer) + } else if !b.readOver { + var obj = b.obj.(DmBlob) + var totalLen, _ = obj.GetLength() + var leaveLen = totalLen - int64(b.position) + var readLen = int32(leaveLen) + if leaveLen > READ_LEN { + readLen = READ_LEN + } + var bytes, _ = obj.getBytes(int64(b.position)+1, readLen) + b.position += readLen + if b.position == int32(totalLen) { + b.readOver = true + } + buf.Dm_build_1525(bytes, 0, len(bytes)) + } +} + +func (b *offRowBlobBinder) isReadOver() bool { + return b.readOver +} + +func (b *offRowBlobBinder) getObj() interface{} { + return b.obj +} + +type offRowClobBinder struct { + *offRowBinder +} + +func newOffRowClobBinder(clob DmClob, encoding string) *offRowClobBinder { + var binder = &offRowClobBinder{ + newOffRowBinder(clob, encoding, int64(IGNORE_TARGET_LENGTH)), + } + binder.read(binder.buffer) + binder.offRow = binder.buffer.Dm_build_1504() > Dm_build_714 + return binder +} + +func (b *offRowClobBinder) read(buf *Dm_build_1499) { + if b.buffer.Dm_build_1504() > 0 { + buf.Dm_build_1536(b.buffer) + } else if !b.readOver { + var obj = b.obj.(DmClob) + var totalLen, _ = obj.GetLength() + var leaveLen = totalLen - int64(b.position) + var readLen = int32(leaveLen) + if leaveLen > READ_LEN { + readLen = READ_LEN + } + var str, _ = obj.getSubString(int64(b.position)+1, readLen) + var bytes = Dm_build_1220.Dm_build_1433(str, b.encoding, nil) + b.position += readLen + if b.position == int32(totalLen) { + b.readOver = true + } + buf.Dm_build_1525(bytes, 0, len(bytes)) + } +} + +func (b *offRowClobBinder) isReadOver() bool { + return b.readOver +} + +func (b *offRowClobBinder) getObj() interface{} { + return b.obj +} + +type offRowReaderBinder struct { + *offRowBinder +} + +func newOffRowReaderBinder(reader io.Reader, encoding string) *offRowReaderBinder { + var binder = &offRowReaderBinder{ + newOffRowBinder(reader, encoding, int64(IGNORE_TARGET_LENGTH)), + } + binder.read(binder.buffer) + binder.offRow = binder.buffer.Dm_build_1504() > Dm_build_714 + return binder +} + +func (b *offRowReaderBinder) read(buf *Dm_build_1499) { + if b.buffer.Dm_build_1504() > 0 { + buf.Dm_build_1536(b.buffer) + } else if !b.readOver { + var err error + var readLen = READ_LEN + var reader = b.obj.(io.Reader) + var bytes = make([]byte, readLen) + readLen, err = reader.Read(bytes) + if err == io.EOF { + b.readOver = true + return + } + b.position += int32(readLen) + if readLen < len(bytes) || b.targetLength != int64(IGNORE_TARGET_LENGTH) && int64(b.position) == b.targetLength { + b.readOver = true + } + buf.Dm_build_1525(bytes[0:readLen], 0, readLen) + } +} + +func (b *offRowReaderBinder) readAll() []byte { + var byteArray = Dm_build_1503() + b.read(byteArray) + for !b.readOver { + b.read(byteArray) + } + return byteArray.Dm_build_1546() +} + +func (b *offRowReaderBinder) isReadOver() bool { + return b.readOver +} + +func (b *offRowReaderBinder) getObj() interface{} { + return b.obj +} diff --git a/dmr/zs.go b/dmr/zs.go new file mode 100644 index 0000000..4dd2e71 --- /dev/null +++ b/dmr/zs.go @@ -0,0 +1,868 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "fmt" + "math" + "strconv" + "strings" + "time" + "unicode" + "unicode/utf8" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +type oracleDateFormat struct { + PM bool + TZNegative bool + pattern string + language int + FormatElementList []interface{} + YearElement yearElement + MonthElement monthElement + MonElement monElement + MMElement mmElement + DDElement ddElement + HH24Element hh24Element + HH12Element hh12Element + MIElement miElement + SSElement ssElement + FElement fElement + TZHElement tzhElement + TZMElement tzmElement + AMElement amElement +} + +type element interface { + /** + * 从字符串中解析出对应的值, + * @param str 完整的字符串 + * @param offset 当前偏移 + * @return 解析后的offset + */ + parse(str string, offset int, dt []int) (int, error) + + /** + * 将时间值value格式化成字符串 + */ + format(dt []int) string +} + +type yearElement struct { + OracleDateFormat *oracleDateFormat + len int +} + +func (YearElement yearElement) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+YearElement.len && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + if YearElement.len < 4 { + today := strconv.FormatInt(int64(dt[OFFSET_YEAR]), 10) + i, err := strconv.ParseInt(today[:4-YearElement.len]+str, 10, 32) + if err != nil { + return 0, err + } + dt[OFFSET_YEAR] = int(i) + } else { + i, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return 0, err + } + dt[OFFSET_YEAR] = int(i) + } + + return offset + strLen, nil +} + +func (YearElement yearElement) format(dt []int) string { + return YearElement.OracleDateFormat.formatInt(dt[OFFSET_YEAR], YearElement.len) +} + +type monthElement struct { + OracleDateFormat *oracleDateFormat + upperCase bool + lowerCase bool +} + +var monthNameList = []string{"", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} + +func (MonthElement monthElement) parse(str string, offset int, dt []int) (int, error) { + + if MonthElement.OracleDateFormat.language == LANGUAGE_CN { + index := strings.IndexRune(str[offset:], '月') + if index == -1 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + index += offset + + mon, err := strconv.ParseInt(str[offset:index], 10, 32) + if err != nil { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + + if mon > 12 || mon < 1 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_MONTH] = int(mon) + return index + utf8.RuneLen('月'), nil + } else { + str = str[offset:] + mon := 0 + for i := 1; i < len(monthNameList); i++ { + if util.StringUtil.StartWithIgnoreCase(str, monthNameList[i]) { + mon = i + break + } + } + if mon == 0 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + dt[OFFSET_MONTH] = mon + return offset + len(monthNameList[mon]), nil + } +} + +func (MonthElement monthElement) format(dt []int) string { + value := dt[OFFSET_MONTH] + + if MonthElement.OracleDateFormat.language == LANGUAGE_CN { + return strconv.FormatInt(int64(value), 10) + "月" + } + + if MonthElement.upperCase { + return strings.ToUpper(monthNameList[value]) + } else if MonthElement.lowerCase { + return strings.ToLower(monthNameList[value]) + } else { + return monthNameList[value] + } + +} + +type monElement struct { + OracleDateFormat *oracleDateFormat + upperCase bool + lowerCase bool +} + +var monNameList []string = []string{"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} + +func (MonElement monElement) parse(str string, offset int, dt []int) (int, error) { + + if MonElement.OracleDateFormat.language == LANGUAGE_CN { + index := strings.IndexRune(str[offset:], '月') + offset + if index == -1+offset { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + + mon, err := strconv.ParseInt(str[offset:index], 10, 32) + if err != nil { + return -1, err + } + + if mon > 12 || mon < 1 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_MONTH] = int(mon) + return index + utf8.RuneLen('月'), nil + } else { + str = str[offset : offset+3] + mon := 0 + for i := 1; i < len(monNameList); i++ { + if util.StringUtil.EqualsIgnoreCase(str, monNameList[i]) { + mon = i + break + } + } + if mon == 0 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + dt[OFFSET_MONTH] = mon + return offset + 3, nil + } + +} + +func (MonElement monElement) format(dt []int) string { + value := dt[OFFSET_MONTH] + language := int(0) + if language == LANGUAGE_CN { + return strconv.FormatInt(int64(value), 10) + "月" + } + + if MonElement.upperCase { + return strings.ToUpper(monNameList[value]) + } else if MonElement.lowerCase { + return strings.ToLower(monNameList[value]) + } else { + return monNameList[value] + } +} + +type mmElement struct { + OracleDateFormat *oracleDateFormat +} + +func (MMElement mmElement) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + month, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + + if month > 12 || month < 1 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_MONTH] = int(month) + return offset + strLen, nil +} + +func (MMElement mmElement) format(dt []int) string { + return MMElement.OracleDateFormat.formatInt(dt[OFFSET_MONTH], 2) +} + +type ddElement struct { + OracleDateFormat *oracleDateFormat +} + +func (DDElement ddElement) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + day, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if day > 31 || day < 1 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_DAY] = int(day) + return offset + strLen, nil +} + +func (DDElement ddElement) format(dt []int) string { + return DDElement.OracleDateFormat.formatInt(dt[OFFSET_DAY], 2) +} + +type hh24Element struct { + OracleDateFormat *oracleDateFormat +} + +func (HH24Element hh24Element) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + hour, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if hour > 23 || hour < 0 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_HOUR] = int(hour) // 0-23 + return offset + strLen, nil +} + +func (HH24Element hh24Element) format(dt []int) string { + return HH24Element.OracleDateFormat.formatInt(dt[OFFSET_HOUR], 2) // 0-23 +} + +type hh12Element struct { + OracleDateFormat *oracleDateFormat +} + +func (HH12Element hh12Element) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + hour, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if hour > 12 || hour < 1 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_HOUR] = int(hour) + return offset + strLen, nil +} + +func (HH12Element hh12Element) format(dt []int) string { + var ret string + value := dt[OFFSET_HOUR] + if value > 12 || value == 0 { + ret = HH12Element.OracleDateFormat.formatInt(int(math.Abs(float64(value-12))), 2) // 1-12 + } else { + ret = HH12Element.OracleDateFormat.formatInt(value, 2) + } + return ret +} + +type miElement struct { + OracleDateFormat *oracleDateFormat +} + +func (MIElement miElement) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + minute, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if minute > 59 || minute < 0 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_MINUTE] = int(minute) // 0-59 + return offset + strLen, nil +} + +func (MIElement miElement) format(dt []int) string { + return MIElement.OracleDateFormat.formatInt(dt[OFFSET_MINUTE], 2) // 0-59 +} + +type ssElement struct { + OracleDateFormat *oracleDateFormat +} + +func (SSElement ssElement) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + second, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if second > 59 || second < 0 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_SECOND] = int(second) // 0-59 + return offset + strLen, nil +} + +func (SSElement ssElement) format(dt []int) string { + return SSElement.OracleDateFormat.formatInt(dt[OFFSET_SECOND], 2) // 0-59 +} + +type fElement struct { + OracleDateFormat *oracleDateFormat + len int +} + +func (FElement fElement) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+FElement.len && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + ms, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if strLen < 6 { + ms *= int64(math.Pow10(6 - strLen)) + } else { + ms /= int64(math.Pow10(strLen - 6)) + } + + dt[OFFSET_MILLISECOND] = int(ms) + return offset + strLen, nil +} + +func (FElement fElement) format(dt []int) string { + return FElement.OracleDateFormat.formatMilliSecond(dt[OFFSET_MILLISECOND], FElement.len) +} + +type tzhElement struct { + OracleDateFormat *oracleDateFormat +} + +func (TZHElement tzhElement) parse(str string, offset int, dt []int) (int, error) { + if str[offset] == '+' { + offset += 1 + } else if str[offset] == '-' { + offset += 1 + TZHElement.OracleDateFormat.TZNegative = true + } + + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + + tzh, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if tzh > 23 || tzh < 0 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + + tzh *= 60 + if dt[OFFSET_TIMEZONE] == int(INVALID_VALUE) { + dt[OFFSET_TIMEZONE] = int(tzh) + } else { + dt[OFFSET_TIMEZONE] += int(tzh) + } + + return offset + strLen, nil +} + +func (TZHElement tzhElement) format(dt []int) string { + var value int + if dt[OFFSET_TIMEZONE] != int(INVALID_VALUE) { + value = int(math.Abs(float64(dt[OFFSET_TIMEZONE]))) / 60 + } else { + value = 0 + } + + return TZHElement.OracleDateFormat.formatInt(value, 2) +} + +type tzmElement struct { + OracleDateFormat *oracleDateFormat +} + +func (TZMElement tzmElement) parse(str string, offset int, dt []int) (int, error) { + if str[offset] == '+' { + offset += 1 + } else if str[offset] == '-' { + offset += 1 + TZMElement.OracleDateFormat.TZNegative = true + } + + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + + tzm, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + if tzm > 59 || tzm < 0 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + + if dt[OFFSET_TIMEZONE] == INVALID_VALUE { + dt[OFFSET_TIMEZONE] = int(tzm) + } else { + dt[OFFSET_TIMEZONE] += int(tzm) + } + return offset + strLen, nil +} + +func (TZMElement tzmElement) format(dt []int) string { + var value int + if dt[OFFSET_TIMEZONE] != int(INVALID_VALUE) { + value = int(math.Abs(float64(dt[OFFSET_TIMEZONE]))) % 60 + } else { + value = 0 + } + + return TZMElement.OracleDateFormat.formatInt(value, 2) +} + +type amElement struct { + OracleDateFormat *oracleDateFormat +} + +func (AMElement amElement) parse(str string, offset int, dt []int) (int, error) { + runeStr := ([]rune(str))[offset : offset+2] + + if AMElement.OracleDateFormat.language == LANGUAGE_CN { + if util.StringUtil.EqualsIgnoreCase("下午", string(runeStr)) { + AMElement.OracleDateFormat.PM = true + return offset + utf8.RuneLen('下') + utf8.RuneLen('午'), nil + } else { + AMElement.OracleDateFormat.PM = false + return offset + utf8.RuneLen('上') + utf8.RuneLen('午'), nil + } + + } else if util.StringUtil.EqualsIgnoreCase("PM", string(runeStr)) { + AMElement.OracleDateFormat.PM = true + } else { + AMElement.OracleDateFormat.PM = false + } + + return offset + 2, nil +} + +func (AMElement amElement) format(dt []int) string { + hour := dt[OFFSET_HOUR] + language := int(0) + if language == LANGUAGE_CN { + if hour > 12 { + return "下午" + } else { + return "上午" + } + } + + if hour > 12 { + return "PM" + } else { + return "AM" + } +} + +/** + * 将int值格式化成指定长度,长度不足前面补0,长度超过的取末尾指定长度 + */ +func (OracleDateFormat *oracleDateFormat) formatInt(value int, len int) string { + pow := int(math.Pow10(len)) + if value >= pow { + value %= pow + } + value += pow + return strconv.FormatInt(int64(value), 10)[1:] +} + +/** + * 格式化毫秒值 + * @param ms + * @param len <= 6 + */ +func (OracleDateFormat *oracleDateFormat) formatMilliSecond(ms int, len int) string { + var ret string + if ms < 10 { + ret = "00000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 100 { + ret = "0000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 1000 { + ret = "000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 10000 { + ret = "00" + strconv.FormatInt(int64(ms), 10) + } else if ms < 100000 { + ret = "0" + strconv.FormatInt(int64(ms), 10) + } else { + ret = strconv.FormatInt(int64(ms), 10) + } + + if len < 6 { + ret = ret[:len] + } + return ret +} + +func getFormat() *oracleDateFormat { + format := new(oracleDateFormat) + format.PM = false + format.TZNegative = false + format.YearElement = yearElement{format, 4} + format.MonthElement = monthElement{format, false, false} + format.MonElement = monElement{format, false, false} + format.MMElement = mmElement{format} + format.DDElement = ddElement{format} + format.HH24Element = hh24Element{format} + format.HH12Element = hh12Element{format} + format.MIElement = miElement{format} + format.SSElement = ssElement{format} + format.FElement = fElement{format, 6} + format.TZHElement = tzhElement{format} + format.TZMElement = tzmElement{format} + format.AMElement = amElement{format} + + return format +} + +func (OracleDateFormat *oracleDateFormat) parse(str string) (ret []int, err error) { + defer func() { + if p := recover(); p != nil { + err = ECGO_INVALID_DATETIME_FORMAT.throw() + } + }() + OracleDateFormat.TZNegative = false + OracleDateFormat.PM = false + dt := make([]int, DT_LEN) + // oracle默认年月日为 当前时间 + today := time.Now() + dt[OFFSET_YEAR] = today.Year() + dt[OFFSET_MONTH] = int(today.Month()) + dt[OFFSET_DAY] = today.Day() + dt[OFFSET_TIMEZONE] = INVALID_VALUE + offset := 0 + str = strings.TrimSpace(str) + for _, obj := range OracleDateFormat.FormatElementList { + // 跳过空格 + for str[offset] == ' ' && fmt.Sprintf("%+v", obj) != " " { + offset++ + } + if e, ok := obj.(element); ok { + offset, err = e.parse(str, offset, dt) + if err != nil { + return nil, err + } + } else { + offset += len(obj.(string)) + } + } + if offset < len(str) { + //[6103]:文字与格式字符串不匹配. + return nil, ECGO_INVALID_DATETIME_VALUE.throw() + } + + // 12小时制时间转换 + if OracleDateFormat.PM { + dt[OFFSET_HOUR] = (dt[OFFSET_HOUR] + 12) % 24 + } + + // 时区符号保留 + if OracleDateFormat.TZNegative { + dt[OFFSET_TIMEZONE] = -dt[OFFSET_TIMEZONE] + } + + // check day + if dt[OFFSET_DAY] > getDaysOfMonth(dt[OFFSET_YEAR], dt[OFFSET_MONTH]) || dt[OFFSET_DAY] < 1 { + return nil, ECGO_INVALID_DATETIME_VALUE.throw() + } + // check timezone 兼容oracle + if dt[OFFSET_TIMEZONE] != INVALID_VALUE && (dt[OFFSET_TIMEZONE] > 14*60 || dt[OFFSET_TIMEZONE] <= -13*60) { + return nil, ECGO_INVALID_DATETIME_VALUE.throw() + } + return dt, nil +} + +func parse(str string, pattern string, language int) ([]int, error) { + f := getFormat() + f.setPattern(pattern) + f.language = language + return f.parse(str) +} + +func (OracleDateFormat *oracleDateFormat) setPattern(pattern string) { + if pattern != OracleDateFormat.pattern { + OracleDateFormat.pattern = pattern + OracleDateFormat.FormatElementList = OracleDateFormat.FormatElementList[:0] + OracleDateFormat.analysePattern(pattern) + } +} + +func format(dt []int, pattern string, language int) string { + f := getFormat() + f.setPattern(pattern) + f.language = language + ret := f.format(dt) + return ret +} + +func (OracleDateFormat *oracleDateFormat) format(dt []int) string { + sf := strings.Builder{} + tzStart := false + for _, obj := range OracleDateFormat.FormatElementList { + _, ok1 := obj.(tzhElement) + _, ok2 := obj.(tzmElement) + if !tzStart && (ok1 || ok2) { + tzStart = true + if dt[OFFSET_TIMEZONE] < 0 { + sf.WriteString("-") + } else { + sf.WriteString("+") + } + } + + if e, ok := obj.(element); ok { + sf.WriteString(e.format(dt)) + } else { + sf.WriteString(obj.(string)) + } + } + return sf.String() +} + +/** + * 解析格式串 + */ +func (OracleDateFormat *oracleDateFormat) analysePattern(pattern string) ([]interface{}, error) { + + // 按分隔符split + pattern = strings.TrimSpace(pattern) + l := len(pattern) + var splitPatterns []string + starti := 0 + var curChar rune + for i := 0; i < l; i++ { + curChar = rune(pattern[i]) + if !unicode.IsDigit(curChar) && !unicode.IsLetter(curChar) { + if i > starti { + splitPatterns = append(splitPatterns, pattern[starti:i]) + } + + splitPatterns = append(splitPatterns, string(curChar)) + starti = i + 1 + } else if i == l-1 { + splitPatterns = append(splitPatterns, pattern[starti:i+1]) + } + } + + // 每个串按照从完整串,然后依次去掉一个末尾字符 来进行尝试规约 + for _, subPattern := range splitPatterns { + if len(subPattern) != 1 || unicode.IsDigit(rune(subPattern[0])) || unicode.IsLetter(rune(subPattern[0])) { + fmtWord := subPattern + for subPattern != "" { + i := len(subPattern) + for ; i > 0; i-- { + fmtWord = subPattern[0:i] + element, err := OracleDateFormat.getFormatElement(fmtWord) + if err != nil { + return nil, err + } + if element != nil { + // 忽略时区前面的+-号 + if element == OracleDateFormat.TZHElement || element == OracleDateFormat.TZMElement { + var lastFormatElement string = OracleDateFormat.FormatElementList[len(OracleDateFormat.FormatElementList)-1].(string) + if util.StringUtil.Equals("+", lastFormatElement) || util.StringUtil.Equals("-", lastFormatElement) { + OracleDateFormat.FormatElementList = OracleDateFormat.FormatElementList[:len(OracleDateFormat.FormatElementList)-2] + } + } + OracleDateFormat.FormatElementList = append(OracleDateFormat.FormatElementList, element) + if i == len(subPattern) { + subPattern = "" + } else { + subPattern = subPattern[i:len(subPattern)] + } + break + } + } + + if i == 0 { + // 非标识符串 + OracleDateFormat.FormatElementList = append(OracleDateFormat.FormatElementList, subPattern) + break + } + } + + } else { + OracleDateFormat.FormatElementList = append(OracleDateFormat.FormatElementList, subPattern) + } + } + return OracleDateFormat.FormatElementList, nil +} + +func (OracleDateFormat *oracleDateFormat) getFormatElement(word string) (element, error) { + if util.StringUtil.EqualsIgnoreCase("HH", word) || util.StringUtil.EqualsIgnoreCase("HH12", word) { + return OracleDateFormat.HH12Element, nil + } else if util.StringUtil.EqualsIgnoreCase("HH24", word) { + return OracleDateFormat.HH24Element, nil + } else if util.StringUtil.EqualsIgnoreCase("MI", word) { + return OracleDateFormat.MIElement, nil + } else if util.StringUtil.EqualsIgnoreCase("SS", word) { + return OracleDateFormat.SSElement, nil + } else if util.StringUtil.EqualsIgnoreCase("AM", word) || util.StringUtil.EqualsIgnoreCase("A.M.", word) || util.StringUtil.EqualsIgnoreCase("PM", word) || util.StringUtil.EqualsIgnoreCase("P.M.", word) { + return OracleDateFormat.AMElement, nil + } else if util.StringUtil.Equals("MONTH", word) { + OracleDateFormat.MonthElement.upperCase = true + OracleDateFormat.MonthElement.lowerCase = false + return OracleDateFormat.MonthElement, nil + } else if util.StringUtil.Equals("month", word) { + OracleDateFormat.MonthElement.upperCase = false + OracleDateFormat.MonthElement.lowerCase = true + return OracleDateFormat.MonthElement, nil + } else if util.StringUtil.EqualsIgnoreCase("Month", word) { + OracleDateFormat.MonthElement.upperCase = false + OracleDateFormat.MonthElement.lowerCase = false + return OracleDateFormat.MonthElement, nil + } else if util.StringUtil.Equals("MON", word) { + OracleDateFormat.MonElement.upperCase = true + OracleDateFormat.MonElement.lowerCase = false + return OracleDateFormat.MonElement, nil + } else if util.StringUtil.Equals("mon", word) { + OracleDateFormat.MonElement.upperCase = false + OracleDateFormat.MonElement.lowerCase = true + return OracleDateFormat.MonElement, nil + } else if util.StringUtil.EqualsIgnoreCase("Mon", word) { + OracleDateFormat.MonElement.upperCase = false + OracleDateFormat.MonElement.lowerCase = false + return OracleDateFormat.MonElement, nil + } else if util.StringUtil.EqualsIgnoreCase("MM", word) { + return OracleDateFormat.MMElement, nil + } else if util.StringUtil.EqualsIgnoreCase("DD", word) { + return OracleDateFormat.DDElement, nil + } else if util.StringUtil.EqualsIgnoreCase("TZH", word) { + return OracleDateFormat.TZHElement, nil + } else if util.StringUtil.EqualsIgnoreCase("TZM", word) { + return OracleDateFormat.TZMElement, nil + } else if strings.Index(word, "Y") == 0 || strings.Index(word, "y") == 0 { + OracleDateFormat.YearElement.len = len(word) + return OracleDateFormat.YearElement, nil + } else if strings.Index(word, "F") == 0 || strings.Index(word, "f") == 0 { + + word = strings.ToUpper(word) + numIndex := strings.LastIndex(word, "F") + 1 + var count int64 + var err error + if numIndex < len(word) { + count, err = strconv.ParseInt(word[numIndex:len(word)], 10, 32) + if err != nil { + return nil, err + } + } else { + count = 9 + } + + OracleDateFormat.FElement.len = int(count) + return OracleDateFormat.FElement, nil + } + + return nil, nil +} diff --git a/dmr/zv.go b/dmr/zv.go new file mode 100644 index 0000000..9597cde --- /dev/null +++ b/dmr/zv.go @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "strconv" + "strings" +) + +type Properties struct { + innerProps map[string]string +} + +func NewProperties() *Properties { + p := Properties{ + innerProps: make(map[string]string, 50), + } + return &p +} + +func (g *Properties) SetProperties(p *Properties) { + if p == nil { + return + } + for k, v := range p.innerProps { + g.Set(strings.ToLower(k), v) + } +} + +func (g *Properties) Len() int { + return len(g.innerProps) +} + +func (g *Properties) IsNil() bool { + return g == nil || g.innerProps == nil +} + +func (g *Properties) GetString(key, def string) string { + v, ok := g.innerProps[strings.ToLower(key)] + + if !ok || v == "" { + return def + } + return v +} + +func (g *Properties) GetInt(key string, def int, min int, max int) int { + value, ok := g.innerProps[strings.ToLower(key)] + if !ok || value == "" { + return def + } + + i, err := strconv.Atoi(value) + if err != nil { + return def + } + + if i > max || i < min { + return def + } + return i +} + +func (g *Properties) GetBool(key string, def bool) bool { + value, ok := g.innerProps[strings.ToLower(key)] + if !ok || value == "" { + return def + } + b, err := strconv.ParseBool(value) + if err != nil { + return def + } + return b +} + +func (g *Properties) GetTrimString(key string, def string) string { + value, ok := g.innerProps[strings.ToLower(key)] + if !ok || value == "" { + return def + } else { + return strings.TrimSpace(value) + } +} + +func (g *Properties) GetStringArray(key string, def []string) []string { + value, ok := g.innerProps[strings.ToLower(key)] + if ok || value != "" { + array := strings.Split(value, ",") + if len(array) > 0 { + return array + } + } + return def +} + +//func (g *Properties) GetBool(key string) bool { +// i, _ := strconv.ParseBool(g.innerProps[key]) +// return i +//} + +func (g *Properties) Set(key, value string) { + g.innerProps[strings.ToLower(key)] = value +} + +func (g *Properties) SetIfNotExist(key, value string) { + if _, ok := g.innerProps[strings.ToLower(key)]; !ok { + g.Set(key, value) + } +} + +// 如果p有g没有的键值对,添加进g中 +func (g *Properties) SetDiffProperties(p *Properties) { + if p == nil { + return + } + for k, v := range p.innerProps { + if _, ok := g.innerProps[strings.ToLower(k)]; !ok { + g.innerProps[strings.ToLower(k)] = v + } + } +} diff --git a/dmr/zw.go b/dmr/zw.go new file mode 100644 index 0000000..8048ed5 --- /dev/null +++ b/dmr/zw.go @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "math/rand" + "strconv" + "time" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +var rwMap = make(map[string]*rwCounter) + +type rwCounter struct { + ntrx_primary int64 + + ntrx_total int64 + + primaryPercent float64 + + standbyPercent float64 + + standbyNTrxMap map[string]int64 + + standbyIdMap map[string]int32 + + standbyCount int32 + + flag []int32 + + increments []int32 +} + +func newRWCounter(primaryPercent int32, standbyCount int32) *rwCounter { + rwc := new(rwCounter) + rwc.standbyNTrxMap = make(map[string]int64) + rwc.standbyIdMap = make(map[string]int32) + rwc.reset(primaryPercent, standbyCount) + return rwc +} + +func (rwc *rwCounter) reset(primaryPercent int32, standbyCount int32) { + rwc.ntrx_primary = 0 + rwc.ntrx_total = 0 + rwc.standbyCount = standbyCount + rwc.increments = make([]int32, standbyCount+1) + rwc.flag = make([]int32, standbyCount+1) + var gcd = util.GCD(primaryPercent*standbyCount, 100-primaryPercent) + rwc.increments[0] = primaryPercent * standbyCount / gcd + for i, tmp := 1, (100-primaryPercent)/gcd; i < len(rwc.increments); i++ { + rwc.increments[i] = tmp + } + copy(rwc.flag, rwc.increments) + + if standbyCount > 0 { + rwc.primaryPercent = float64(primaryPercent) / 100.0 + rwc.standbyPercent = float64(100-primaryPercent) / 100.0 / float64(standbyCount) + } else { + rwc.primaryPercent = 1 + rwc.standbyPercent = 0 + } +} + +// 连接创建成功后调用,需要服务器返回standbyCount +func getRwCounterInstance(conn *DmConnection, standbyCount int32) *rwCounter { + key := conn.dmConnector.host + "_" + strconv.Itoa(int(conn.dmConnector.port)) + "_" + strconv.Itoa(int(conn.dmConnector.rwPercent)) + + rwc, ok := rwMap[key] + if !ok { + rwc = newRWCounter(conn.dmConnector.rwPercent, standbyCount) + rwMap[key] = rwc + } else if rwc.standbyCount != standbyCount { + rwc.reset(conn.dmConnector.rwPercent, standbyCount) + } + return rwc +} + +/** +* @return 主机; + */ +func (rwc *rwCounter) countPrimary() RWSiteEnum { + rwc.adjustNtrx() + rwc.increasePrimaryNtrx() + return PRIMARY +} + +/** +* @param dest 主机; 备机; any; +* @return 主机; 备机 + */ +func (rwc *rwCounter) count(dest RWSiteEnum, standby *DmConnection) RWSiteEnum { + rwc.adjustNtrx() + switch dest { + case ANYSITE: + { + if rwc.primaryPercent == 1 || (rwc.flag[0] > rwc.getStandbyFlag(standby) && rwc.flag[0] > util.Sum(rwc.flag[1:])) { + rwc.increasePrimaryNtrx() + dest = PRIMARY + } else { + rwc.increaseStandbyNtrx(standby) + dest = STANDBY + } + } + case STANDBY: + { + rwc.increaseStandbyNtrx(standby) + } + case PRIMARY: + { + rwc.increasePrimaryNtrx() + } + } + return dest +} + +/** +* 防止ntrx超出有效范围,等比调整 + */ +func (rwc *rwCounter) adjustNtrx() { + if rwc.ntrx_total >= INT64_MAX { + var min int64 + var i = 0 + for _, num := range rwc.standbyNTrxMap { + if i == 0 || num < min { + min = num + } + i++ + } + if rwc.ntrx_primary < min { + min = rwc.ntrx_primary + } + rwc.ntrx_primary /= min + rwc.ntrx_total /= min + for k, v := range rwc.standbyNTrxMap { + rwc.standbyNTrxMap[k] = v / min + } + } + + if rwc.flag[0] <= 0 && util.Sum(rwc.flag[1:]) <= 0 { + // 如果主库事务数以及所有备库事务数的总和 都 <= 0, 重置事务计数,给每个库的事务计数加上初始计数值 + for i := 0; i < len(rwc.flag); i++ { + rwc.flag[i] += rwc.increments[i] + } + } +} + +func (rwc *rwCounter) increasePrimaryNtrx() { + rwc.ntrx_primary++ + rwc.flag[0]-- + rwc.ntrx_total++ +} + +//func (rwc *rwCounter) getStandbyNtrx(standby *DmConnection) int64 { +// key := standby.dmConnector.host + ":" + strconv.Itoa(int(standby.dmConnector.port)) +// ret, ok := rwc.standbyNTrxMap[key] +// if !ok { +// ret = 0 +// } +// +// return ret +//} + +func (rwc *rwCounter) getStandbyId(standby *DmConnection) int32 { + key := standby.dmConnector.host + ":" + strconv.Itoa(int(standby.dmConnector.port)) + sid, ok := rwc.standbyIdMap[key] + if !ok { + sid = int32(len(rwc.standbyIdMap) + 1) // 下标0是primary + if sid > rwc.standbyCount { + // 不在有效备库中 + return -1 + } + rwc.standbyIdMap[key] = sid + } + return sid +} + +func (rwc *rwCounter) getStandbyFlag(standby *DmConnection) int32 { + sid := rwc.getStandbyId(standby) + if sid > 0 && sid < int32(len(rwc.flag)) { + // 保证备库有效 + return rwc.flag[sid] + } + return 0 +} + +func (rwc *rwCounter) increaseStandbyNtrx(standby *DmConnection) { + key := standby.dmConnector.host + ":" + strconv.Itoa(int(standby.dmConnector.port)) + ret, ok := rwc.standbyNTrxMap[key] + if ok { + ret += 1 + } else { + ret = 1 + } + rwc.standbyNTrxMap[key] = ret + sid, ok := rwc.standbyIdMap[key] + if !ok { + sid = int32(len(rwc.standbyIdMap) + 1) // 下标0是primary + rwc.standbyIdMap[key] = sid + } + rwc.flag[sid]-- + rwc.ntrx_total++ +} + +func (rwc *rwCounter) random(rowCount int32) int32 { + rand.Seed(time.Now().UnixNano()) + if rowCount > rwc.standbyCount { + return rand.Int31n(rwc.standbyCount) + } else { + return rand.Int31n(rowCount) + } +} + +func (rwc *rwCounter) String() string { + return "PERCENT(P/S) : " + strconv.FormatFloat(rwc.primaryPercent, 'f', -1, 64) + "/" + strconv.FormatFloat(rwc.standbyPercent, 'f', -1, 64) + "\nNTRX_PRIMARY : " + + strconv.FormatInt(rwc.ntrx_primary, 10) + "\nNTRX_TOTAL : " + strconv.FormatInt(rwc.ntrx_total, 10) + "\nNTRX_STANDBY : " +} diff --git a/dmr/zx.go b/dmr/zx.go new file mode 100644 index 0000000..afe0abe --- /dev/null +++ b/dmr/zx.go @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "context" + "database/sql" + "database/sql/driver" + "errors" + "io" + "regexp" + "strings" + "time" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +const ( + SQL_SELECT_STANDBY = "select distinct mailIni.inst_name, mailIni.INST_IP, mailIni.INST_PORT, archIni.arch_status " + + "from v$arch_status archIni " + + "left join (select * from V$DM_MAL_INI) mailIni on archIni.arch_dest = mailIni.inst_name " + + "left join V$MAL_LINK_STATUS on CTL_LINK_STATUS = 'CONNECTED' AND DATA_LINK_STATUS = 'CONNECTED' " + + "where archIni.arch_type in ('TIMELY', 'REALTIME') AND archIni.arch_status = 'VALID'" + + SQL_SELECT_STANDBY2 = "select distinct " + + "mailIni.mal_inst_name, mailIni.mal_INST_HOST, mailIni.mal_INST_PORT, archIni.arch_status " + + "from v$arch_status archIni " + "left join (select * from V$DM_MAL_INI) mailIni " + + "on archIni.arch_dest = mailIni.mal_inst_name " + "left join V$MAL_LINK_STATUS " + + "on CTL_LINK_STATUS = 'CONNECTED' AND DATA_LINK_STATUS = 'CONNECTED' " + + "where archIni.arch_type in ('TIMELY', 'REALTIME') AND archIni.arch_status = 'VALID'" +) + +type rwUtil struct { +} + +var RWUtil = rwUtil{} + +func (RWUtil rwUtil) connect(c *DmConnector, ctx context.Context) (*DmConnection, error) { + c.loginMode = LOGIN_MODE_PRIMARY_ONLY + connection, err := c.connect(ctx) + if err != nil { + return nil, err + } + + connection.rwInfo.rwCounter = getRwCounterInstance(connection, connection.StandbyCount) + err = RWUtil.connectStandby(connection) + + return connection, err +} + +func (RWUtil rwUtil) reconnect(connection *DmConnection) error { + if connection.rwInfo == nil { + return nil + } + + RWUtil.removeStandby(connection) + + err := connection.reconnect() + if err != nil { + return err + } + connection.rwInfo.cleanup() + connection.rwInfo.rwCounter = getRwCounterInstance(connection, connection.StandbyCount) + + err = RWUtil.connectStandby(connection) + + return err +} + +func (RWUtil rwUtil) recoverStandby(connection *DmConnection) error { + if connection.closed.IsSet() || RWUtil.isStandbyAlive(connection) { + return nil + } + + ts := time.Now().UnixNano() / 1000000 + + freq := int64(connection.dmConnector.rwStandbyRecoverTime) + if freq <= 0 || ts-connection.rwInfo.tryRecoverTs < freq { + return nil + } + + err := RWUtil.connectStandby(connection) + connection.rwInfo.tryRecoverTs = ts + + return err +} + +func (RWUtil rwUtil) connectStandby(connection *DmConnection) error { + var err error + db, err := RWUtil.chooseValidStandby(connection) + if err != nil { + return err + } + if db == nil { + return nil + } + + standbyConnectorValue := *connection.dmConnector + standbyConnector := &standbyConnectorValue + standbyConnector.host = db.host + standbyConnector.port = db.port + standbyConnector.rwStandby = true + standbyConnector.group = nil + standbyConnector.loginMode = LOGIN_MODE_STANDBY_ONLY + standbyConnector.switchTimes = 0 + connection.rwInfo.connStandby, err = standbyConnector.connectSingle(context.Background()) + if err != nil { + return err + } + + if connection.rwInfo.connStandby.SvrMode != SERVER_MODE_STANDBY || connection.rwInfo.connStandby.SvrStat != SERVER_STATUS_OPEN { + RWUtil.removeStandby(connection) + } + return nil +} + +func (RWUtil rwUtil) chooseValidStandby(connection *DmConnection) (*ep, error) { + stmt, rs, err := connection.driverQuery(SQL_SELECT_STANDBY2) + if err != nil { + stmt, rs, err = connection.driverQuery(SQL_SELECT_STANDBY) + } + defer func() { + if rs != nil { + rs.close() + } + if stmt != nil { + stmt.close() + } + }() + if err == nil { + count := int32(rs.CurrentRows.getRowCount()) + if count > 0 { + connection.rwInfo.rwCounter = getRwCounterInstance(connection, count) + i := int32(0) + rowIndex := connection.rwInfo.rwCounter.random(count) + dest := make([]driver.Value, 3) + for err := rs.next(dest); err != io.EOF; err = rs.next(dest) { + if i == rowIndex { + ep := newEP(dest[1].(string), dest[2].(int32)) + return ep, nil + } + i++ + } + } + } + if err != nil { + return nil, errors.New("choose valid standby error!" + err.Error()) + } + return nil, nil +} + +func (RWUtil rwUtil) afterExceptionOnStandby(connection *DmConnection, e error) { + if e.(*DmError).ErrCode == ECGO_COMMUNITION_ERROR.ErrCode { + RWUtil.removeStandby(connection) + } +} + +func (RWUtil rwUtil) removeStandby(connection *DmConnection) { + if connection.rwInfo.connStandby != nil { + connection.rwInfo.connStandby.close() + connection.rwInfo.connStandby = nil + } +} + +func (RWUtil rwUtil) isCreateStandbyStmt(stmt *DmStatement) bool { + return stmt != nil && stmt.rwInfo.readOnly && RWUtil.isStandbyAlive(stmt.dmConn) +} + +func (RWUtil rwUtil) executeByConn(conn *DmConnection, query string, execute1 func() (interface{}, error), execute2 func(otherConn *DmConnection) (interface{}, error)) (interface{}, error) { + + if err := RWUtil.recoverStandby(conn); err != nil { + return nil, err + } + RWUtil.distributeSqlByConn(conn, query) + + turnToPrimary := false + + ret, err := execute1() + if err != nil { + if conn.rwInfo.connCurrent == conn.rwInfo.connStandby { + + RWUtil.afterExceptionOnStandby(conn, err) + turnToPrimary = true + } else { + + return nil, err + } + } + + curConn := conn.rwInfo.connCurrent + var otherConn *DmConnection + if curConn != conn { + otherConn = conn + } else { + otherConn = conn.rwInfo.connStandby + } + + switch curConn.lastExecInfo.retSqlType { + case Dm_build_691, Dm_build_692, Dm_build_696, Dm_build_703, Dm_build_702, Dm_build_694: + { + + if otherConn != nil { + execute2(otherConn) + } + } + case Dm_build_701: + { + + sqlhead := regexp.MustCompile("[ (]").Split(strings.TrimSpace(query), 2)[0] + if util.StringUtil.EqualsIgnoreCase(sqlhead, "SP_SET_PARA_VALUE") || util.StringUtil.EqualsIgnoreCase(sqlhead, "SP_SET_SESSION_READONLY") { + if otherConn != nil { + execute2(otherConn) + } + } + } + case Dm_build_700: + { + + if conn.dmConnector.rwHA && curConn == conn.rwInfo.connStandby && + (curConn.lastExecInfo.rsDatas == nil || len(curConn.lastExecInfo.rsDatas) == 0) { + turnToPrimary = true + } + } + } + + if turnToPrimary { + conn.rwInfo.toPrimary() + conn.rwInfo.connCurrent = conn + + return execute2(conn) + } + return ret, nil +} + +func (RWUtil rwUtil) executeByStmt(stmt *DmStatement, execute1 func() (interface{}, error), execute2 func(otherStmt *DmStatement) (interface{}, error)) (interface{}, error) { + orgStmt := stmt.rwInfo.stmtCurrent + query := stmt.nativeSql + + if err := RWUtil.recoverStandby(stmt.dmConn); err != nil { + return nil, err + } + RWUtil.distributeSqlByStmt(stmt) + if orgStmt != stmt.rwInfo.stmtCurrent { + RWUtil.copyStatement(orgStmt, stmt.rwInfo.stmtCurrent) + stmt.rwInfo.stmtCurrent.nativeSql = orgStmt.nativeSql + } + + turnToPrimary := false + + ret, err := execute1() + if err != nil { + + if stmt.rwInfo.stmtCurrent == stmt.rwInfo.stmtStandby { + RWUtil.afterExceptionOnStandby(stmt.dmConn, err) + turnToPrimary = true + } else { + return nil, err + } + } + + curStmt := stmt.rwInfo.stmtCurrent + var otherStmt *DmStatement + if curStmt != stmt { + otherStmt = stmt + } else { + otherStmt = stmt.rwInfo.stmtStandby + } + + switch curStmt.execInfo.retSqlType { + case Dm_build_691, Dm_build_692, Dm_build_696, Dm_build_703, Dm_build_702, Dm_build_694: + { + + if otherStmt != nil { + RWUtil.copyStatement(curStmt, otherStmt) + execute2(otherStmt) + } + } + case Dm_build_701: + { + + var tmpsql string + if query != "" { + tmpsql = strings.TrimSpace(query) + } else if stmt.nativeSql != "" { + tmpsql = strings.TrimSpace(stmt.nativeSql) + } else { + tmpsql = "" + } + sqlhead := regexp.MustCompile("[ (]").Split(tmpsql, 2)[0] + if util.StringUtil.EqualsIgnoreCase(sqlhead, "SP_SET_PARA_VALUE") || util.StringUtil.EqualsIgnoreCase(sqlhead, "SP_SET_SESSION_READONLY") { + if otherStmt != nil { + RWUtil.copyStatement(curStmt, otherStmt) + execute2(otherStmt) + } + } + } + case Dm_build_700: + { + + if stmt.dmConn.dmConnector.rwHA && curStmt == stmt.rwInfo.stmtStandby && + (curStmt.execInfo.rsDatas == nil || len(curStmt.execInfo.rsDatas) == 0) { + turnToPrimary = true + } + } + } + + if turnToPrimary { + stmt.dmConn.rwInfo.toPrimary() + stmt.rwInfo.stmtCurrent = stmt + + RWUtil.copyStatement(stmt.rwInfo.stmtStandby, stmt) + + return execute2(stmt) + } + return ret, nil +} + +func (RWUtil rwUtil) checkReadonlyByConn(conn *DmConnection, sql string) bool { + readonly := true + + if sql != "" && !conn.dmConnector.rwIgnoreSql { + tmpsql := strings.TrimSpace(sql) + sqlhead := strings.SplitN(tmpsql, " ", 2)[0] + if util.StringUtil.EqualsIgnoreCase(sqlhead, "INSERT") || + util.StringUtil.EqualsIgnoreCase(sqlhead, "UPDATE") || + util.StringUtil.EqualsIgnoreCase(sqlhead, "DELETE") || + util.StringUtil.EqualsIgnoreCase(sqlhead, "CREATE") || + util.StringUtil.EqualsIgnoreCase(sqlhead, "TRUNCATE") || + util.StringUtil.EqualsIgnoreCase(sqlhead, "DROP") || + util.StringUtil.EqualsIgnoreCase(sqlhead, "ALTER") { + readonly = false + } else { + readonly = true + } + } + return readonly +} + +func (RWUtil rwUtil) checkReadonlyByStmt(stmt *DmStatement) bool { + return RWUtil.checkReadonlyByConn(stmt.dmConn, stmt.nativeSql) +} + +func (RWUtil rwUtil) distributeSqlByConn(conn *DmConnection, query string) RWSiteEnum { + var dest RWSiteEnum + if !RWUtil.isStandbyAlive(conn) { + + dest = conn.rwInfo.toPrimary() + } else if !RWUtil.checkReadonlyByConn(conn, query) { + + dest = conn.rwInfo.toPrimary() + } else if (conn.rwInfo.distribute == PRIMARY && !conn.trxFinish) || + (conn.rwInfo.distribute == STANDBY && !conn.rwInfo.connStandby.trxFinish) { + + dest = conn.rwInfo.distribute + } else if conn.IsoLevel != int32(sql.LevelSerializable) { + + dest = conn.rwInfo.toAny() + } else { + dest = conn.rwInfo.toPrimary() + } + + if dest == PRIMARY { + conn.rwInfo.connCurrent = conn + } else { + conn.rwInfo.connCurrent = conn.rwInfo.connStandby + } + return dest +} + +func (RWUtil rwUtil) distributeSqlByStmt(stmt *DmStatement) RWSiteEnum { + var dest RWSiteEnum + if !RWUtil.isStandbyAlive(stmt.dmConn) { + + dest = stmt.dmConn.rwInfo.toPrimary() + } else if !RWUtil.checkReadonlyByStmt(stmt) { + + dest = stmt.dmConn.rwInfo.toPrimary() + } else if (stmt.dmConn.rwInfo.distribute == PRIMARY && !stmt.dmConn.trxFinish) || + (stmt.dmConn.rwInfo.distribute == STANDBY && !stmt.dmConn.rwInfo.connStandby.trxFinish) { + + dest = stmt.dmConn.rwInfo.distribute + } else if stmt.dmConn.IsoLevel != int32(sql.LevelSerializable) { + + dest = stmt.dmConn.rwInfo.toAny() + } else { + dest = stmt.dmConn.rwInfo.toPrimary() + } + + if dest == STANDBY && !RWUtil.isStandbyStatementValid(stmt) { + + var err error + stmt.rwInfo.stmtStandby, err = stmt.dmConn.rwInfo.connStandby.prepare(stmt.nativeSql) + if err != nil { + dest = stmt.dmConn.rwInfo.toPrimary() + } + } + + if dest == PRIMARY { + stmt.rwInfo.stmtCurrent = stmt + } else { + stmt.rwInfo.stmtCurrent = stmt.rwInfo.stmtStandby + } + return dest +} + +func (RWUtil rwUtil) isStandbyAlive(connection *DmConnection) bool { + return connection.rwInfo.connStandby != nil && !connection.rwInfo.connStandby.closed.IsSet() +} + +func (RWUtil rwUtil) isStandbyStatementValid(statement *DmStatement) bool { + return statement.rwInfo.stmtStandby != nil && !statement.rwInfo.stmtStandby.closed +} + +func (RWUtil rwUtil) copyStatement(srcStmt *DmStatement, destStmt *DmStatement) { + destStmt.nativeSql = srcStmt.nativeSql + destStmt.params = srcStmt.params + destStmt.paramCount = srcStmt.paramCount + destStmt.curRowBindIndicator = srcStmt.curRowBindIndicator +} diff --git a/dmr/zzj.go b/dmr/zzj.go new file mode 100644 index 0000000..320262f --- /dev/null +++ b/dmr/zzj.go @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import "database/sql/driver" + +var SQLName sqlName + +type sqlName struct { + m_name string // 描述对象自身名称, + + // 若为内置类型,则表示数据库端定义的名称,与dType相对应 + m_pkgName string // 所在包的名称,适用于包中类型的定义 + + m_schName string // 描述对象所在模式名 + + m_fulName string // 描述对象完全限定名, 记录用户发送的名称信息; + + // 以及接受服务器响应后,拼成的名称信息 + + m_schId int // 保存模式id,模式名无法传出,利用模式id查找 + + m_packId int // 保存包的id,包名无法传出,用于查找包名 + + m_conn *DmConnection +} + +func (SqlName *sqlName) init() { + SqlName.m_name = "" + SqlName.m_pkgName = "" + SqlName.m_schName = "" + SqlName.m_fulName = "" + SqlName.m_schId = -1 + SqlName.m_packId = -1 + SqlName.m_conn = nil +} + +func newSqlNameByFulName(fulName string) *sqlName { + o := new(sqlName) + o.init() + o.m_fulName = fulName + return o +} + +func newSqlNameByConn(conn *DmConnection) *sqlName { + o := new(sqlName) + o.init() + o.m_conn = conn + return o +} + +func (SqlName *sqlName) getFulName() (string, error) { + // 说明非内嵌式数据类型名称描述信息传入或已经获取过描述信息 + if len(SqlName.m_fulName) > 0 { + return SqlName.m_fulName, nil + } + + // 内嵌式数据类型无名称描述信息返回,直接返回null + if SqlName.m_name == "" { + // DBError.throwUnsupportedSQLException(); + return "", nil + } + + // 其他数据名描述信息 + if SqlName.m_packId != 0 || SqlName.m_schId != 0 { + sql := "SELECT NAME INTO ? FROM SYS.SYSOBJECTS WHERE ID=?" + + params := make([]driver.Value, 2) + var v string + params[0] = &v + if SqlName.m_packId != 0 { + params[1] = SqlName.m_packId + } else { + params[1] = SqlName.m_schId + } + + rs, err := SqlName.m_conn.query(sql, params) + if err != nil { + return "", err + } + rs.close() + + // 说明是包中定义的对象 + if SqlName.m_packId != 0 { + // pkg全名 + SqlName.m_pkgName = v + SqlName.m_fulName = SqlName.m_pkgName + "." + SqlName.m_name + } else { + // 非包中定义的对象 + // schema 名称 + SqlName.m_schName = v + SqlName.m_fulName = SqlName.m_schName + "." + SqlName.m_name + } + } + // 将有效值返回 + if len(SqlName.m_fulName) > 0 { + return SqlName.m_fulName, nil + } else { + return SqlName.m_name, nil + } + +} diff --git a/dmr/zzk.go b/dmr/zzk.go new file mode 100644 index 0000000..015e0f8 --- /dev/null +++ b/dmr/zzk.go @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "bytes" + "strconv" + "strings" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" + + "github.com/nfjBill/gorm-driver-dm/dmr/parser" +) + +func (dc *DmConnection) lex(sql string) ([]*parser.LVal, error) { + if dc.lexer == nil { + dc.lexer = parser.NewLexer(strings.NewReader(sql), false) + } else { + dc.lexer.Reset(strings.NewReader(sql)) + } + + lexer := dc.lexer + var lval *parser.LVal + var err error + lvalList := make([]*parser.LVal, 0, 64) + lval, err = lexer.Yylex() + if err != nil { + return nil, err + } + + for lval != nil { + lvalList = append(lvalList, lval) + lval.Position = len(lvalList) + lval, err = lexer.Yylex() + if err != nil { + return nil, err + } + } + + return lvalList, nil +} + +func lexSkipWhitespace(sql string, n int) ([]*parser.LVal, error) { + lexer := parser.NewLexer(strings.NewReader(sql), false) + + var lval *parser.LVal + var err error + lvalList := make([]*parser.LVal, 0, 64) + lval, err = lexer.Yylex() + if err != nil { + return nil, err + } + + for lval != nil && n > 0 { + lval.Position = len(lvalList) + if lval.Tp == parser.WHITESPACE_OR_COMMENT { + continue + } + + lvalList = append(lvalList, lval) + n-- + lval, err = lexer.Yylex() + if err != nil { + return nil, err + } + + } + + return lvalList, nil +} + +func (dc *DmConnection) escape(sql string, keywords []string) (string, error) { + + if (keywords == nil || len(keywords) == 0) && strings.Index(sql, "{") == -1 { + return sql, nil + } + var keywordMap map[string]interface{} + if keywords != nil && len(keywords) > 0 { + keywordMap = make(map[string]interface{}, len(keywords)) + for _, keyword := range keywords { + keywordMap[strings.ToUpper(keyword)] = nil + } + } + nsql := bytes.NewBufferString("") + stack := make([]bool, 0, 64) + lvalList, err := dc.lex(sql) + if err != nil { + return "", err + } + + for i := 0; i < len(lvalList); i++ { + lval0 := lvalList[i] + if lval0.Tp == parser.NORMAL { + if lval0.Value == "{" { + lval1 := next(lvalList, i+1) + if lval1 == nil || lval1.Tp != parser.NORMAL { + stack = append(stack, false) + nsql.WriteString(lval0.Value) + } else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "escape") || util.StringUtil.EqualsIgnoreCase(lval1.Value, "call") { + stack = append(stack, true) + } else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "oj") { + stack = append(stack, true) + lval1.Value = "" + lval1.Tp = parser.WHITESPACE_OR_COMMENT + } else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "d") { + stack = append(stack, true) + lval1.Value = "date" + } else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "t") { + stack = append(stack, true) + lval1.Value = "time" + } else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "ts") { + stack = append(stack, true) + lval1.Value = "datetime" + } else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "fn") { + stack = append(stack, true) + lval1.Value = "" + lval1.Tp = parser.WHITESPACE_OR_COMMENT + lval2 := next(lvalList, lval1.Position+1) + if lval2 != nil && lval2.Tp == parser.NORMAL && util.StringUtil.EqualsIgnoreCase(lval2.Value, "database") { + lval2.Value = "cur_database" + } + } else if util.StringUtil.Equals(lval1.Value, "?") { + lval2 := next(lvalList, lval1.Position+1) + if lval2 != nil && lval2.Tp == parser.NORMAL && util.StringUtil.EqualsIgnoreCase(lval2.Value, "=") { + lval3 := next(lvalList, lval2.Position+1) + if lval3 != nil && lval3.Tp == parser.NORMAL && util.StringUtil.EqualsIgnoreCase(lval3.Value, "call") { + stack = append(stack, true) + lval3.Value = "" + lval3.Tp = parser.WHITESPACE_OR_COMMENT + } else { + stack = append(stack, false) + nsql.WriteString(lval0.Value) + } + } else { + stack = append(stack, false) + nsql.WriteString(lval0.Value) + } + } else { + stack = append(stack, false) + nsql.WriteString(lval0.Value) + } + } else if util.StringUtil.Equals(lval0.Value, "}") { + if len(stack) != 0 && stack[len(stack)-1] { + + } else { + nsql.WriteString(lval0.Value) + } + stack = stack[:len(stack)-1] + } else { + if keywordMap != nil { + _, ok := keywordMap[strings.ToUpper(lval0.Value)] + if ok { + nsql.WriteString("\"" + util.StringUtil.ProcessDoubleQuoteOfName(strings.ToUpper(lval0.Value)) + "\"") + } else { + nsql.WriteString(lval0.Value) + } + } else { + nsql.WriteString(lval0.Value) + } + } + } else if lval0.Tp == parser.STRING { + nsql.WriteString("'" + util.StringUtil.ProcessSingleQuoteOfName(lval0.Value) + "'") + } else { + nsql.WriteString(lval0.Value) + } + } + + return nsql.String(), nil +} + +func next(lvalList []*parser.LVal, start int) *parser.LVal { + var lval *parser.LVal + + size := len(lvalList) + for i := start; i < size; i++ { + lval = lvalList[i] + if lval.Tp != parser.WHITESPACE_OR_COMMENT { + break + } + } + return lval +} + +func (dc *DmConnection) execOpt(sql string, optParamList []OptParameter, serverEncoding string) (string, []OptParameter, error) { + nsql := bytes.NewBufferString("") + + lvalList, err := dc.lex(sql) + if err != nil { + return "", optParamList, err + } + + if nil == lvalList || len(lvalList) == 0 { + return sql, optParamList, nil + } + + firstWord := lvalList[0].Value + if !(util.StringUtil.EqualsIgnoreCase(firstWord, "INSERT") || util.StringUtil.EqualsIgnoreCase(firstWord, "SELECT") || + util.StringUtil.EqualsIgnoreCase(firstWord, "UPDATE") || util.StringUtil.EqualsIgnoreCase(firstWord, "DELETE")) { + return sql, optParamList, nil + } + + breakIndex := 0 + for i := 0; i < len(lvalList); i++ { + lval := lvalList[i] + switch lval.Tp { + case parser.NULL: + { + nsql.WriteString("?") + optParamList = append(optParamList, newOptParameter(nil, NULL, NULL_PREC)) + } + case parser.INT: + { + nsql.WriteString("?") + value, err := strconv.Atoi(lval.Value) + if err != nil { + return "", optParamList, err + } + + if value <= int(INT32_MAX) && value >= int(INT32_MIN) { + optParamList = append(optParamList, newOptParameter(G2DB.toInt32(int32(value)), INT, INT_PREC)) + + } else { + optParamList = append(optParamList, newOptParameter(G2DB.toInt64(int64(value)), BIGINT, BIGINT_PREC)) + } + } + case parser.DOUBLE: + { + nsql.WriteString("?") + f, err := strconv.ParseFloat(lval.Value, 64) + if err != nil { + return "", optParamList, err + } + + optParamList = append(optParamList, newOptParameter(G2DB.toFloat64(f), DOUBLE, DOUBLE_PREC)) + } + case parser.DECIMAL: + { + nsql.WriteString("?") + bytes, err := G2DB.toDecimal(lval.Value, 0, 0) + if err != nil { + return "", optParamList, err + } + optParamList = append(optParamList, newOptParameter(bytes, DECIMAL, 0)) + } + case parser.STRING: + { + + if len(lval.Value) > int(INT16_MAX) { + + nsql.WriteString("'" + util.StringUtil.ProcessSingleQuoteOfName(lval.Value) + "'") + } else { + nsql.WriteString("?") + optParamList = append(optParamList, newOptParameter(Dm_build_1220.Dm_build_1433(lval.Value, serverEncoding, dc), VARCHAR, VARCHAR_PREC)) + } + } + case parser.HEX_INT: + + nsql.WriteString(lval.Value) + default: + + nsql.WriteString(lval.Value) + } + + if breakIndex > 0 { + break + } + } + + if breakIndex > 0 { + for i := breakIndex + 1; i < len(lvalList); i++ { + nsql.WriteString(lvalList[i].Value) + } + } + + return nsql.String(), optParamList, nil +} + +func (dc *DmConnection) hasConst(sql string) (bool, error) { + lvalList, err := dc.lex(sql) + if err != nil { + return false, err + } + + if nil == lvalList || len(lvalList) == 0 { + return false, nil + } + + for i := 0; i < len(lvalList); i++ { + switch lvalList[i].Tp { + case parser.NULL, parser.INT, parser.DOUBLE, parser.DECIMAL, parser.STRING, parser.HEX_INT: + return true, nil + } + } + return false, nil +} + +type OptParameter struct { + bytes []byte + ioType byte + tp int + prec int + scale int +} + +func newOptParameter(bytes []byte, tp int, prec int) OptParameter { + o := new(OptParameter) + o.bytes = bytes + o.tp = tp + o.prec = prec + return *o +} + +func (parameter *OptParameter) String() string { + if parameter.bytes == nil { + return "" + } + return string(parameter.bytes) +} diff --git a/dmr/zzl.go b/dmr/zzl.go new file mode 100644 index 0000000..250d9cf --- /dev/null +++ b/dmr/zzl.go @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +type StructDescriptor struct { + m_typeDesc *TypeDescriptor +} + +func newStructDescriptor(fulName string, conn *DmConnection) (*StructDescriptor, error) { + sd := new(StructDescriptor) + if fulName == "" { + return nil, ECGO_INVALID_COMPLEX_TYPE_NAME.throw() + } + + sd.m_typeDesc = newTypeDescriptorWithFulName(fulName, conn) + + err := sd.m_typeDesc.parseDescByName() + if err != nil { + return nil, err + } + + return sd, nil +} + +func newStructDescriptorByTypeDescriptor(desc *TypeDescriptor) *StructDescriptor { + sd := new(StructDescriptor) + sd.m_typeDesc = desc + return sd +} + +func (sd *StructDescriptor) getSize() int { + return sd.m_typeDesc.m_size +} + +func (sd *StructDescriptor) getObjId() int { + return sd.m_typeDesc.m_objId +} + +func (sd *StructDescriptor) getItemsDesc() []TypeDescriptor { + return sd.m_typeDesc.m_fieldsObj +} diff --git a/dmr/zzm.go b/dmr/zzm.go new file mode 100644 index 0000000..ce6b403 --- /dev/null +++ b/dmr/zzm.go @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dmr + +import ( + "bufio" + "io" + "os" + "runtime" + "strconv" + "strings" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +var LogDirDef, _ = os.Getwd() + +var StatDirDef, _ = os.Getwd() + +const ( + DEFAULT_PORT int32 = 5236 + + //log level + LOG_OFF int = 0 + + LOG_ERROR int = 1 + + LOG_WARN int = 2 + + LOG_SQL int = 3 + + LOG_INFO int = 4 + + LOG_DEBUG int = 5 + + LOG_ALL int = 9 + + //stat + STAT_SQL_REMOVE_LATEST int = 0 + + STAT_SQL_REMOVE_OLDEST int = 1 + + // 编码字符集 + ENCODING_UTF8 string = "UTF-8" + + ENCODING_EUCKR string = "EUC-KR" + + ENCODING_GB18030 string = "GB18030" + + DbAliveCheckFreqDef = 0 + + LocaleDef = 0 + + // log + LogLevelDef = LOG_OFF // 日志级别:off, error, warn, sql, info, all + + LogFlushFreqDef = 10 // 日志刷盘时间s (>=0) + + LogFlushQueueSizeDef = 100 //日志队列大小 + + LogBufferSizeDef = 32 * 1024 // 日志缓冲区大小 (>0) + + // stat + StatEnableDef = false // + + StatFlushFreqDef = 3 // 日志刷盘时间s (>=0) + + StatSlowSqlCountDef = 100 // 慢sql top行数,(0-1000) + + StatHighFreqSqlCountDef = 100 // 高频sql top行数, (0-1000) + + StatSqlMaxCountDef = 100000 // sql 统计最大值(0-100000) + + StatSqlRemoveModeDef = STAT_SQL_REMOVE_LATEST // 记录sql数超过最大值时,sql淘汰方式 +) + +var ( + DbAliveCheckFreq = DbAliveCheckFreqDef + + Locale = LocaleDef // 0:简体中文 1:英文 2:繁体中文 + + // log + LogLevel = LogLevelDef // 日志级别:off, error, warn, sql, info, all + + LogDir = LogDirDef + + LogFlushFreq = LogFlushFreqDef // 日志刷盘时间s (>=0) + + LogFlushQueueSize = LogFlushQueueSizeDef + + LogBufferSize = LogBufferSizeDef // 日志缓冲区大小 (>0) + + // stat + StatEnable = StatEnableDef // + + StatDir = StatDirDef // jdbc工作目录,所有生成的文件都在该目录下 + + StatFlushFreq = StatFlushFreqDef // 日志刷盘时间s (>=0) + + StatSlowSqlCount = StatSlowSqlCountDef // 慢sql top行数,(0-1000) + + StatHighFreqSqlCount = StatHighFreqSqlCountDef // 高频sql top行数, (0-1000) + + StatSqlMaxCount = StatSqlMaxCountDef // sql 统计最大值(0-100000) + + StatSqlRemoveMode = StatSqlRemoveModeDef // 记录sql数超过最大值时,sql淘汰方式 + + /*---------------------------------------------------------------*/ + ServerGroupMap = make(map[string]*epGroup) + + GlobalProperties = NewProperties() +) + +// filePath: dm_svc.conf 文件路径 +func load(filePath string) { + if filePath == "" { + switch runtime.GOOS { + case "windows": + filePath = os.Getenv("SystemRoot") + "\\system32\\dm_svc.conf" + case "linux": + filePath = "/etc/dm_svc.conf" + default: + return + } + } + file, err := os.Open(filePath) + defer file.Close() + if err != nil { + return + } + fileReader := bufio.NewReader(file) + + // GlobalProperties = NewProperties() + var groupProps *Properties + var line string //dm_svc.conf读取到的一行 + + for line, err = fileReader.ReadString('\n'); line != "" && (err == nil || err == io.EOF); line, err = fileReader.ReadString('\n') { + // 去除#标记的注释 + if notesIndex := strings.IndexByte(line, '#'); notesIndex != -1 { + line = line[:notesIndex] + } + // 去除前后多余的空格 + line = strings.TrimSpace(line) + if line == "" { + continue + } + + if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") { + groupName := strings.ToLower(line[1 : len(line)-1]) + dbGroup, ok := ServerGroupMap[groupName] + if groupName == "" || !ok { + continue + } + groupProps = dbGroup.props + if groupProps.IsNil() { + groupProps = NewProperties() + groupProps.SetProperties(GlobalProperties) + dbGroup.props = groupProps + } + + } else { + cfgInfo := strings.Split(line, "=") + if len(cfgInfo) < 2 { + continue + } + key := strings.TrimSpace(cfgInfo[0]) + value := strings.TrimSpace(cfgInfo[1]) + if strings.HasPrefix(value, "(") && strings.HasSuffix(value, ")") { + value = strings.TrimSpace(value[1 : len(value)-1]) + } + if key == "" || value == "" { + continue + } + // 区分属性是全局的还是组的 + var success bool + if groupProps.IsNil() { + success = SetServerGroupProperties(GlobalProperties, key, value) + } else { + success = SetServerGroupProperties(groupProps, key, value) + } + if !success { + var serverGroup = parseServerName(key, value) + if serverGroup != nil { + serverGroup.props = NewProperties() + serverGroup.props.SetProperties(GlobalProperties) + ServerGroupMap[strings.ToLower(key)] = serverGroup + } + } + } + } +} + +func SetServerGroupProperties(props *Properties, key string, value string) bool { + if util.StringUtil.EqualsIgnoreCase(key, "ADDRESS_REMAP") { + tmp := props.GetString(AddressRemapKey, "") + props.Set(AddressRemapKey, tmp+"("+value+")") + } else if util.StringUtil.EqualsIgnoreCase(key, "ALWAYS_ALLOW_COMMIT") { + props.Set(AlwayseAllowCommitKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "APP_NAME") { + props.Set(AppNameKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "AUTO_COMMIT") { + props.Set(AutoCommitKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "BATCH_ALLOW_MAX_ERRORS") { + props.Set(BatchAllowMaxErrorsKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "BATCH_CONTINUE_ON_ERROR") || + util.StringUtil.EqualsIgnoreCase(key, "CONTINUE_BATCH_ON_ERROR") { + props.Set(ContinueBatchOnErrorKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "BATCH_NOT_ON_CALL") { + props.Set(BatchNotOnCallKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "BATCH_TYPE") { + props.Set(BatchTypeKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "BUF_PREFETCH") { + props.Set(BufPrefetchKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "CIPHER_PATH") { + props.Set(CipherPathKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "CLUSTER") { + props.Set(ClusterKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "COLUMN_NAME_UPPER_CASE") { + props.Set(ColumnNameUpperCaseKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "COLUMN_NAME_CASE") { + props.Set(ColumnNameCaseKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "COMPATIBLE_MODE") { + props.Set(CompatibleModeKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "COMPRESS") || + util.StringUtil.EqualsIgnoreCase(key, "COMPRESS_MSG") { + props.Set(CompressKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "COMPRESS_ID") { + props.Set(CompressIdKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "CONNECT_TIMEOUT") { + props.Set(ConnectTimeoutKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "DO_SWITCH") || + util.StringUtil.EqualsIgnoreCase(key, "AUTO_RECONNECT") { + props.Set(DoSwitchKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "ENABLE_RS_CACHE") { + props.Set(EnRsCacheKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "EP_SELECTION") { + props.Set(EpSelectorKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "ESCAPE_PROCESS") { + props.Set(EscapeProcessKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "IS_BDTA_RS") { + props.Set(IsBdtaRSKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "KEY_WORDS") || + util.StringUtil.EqualsIgnoreCase(key, "KEYWORDS") { + props.Set(KeywordsKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "LANGUAGE") { + props.Set(LanguageKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "LOB_MODE") { + props.Set(LobModeKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "LOG_DIR") { + props.Set(LogDirKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "LOG_FLUSH_FREQ") { + props.Set(LogFlushFreqKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "LOG_LEVEL") { + props.Set(LogLevelKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "LOGIN_DSC_CTRL") { + props.Set(LoginDscCtrlKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "LOGIN_ENCRYPT") { + props.Set(LoginEncryptKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "LOGIN_MODE") { + props.Set(LoginModeKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "LOGIN_STATUS") { + props.Set(LoginStatusKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "MAX_ROWS") { + props.Set(MaxRowsKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "MPP_LOCAL") { + props.Set(MppLocalKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "OS_NAME") { + props.Set(OsNameKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "RS_CACHE_SIZE") { + props.Set(RsCacheSizeKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "RS_REFRESH_FREQ") { + props.Set(RsRefreshFreqKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "RW_HA") { + props.Set(RwHAKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "RW_IGNORE_SQL") { + props.Set(RwIgnoreSqlKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "RW_PERCENT") { + props.Set(RwPercentKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "RW_SEPARATE") { + props.Set(RwSeparateKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "RW_STANDBY_RECOVER_TIME") { + props.Set(RwStandbyRecoverTimeKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "SCHEMA") { + props.Set(SchemaKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "SESS_ENCODE") { + if IsSupportedCharset(value) { + props.Set("sessEncode", value) + } + } else if util.StringUtil.EqualsIgnoreCase(key, "SESSION_TIMEOUT") { + props.Set(SessionTimeoutKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "SOCKET_TIMEOUT") { + props.Set(SocketTimeoutKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "SSL_FILES_PATH") { + props.Set(SslFilesPathKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "STAT_DIR") { + props.Set(StatDirKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "STAT_ENABLE") { + props.Set(StatEnableKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "STAT_FLUSH_FREQ") { + props.Set(StatFlushFreqKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "STAT_HIGH_FREQ_SQL_COUNT") { + props.Set(StatHighFreqSqlCountKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "STAT_SLOW_SQL_COUNT") { + props.Set(StatSlowSqlCountKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "STAT_SQL_MAX_COUNT") { + props.Set(StatSqlMaxCountKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "STAT_SQL_REMOVE_MODE") { + props.Set(StatSqlRemoveModeKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "SWITCH_INTERVAL") { + props.Set(SwitchIntervalKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "SWITCH_TIME") || + util.StringUtil.EqualsIgnoreCase(key, "SWITCH_TIMES") { + props.Set(SwitchTimesKey, value) + } else if util.StringUtil.EqualsIgnoreCase(key, "TIME_ZONE") { + props.Set(TimeZoneKey, value) + props.Set("localTimezone", value) + } else if util.StringUtil.EqualsIgnoreCase(key, "USER_REMAP") { + tmp := props.GetString(UserRemapKey, "") + props.Set(UserRemapKey, tmp+"("+value+")") + } else { + return false + } + return true +} + +func parseServerName(name string, value string) *epGroup { + values := strings.Split(value, ",") + + var tmpVals []string + var tmpName string + var tmpPort int + var svrList = make([]*ep, 0, len(values)) + + for _, v := range values { + + var tmp *ep + // 先查找IPV6,以[]包括 + begin := strings.IndexByte(v, '[') + end := -1 + if begin != -1 { + end = strings.IndexByte(v[begin:], ']') + } + if end != -1 { + tmpName = v[begin+1 : end] + + // port + if portIndex := strings.IndexByte(v[end:], ':'); portIndex != -1 { + tmpPort, _ = strconv.Atoi(strings.TrimSpace(v[portIndex+1:])) + } else { + tmpPort = int(DEFAULT_PORT) + } + tmp = newEP(tmpName, int32(tmpPort)) + svrList = append(svrList, tmp) + continue + } + // IPV4 + tmpVals = strings.Split(v, ":") + tmpName = strings.TrimSpace(tmpVals[0]) + if len(tmpVals) >= 2 { + tmpPort, _ = strconv.Atoi(tmpVals[1]) + } else { + tmpPort = int(DEFAULT_PORT) + } + tmp = newEP(tmpName, int32(tmpPort)) + svrList = append(svrList, tmp) + } + + if len(svrList) == 0 { + return nil + } + return newEPGroup(name, svrList) +} + +func setDriverAttributes(props *Properties) { + if props == nil || props.Len() == 0 { + return + } + + parseLanguage(props.GetString(LanguageKey, "cn")) + DbAliveCheckFreq = props.GetInt(DbAliveCheckFreqKey, DbAliveCheckFreqDef, 1, int(INT32_MAX)) + + //// log + //LogLevel = ParseLogLevel(props) + //LogDir = util.StringUtil.FormatDir(props.GetTrimString(LogDirKey, LogDirDef)) + //LogBufferSize = props.GetInt(LogBufferSizeKey, LogBufferSizeDef, 1, int(INT32_MAX)) + //LogFlushFreq = props.GetInt(LogFlushFreqKey, LogFlushFreqDef, 1, int(INT32_MAX)) + //LogFlushQueueSize = props.GetInt(LogFlusherQueueSizeKey, LogFlushQueueSizeDef, 1, int(INT32_MAX)) + // + //// stat + //StatEnable = props.GetBool(StatEnableKey, StatEnableDef) + //StatDir = util.StringUtil.FormatDir(props.GetTrimString(StatDirKey, StatDirDef)) + //StatFlushFreq = props.GetInt(StatFlushFreqKey, StatFlushFreqDef, 1, int(INT32_MAX)) + //StatHighFreqSqlCount = props.GetInt(StatHighFreqSqlCountKey, StatHighFreqSqlCountDef, 0, 1000) + //StatSlowSqlCount = props.GetInt(StatSlowSqlCountKey, StatSlowSqlCountDef, 0, 1000) + //StatSqlMaxCount = props.GetInt(StatSqlMaxCountKey, StatSqlMaxCountDef, 0, 100000) + //parseStatSqlRemoveMode(props) +} + +func parseLanguage(value string) { + if util.StringUtil.EqualsIgnoreCase("cn", value) { + Locale = 0 + } else if util.StringUtil.EqualsIgnoreCase("en", value) { + Locale = 1 + } +} + +func IsSupportedCharset(charset string) bool { + if util.StringUtil.EqualsIgnoreCase(ENCODING_UTF8, charset) || util.StringUtil.EqualsIgnoreCase(ENCODING_GB18030, charset) || util.StringUtil.EqualsIgnoreCase(ENCODING_EUCKR, charset) { + return true + } + return false +} + +func ParseLogLevel(props *Properties) int { + logLevel := LOG_OFF + value := props.GetString(LogLevelKey, "") + if value != "" && !util.StringUtil.IsDigit(value) { + if util.StringUtil.EqualsIgnoreCase("debug", value) { + logLevel = LOG_DEBUG + } else if util.StringUtil.EqualsIgnoreCase("info", value) { + logLevel = LOG_INFO + } else if util.StringUtil.EqualsIgnoreCase("sql", value) { + logLevel = LOG_SQL + } else if util.StringUtil.EqualsIgnoreCase("warn", value) { + logLevel = LOG_WARN + } else if util.StringUtil.EqualsIgnoreCase("error", value) { + logLevel = LOG_ERROR + } else if util.StringUtil.EqualsIgnoreCase("off", value) { + logLevel = LOG_OFF + } else if util.StringUtil.EqualsIgnoreCase("all", value) { + logLevel = LOG_ALL + } + } else { + logLevel = props.GetInt(LogLevelKey, logLevel, LOG_OFF, LOG_INFO) + } + + return logLevel +} diff --git a/dmr/zzn.go b/dmr/zzn.go new file mode 100644 index 0000000..6e446cb --- /dev/null +++ b/dmr/zzn.go @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "database/sql" + "database/sql/driver" + "math" + "reflect" + "strings" + "time" +) + +const ( + INT8_MAX int8 = math.MaxInt8 + + INT8_MIN int8 = math.MinInt8 + + BYTE_MAX byte = math.MaxUint8 + + BYTE_MIN byte = 0 + + INT16_MAX int16 = math.MaxInt16 + + INT16_MIN int16 = math.MinInt16 + + UINT16_MAX uint16 = math.MaxUint16 + + UINT16_MIN uint16 = 0 + + INT32_MAX int32 = math.MaxInt32 + + INT32_MIN int32 = math.MinInt32 + + UINT32_MAX uint32 = math.MaxUint32 + + UINT32_MIN uint32 = 0 + + INT64_MAX int64 = math.MaxInt64 + + INT64_MIN int64 = math.MinInt64 + + UINT64_MAX uint64 = math.MaxUint64 + + UINT64_MIN uint64 = 0 + + FLOAT32_MAX float32 = 3.4e+38 + + FLOAT32_MIN float32 = -3.4e+38 + + BYTE_SIZE = 1 + + USINT_SIZE = 2 + + ULINT_SIZE = 4 + + DDWORD_SIZE = 8 + + LINT64_SIZE = 8 + + CHAR = 0 + + VARCHAR2 = 1 + + VARCHAR = 2 + + BIT = 3 + + TINYINT = 5 + + SMALLINT = 6 + + INT = 7 + + BIGINT = 8 + + DECIMAL = 9 + + REAL = 10 + + DOUBLE = 11 + + BLOB = 12 + + BOOLEAN = 13 + + DATE = 14 + + TIME = 15 + + DATETIME = 16 + + BINARY = 17 + + VARBINARY = 18 + + CLOB = 19 + + INTERVAL_YM = 20 + + INTERVAL_DT = 21 + + TIME_TZ = 22 + + DATETIME_TZ = 23 + + NULL = 25 + + ANY = 31 + + STAR_ALL = 32 + + STAR = 33 + + RECORD = 40 + + TYPE = 41 + + TYPE_REF = 42 + + UNKNOWN = 54 + + ARRAY = 117 + + CLASS = 119 + + CURSOR = 120 + + PLTYPE_RECORD = 121 + + SARRAY = 122 + + CURSOR_ORACLE = -10 + + BIT_PREC = BYTE_SIZE + + TINYINT_PREC = BYTE_SIZE + + SMALLINT_PREC = USINT_SIZE + + INT_PREC = ULINT_SIZE + + BIGINT_PREC = LINT64_SIZE + + REAL_PREC = 4 + + DOUBLE_PREC = 8 + + DATE_PREC = 3 + + TIME_PREC = 5 + + DATETIME_PREC = 8 + + INTERVAL_YM_PREC = 3 * ULINT_SIZE + + INTERVAL_DT_PREC = 6 * ULINT_SIZE + + TIME_TZ_PREC = 12 + + DATETIME_TZ_PREC = 12 + + VARCHAR_PREC = 8188 + + VARBINARY_PREC = 8188 + + BLOB_PREC int32 = INT32_MAX + + CLOB_PREC int32 = INT32_MAX + + NULL_PREC = 0 + + LOCAL_TIME_ZONE_SCALE_MASK = 0x00001000 + + BFILE_PREC = 512 + + BFILE_SCALE = 6 + + COMPLEX_SCALE = 5 + + CURRENCY_PREC = 19 + + CURRENCY_SCALE = 4 + + FLOAT_SCALE_MASK = 0X81 +) + +func resetColType(stmt *DmStatement, i int, colType int32) bool { + + parameter := &stmt.params[i] + + if parameter.ioType == IO_TYPE_OUT { + stmt.curRowBindIndicator[i] |= BIND_OUT + return false + } else if parameter.ioType == IO_TYPE_IN { + stmt.curRowBindIndicator[i] |= BIND_IN + } else { + stmt.curRowBindIndicator[i] |= BIND_IN + stmt.curRowBindIndicator[i] |= BIND_OUT + } + + if parameter.typeFlag != TYPE_FLAG_EXACT { + + parameter.colType = colType + parameter.scale = 0 + switch colType { + case CHAR, VARCHAR, VARCHAR2: + parameter.prec = VARCHAR_PREC + case CLOB: + parameter.prec = CLOB_PREC + case BINARY, VARBINARY: + parameter.prec = VARBINARY_PREC + case BLOB: + parameter.prec = BLOB_PREC + case BOOLEAN, BIT: + parameter.prec = BIT_PREC + } + } + + return true +} + +func isBFile(colType int, prec int, scale int) bool { + return colType == VARCHAR && prec == BFILE_PREC && scale == BFILE_SCALE +} + +func isComplexType(colType int, scale int) bool { + return (colType == BLOB && scale == COMPLEX_SCALE) || colType == ARRAY || colType == SARRAY || colType == CLASS || colType == PLTYPE_RECORD +} + +func isLocalTimeZone(colType int, scale int) bool { + return colType == DATETIME && (scale&LOCAL_TIME_ZONE_SCALE_MASK) != 0 +} + +func getLocalTimeZoneScale(colType int, scale int) int { + return scale & (^LOCAL_TIME_ZONE_SCALE_MASK) +} + +func isFloat(colType int, scale int) bool { + return colType == DECIMAL && scale == FLOAT_SCALE_MASK +} + +func getFloatPrec(prec int) int { + return int(math.Round(float64(prec)*0.30103)) + 1 +} + +func getFloatScale(scale int) int { + return scale & (^FLOAT_SCALE_MASK) +} + +var ( + scanTypeFloat32 = reflect.TypeOf(float32(0)) + scanTypeFloat64 = reflect.TypeOf(float64(0)) + scanTypeBool = reflect.TypeOf(false) + scanTypeInt8 = reflect.TypeOf(int8(0)) + scanTypeInt16 = reflect.TypeOf(int16(0)) + scanTypeInt32 = reflect.TypeOf(int32(0)) + scanTypeInt64 = reflect.TypeOf(int64(0)) + scanTypeNullBool = reflect.TypeOf(sql.NullBool{}) + scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{}) + scanTypeNullInt = reflect.TypeOf(sql.NullInt64{}) + scanTypeNullString = reflect.TypeOf(sql.NullString{}) + scanTypeNullTime = reflect.TypeOf(sql.NullTime{}) + scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{}) + scanTypeString = reflect.TypeOf("") + scanTypeTime = reflect.TypeOf(time.Now()) + scanTypeUnknown = reflect.TypeOf(new(interface{})) +) + +func (column *column) ScanType() reflect.Type { + + switch column.colType { + case BOOLEAN: + if column.nullable { + return scanTypeNullBool + } + + return scanTypeBool + + case BIT: + if strings.ToLower(column.typeName) == "boolean" { + + if column.nullable { + return scanTypeNullBool + } + + return scanTypeBool + } else { + + if column.nullable { + return scanTypeNullInt + } + return scanTypeInt8 + } + + case TINYINT: + if column.nullable { + return scanTypeNullInt + } + return scanTypeInt8 + + case SMALLINT: + if column.nullable { + return scanTypeNullInt + } + return scanTypeInt16 + + case INT: + if column.nullable { + return scanTypeNullInt + } + + return scanTypeInt32 + + case BIGINT: + if column.nullable { + return scanTypeNullInt + } + return scanTypeInt64 + + case REAL: + if column.nullable { + return scanTypeNullFloat + } + + return scanTypeFloat32 + + case DOUBLE: + + if strings.ToLower(column.typeName) == "float" { + if column.nullable { + return scanTypeNullFloat + } + + return scanTypeFloat32 + } + + if column.nullable { + return scanTypeNullFloat + } + + return scanTypeFloat64 + case DATE, TIME, DATETIME: + if column.nullable { + return scanTypeNullTime + } + + return scanTypeTime + + case DECIMAL, BINARY, VARBINARY, BLOB: + return scanTypeRawBytes + + case CHAR, VARCHAR2, VARCHAR, CLOB: + if column.nullable { + return scanTypeNullString + } + return scanTypeString + } + + return scanTypeUnknown +} + +func (column *column) Length() (length int64, ok bool) { + + switch column.colType { + case BINARY: + case VARBINARY: + case BLOB: + case CHAR: + case VARCHAR2: + case VARCHAR: + case CLOB: + return int64(column.prec), true + } + + return int64(0), false +} + +func (column *column) PrecisionScale() (precision, scale int64, ok bool) { + switch column.colType { + case DECIMAL: + return int64(column.prec), int64(column.scale), true + } + + return int64(0), int64(0), false +} + +func (column *column) getColumnData(bytes []byte, conn *DmConnection) (driver.Value, error) { + if bytes == nil { + return nil, nil + } + + switch column.colType { + case BOOLEAN: + return bytes[0] != 0, nil + case BIT: + if strings.ToLower(column.typeName) == "boolean" { + return bytes[0] != 0, nil + } + + return int8(bytes[0]), nil + case TINYINT: + return int8(bytes[0]), nil + case SMALLINT: + return Dm_build_1220.Dm_build_1317(bytes, 0), nil + case INT: + return Dm_build_1220.Dm_build_1322(bytes, 0), nil + case BIGINT: + return Dm_build_1220.Dm_build_1327(bytes, 0), nil + case REAL: + return Dm_build_1220.Dm_build_1332(bytes, 0), nil + case DOUBLE: + + return Dm_build_1220.Dm_build_1336(bytes, 0), nil + case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ: + return DB2G.toTime(bytes, column, conn) + case INTERVAL_DT: + return newDmIntervalDTByBytes(bytes).String(), nil + case INTERVAL_YM: + return newDmIntervalYMByBytes(bytes).String(), nil + case DECIMAL: + tmp, err := DB2G.toDmDecimal(bytes, column, conn) + if err != nil { + return nil, err + } + return tmp.String(), nil + + case BINARY, VARBINARY: + return bytes, nil + case BLOB: + return DB2G.toDmBlob(bytes, column, conn), nil + case CHAR, VARCHAR2, VARCHAR: + return Dm_build_1220.Dm_build_1377(bytes, 0, len(bytes), conn.getServerEncoding(), conn), nil + case CLOB: + return DB2G.toDmClob(bytes, conn, column), nil + } + + return string(bytes), nil +} + +func emptyStringToNil(t int32) bool { + switch t { + case BOOLEAN, BIT, TINYINT, SMALLINT, INT, BIGINT, REAL, DOUBLE, DECIMAL, + DATE, TIME, DATETIME, INTERVAL_DT, INTERVAL_YM, TIME_TZ, DATETIME_TZ: + return true + default: + return false + } +} diff --git a/dmr/zzo.go b/dmr/zzo.go new file mode 100644 index 0000000..3adf1f2 --- /dev/null +++ b/dmr/zzo.go @@ -0,0 +1,1389 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "strconv" + + "github.com/nfjBill/gorm-driver-dm/dmr/util" +) + +const ( + ARRAY_TYPE_SHORT = 1 + + ARRAY_TYPE_INTEGER = 2 + + ARRAY_TYPE_LONG = 3 + + ARRAY_TYPE_FLOAT = 4 + + ARRAY_TYPE_DOUBLE = 5 +) + +var TypeDataSV TypeData + +type InterfaceTypeData interface { + toBytes(x *TypeData, typeDesc *TypeDescriptor) ([]byte, error) +} + +type TypeData struct { + m_dumyData interface{} + + m_offset int + + m_bufLen int + + m_dataBuf []byte + + m_objBlobDescBuf []byte + + m_isFromBlob bool + + m_packid int + + m_objRefArr []interface{} +} + +func newTypeData(val interface{}, dataBuf []byte) *TypeData { + td := new(TypeData).initTypeData() + td.m_dumyData = val + td.m_offset = 0 + td.m_bufLen = 0 + td.m_dataBuf = dataBuf + return td +} + +func (td *TypeData) initTypeData() *TypeData { + td.m_dumyData = nil + + td.m_offset = 0 + + td.m_bufLen = 0 + + td.m_dataBuf = nil + + td.m_objBlobDescBuf = nil + + td.m_isFromBlob = false + + td.m_packid = -1 + + td.m_objRefArr = make([]interface{}, 0) + + return td +} + +func (sv TypeData) toStruct(objArr []interface{}, desc *TypeDescriptor) ([]TypeData, error) { + size := desc.getStrctMemSize() + retData := make([]TypeData, size) + + for i := 0; i < size; i++ { + + if objArr[i] == nil { + retData[i] = *newTypeData(objArr[i], nil) + continue + } + + switch objArr[i].(type) { + case DmStruct, DmArray: + retData[i] = *newTypeData(objArr[i], nil) + default: + switch desc.m_fieldsObj[i].getDType() { + case CLASS, PLTYPE_RECORD: + tdArr, err := sv.toStruct(objArr[i].([]interface{}), &desc.m_fieldsObj[i]) + if err != nil { + return nil, err + } + + retData[i] = *newTypeData(newDmStructByTypeData(tdArr, &desc.m_fieldsObj[i]), nil) + case ARRAY, SARRAY: + tdArr, err := sv.toArray(objArr[i].([]interface{}), &desc.m_fieldsObj[i]) + if err != nil { + return nil, err + } + + retData[i] = *newTypeData(newDmArrayByTypeData(tdArr, &desc.m_fieldsObj[i]), nil) + default: + tdArr, err := sv.toMemberObj(objArr[i], &desc.m_fieldsObj[i]) + if err != nil { + return nil, err + } + retData[i] = *tdArr + } + + } + } + return retData, nil +} + +func (sv TypeData) toArray(objArr []interface{}, desc *TypeDescriptor) ([]TypeData, error) { + size := len(objArr) + retData := make([]TypeData, size) + for i := 0; i < size; i++ { + if objArr[i] == nil { + retData[i] = *newTypeData(objArr[i], nil) + continue + } + + switch objArr[i].(type) { + case DmStruct, DmArray: + retData[i] = *newTypeData(objArr[i], nil) + default: + switch desc.m_arrObj.getDType() { + case CLASS, PLTYPE_RECORD: + tdArr, err := sv.toStruct(objArr[i].([]interface{}), desc.m_arrObj) + if err != nil { + return nil, err + } + retData[i] = *newTypeData(newDmStructByTypeData(tdArr, desc.m_arrObj), nil) + case ARRAY, SARRAY: + + tmp, ok := objArr[i].([]interface{}) + + if !ok && desc.m_arrObj.m_arrObj != nil { + obj, err := sv.makeupObjToArr(tmp[i], desc.m_arrObj) + if err != nil { + return nil, err + } + objArr[i] = obj + } + + tdArr, err := sv.toArray(objArr[i].([]interface{}), desc.m_arrObj) + if err != nil { + return nil, err + } + + retData[i] = *newTypeData(newDmArrayByTypeData(tdArr, desc.m_arrObj), nil) + default: + tdArr, err := sv.toMemberObj(objArr[i], desc.m_arrObj) + if err != nil { + return nil, err + } + retData[i] = *tdArr + } + } + } + + return retData, nil +} + +func (sv TypeData) makeupObjToArr(obj interface{}, objDesc *TypeDescriptor) ([]interface{}, error) { + arrType := objDesc.getDType() + dynamic := true + arrLen := 0 + if arrType == SARRAY { + dynamic = false + arrLen = objDesc.m_length + } + + subType := objDesc.m_arrObj.getDType() + if subType == BINARY || subType == VARBINARY || subType == BIT { + + strRet := "" + switch v := obj.(type) { + case int: + strRet = strconv.FormatInt(int64(v), 2) + case int32: + strRet = strconv.FormatInt(int64(v), 2) + case int64: + strRet = strconv.FormatInt(v, 2) + case string: + strRet = v + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + var prec int + if dynamic { + prec = len(strRet) + } else { + prec = arrLen + } + + ret := make([]interface{}, prec) + rs := Dm_build_1220.Dm_build_1433(strRet, objDesc.getServerEncoding(), objDesc.m_conn) + for i := 0; i < prec; i++ { + ret[i] = rs[i] + } + + return ret, nil + } + + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (sv TypeData) toMemberObj(mem interface{}, desc *TypeDescriptor) (*TypeData, error) { + var bs []byte + scale := desc.getScale() + prec := desc.getPrec() + dtype := desc.getDType() + if mem == nil { + return newTypeData(nil, nil), nil + } + + param := new(parameter).InitParameter() + param.colType = int32(dtype) + param.prec = int32(prec) + param.scale = int32(scale) + + var err error + bs, err = G2DB.fromObject(mem, *param, desc.m_conn) + if err != nil { + return nil, err + } + + return newTypeData(mem, bs), nil +} + +func (sv TypeData) typeDataToBytes(data *TypeData, desc *TypeDescriptor) ([]byte, error) { + dType := desc.getDType() + var innerData []byte + var err error + if nil == data.m_dumyData { + innerData = sv.realocBuffer(nil, 0, 2) + Dm_build_1220.Dm_build_1221(innerData, 0, byte(0)) + Dm_build_1220.Dm_build_1221(innerData, 1, byte(0)) + return innerData, nil + } + + var result []byte + var offset int + switch dType { + case ARRAY: + + innerData, err = sv.arrayToBytes(data.m_dumyData.(*DmArray), desc) + if err != nil { + return nil, err + } + + result = sv.realocBuffer(nil, 0, len(innerData)+BYTE_SIZE+BYTE_SIZE) + + Dm_build_1220.Dm_build_1221(result, 0, byte(0)) + offset = 1 + + Dm_build_1220.Dm_build_1221(result, offset, byte(1)) + offset += 1 + copy(result[offset:offset+len(innerData)], innerData[:len(innerData)]) + return result, nil + + case SARRAY: + + innerData, err = sv.sarrayToBytes(data.m_dumyData.(*DmArray), desc) + if err != nil { + return nil, err + } + result = sv.realocBuffer(nil, 0, len(innerData)+BYTE_SIZE+BYTE_SIZE) + + Dm_build_1220.Dm_build_1221(result, 0, byte(0)) + offset = 1 + + Dm_build_1220.Dm_build_1221(result, offset, byte(1)) + offset += 1 + + copy(result[offset:offset+len(innerData)], innerData[:len(innerData)]) + return result, nil + + case CLASS: + + innerData, err = sv.objToBytes(data.m_dumyData, desc) + if err != nil { + return nil, err + } + result = sv.realocBuffer(nil, 0, len(innerData)+BYTE_SIZE+BYTE_SIZE) + + Dm_build_1220.Dm_build_1221(result, 0, byte(0)) + offset = 1 + + Dm_build_1220.Dm_build_1221(result, offset, byte(1)) + offset += 1 + copy(result[offset:offset+len(innerData)], innerData[:len(innerData)]) + return result, nil + + case PLTYPE_RECORD: + + innerData, err = sv.recordToBytes(data.m_dumyData.(*DmStruct), desc) + if err != nil { + return nil, err + } + result = sv.realocBuffer(nil, 0, len(innerData)+BYTE_SIZE+BYTE_SIZE) + + Dm_build_1220.Dm_build_1221(result, 0, byte(0)) + offset = 1 + + Dm_build_1220.Dm_build_1221(result, offset, byte(1)) + offset += 1 + + copy(result[offset:offset+len(innerData)], innerData[:len(innerData)]) + return result, nil + + case BLOB, CLOB: + innerData, err = sv.convertLobToBytes(data.m_dumyData, int(desc.column.colType), desc.getServerEncoding()) + + result = sv.realocBuffer(nil, 0, len(innerData)+BYTE_SIZE+BYTE_SIZE) + + Dm_build_1220.Dm_build_1221(result, 0, byte(0)) + offset = 1 + + Dm_build_1220.Dm_build_1221(result, offset, byte(1)) + offset += 1 + copy(result[offset:offset+len(innerData)], innerData[:len(innerData)]) + return result, nil + + case BOOLEAN: + innerData = sv.realocBuffer(nil, 0, 2) + Dm_build_1220.Dm_build_1221(innerData, 0, byte(0)) + if data.m_dataBuf != nil && len(data.m_dataBuf) > 0 { + Dm_build_1220.Dm_build_1221(innerData, 1, data.m_dataBuf[0]) + } else { + Dm_build_1220.Dm_build_1221(innerData, 1, byte(0)) + } + return innerData, nil + + default: + + innerData = data.m_dataBuf + result = sv.realocBuffer(nil, 0, len(innerData)+BYTE_SIZE+BYTE_SIZE+USINT_SIZE) + + Dm_build_1220.Dm_build_1221(result, 0, byte(0)) + offset = 1 + + Dm_build_1220.Dm_build_1221(result, offset, byte(1)) + offset += 1 + + Dm_build_1220.Dm_build_1231(result, offset, int16(len(innerData))) + offset += 2 + + copy(result[offset:offset+len(innerData)], innerData[:len(innerData)]) + + return result, nil + } +} + +func (sv TypeData) convertLobToBytes(value interface{}, dtype int, serverEncoding string) ([]byte, error) { + var tmp []byte + var ret []byte + if dtype == BLOB { + lob, ok := value.(DmBlob) + if ok { + l, err := lob.GetLength() + if err != nil { + return nil, err + } + tmp, err = lob.getBytes(1, int32(l)) + if err != nil { + return nil, err + } + + ret = make([]byte, l+ULINT_SIZE) + Dm_build_1220.Dm_build_1236(ret, 0, int32(l)) + copy(ret[:ULINT_SIZE:ULINT_SIZE+l], tmp[:l]) + return ret, nil + } + + } + + if dtype == CLOB { + lob, ok := value.(DmClob) + if ok { + l, err := lob.GetLength() + if err != nil { + return nil, err + } + + subString, err := lob.getSubString(1, int32(l)) + if err != nil { + return nil, err + } + + tmp = Dm_build_1220.Dm_build_1433(subString, serverEncoding, nil) + ret = make([]byte, len(tmp)+ULINT_SIZE) + Dm_build_1220.Dm_build_1236(ret, 0, int32(l)) + copy(ret[:ULINT_SIZE:ULINT_SIZE+l], tmp[:l]) + } + return ret, nil + } + + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (sv TypeData) sarrayToBytes(data *DmArray, desc *TypeDescriptor) ([]byte, error) { + realLen := len(data.m_arrData) + results := make([][]byte, realLen) + var rdata []byte + var err error + + if desc.getObjId() == 4 { + return sv.ctlnToBytes(data, desc) + } + + totalLen := 0 + for i := 0; i < realLen; i++ { + results[i], err = sv.typeDataToBytes(&data.m_arrData[i], desc.m_arrObj) + if err != nil { + return nil, err + } + totalLen += len(results[i]) + } + + totalLen += (ULINT_SIZE + ULINT_SIZE) + rdata = sv.realocBuffer(nil, 0, totalLen) + off := 0 + + Dm_build_1220.Dm_build_1236(rdata, off, int32(totalLen)) + off += ULINT_SIZE + + Dm_build_1220.Dm_build_1236(rdata, off, int32(data.m_arrDesc.getLength())) + off += ULINT_SIZE + + for i := 0; i < realLen; i++ { + copy(rdata[off:off+len(results[i])], results[i][:len(results[i])]) + off += len(results[i]) + } + + return rdata, nil +} + +func (sv TypeData) ctlnToBytes(data *DmArray, desc *TypeDescriptor) ([]byte, error) { + results := make([][]byte, len(data.m_arrData)) + var rdata []byte + var err error + + var totalLen int + totalLen = BYTE_SIZE + ULINT_SIZE + + totalLen += USINT_SIZE + USINT_SIZE + ULINT_SIZE + + for i := 0; i < len(data.m_arrData); i++ { + results[i], err = sv.typeDataToBytes(&data.m_arrData[i], desc.m_arrObj) + if err != nil { + return nil, err + } + totalLen += len(results[i]) + } + + rdata = sv.realocBuffer(nil, 0, totalLen) + + offset := 0 + + Dm_build_1220.Dm_build_1221(rdata, offset, byte(0)) + offset += BYTE_SIZE + + offset += ULINT_SIZE + + Dm_build_1220.Dm_build_1231(rdata, offset, int16(desc.getCltnType())) + offset += USINT_SIZE + + Dm_build_1220.Dm_build_1231(rdata, offset, int16(desc.m_arrObj.getDType())) + offset += USINT_SIZE + + Dm_build_1220.Dm_build_1236(rdata, offset, int32(len(data.m_arrData))) + offset += ULINT_SIZE + + for i := 0; i < len(data.m_arrData); i++ { + copy(rdata[offset:offset+len(results[i])], results[i][:len(results[i])]) + offset += len(results[i]) + } + + Dm_build_1220.Dm_build_1236(rdata, BYTE_SIZE, int32(offset)) + + return rdata, nil +} + +func (sv TypeData) arrayToBytes(data *DmArray, desc *TypeDescriptor) ([]byte, error) { + results := make([][]byte, len(data.m_arrData)) + var rdata []byte + var err error + if desc.getObjId() == 4 { + return sv.ctlnToBytes(data, desc) + } + + totalLen := 0 + for i := 0; i < len(data.m_arrData); i++ { + results[i], err = sv.typeDataToBytes(&data.m_arrData[i], desc.m_arrObj) + if err != nil { + return nil, err + } + totalLen += len(results[i]) + } + + totalLen += (ULINT_SIZE + ULINT_SIZE + ULINT_SIZE + ULINT_SIZE + ULINT_SIZE) + + total := data.m_objCount + data.m_strCount + if total > 0 { + totalLen += USINT_SIZE * total + } + + rdata = sv.realocBuffer(nil, 0, totalLen) + + Dm_build_1220.Dm_build_1236(rdata, 0, int32(totalLen)) + offset := ULINT_SIZE + + Dm_build_1220.Dm_build_1236(rdata, offset, int32(len(data.m_arrData))) + offset += ULINT_SIZE + + Dm_build_1220.Dm_build_1236(rdata, offset, 0) + offset += ULINT_SIZE + + Dm_build_1220.Dm_build_1236(rdata, offset, int32(data.m_objCount)) + offset += ULINT_SIZE + + Dm_build_1220.Dm_build_1236(rdata, offset, int32(data.m_strCount)) + offset += ULINT_SIZE + + for i := 0; i < total; i++ { + Dm_build_1220.Dm_build_1236(rdata, offset, int32(data.m_objStrOffs[i])) + offset += ULINT_SIZE + } + + for i := 0; i < len(data.m_arrData); i++ { + copy(rdata[offset:offset+len(results[i])], results[i][:len(results[i])]) + offset += len(results[i]) + } + + return rdata, nil +} + +func (sv TypeData) objToBytes(data interface{}, desc *TypeDescriptor) ([]byte, error) { + + switch data.(type) { + case DmArray: + return sv.arrayToBytes(data.(*DmArray), desc) + default: + return sv.structToBytes(data.(*DmStruct), desc) + } +} + +func (sv TypeData) structToBytes(data *DmStruct, desc *TypeDescriptor) ([]byte, error) { + size := desc.getStrctMemSize() + results := make([][]byte, size) + var rdata []byte + var err error + + totalLen := 0 + for i := 0; i < size; i++ { + results[i], err = sv.typeDataToBytes(&data.m_attribs[i], &desc.m_fieldsObj[i]) + if err != nil { + return nil, err + } + totalLen += len(results[i]) + } + + totalLen += (BYTE_SIZE + ULINT_SIZE) + + rdata = sv.realocBuffer(nil, 0, totalLen) + offset := 0 + + Dm_build_1220.Dm_build_1221(rdata, offset, byte(0)) + offset += BYTE_SIZE + + Dm_build_1220.Dm_build_1236(rdata, offset, int32(totalLen)) + offset += ULINT_SIZE + + for i := 0; i < size; i++ { + copy(rdata[offset:offset+len(results[i])], results[i][:len(results[i])]) + offset += len(results[i]) + } + + return rdata, nil +} + +func (sv TypeData) recordToBytes(data *DmStruct, desc *TypeDescriptor) ([]byte, error) { + size := desc.getStrctMemSize() + results := make([][]byte, size) + var rdata []byte + var err error + + totalLen := 0 + for i := 0; i < size; i++ { + results[i], err = sv.typeDataToBytes(&data.m_attribs[i], &desc.m_fieldsObj[i]) + if err != nil { + return nil, err + } + totalLen += len(results[i]) + } + + totalLen += ULINT_SIZE + rdata = sv.realocBuffer(nil, 0, totalLen) + Dm_build_1220.Dm_build_1236(rdata, 0, int32(totalLen)) + + offset := ULINT_SIZE + for i := 0; i < desc.getStrctMemSize(); i++ { + copy(rdata[offset:offset+len(results[i])], results[i][:len(results[i])]) + offset += len(results[i]) + } + + return rdata, nil +} + +func (sv TypeData) bytesToBlob(val []byte, out *TypeData, desc *TypeDescriptor) (*TypeData, error) { + offset := out.m_offset + l := Dm_build_1220.Dm_build_1322(val, offset) + offset += ULINT_SIZE + + tmp := Dm_build_1220.Dm_build_1371(val, offset, int(l)) + offset += int(l) + out.m_offset = offset + + return newTypeData(newBlobOfLocal(tmp, desc.m_conn), tmp), nil +} + +func (sv TypeData) bytesToClob(val []byte, out *TypeData, desc *TypeDescriptor, serverEncoding string) (*TypeData, error) { + offset := out.m_offset + l := Dm_build_1220.Dm_build_1322(val, offset) + offset += ULINT_SIZE + + tmp := Dm_build_1220.Dm_build_1371(val, offset, int(l)) + offset += int(l) + out.m_offset = offset + + return newTypeData(newClobOfLocal(Dm_build_1220.Dm_build_1377(tmp, 0, len(tmp), serverEncoding, desc.m_conn), desc.m_conn), tmp), nil +} + +func (sv TypeData) bytesToTypeData(val []byte, out *TypeData, desc *TypeDescriptor) (*TypeData, error) { + offset := out.m_offset + + offset += 1 + + null_flag := Dm_build_1220.Dm_build_1313(val, offset) + offset += 1 + + out.m_offset = offset + + if desc.getDType() == BOOLEAN { + b := false + if null_flag != byte(0) { + b = true + } + + tmp := Dm_build_1220.Dm_build_1371(val, offset-1, 1) + return newTypeData(b, tmp), nil + } + + var retObj interface{} + var err error + var retDataBuf []byte + switch desc.getDType() { + case CLASS: + if null_flag&byte(1) != byte(0) { + retObj, err = sv.bytesToObj(val, out, desc) + if err != nil { + return nil, err + } + + if out.m_offset > offset { + retDataBuf = Dm_build_1220.Dm_build_1371(val, offset, out.m_offset-offset) + } + + return newTypeData(retObj, retDataBuf), nil + } else { + return newTypeData(nil, nil), nil + } + + case ARRAY: + if (null_flag & byte(1)) != byte(0) { + retObj, err = sv.bytesToArray(val, out, desc) + if err != nil { + return nil, err + } + + if out.m_offset > offset { + retDataBuf = Dm_build_1220.Dm_build_1371(val, offset, out.m_offset-offset) + } + + return newTypeData(retObj, retDataBuf), nil + } else { + return newTypeData(nil, nil), nil + } + + case PLTYPE_RECORD: + if (null_flag & byte(1)) != byte(0) { + retObj, err = sv.bytesToRecord(val, out, desc) + if err != nil { + return nil, err + } + + if out.m_offset > offset { + retDataBuf = Dm_build_1220.Dm_build_1371(val, offset, out.m_offset-offset) + } + + return newTypeData(retObj, retDataBuf), nil + } else { + return newTypeData(nil, nil), nil + } + + case SARRAY: + if (null_flag & byte(1)) != byte(0) { + retObj, err = sv.bytesToSArray(val, out, desc) + if err != nil { + return nil, err + } + + if out.m_offset > offset { + retDataBuf = Dm_build_1220.Dm_build_1371(val, offset, out.m_offset-offset) + } + + return newTypeData(retObj, retDataBuf), nil + } else { + return newTypeData(nil, nil), nil + } + + case BLOB: + if null_flag&byte(1) != byte(0) { + return sv.bytesToBlob(val, out, desc) + } else { + return newTypeData(nil, nil), nil + } + + case CLOB: + if null_flag&byte(1) != byte(0) { + return sv.bytesToClob(val, out, desc, desc.getServerEncoding()) + } else { + return newTypeData(nil, nil), nil + } + + default: + if null_flag&byte(1) != byte(0) { + return sv.convertBytes2BaseData(val, out, desc) + } else { + return newTypeData(nil, nil), nil + } + + } +} + +func (sv TypeData) checkObjExist(val []byte, out *TypeData) bool { + offset := out.m_offset + exist_flag := Dm_build_1220.Dm_build_1313(val, offset) + offset += 1 + + out.m_offset = offset + + if exist_flag == byte(1) { + return true + } + + out.m_offset += ULINT_SIZE + return false +} + +func (sv TypeData) findObjByPackId(val []byte, out *TypeData) (*DmStruct, error) { + offset := out.m_offset + + pack_id := int(Dm_build_1220.Dm_build_1322(val, offset)) + offset += ULINT_SIZE + + out.m_offset = offset + + if pack_id < 0 || pack_id > out.m_packid { + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + + return out.m_objRefArr[pack_id].(*DmStruct), nil +} + +func (sv TypeData) addObjToRefArr(out *TypeData, objToAdd interface{}) { + out.m_objRefArr = append(out.m_objRefArr, objToAdd) + out.m_packid++ +} + +func (sv TypeData) checkObjClnt(desc *TypeDescriptor) bool { + return desc.m_objId == 4 +} + +func (sv TypeData) bytesToObj_EXACT(val []byte, out *TypeData, desc *TypeDescriptor) (*DmStruct, error) { + strOut := newDmStructByTypeData(nil, desc) + var sub_desc *TypeDescriptor + offset := out.m_offset + + size := desc.getStrctMemSize() + + out.m_offset = offset + + strOut.m_attribs = make([]TypeData, size) + for i := 0; i < size; i++ { + sub_desc = &desc.m_fieldsObj[i] + tmp, err := sv.bytesToTypeData(val, out, sub_desc) + if err != nil { + return nil, err + } + strOut.m_attribs[i] = *tmp + } + + strOut.m_dataBuf = Dm_build_1220.Dm_build_1371(val, offset, out.m_offset-offset) + + return strOut, nil +} + +func (sv TypeData) bytesToNestTab(val []byte, out *TypeData, desc *TypeDescriptor) (*DmArray, error) { + offset := out.m_offset + + offset += USINT_SIZE + + count := Dm_build_1220.Dm_build_1322(val, offset) + offset += ULINT_SIZE + + out.m_offset = offset + + arrOut := newDmArrayByTypeData(nil, desc) + arrOut.m_itemCount = int(count) + arrOut.m_arrData = make([]TypeData, count) + for i := 0; i < int(count); i++ { + tmp, err := sv.bytesToTypeData(val, out, desc.m_arrObj) + if err != nil { + return nil, err + } + arrOut.m_arrData[i] = *tmp + } + + arrOut.m_dataBuf = Dm_build_1220.Dm_build_1371(val, offset, out.m_offset-offset) + + return arrOut, nil +} + +func (sv TypeData) bytesToClnt(val []byte, out *TypeData, desc *TypeDescriptor) (*DmArray, error) { + var array *DmArray + + offset := out.m_offset + + cltn_type := Dm_build_1220.Dm_build_1317(val, offset) + offset += USINT_SIZE + + out.m_offset = offset + switch cltn_type { + case CLTN_TYPE_IND_TABLE: + return nil, ECGO_UNSUPPORTED_TYPE.throw() + + case CLTN_TYPE_NST_TABLE, CLTN_TYPE_VARRAY: + return sv.bytesToNestTab(val, out, desc) + } + + return array, nil +} + +func (sv TypeData) bytesToObj(val []byte, out *TypeData, desc *TypeDescriptor) (interface{}, error) { + var retObj interface{} + var err error + if out == nil { + out = newTypeData(nil, nil) + } + + if sv.checkObjExist(val, out) { + retObj, err = sv.findObjByPackId(val, out) + if err != nil { + return nil, err + } + } else { + sv.addObjToRefArr(out, retObj) + } + + if sv.checkObjClnt(desc) { + retObj, err = sv.bytesToClnt(val, out, desc) + if err != nil { + return nil, err + } + } else { + retObj, err = sv.bytesToObj_EXACT(val, out, desc) + if err != nil { + return nil, err + } + } + + return retObj, nil +} + +func (sv TypeData) bytesToArray(val []byte, out *TypeData, desc *TypeDescriptor) (*DmArray, error) { + arrOut := newDmArrayByTypeData(nil, desc) + if out == nil { + out = newTypeData(nil, nil) + } + + offset := out.m_offset + + arrOut.m_bufLen = int(Dm_build_1220.Dm_build_1322(val, offset)) + offset += 4 + + arrOut.m_itemCount = int(Dm_build_1220.Dm_build_1322(val, offset)) + offset += ULINT_SIZE + + arrOut.m_itemSize = int(Dm_build_1220.Dm_build_1322(val, offset)) + offset += ULINT_SIZE + + arrOut.m_objCount = int(Dm_build_1220.Dm_build_1322(val, offset)) + offset += ULINT_SIZE + + arrOut.m_strCount = int(Dm_build_1220.Dm_build_1322(val, offset)) + offset += ULINT_SIZE + + total := arrOut.m_objCount + arrOut.m_strCount + arrOut.m_objStrOffs = make([]int, total) + for i := 0; i < total; i++ { + arrOut.m_objStrOffs[i] = int(Dm_build_1220.Dm_build_1322(val, offset)) + offset += 4 + } + + out.m_offset = offset + + arrOut.m_arrData = make([]TypeData, arrOut.m_itemCount) + for i := 0; i < arrOut.m_itemCount; i++ { + tmp, err := sv.bytesToTypeData(val, out, desc.m_arrObj) + if err != nil { + return nil, err + } + arrOut.m_arrData[i] = *tmp + } + + arrOut.m_dataBuf = Dm_build_1220.Dm_build_1371(val, offset, out.m_offset-offset) + + return arrOut, nil +} + +func (sv TypeData) bytesToSArray(val []byte, out *TypeData, desc *TypeDescriptor) (*DmArray, error) { + if out == nil { + out = newTypeData(nil, nil) + } + + offset := out.m_offset + + arrOut := newDmArrayByTypeData(nil, desc) + arrOut.m_bufLen = int(Dm_build_1220.Dm_build_1322(val, offset)) + offset += ULINT_SIZE + + arrOut.m_itemCount = int(Dm_build_1220.Dm_build_1322(val, offset)) + offset += ULINT_SIZE + + out.m_offset = offset + + arrOut.m_arrData = make([]TypeData, arrOut.m_itemCount) + for i := 0; i < arrOut.m_itemCount; i++ { + tmp, err := sv.bytesToTypeData(val, out, desc.m_arrObj) + if err != nil { + return nil, err + } + arrOut.m_arrData[i] = *tmp + } + + arrOut.m_dataBuf = Dm_build_1220.Dm_build_1371(val, offset, out.m_offset-offset) + + return arrOut, nil +} + +func (sv TypeData) bytesToRecord(val []byte, out *TypeData, desc *TypeDescriptor) (*DmStruct, error) { + if out == nil { + out = newTypeData(nil, nil) + } + + offset := out.m_offset + + strOut := newDmStructByTypeData(nil, desc) + strOut.m_bufLen = int(Dm_build_1220.Dm_build_1322(val, offset)) + offset += ULINT_SIZE + + out.m_offset = offset + + strOut.m_attribs = make([]TypeData, desc.getStrctMemSize()) + for i := 0; i < desc.getStrctMemSize(); i++ { + tmp, err := sv.bytesToTypeData(val, out, desc.m_arrObj) + if err != nil { + return nil, err + } + strOut.m_attribs[i] = *tmp + } + + strOut.m_dataBuf = Dm_build_1220.Dm_build_1371(val, offset, out.m_offset-offset) + + return strOut, nil +} + +func (sv TypeData) objBlob_GetChkBuf(buf []byte, typeData *TypeData) { + + offset := 4 + + l := int(Dm_build_1220.Dm_build_1322(buf, offset)) + offset += ULINT_SIZE + + typeData.m_objBlobDescBuf = Dm_build_1220.Dm_build_1371(buf, offset, l) + offset += l + + typeData.m_isFromBlob = true + + typeData.m_offset = offset +} + +func (sv TypeData) objBlobToObj(lob *DmBlob, desc *TypeDescriptor) (interface{}, error) { + typeData := newTypeData(nil, nil) + loblen, err := lob.GetLength() + if err != nil { + return nil, err + } + + buf, err := lob.getBytes(1, int32(loblen)) + if err != nil { + return nil, err + } + + sv.objBlob_GetChkBuf(buf, typeData) + + return sv.bytesToObj(buf, typeData, desc) +} + +func (sv TypeData) objBlobToBytes(lobBuf []byte, desc *TypeDescriptor) ([]byte, error) { + l := len(lobBuf) + offset := 0 + + magic := Dm_build_1220.Dm_build_1322(lobBuf, offset) + offset += ULINT_SIZE + + if OBJ_BLOB_MAGIC != magic { + return nil, ECGO_INVALID_OBJ_BLOB.throw() + } + + descLen := int(Dm_build_1220.Dm_build_1322(lobBuf, offset)) + offset += ULINT_SIZE + descBuf := Dm_build_1220.Dm_build_1371(lobBuf, offset, descLen) + tmp, err := desc.getClassDescChkInfo() + if err != nil { + return nil, err + } + if !util.SliceEquals(descBuf, tmp) { + return nil, ECGO_INVALID_OBJ_BLOB.throw() + } + offset += descLen + + ret := make([]byte, l-offset) + copy(ret[:len(ret)], lobBuf[offset:offset+len(ret)]) + return ret, nil +} + +func (sv TypeData) realocBuffer(oldBuf []byte, offset int, needLen int) []byte { + var retBuf []byte + + if oldBuf == nil { + return make([]byte, needLen) + } else if needLen+offset > len(oldBuf) { + retBuf = make([]byte, len(oldBuf)+needLen) + copy(retBuf[:offset], oldBuf[:offset]) + } else { + retBuf = oldBuf + } + + return retBuf +} + +func (sv TypeData) convertBytes2BaseData(val []byte, out *TypeData, desc *TypeDescriptor) (*TypeData, error) { + offset := out.m_offset + isNull := false + valueLen := int(Dm_build_1220.Dm_build_1344(val, offset)) + offset += USINT_SIZE + + if valueLen == int(Dm_build_650) { + valueLen = 0 + isNull = true + } + + if -1 == valueLen { + valueLen = int(Dm_build_1220.Dm_build_1322(val, offset)) + offset += ULINT_SIZE + } + + if isNull { + out.m_offset = offset + return newTypeData(nil, nil), nil + } + + var tmpObj interface{} + var err error + temp := Dm_build_1220.Dm_build_1371(val, offset, valueLen) + offset += valueLen + out.m_offset = offset + + tmpObj, err = DB2G.toObject(temp, desc.column, desc.m_conn) + if err != nil { + return nil, err + } + return newTypeData(tmpObj, temp), nil +} + +func (td *TypeData) toJavaArray(arr *DmArray, index int64, l int, dType int) (interface{}, error) { + if arr.m_objArray != nil { + return arr.m_objArray, nil + } + + var nr = make([]interface{}, l) + var tempData *TypeData + switch dType { + case CHAR, VARCHAR, VARCHAR2: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + case BIT, TINYINT: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case BINARY, VARBINARY: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + + case BOOLEAN: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case SMALLINT: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case INT: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case BIGINT: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case DECIMAL: + + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + case REAL: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case DOUBLE: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + + case INTERVAL_YM: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + + case INTERVAL_DT: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + + case PLTYPE_RECORD, CLASS, ARRAY, SARRAY: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil { + nr[i] = tempData.m_dumyData + } + } + + case BLOB: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + + case CLOB: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + + default: + return nil, ECGO_UNSUPPORTED_TYPE.throw() + } + + return nr, nil +} + +func (td *TypeData) toNumericArray(arr *DmArray, index int64, l int, flag int) (interface{}, error) { + if nil == arr.m_objArray { + return nil, nil + } + + var retObj interface{} + switch arr.m_objArray.(type) { + case []int16: + if flag == ARRAY_TYPE_SHORT { + ret := make([]int16, l) + copy(ret[:l], arr.m_objArray.([]int16)[index:index+int64(l)]) + retObj = ret + } + case []int: + if flag == ARRAY_TYPE_INTEGER { + ret := make([]int, l) + copy(ret[:l], arr.m_objArray.([]int)[index:index+int64(l)]) + retObj = ret + } + case []int64: + if flag == ARRAY_TYPE_LONG { + ret := make([]int64, l) + copy(ret[:l], arr.m_objArray.([]int64)[index:index+int64(l)]) + retObj = ret + } + case []float32: + if flag == ARRAY_TYPE_FLOAT { + ret := make([]float32, l) + copy(ret[:l], arr.m_objArray.([]float32)[index:index+int64(l)]) + retObj = ret + } + case []float64: + if flag == ARRAY_TYPE_DOUBLE { + ret := make([]float64, l) + copy(ret[:l], arr.m_objArray.([]float64)[index:index+int64(l)]) + retObj = ret + } + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + + return retObj, nil +} + +func (td *TypeData) toJavaArrayByDmStruct(st *DmStruct) ([]interface{}, error) { + attrsData := st.getAttribsTypeData() + if nil == st.getAttribsTypeData() || len(st.getAttribsTypeData()) <= 0 { + return nil, nil + } + + fields := st.m_strctDesc.getItemsDesc() + if len(attrsData) != len(fields) { + return nil, ECGO_STRUCT_MEM_NOT_MATCH.throw() + } + + out := make([]interface{}, len(fields)) + for i := 0; i < len(fields); i++ { + out[i] = attrsData[i].m_dumyData + } + + return out, nil +} + +func (td *TypeData) toBytesFromDmArray(x *DmArray, typeDesc *TypeDescriptor) ([]byte, error) { + var err error + desc, err := typeDesc.getClassDescChkInfo() + if err != nil { + return nil, err + } + var data []byte + switch typeDesc.getDType() { + case ARRAY: + data, err = TypeDataSV.arrayToBytes(x, typeDesc) + if err != nil { + return nil, err + } + case SARRAY: + data, err = TypeDataSV.sarrayToBytes(x, typeDesc) + if err != nil { + return nil, err + } + case PLTYPE_RECORD: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + case CLASS: + data, err = TypeDataSV.objToBytes(x, typeDesc) + if err != nil { + return nil, err + } + } + ret := make([]byte, ULINT_SIZE+ULINT_SIZE+len(desc)+len(data)) + Dm_build_1220.Dm_build_1236(ret, 0, OBJ_BLOB_MAGIC) + Dm_build_1220.Dm_build_1236(ret, ULINT_SIZE, int32(len(desc))) + copy(ret[ULINT_SIZE+ULINT_SIZE:ULINT_SIZE+ULINT_SIZE+len(desc)], desc[:len(desc)]) + copy(ret[ULINT_SIZE+ULINT_SIZE:ULINT_SIZE+ULINT_SIZE+len(desc)+len(data)], desc[:len(data)]) + return ret, nil +} + +func (td *TypeData) toBytesFromDmStruct(x *DmStruct, typeDesc *TypeDescriptor) ([]byte, error) { + var err error + desc, err := typeDesc.getClassDescChkInfo() + if err != nil { + return nil, err + } + var data []byte + switch typeDesc.getDType() { + case ARRAY: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + case SARRAY: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + case PLTYPE_RECORD: + data, err = TypeDataSV.recordToBytes(x, typeDesc) + if err != nil { + return nil, err + } + case CLASS: + data, err = TypeDataSV.objToBytes(x, typeDesc) + if err != nil { + return nil, err + } + } + ret := make([]byte, ULINT_SIZE+ULINT_SIZE+len(desc)+len(data)) + Dm_build_1220.Dm_build_1236(ret, 0, OBJ_BLOB_MAGIC) + Dm_build_1220.Dm_build_1236(ret, ULINT_SIZE, int32(len(desc))) + copy(ret[ULINT_SIZE+ULINT_SIZE:ULINT_SIZE+ULINT_SIZE+len(desc)], desc[:len(desc)]) + copy(ret[ULINT_SIZE+ULINT_SIZE:ULINT_SIZE+ULINT_SIZE+len(desc)+len(data)], desc[:len(data)]) + return ret, nil +} diff --git a/dmr/zzp.go b/dmr/zzp.go new file mode 100644 index 0000000..6dc4a8c --- /dev/null +++ b/dmr/zzp.go @@ -0,0 +1,763 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dmr + +import ( + "database/sql/driver" +) + +const ( + OBJ_BLOB_MAGIC = 78111999 + + CLTN_TYPE_IND_TABLE = 3 + + CLTN_TYPE_NST_TABLE = 2 + + CLTN_TYPE_VARRAY = 1 +) + +type TypeDescriptor struct { + column *column + + m_sqlName *sqlName + + m_objId int + + m_objVersion int + + m_outerId int + + m_outerVer int + + m_subId int + + m_cltnType int + + m_maxCnt int + + m_length int + + m_size int + + m_conn *DmConnection + + m_serverEncoding string + + m_arrObj *TypeDescriptor + + m_fieldsObj []TypeDescriptor + + m_descBuf []byte +} + +func newTypeDescriptorWithFulName(fulName string, conn *DmConnection) *TypeDescriptor { + td := new(TypeDescriptor) + td.init() + td.m_sqlName = newSqlNameByFulName(fulName) + td.m_conn = conn + return td +} + +func newTypeDescriptor(conn *DmConnection) *TypeDescriptor { + td := new(TypeDescriptor) + td.init() + td.m_sqlName = newSqlNameByConn(conn) + td.m_conn = conn + return td +} + +func (typeDescriptor *TypeDescriptor) init() { + typeDescriptor.column = new(column).InitColumn() + + typeDescriptor.m_sqlName = nil + + typeDescriptor.m_objId = -1 + + typeDescriptor.m_objVersion = -1 + + typeDescriptor.m_outerId = 0 + + typeDescriptor.m_outerVer = 0 + + typeDescriptor.m_subId = 0 + + typeDescriptor.m_cltnType = 0 + + typeDescriptor.m_maxCnt = 0 + + typeDescriptor.m_length = 0 + + typeDescriptor.m_size = 0 + + typeDescriptor.m_conn = nil + + typeDescriptor.m_serverEncoding = "" + + typeDescriptor.m_arrObj = nil + + typeDescriptor.m_fieldsObj = nil + + typeDescriptor.m_descBuf = nil +} + +func (typeDescriptor *TypeDescriptor) parseDescByName() error { + sql := "BEGIN ? = SF_DESCRIBE_TYPE(?); END;" + + params := make([]driver.Value, 2) + params[1] = typeDescriptor.m_sqlName.m_fulName + + rs, err := typeDescriptor.m_conn.query(sql, params) + if err != nil { + return err + } + rs.close() + l, err := params[0].(*DmBlob).GetLength() + if err != nil { + return err + } + + buf, err := params[0].(*DmBlob).getBytes(1, int32(l)) + if err != nil { + return err + } + typeDescriptor.m_serverEncoding = typeDescriptor.m_conn.getServerEncoding() + err = typeDescriptor.unpack(Dm_build_5(buf)) + if err != nil { + return err + } + return nil +} + +func (typeDescriptor *TypeDescriptor) getFulName() (string, error) { + return typeDescriptor.m_sqlName.getFulName() +} + +func (typeDescriptor *TypeDescriptor) getDType() int { + return int(typeDescriptor.column.colType) +} + +func (typeDescriptor *TypeDescriptor) getPrec() int { + return int(typeDescriptor.column.prec) +} + +func (typeDescriptor *TypeDescriptor) getScale() int { + return int(typeDescriptor.column.scale) +} + +func (typeDescriptor *TypeDescriptor) getServerEncoding() string { + if typeDescriptor.m_serverEncoding == "" { + return typeDescriptor.m_conn.getServerEncoding() + } else { + return typeDescriptor.m_serverEncoding + } +} + +func (typeDescriptor *TypeDescriptor) getObjId() int { + return typeDescriptor.m_objId +} + +func (typeDescriptor *TypeDescriptor) getStaticArrayLength() int { + return typeDescriptor.m_length +} + +func (typeDescriptor *TypeDescriptor) getStrctMemSize() int { + return typeDescriptor.m_size +} + +func (typeDescriptor *TypeDescriptor) getOuterId() int { + return typeDescriptor.m_outerId +} + +func (typeDescriptor *TypeDescriptor) getCltnType() int { + return typeDescriptor.m_cltnType +} + +func (typeDescriptor *TypeDescriptor) getMaxCnt() int { + return typeDescriptor.m_maxCnt +} + +func getPackSize(typeDesc *TypeDescriptor) (int, error) { + len := 0 + + switch typeDesc.column.colType { + case ARRAY, SARRAY: + return getPackArraySize(typeDesc) + + case CLASS: + return getPackClassSize(typeDesc) + + case PLTYPE_RECORD: + return getPackRecordSize(typeDesc) + } + + len += ULINT_SIZE + + len += ULINT_SIZE + + len += ULINT_SIZE + + return len, nil +} + +func pack(typeDesc *TypeDescriptor, msg *Dm_build_0) error { + switch typeDesc.column.colType { + case ARRAY, SARRAY: + return packArray(typeDesc, msg) + case CLASS: + return packClass(typeDesc, msg) + case PLTYPE_RECORD: + return packRecord(typeDesc, msg) + } + + msg.Dm_build_51(typeDesc.column.colType) + + msg.Dm_build_51(typeDesc.column.prec) + + msg.Dm_build_51(typeDesc.column.scale) + return nil +} + +func getPackArraySize(arrDesc *TypeDescriptor) (int, error) { + l := 0 + + l += ULINT_SIZE + + name := arrDesc.m_sqlName.m_name + l += USINT_SIZE + + serverEncoding := arrDesc.getServerEncoding() + ret := Dm_build_1220.Dm_build_1433(name, serverEncoding, arrDesc.m_conn) + l += len(ret) + + l += ULINT_SIZE + + l += ULINT_SIZE + + l += ULINT_SIZE + + i, err := getPackSize(arrDesc.m_arrObj) + if err != nil { + return 0, err + } + + l += i + + return l, nil +} + +func packArray(arrDesc *TypeDescriptor, msg *Dm_build_0) error { + + msg.Dm_build_51(arrDesc.column.colType) + + msg.Dm_build_107(arrDesc.m_sqlName.m_name, arrDesc.getServerEncoding(), arrDesc.m_conn) + + msg.Dm_build_51(int32(arrDesc.m_objId)) + + msg.Dm_build_51(int32(arrDesc.m_objVersion)) + + msg.Dm_build_51(int32(arrDesc.m_length)) + + return pack(arrDesc.m_arrObj, msg) +} + +func packRecord(strctDesc *TypeDescriptor, msg *Dm_build_0) error { + + msg.Dm_build_51(strctDesc.column.colType) + + msg.Dm_build_107(strctDesc.m_sqlName.m_name, strctDesc.getServerEncoding(), strctDesc.m_conn) + + msg.Dm_build_51(int32(strctDesc.m_objId)) + + msg.Dm_build_51(int32(strctDesc.m_objVersion)) + + msg.Dm_build_47(int16(strctDesc.m_size)) + + for i := 0; i < strctDesc.m_size; i++ { + err := pack(&strctDesc.m_fieldsObj[i], msg) + if err != nil { + return err + } + } + return nil +} + +func getPackRecordSize(strctDesc *TypeDescriptor) (int, error) { + l := 0 + + l += ULINT_SIZE + + name := strctDesc.m_sqlName.m_name + l += USINT_SIZE + + serverEncoding := strctDesc.getServerEncoding() + ret := Dm_build_1220.Dm_build_1433(name, serverEncoding, strctDesc.m_conn) + l += len(ret) + + l += ULINT_SIZE + + l += ULINT_SIZE + + l += USINT_SIZE + + for i := 0; i < strctDesc.m_size; i++ { + i, err := getPackSize(&strctDesc.m_fieldsObj[i]) + if err != nil { + return 0, err + } + l += i + } + + return l, nil +} + +func getPackClassSize(strctDesc *TypeDescriptor) (int, error) { + l := 0 + + l += ULINT_SIZE + + name := strctDesc.m_sqlName.m_name + l += USINT_SIZE + + serverEncoding := strctDesc.getServerEncoding() + ret := Dm_build_1220.Dm_build_1433(name, serverEncoding, strctDesc.m_conn) + l += len(ret) + + l += ULINT_SIZE + + l += ULINT_SIZE + + if strctDesc.m_objId == 4 { + + l += ULINT_SIZE + + l += ULINT_SIZE + + l += USINT_SIZE + } + + return l, nil +} + +func packClass(strctDesc *TypeDescriptor, msg *Dm_build_0) error { + + msg.Dm_build_51(strctDesc.column.colType) + + msg.Dm_build_107(strctDesc.m_sqlName.m_name, strctDesc.getServerEncoding(), strctDesc.m_conn) + + msg.Dm_build_51(int32(strctDesc.m_objId)) + + msg.Dm_build_51(int32(strctDesc.m_objVersion)) + + if strctDesc.m_objId == 4 { + + msg.Dm_build_51(int32(strctDesc.m_outerId)) + + msg.Dm_build_51(int32(strctDesc.m_outerVer)) + + msg.Dm_build_51(int32(strctDesc.m_subId)) + + } + + return nil +} + +func (typeDescriptor *TypeDescriptor) unpack(buffer *Dm_build_0) error { + + typeDescriptor.column.colType = buffer.Dm_build_125() + + switch typeDescriptor.column.colType { + case ARRAY, SARRAY: + return typeDescriptor.unpackArray(buffer) + case CLASS: + return typeDescriptor.unpackClass(buffer) + case PLTYPE_RECORD: + return typeDescriptor.unpackRecord(buffer) + } + + typeDescriptor.column.prec = buffer.Dm_build_125() + + typeDescriptor.column.scale = buffer.Dm_build_125() + return nil +} + +func (typeDescriptor *TypeDescriptor) unpackArray(buffer *Dm_build_0) error { + + typeDescriptor.m_sqlName.m_name = buffer.Dm_build_175(typeDescriptor.getServerEncoding(), typeDescriptor.m_conn) + + typeDescriptor.m_sqlName.m_schId = int(buffer.Dm_build_125()) + + typeDescriptor.m_sqlName.m_packId = int(buffer.Dm_build_125()) + + typeDescriptor.m_objId = int(buffer.Dm_build_125()) + + typeDescriptor.m_objVersion = int(buffer.Dm_build_125()) + + typeDescriptor.m_length = int(buffer.Dm_build_125()) + if typeDescriptor.column.colType == ARRAY { + typeDescriptor.m_length = 0 + } + + typeDescriptor.m_arrObj = newTypeDescriptor(typeDescriptor.m_conn) + return typeDescriptor.m_arrObj.unpack(buffer) +} + +func (typeDescriptor *TypeDescriptor) unpackRecord(buffer *Dm_build_0) error { + + typeDescriptor.m_sqlName.m_name = buffer.Dm_build_175(typeDescriptor.getServerEncoding(), typeDescriptor.m_conn) + + typeDescriptor.m_sqlName.m_schId = int(buffer.Dm_build_125()) + + typeDescriptor.m_sqlName.m_packId = int(buffer.Dm_build_125()) + + typeDescriptor.m_objId = int(buffer.Dm_build_125()) + + typeDescriptor.m_objVersion = int(buffer.Dm_build_125()) + + typeDescriptor.m_size = int(buffer.Dm_build_140()) + + typeDescriptor.m_fieldsObj = make([]TypeDescriptor, typeDescriptor.m_size) + for i := 0; i < typeDescriptor.m_size; i++ { + typeDescriptor.m_fieldsObj[i] = *newTypeDescriptor(typeDescriptor.m_conn) + typeDescriptor.m_fieldsObj[i].unpack(buffer) + } + + return nil +} + +func (typeDescriptor *TypeDescriptor) unpackClnt_nestTab(buffer *Dm_build_0) error { + + typeDescriptor.m_maxCnt = int(buffer.Dm_build_125()) + + typeDescriptor.m_arrObj = newTypeDescriptor(typeDescriptor.m_conn) + + typeDescriptor.m_arrObj.unpack(buffer) + + return nil +} + +func (typeDescriptor *TypeDescriptor) unpackClnt(buffer *Dm_build_0) error { + + typeDescriptor.m_outerId = int(buffer.Dm_build_125()) + + typeDescriptor.m_outerVer = int(buffer.Dm_build_125()) + + typeDescriptor.m_subId = int(buffer.Dm_build_140()) + + typeDescriptor.m_cltnType = int(buffer.Dm_build_140()) + + switch typeDescriptor.m_cltnType { + case CLTN_TYPE_IND_TABLE: + return ECGO_UNSUPPORTED_TYPE.throw() + + case CLTN_TYPE_NST_TABLE, CLTN_TYPE_VARRAY: + return typeDescriptor.unpackClnt_nestTab(buffer) + + } + return nil +} + +func (typeDescriptor *TypeDescriptor) unpackClass(buffer *Dm_build_0) error { + + typeDescriptor.m_sqlName.m_name = buffer.Dm_build_175(typeDescriptor.getServerEncoding(), typeDescriptor.m_conn) + + typeDescriptor.m_sqlName.m_schId = int(buffer.Dm_build_125()) + + typeDescriptor.m_sqlName.m_packId = int(buffer.Dm_build_125()) + + typeDescriptor.m_objId = int(buffer.Dm_build_125()) + + typeDescriptor.m_objVersion = int(buffer.Dm_build_125()) + + if typeDescriptor.m_objId == 4 { + return typeDescriptor.unpackClnt(buffer) + } else { + + typeDescriptor.m_size = int(buffer.Dm_build_140()) + + typeDescriptor.m_fieldsObj = make([]TypeDescriptor, typeDescriptor.m_size) + for i := 0; i < typeDescriptor.m_size; i++ { + typeDescriptor.m_fieldsObj[i] = *newTypeDescriptor(typeDescriptor.m_conn) + err := typeDescriptor.m_fieldsObj[i].unpack(buffer) + if err != nil { + return err + } + } + return nil + } + +} + +func calcChkDescLen_array(desc *TypeDescriptor) (int, error) { + offset := 0 + + offset += USINT_SIZE + + offset += ULINT_SIZE + + tmp, err := calcChkDescLen(desc) + if err != nil { + return 0, err + } + + offset += tmp + + return offset, nil +} + +func calcChkDescLen_record(desc *TypeDescriptor) (int, error) { + offset := 0 + + offset += USINT_SIZE + + offset += USINT_SIZE + + for i := 0; i < desc.m_size; i++ { + tmp, err := calcChkDescLen(&desc.m_fieldsObj[i]) + if err != nil { + return 0, err + } + offset += tmp + } + + return offset, nil +} + +func calcChkDescLen_class_normal(desc *TypeDescriptor) (int, error) { + offset := 0 + + offset += USINT_SIZE + + for i := 0; i < desc.m_size; i++ { + tmp, err := calcChkDescLen(&desc.m_fieldsObj[i]) + if err != nil { + return 0, err + } + offset += tmp + } + + return offset, nil +} + +func calcChkDescLen_class_cnlt(desc *TypeDescriptor) (int, error) { + offset := 0 + + offset += USINT_SIZE + + offset += ULINT_SIZE + + switch desc.getCltnType() { + case CLTN_TYPE_IND_TABLE: + return 0, ECGO_UNSUPPORTED_TYPE.throw() + + case CLTN_TYPE_VARRAY, CLTN_TYPE_NST_TABLE: + + i, err := calcChkDescLen(desc.m_arrObj) + if err != nil { + return 0, err + } + + offset += i + } + + return offset, nil +} + +func calcChkDescLen_class(desc *TypeDescriptor) (int, error) { + offset := 0 + + offset += USINT_SIZE + + offset += BYTE_SIZE + + if desc.m_objId == 4 { + i, err := calcChkDescLen_class_cnlt(desc) + if err != nil { + return 0, err + } + offset += i + } else { + i, err := calcChkDescLen_class_normal(desc) + if err != nil { + return 0, err + } + offset += i + } + + return offset, nil +} + +func calcChkDescLen_buildin() int { + offset := 0 + + offset += USINT_SIZE + + offset += USINT_SIZE + + offset += USINT_SIZE + + return offset +} + +func calcChkDescLen(desc *TypeDescriptor) (int, error) { + + switch desc.getDType() { + case ARRAY, SARRAY: + return calcChkDescLen_array(desc) + + case PLTYPE_RECORD: + return calcChkDescLen_record(desc) + + case CLASS: + return calcChkDescLen_class(desc) + + default: + return calcChkDescLen_buildin(), nil + } + +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc_array(offset int, desc *TypeDescriptor) (int, error) { + + Dm_build_1220.Dm_build_1231(typeDescriptor.m_descBuf, offset, ARRAY) + offset += USINT_SIZE + + Dm_build_1220.Dm_build_1236(typeDescriptor.m_descBuf, offset, int32(desc.m_length)) + offset += ULINT_SIZE + + return typeDescriptor.makeChkDesc(offset, desc) +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc_record(offset int, desc *TypeDescriptor) (int, error) { + + Dm_build_1220.Dm_build_1231(typeDescriptor.m_descBuf, offset, PLTYPE_RECORD) + offset += USINT_SIZE + + Dm_build_1220.Dm_build_1231(typeDescriptor.m_descBuf, offset, int16(desc.m_size)) + offset += USINT_SIZE + var err error + for i := 0; i < desc.m_size; i++ { + offset, err = typeDescriptor.makeChkDesc(offset, &desc.m_fieldsObj[i]) + if err != nil { + return 0, err + } + } + + return offset, nil +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc_buildin(offset int, desc *TypeDescriptor) int { + dtype := int16(desc.getDType()) + prec := 0 + scale := 0 + + if dtype != BLOB { + prec = desc.getPrec() + scale = desc.getScale() + } + + Dm_build_1220.Dm_build_1231(typeDescriptor.m_descBuf, offset, dtype) + offset += USINT_SIZE + + Dm_build_1220.Dm_build_1231(typeDescriptor.m_descBuf, offset, int16(prec)) + offset += USINT_SIZE + + Dm_build_1220.Dm_build_1231(typeDescriptor.m_descBuf, offset, int16(scale)) + offset += USINT_SIZE + + return offset +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc_class_normal(offset int, desc *TypeDescriptor) (int, error) { + + Dm_build_1220.Dm_build_1231(typeDescriptor.m_descBuf, offset, int16(desc.m_size)) + offset += USINT_SIZE + var err error + + for i := 0; i < desc.m_size; i++ { + offset, err = typeDescriptor.makeChkDesc(offset, &desc.m_fieldsObj[i]) + if err != nil { + return 0, err + } + } + + return offset, nil +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc_class_clnt(offset int, desc *TypeDescriptor) (int, error) { + + Dm_build_1220.Dm_build_1231(typeDescriptor.m_descBuf, offset, int16(desc.m_cltnType)) + offset += USINT_SIZE + + Dm_build_1220.Dm_build_1236(typeDescriptor.m_descBuf, offset, int32(desc.getMaxCnt())) + offset += ULINT_SIZE + + switch desc.m_cltnType { + case CLTN_TYPE_IND_TABLE: + return 0, ECGO_UNSUPPORTED_TYPE.throw() + + case CLTN_TYPE_NST_TABLE, CLTN_TYPE_VARRAY: + + return typeDescriptor.makeChkDesc(offset, desc.m_arrObj) + } + + return offset, nil +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc_class(offset int, desc *TypeDescriptor) (int, error) { + + Dm_build_1220.Dm_build_1231(typeDescriptor.m_descBuf, offset, CLASS) + offset += USINT_SIZE + + isClnt := false + if desc.m_objId == 4 { + isClnt = true + } + + if isClnt { + Dm_build_1220.Dm_build_1221(typeDescriptor.m_descBuf, offset, byte(1)) + } else { + Dm_build_1220.Dm_build_1221(typeDescriptor.m_descBuf, offset, byte(0)) + } + + offset += BYTE_SIZE + + if isClnt { + return typeDescriptor.makeChkDesc_class_clnt(offset, desc) + } else { + return typeDescriptor.makeChkDesc_class_normal(offset, desc) + } +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc(offset int, subDesc *TypeDescriptor) (int, error) { + switch subDesc.getDType() { + case ARRAY, SARRAY: + return typeDescriptor.makeChkDesc_array(offset, subDesc) + + case PLTYPE_RECORD: + return typeDescriptor.makeChkDesc_record(offset, subDesc) + + case CLASS: + return typeDescriptor.makeChkDesc_class(offset, subDesc) + + default: + return typeDescriptor.makeChkDesc_buildin(offset, subDesc), nil + } + +} + +func (typeDescriptor *TypeDescriptor) getClassDescChkInfo() ([]byte, error) { + if typeDescriptor.m_descBuf != nil { + return typeDescriptor.m_descBuf, nil + } + + l, err := calcChkDescLen(typeDescriptor) + if err != nil { + return nil, err + } + typeDescriptor.m_descBuf = make([]byte, l) + + typeDescriptor.makeChkDesc(0, typeDescriptor) + return typeDescriptor.m_descBuf, nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..919d573 --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module github.com/nfjBill/gorm-driver-dm + +go 1.17 + +require ( + github.com/emirpasic/gods v1.12.0 // indirect + github.com/golang/snappy v0.0.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.4 // indirect + github.com/thoas/go-funk v0.9.1 // indirect + golang.org/x/text v0.3.2 // indirect + gorm.io/gorm v1.22.5 // indirect +) diff --git a/mask.go b/mask.go new file mode 100644 index 0000000..cda6f0d --- /dev/null +++ b/mask.go @@ -0,0 +1,82 @@ +package dm + +import ( + "database/sql" + "gorm.io/gorm" + "gorm.io/gorm/clause" + "reflect" +) + +type STable struct { + Conn *gorm.DB + Table interface{} +} + +var conn *gorm.DB + +func Table(table ...interface{}) *STable { + var tb interface{} + if len(table) == 1 { + tb = table[0] + } + return &STable{Table: tb, Conn: conn} +} + +func TB(db *gorm.DB) { + conn = db +} + +func (stb *STable) DB() (*sql.DB, error) { + return stb.Conn.DB() +} + +func (stb *STable) Model() *gorm.DB { + if reflect.ValueOf(stb.Table).Kind() == reflect.String { + return stb.Conn.Table(stb.Table.(string)) + } + return stb.Conn.Model(stb.Table) +} + +func (stb *STable) Create() error { + return stb.Conn.Create(stb.Table).Error +} + +func (stb *STable) Get(dest interface{}, conds ...interface{}) error { + return stb.Conn.Where(stb.Table).First(dest, conds...).Error +} + +func (stb *STable) GetWhere(dest interface{}) error { + return stb.Conn.Model(stb.Table).Where(stb.Table).Find(dest).Error +} + +func (stb *STable) GetAll(dest interface{}) error { + return stb.Conn.Model(stb.Table).Find(dest).Error +} + +func (stb *STable) ClausesAssignmentColumns(name string, doUpdates []string) error { + return stb.Conn.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: name}}, + DoUpdates: clause.AssignmentColumns(doUpdates), + }).Create(stb.Table).Error +} + +func (stb *STable) Delete() error { + tx := stb.Conn.Begin() + if err := tx.Where(stb.Table).Delete(stb.Table).Error; err != nil { + tx.Rollback() + return err + } + return tx.Commit().Error +} + +func (stb *STable) AutoMigrate(dst ...interface{}) error { + return stb.Conn.AutoMigrate(dst...) +} + +func (stb *STable) DropTable(dest ...interface{}) error { + return stb.Conn.Migrator().DropTable(dest...) +} + +func (stb *STable) HasTable(dest interface{}) bool { + return stb.Conn.Migrator().HasTable(dest) +} diff --git a/migrator.go b/migrator.go new file mode 100644 index 0000000..1268f72 --- /dev/null +++ b/migrator.go @@ -0,0 +1,367 @@ +package dm + +import ( + "fmt" + "gorm.io/gorm/schema" + "strconv" + "strings" + + "gorm.io/gorm" + "gorm.io/gorm/clause" + "gorm.io/gorm/migrator" +) + +type Migrator struct { + migrator.Migrator +} + +func (m Migrator) CurrentDatabase() (name string) { + m.DB.Raw( + fmt.Sprintf(`SELECT ORA_DATABASE_NAME as "Current Database" FROM %s`, m.Dialector.(Dialector).DummyTableName()), + ).Row().Scan(&name) + return +} + +func buildConstraint(constraint *schema.Constraint) (sql string, results []interface{}) { + sql = "CONSTRAINT ? FOREIGN KEY ? REFERENCES ??" + if constraint.OnDelete != "" { + sql += " ON DELETE " + constraint.OnDelete + } + + if constraint.OnUpdate != "" { + sql += " ON UPDATE " + constraint.OnUpdate + } + + var foreignKeys, references []interface{} + for _, field := range constraint.ForeignKeys { + foreignKeys = append(foreignKeys, clause.Column{Name: field.DBName}) + } + + for _, field := range constraint.References { + references = append(references, clause.Column{Name: field.DBName}) + } + results = append(results, clause.Table{Name: constraint.Name}, foreignKeys, clause.Table{Name: constraint.ReferenceSchema.Table}, references) + return +} + +func (m Migrator) CreateTable(values ...interface{}) error { + for _, value := range values { + m.TryQuotifyReservedWords(value) + m.TryRemoveOnUpdate(value) + } + + for _, value := range m.ReorderModels(values, false) { + tx := m.DB.Session(&gorm.Session{}) + if err := m.RunWithValue(value, func(stmt *gorm.Statement) (errr error) { + var ( + createTableSQL = "CREATE TABLE ? (" + values = []interface{}{m.CurrentTable(stmt)} + hasPrimaryKeyInDataType bool + ) + + for _, dbName := range stmt.Schema.DBNames { + field := stmt.Schema.FieldsByDBName[dbName] + if !field.IgnoreMigration { + createTableSQL += "? ?" + hasPrimaryKeyInDataType = hasPrimaryKeyInDataType || strings.Contains(strings.ToUpper(string(field.DataType)), "PRIMARY KEY") + f := m.DB.Migrator().FullDataTypeOf(field) + if field.AutoIncrement { + f.SQL = "INTEGER IDENTITY(1, " + strconv.FormatInt(field.AutoIncrementIncrement, 10) + ")" + } + values = append(values, clause.Column{Name: dbName}, f) + createTableSQL += "," + } + } + + if !hasPrimaryKeyInDataType && len(stmt.Schema.PrimaryFields) > 0 { + createTableSQL += "PRIMARY KEY ?," + primaryKeys := []interface{}{} + for _, field := range stmt.Schema.PrimaryFields { + primaryKeys = append(primaryKeys, clause.Column{Name: field.DBName}) + } + + values = append(values, primaryKeys) + } + + for _, idx := range stmt.Schema.ParseIndexes() { + if m.CreateIndexAfterCreateTable { + //defer func(value interface{}, name string) { + // if errr == nil { + // errr = tx.Migrator().CreateIndex(value, name) + // } + //}(value, idx.Name) + } else { + if idx.Class != "" { + createTableSQL += idx.Class + " " + } + createTableSQL += "INDEX ? ?" + + if idx.Comment != "" { + createTableSQL += fmt.Sprintf(" COMMENT '%s'", idx.Comment) + } + + if idx.Option != "" { + createTableSQL += " " + idx.Option + } + + createTableSQL += "," + values = append(values, clause.Expr{SQL: idx.Name}, tx.Migrator().(migrator.BuildIndexOptionsInterface).BuildIndexOptions(idx.Fields, stmt)) + } + } + + for _, rel := range stmt.Schema.Relationships.Relations { + if !m.DB.DisableForeignKeyConstraintWhenMigrating { + if constraint := rel.ParseConstraint(); constraint != nil { + if constraint.Schema == stmt.Schema { + sql, vars := buildConstraint(constraint) + createTableSQL += sql + "," + values = append(values, vars...) + } + } + } + } + + for _, chk := range stmt.Schema.ParseCheckConstraints() { + createTableSQL += "CONSTRAINT ? CHECK (?)," + values = append(values, clause.Column{Name: chk.Name}, clause.Expr{SQL: chk.Constraint}) + } + + createTableSQL = strings.TrimSuffix(createTableSQL, ",") + + createTableSQL += ")" + + if tableOption, ok := m.DB.Get("gorm:table_options"); ok { + createTableSQL += fmt.Sprint(tableOption) + } + + errr = tx.Exec(createTableSQL, values...).Error + return errr + }); err != nil { + return err + } + } + return nil +} + +func (m Migrator) DropTable(values ...interface{}) error { + values = m.ReorderModels(values, false) + for i := len(values) - 1; i >= 0; i-- { + value := values[i] + tx := m.DB.Session(&gorm.Session{}) + if m.HasTable(value) { + if err := m.RunWithValue(value, func(stmt *gorm.Statement) error { + return tx.Exec("DROP TABLE ? CASCADE CONSTRAINTS", clause.Table{Name: stmt.Table}).Error + }); err != nil { + return err + } + } + } + return nil +} + +func (m Migrator) HasTable(value interface{}) bool { + var count int64 + + m.RunWithValue(value, func(stmt *gorm.Statement) error { + return m.DB.Raw("SELECT COUNT(*) FROM USER_TABLES WHERE TABLE_NAME = ?", stmt.Table).Row().Scan(&count) + }) + + return count > 0 +} + +func (m Migrator) RenameTable(oldName, newName interface{}) (err error) { + resolveTable := func(name interface{}) (result string, err error) { + if v, ok := name.(string); ok { + result = v + } else { + stmt := &gorm.Statement{DB: m.DB} + if err = stmt.Parse(name); err == nil { + result = stmt.Table + } + } + return + } + + var oldTable, newTable string + + if oldTable, err = resolveTable(oldName); err != nil { + return + } + + if newTable, err = resolveTable(newName); err != nil { + return + } + + if !m.HasTable(oldTable) { + return + } + + return m.DB.Exec("RENAME TABLE ? TO ?", + clause.Table{Name: oldTable}, + clause.Table{Name: newTable}, + ).Error +} + +func (m Migrator) AddColumn(value interface{}, field string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + if field := stmt.Schema.LookUpField(field); field != nil { + return m.DB.Exec( + "ALTER TABLE ? ADD ? ?", + clause.Table{Name: stmt.Table}, clause.Column{Name: field.DBName}, m.DB.Migrator().FullDataTypeOf(field), + ).Error + } + return fmt.Errorf("failed to look up field with name: %s", field) + }) +} + +func (m Migrator) DropColumn(value interface{}, name string) error { + if !m.HasColumn(value, name) { + return nil + } + + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + if field := stmt.Schema.LookUpField(name); field != nil { + name = field.DBName + } + + return m.DB.Exec( + "ALTER TABLE ? DROP ?", + clause.Table{Name: stmt.Table}, + clause.Column{Name: name}, + ).Error + }) +} + +func (m Migrator) AlterColumn(value interface{}, field string) error { + if !m.HasColumn(value, field) { + return nil + } + + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + if field := stmt.Schema.LookUpField(field); field != nil { + return m.DB.Exec( + "ALTER TABLE ? MODIFY ? ?", + clause.Table{Name: stmt.Table}, + clause.Column{Name: field.DBName}, + m.FullDataTypeOf(field), + ).Error + } + return fmt.Errorf("failed to look up field with name: %s", field) + }) +} + +func (m Migrator) HasColumn(value interface{}, field string) bool { + var count int64 + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + return m.DB.Raw("SELECT COUNT(*) FROM USER_TAB_COLUMNS WHERE TABLE_NAME = ? AND COLUMN_NAME = ?", stmt.Table, field).Row().Scan(&count) + }) == nil && count > 0 +} + +func (m Migrator) CreateConstraint(value interface{}, name string) error { + m.TryRemoveOnUpdate(value) + return m.Migrator.CreateConstraint(value, name) +} + +func (m Migrator) DropConstraint(value interface{}, name string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + for _, chk := range stmt.Schema.ParseCheckConstraints() { + if chk.Name == name { + return m.DB.Exec( + "ALTER TABLE ? DROP CHECK ?", + clause.Table{Name: stmt.Table}, clause.Column{Name: name}, + ).Error + } + } + + return m.DB.Exec( + "ALTER TABLE ? DROP CONSTRAINT ?", + clause.Table{Name: stmt.Table}, clause.Column{Name: name}, + ).Error + }) +} + +func (m Migrator) HasConstraint(value interface{}, name string) bool { + var count int64 + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + return m.DB.Raw( + "SELECT COUNT(*) FROM USER_CONSTRAINTS WHERE TABLE_NAME = ? AND CONSTRAINT_NAME = ?", stmt.Table, name, + ).Row().Scan(&count) + }) == nil && count > 0 +} + +func (m Migrator) DropIndex(value interface{}, name string) error { + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + if idx := stmt.Schema.LookIndex(name); idx != nil { + name = idx.Name + } + + return m.DB.Exec("DROP INDEX ?", clause.Column{Name: name}, clause.Table{Name: stmt.Table}).Error + }) +} + +func (m Migrator) HasIndex(value interface{}, name string) bool { + var count int64 + m.RunWithValue(value, func(stmt *gorm.Statement) error { + if idx := stmt.Schema.LookIndex(name); idx != nil { + name = idx.Name + } + + return m.DB.Raw( + "SELECT COUNT(*) FROM USER_INDEXES WHERE TABLE_NAME = ? AND INDEX_NAME = ?", + m.Migrator.DB.NamingStrategy.TableName(stmt.Table), + m.Migrator.DB.NamingStrategy.IndexName(stmt.Table, name), + ).Row().Scan(&count) + }) + + return count > 0 +} + +// https://docs.dm.com/database/121/SPATL/alter-index-rename.htm +func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error { + panic("TODO") + return m.RunWithValue(value, func(stmt *gorm.Statement) error { + return m.DB.Exec( + "ALTER INDEX ?.? RENAME TO ?", // wat + clause.Table{Name: stmt.Table}, clause.Column{Name: oldName}, clause.Column{Name: newName}, + ).Error + }) +} + +func (m Migrator) TryRemoveOnUpdate(values ...interface{}) error { + for _, value := range values { + if err := m.RunWithValue(value, func(stmt *gorm.Statement) error { + for _, rel := range stmt.Schema.Relationships.Relations { + constraint := rel.ParseConstraint() + if constraint != nil { + rel.Field.TagSettings["CONSTRAINT"] = strings.ReplaceAll(rel.Field.TagSettings["CONSTRAINT"], fmt.Sprintf("ON UPDATE %s", constraint.OnUpdate), "") + } + } + return nil + }); err != nil { + return err + } + } + return nil +} + +func (m Migrator) TryQuotifyReservedWords(values ...interface{}) error { + for _, value := range values { + if err := m.RunWithValue(value, func(stmt *gorm.Statement) error { + for idx, v := range stmt.Schema.DBNames { + if IsReservedWord(v) { + stmt.Schema.DBNames[idx] = fmt.Sprintf(`"%s"`, v) + } + } + + for _, v := range stmt.Schema.Fields { + if IsReservedWord(v.DBName) { + v.DBName = fmt.Sprintf(`"%s"`, v.DBName) + } + } + return nil + }); err != nil { + return err + } + } + return nil +} diff --git a/namer.go b/namer.go new file mode 100644 index 0000000..b06d059 --- /dev/null +++ b/namer.go @@ -0,0 +1,38 @@ +package dm + +import ( + "gorm.io/gorm/schema" + "strings" +) + +type Namer struct { + schema.NamingStrategy +} + +func ConvertNameToFormat(x string) string { + return strings.ToUpper(x) +} + +func (n Namer) TableName(table string) (name string) { + return ConvertNameToFormat(n.NamingStrategy.TableName(table)) +} + +func (n Namer) ColumnName(table, column string) (name string) { + return ConvertNameToFormat(n.NamingStrategy.ColumnName(table, column)) +} + +func (n Namer) JoinTableName(table string) (name string) { + return ConvertNameToFormat(n.NamingStrategy.JoinTableName(table)) +} + +func (n Namer) RelationshipFKName(relationship schema.Relationship) (name string) { + return ConvertNameToFormat(n.NamingStrategy.RelationshipFKName(relationship)) +} + +func (n Namer) CheckerName(table, column string) (name string) { + return ConvertNameToFormat(n.NamingStrategy.CheckerName(table, column)) +} + +func (n Namer) IndexName(table, column string) (name string) { + return ConvertNameToFormat(n.NamingStrategy.IndexName(table, column)) +} diff --git a/reserved.go b/reserved.go new file mode 100644 index 0000000..f2a7d50 --- /dev/null +++ b/reserved.go @@ -0,0 +1,28 @@ +package dm + +import ( + "github.com/emirpasic/gods/sets/hashset" + "github.com/thoas/go-funk" +) + +var ReservedWords = hashset.New(funk.Map(ReservedWordsList, func(s string) interface{} { return s }).([]interface{})...) + +func IsReservedWord(v string) bool { + return ReservedWords.Contains(v) +} + +var ReservedWordsList = []string{ + "AGGREGATE", "AGGREGATES", "ALL", "ALLOW", "ANALYZE", "ANCESTOR", "AND", "ANY", "AS", "ASC", "AT", "AVG", "BETWEEN", + "BINARY_DOUBLE", "BINARY_FLOAT", "BLOB", "BRANCH", "BUILD", "BY", "BYTE", "CASE", "CAST", "CHAR", "CHILD", "CLEAR", + "CLOB", "COMMIT", "COMPILE", "CONSIDER", "COUNT", "DATATYPE", "DATE", "DATE_MEASURE", "DAY", "DECIMAL", "DELETE", + "DESC", "DESCENDANT", "DIMENSION", "DISALLOW", "DIVISION", "DML", "ELSE", "END", "ESCAPE", "EXECUTE", "FIRST", + "FLOAT", "FOR", "FROM", "HIERARCHIES", "HIERARCHY", "HOUR", "IGNORE", "IN", "INFINITE", "INSERT", "INTEGER", + "INTERVAL", "INTO", "IS", "LAST", "LEAF_DESCENDANT", "LEAVES", "LEVEL", "LIKE", "LIKEC", "LIKE2", "LIKE4", "LOAD", + "LOCAL", "LOG_SPEC", "LONG", "MAINTAIN", "MAX", "MEASURE", "MEASURES", "MEMBER", "MEMBERS", "MERGE", "MLSLABEL", + "MIN", "MINUTE", "MODEL", "MONTH", "NAN", "NCHAR", "NCLOB", "NO", "NONE", "NOT", "NULL", "NULLS", "NUMBER", + "NVARCHAR2", "OF", "OLAP", "OLAP_DML_EXPRESSION", "ON", "ONLY", "OPERATOR", "OR", "ORDER", "OVER", "OVERFLOW", + "PARALLEL", "PARENT", "PLSQL", "PRUNE", "RAW", "RELATIVE", "ROOT_ANCESTOR", "ROWID", "SCN", "SECOND", "SELF", + "SERIAL", "SET", "SOLVE", "SOME", "SORT", "SPEC", "SUM", "SYNCH", "TEXT_MEASURE", "THEN", "TIME", "TIMESTAMP", + "TO", "UNBRANCH", "UPDATE", "USING", "VALIDATE", "VALUES", "VARCHAR2", "WHEN", "WHERE", "WITHIN", "WITH", "YEAR", + "ZERO", "ZONE", +} diff --git a/schema/clob.go b/schema/clob.go new file mode 100644 index 0000000..d27ba35 --- /dev/null +++ b/schema/clob.go @@ -0,0 +1,40 @@ +package dmSchema + +import ( + "database/sql/driver" + "errors" + "fmt" + + "github.com/nfjBill/gorm-driver-dm/dmr" +) + +type Clob string + +// 写入数据库之前,对数据做类型转换 +func (clob Clob) Value() (driver.Value, error) { + if len(clob) == 0 { + return nil, nil + } + return string(clob), nil +} + +// 将数据库中取出的数据,赋值给目标类型 +func (clob *Clob) Scan(v interface{}) error { + switch v.(type) { + case *dmr.DmClob: + tmp := v.(*dmr.DmClob) + le, err := tmp.GetLength() + if err != nil { + return errors.New(fmt.Sprint("err:", err)) + } + + str, err := tmp.ReadString(1, int(le)) + *clob = Clob(str) + break + + //非clob,当成字符串,兼容oracle + default: + *clob = Clob(v.(string)) + } + return nil +}