master
李光春 2 years ago
parent c8d9f0b62b
commit 0b7909eb09

@ -3,10 +3,10 @@ module go.dtapp.net/library
go 1.18
require (
gitee.com/chunanyong/zorm v1.5.5
gitee.com/chunanyong/zorm v1.5.6
github.com/aliyun/aliyun-oss-go-sdk v2.2.4+incompatible
github.com/allegro/bigcache/v3 v3.0.2
github.com/aws/aws-sdk-go v1.44.51
github.com/aws/aws-sdk-go v1.44.53
github.com/baidubce/bce-sdk-go v0.9.128
github.com/basgys/goxml2json v1.1.0
github.com/beego/beego/v2 v2.0.4
@ -39,7 +39,7 @@ require (
go.uber.org/zap v1.21.0
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
golang.org/x/text v0.3.7
google.golang.org/grpc v1.47.0
google.golang.org/grpc v1.48.0
google.golang.org/protobuf v1.28.0
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
@ -105,11 +105,11 @@ require (
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d // indirect
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e // indirect
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
google.golang.org/genproto v0.0.0-20220708155623-50e5f4832e73 // indirect
google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
xorm.io/builder v0.3.11 // indirect
xorm.io/builder v0.3.12 // indirect
)

@ -2,8 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
gitee.com/chunanyong/zorm v1.5.5 h1:Wfy28qXB4FhnWC09sEbGaqxMAy4UdC5qe/XaCqlVqVo=
gitee.com/chunanyong/zorm v1.5.5/go.mod h1:Sk+vofBqQXgNrDTe+nWhV6iMXhiBObFHdCo1MfvAdi8=
gitee.com/chunanyong/zorm v1.5.6 h1:d5y5u7mYdDU3iuAUDXNf64xqtmdj0LCjz/BJhv6XRFE=
gitee.com/chunanyong/zorm v1.5.6/go.mod h1:Sk+vofBqQXgNrDTe+nWhV6iMXhiBObFHdCo1MfvAdi8=
gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
@ -39,8 +39,8 @@ github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQ
github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.42.27/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc=
github.com/aws/aws-sdk-go v1.44.51 h1:jO9hoLynZOrMM4dj0KjeKIK+c6PA+HQbKoHOkAEye2Y=
github.com/aws/aws-sdk-go v1.44.51/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.53 h1:2MErE8gRyBLuE1fuH2Sqlj1xoN3S6/jXb0aO/A1jGfk=
github.com/aws/aws-sdk-go v1.44.53/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/baidubce/bce-sdk-go v0.9.128 h1:SacX3qlQqS0hS4a5HWucQqOObGSLBmK/5W3PJwTi9/8=
github.com/baidubce/bce-sdk-go v0.9.128/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
@ -774,8 +774,8 @@ golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d h1:/m5NbqQelATgoSPVC2Z23sR4kVNokFwDDyWh/3rGY+I=
golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e h1:NHvCuwuS43lGnYhten69ZWqi2QOj/CiDNcKbVqwVoew=
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
@ -835,8 +835,8 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20220708155623-50e5f4832e73 h1:sdZWfcGN37Dv0QWIhuasQGMzAQJOL2oqnvot4/kPgfQ=
google.golang.org/genproto v0.0.0-20220708155623-50e5f4832e73/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d h1:YbuF5+kdiC516xIP60RvlHeFbY9sRDR73QsAGHpkeVw=
google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@ -851,8 +851,9 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -907,8 +908,6 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/datatypes v1.0.7 h1:8NhJN4+annFjwV1WufDhFiPjdUvV1lSGUdg1UCjQIWY=
gorm.io/datatypes v1.0.7/go.mod h1:l9qkCuy0CdzDEop9HKUdcnC9gHC2sRlaFtHkTzsZRqg=
gorm.io/driver/mysql v1.3.2/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U=
gorm.io/driver/mysql v1.3.4 h1:/KoBMgsUHC3bExsekDcmNYaBnfH2WNeFuXqqrqMc98Q=
gorm.io/driver/mysql v1.3.4/go.mod h1:s4Tq0KmD0yhPGHbZEwg1VPlH0vT/GBHJZorPzhcxBUE=
gorm.io/driver/mysql v1.3.5 h1:iWBTVW/8Ij5AG4e0G/zqzaJblYkBI1VIL1LG2HUGsvY=
gorm.io/driver/mysql v1.3.5/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
gorm.io/driver/postgres v1.3.4/go.mod h1:y0vEuInFKJtijuSGu9e5bs5hzzSzPK+LancpKpvbRBw=
@ -919,7 +918,6 @@ gorm.io/driver/sqlite v1.3.1/go.mod h1:wJx0hJspfycZ6myN38x1O/AqLtNS6c5o9TndewFbE
gorm.io/driver/sqlserver v1.3.1 h1:F5t6ScMzOgy1zukRTIZgLZwKahgt3q1woAILVolKpOI=
gorm.io/driver/sqlserver v1.3.1/go.mod h1:w25Vrx2BG+CJNUu/xKbFhaKlGxT/nzRkhWCCoptX8tQ=
gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
@ -1040,7 +1038,7 @@ sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.11 h1:naLkJitGyYW7ZZdncsh/JW+HF4HshmvTHTyUyPwJS00=
xorm.io/builder v0.3.11/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.12 h1:ASZYX7fQmy+o8UJdhlLHSW57JDOkM8DNhcAF5d0LiJM=
xorm.io/builder v0.3.12/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/xorm v1.3.1 h1:z5egKrDoOLqZFhMjcGF4FBHiTmE5/feQoHclfhNidfM=
xorm.io/xorm v1.3.1/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw=

@ -1,3 +1,11 @@
v1.5.6
更新内容:
- 感谢@无泪发现Transaction方法返回值为nil的bug,已修复
- 感谢社区贡献,https://zorm.cn 官网上线,很丑的logo上线 :).
- 支持已经存在的数据库连接
- 修改panic的异常记录和主键零值判断,用于支持基础类型扩展的主键
- 完善文档,注释
v1.5.5
更新内容:
- 增加CloseDB函数,关闭数据库连接池

@ -278,6 +278,8 @@ func Transaction(ctx context.Context, doTransaction func(ctx context.Context) (i
if errOk {
err = fmt.Errorf("recover异常:%w", err)
FuncLogPanic(err)
} else {
FuncLogPanic(fmt.Errorf("recover异常:%v", r))
}
//if !txOpen { //如果不是开启方,也应该回滚事务,虽然可能造成日志不准确,但是回滚要尽早
// return
@ -362,7 +364,7 @@ func Transaction(ctx context.Context, doTransaction func(ctx context.Context) (i
}
return nil, nil
return info, err
}
// QueryRow 不要偷懒调用Query返回第一条,问题1.需要构建一个slice,问题2.调用方传递的对象其他值会被抛弃或者覆盖.

File diff suppressed because it is too large Load Diff

@ -1,744 +0,0 @@
## Introduction
This is a lightweight ORM,zero dependency, that supports DM,Kingbase,shentong,mysql,postgresql,oracle,mssql,sqlite,clickhouse databases.
Source address:https://gitee.com/chunanyong/zorm
Author blog:[https://www.jiagou.com](https://www.jiagou.com)
```
go get gitee.com/chunanyong/zorm
```
* Written based on native SQL statements,It is the streamlining and optimization of [springrain](https://gitee.com/chunanyong/springrain).
* [Built-in code generator](https://gitee.com/chunanyong/readygo/tree/master/codegenerator)
* The code is streamlined, main part 2500 lines, zero dependency 4000 lines, detailed comments, convenient for customization and modification.
* <font color=red>Support transaction propagation, which is the main reason for the birth of zorm</font>
* Support mysql, postgresql, oracle, mssql, sqlite, dm (Da Meng), kingbase (Ren Da Jincang),clickhouse
* Support more databases, read and write separation.
* The update performance of zorm, gorm, and xorm is equivalent. The read performance of zorm is twice as fast as that of gorm and xorm.
* Does not support joint primary keys, alternatively thinks that there is no primary key, and business control is implemented (difficult choice)
* Integrate seata-golang, support global hosting, do not modify business code, and zero intrusive distributed transactions
* Support clickhouse, update and delete statements use SQL92 standard syntax. The official clickhouse-go driver does not support batch insert syntax, it is recommended to use https://github.com/mailru/go-clickhouse
zorm Production environment reference: [UserStructService.go](https://gitee.com/chunanyong/readygo/tree/master/permission/permservice)
## Support domestic database
DM(Da Meng) database driver: [https://gitee.com/chunanyong/dm](https://gitee.com/chunanyong/dm)
kingbase(Ren Da Jincang)Driver Instructions: [https://help.kingbase.com.cn/doc-view-8108.html](https://help.kingbase.com.cn/doc-view-8108.html)
The core of Kingbase(Ren Da Jincang) 8 is based on postgresql 9.6. You can use [https://github.com/lib/pq](https://github.com/lib/pq) for testing. The official driver is recommended for the production environment.
Pay attention to modify ora_input_emptystr_isnull = false in the data/kingbase.conf file , because golang has no null value. Generally, the database is not null, the default value of golang string is' '.
If this value is set to true, the database will set the value to null, which conflicts with the field property not null. Therefore, an error is reported.
shentong(Shenzhou General Data)Instructions:
It is recommended to use official driver, configure zorm.DataSourceConfig DriverName:aci ,DBType:shentong
gbase(GENERAL DATA)
~~The official golang driver has not been found yet. Please configure it zorm.DataSourceConfig DriverName:gbase ,DBType:gbase~~
Use odbc driver for the time being,DriverName:odbc ,DBType:gbase
## Test case
https://gitee.com/chunanyong/readygo/blob/master/test/testzorm/BaseDao_test.go
```go
// Zorm uses native SQL statements and does not impose restrictions on SQL syntax. Statements use Finder as the carrier.
// Use "?" as a placeholder. , Zorm automatically replaces placeholders based on the database type,
// such as "?" in a PostgreSQL database, Replaced with $1, $2...
// Zorm uses the ctx context. context parameter to propagate the transaction, and ctx is passed in from the web layer, such as gin's c.retest.context ().
// The transaction operation of zorm needs to be displayed using zorm.Transaction(ctx, func(ctx context.Context) (interface(), error) ()) to open
```
## Database scripts and entity classes
https://gitee.com/chunanyong/readygo/blob/master/test/testzorm/demoStruct.go
Generate entity classes or write manually, it is recommended to use a code generator
https://gitee.com/chunanyong/readygo/tree/master/codegenerator
```go
package testzorm
import (
"time"
"gitee.com/chunanyong/zorm"
)
//Table building statement
/*
DROP TABLE IF EXISTS `t_demo`;
CREATE TABLE `t_demo` (
`id` varchar(50) NOT NULL COMMENT 'Primary key',
`userName` varchar(30) NOT NULL COMMENT 'Name',
`password` varchar(50) NOT NULL COMMENT 'password',
`createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`active` int COMMENT 'Is it valid (0 no, 1 yes)',
PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = 'example' ;
*/
//demoStructTableName Table name constant, easy to call directly
const demoStructTableName = "t_demo"
// demoStruct example
type demoStruct struct {
//Default structs are introduced to insulate IEntityStructs from method changes
zorm.EntityStruct
//Id: Primary key
Id string `column:"id"`
//UserName: Name
UserName string `column:"userName"`
//Password: password
Password string `column:"password"`
//CreateTime <no value>
CreateTime time.Time `column:"createTime"`
//Active: Is it valid (0 no, 1 yes)
//Active int `column:"active"`
//------------------The end of the database field, the custom field is written below---------------//
//If the query field is not found in the column tag, it will be mapped to the struct attribute based on the name (case insensitive, _ underscore to hump)
//Custom field Active
Active int
}
//GetTableName: Get the table name
func (entity *demoStruct) GetTableName() string {
return demoStructTableName
}
//GetPKColumnName: Get the primary key field name of the database table. Because it is compatible with Map, it can only be the field name of the database.
func (entity *demoStruct) GetPKColumnName() string {
return "id"
}
//newDemoStruct: Create a default object
func newDemoStruct() demoStruct {
demo := demoStruct{
// If Id=="",When saving, zorm will call zorm.Func Generate String ID(),
// the default UUID string, or you can define your own implementation,E.g: zorm.FuncGenerateStringID=funcmyId
Id: zorm.FuncGenerateStringID(),
UserName: "defaultUserName",
Password: "defaultPassword",
Active: 1,
CreateTime: time.Now(),
}
return demo
}
```
## Test cases are documents
```go
// testzorm: Use native SQL statements, no restrictions on SQL syntax. Statements use Finder as a carrier
// Use "?" as a placeholder. , Zorm automatically replaces placeholders based on the database type,
// such as "?" in a PostgreSQL database, Replaced with $1, $2...
// Zorm uses the ctx context. context parameter to propagate the transaction, and ctx is passed in from the web layer, such as gin's c.retest.context ().
// The transaction operation of zorm needs to be displayed using zorm.Transaction(ctx, func(ctx context.Context) (interface(), error) ()) to open
package testzorm
import (
"context"
"fmt"
"testing"
"time"
"gitee.com/chunanyong/zorm"
//00.Introduce database driver
_ "github.com/go-sql-driver/mysql"
)
//dbDao: Represents a database. If there are multiple databases, declare multiple DB Dao accordingly
var dbDao *zorm.DBDao
// ctx should be passed in by the web layer by default, such as gin's c.Request.Context(). This is just a simulation.
var ctx = context.Background()
//01.Initialize DB Dao
func init() {
//Custom zorm log output
//zorm.LogCallDepth = 4 //Level of log call
//zorm.FuncLogError = myFuncLogError //Function to record exception log.
//zorm.FuncLogPanic = myFuncLogPanic //Record panic log, use Zorm Error Log by default
//zorm.FuncPrintSQL = myFuncPrintSQL //A function that prints SQL
//Customize the log output format and re-assign the Func Print SQL functio.
//log.SetFlags(log.LstdFlags)
//zorm.FuncPrintSQL = zorm.FuncPrintSQL
//dbDaoConfig: Database configuration
dbDaoConfig := zorm.DataSourceConfig{
// DSN: Database connection string
DSN: "root:root@tcp(127.0.0.1:3306)/readygo?charset=utf8&parseTime=true",
// Database driver name: mysql, postgres, oci8, sqlserver, sqlite3,clickhouse,
// dm, kingbase and DBType correspond, there are multiple drivers for processing databases
DriverName: "mysql",
// Database type (based on dialect judgment): mysql, postgresql,oracle, mssql, sqlite, clickhouse,
// dm, kingbase and DriverName correspond to multiple drivers for processing databases
DBType: "mysql",
//MaxOpenConns: Maximum number of database connections Default 50
MaxOpenConns: 50,
//MaxIdleConns: The maximum number of free connections to the database default 50
MaxIdleConns: 50,
//ConnMaxLifetimeSecond: The connection survival time in seconds. The connection is destroyed and rebuilt after the default 600 (10 minutes).
//To prevent the database from actively disconnecting and causing dead connections. MySQL default wait_timeout 28800 seconds (8 hours)
ConnMaxLifetimeSecond: 600,
//PrintSQL: Print SQL. Func Print SQL will be used to record SQL
PrintSQL: true,
//DefaultTxOptions The default configuration of the transaction isolation level, the default is nil
//DefaultTxOptions: nil,
//如果是使用seata-golang分布式事务,建议使用默认配置
//DefaultTxOptions: &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false},
//FuncSeataGlobalTransaction seata-golang分布式的适配函数,返回ISeataGlobalTransaction接口的实现
//FuncSeataGlobalTransaction : MyFuncSeataGlobalTransaction,
}
// Create dbDao according to dbDaoConfig, a database is executed only once,
// the first executed database is defaultDao, and subsequent zorm.xxx methods, defaultDao is used by default.
dbDao, _ = zorm.NewDBDao(&dbDaoConfig)
}
//TestInsert: 02.Test save Struct object
func TestInsert(t *testing.T) {
//You need to manually start the transaction.
//If the error returned by the anonymous function is not nil, the transaction will be rolled back.
//If the global DefaultTxOptions configuration does not meet the requirements, you can set the isolation level of the transaction before the zorm.Transaction transaction method, such as ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}), if txOptions is nil , Use the global DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
//Create a demo object
demo := newDemoStruct()
// Save the object, the parameter is the object pointer.
// If the primary key is incremented, it will be assigned to the primary key attribute of the object
_, err := zorm.Insert(ctx, &demo)
//If the returned err is not nil, the transaction will be rolled back.
return nil, err
})
//Mark test failed.
if err != nil {
t.Errorf("err:%v", err)
}
}
//TestInsertSlice 03.Test the Slice that saves Struct objects in batches.
//If it is an auto-increasing primary key, you cannot assign a value to the primary key attribute in the Struct object.
func TestInsertSlice(t *testing.T) {
// You need to manually start the transaction.
// If the error returned by the anonymous function is not nil, the transaction will be rolled back.
//If the global DefaultTxOptions configuration does not meet the requirements, you can set the isolation level of the transaction before the zorm.Transaction transaction method, such as ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}), if txOptions is nil , Use the global DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
//The type stored by slice is zorm.I Entity Struct!!!, golang currently does not have generics,
//uses the I Entity Struct interface, and is compatible with the Struct entity class.
demoSlice := make([]zorm.IEntityStruct, 0)
//Create object 1
demo1 := newDemoStruct()
demo1.UserName = "demo1"
//Create object 2
demo2 := newDemoStruct()
demo2.UserName = "demo2"
demoSlice = append(demoSlice, &demo1, &demo2)
//To save objects in batches, if the primary key is auto-increment, the auto-increment ID cannot be saved in the object.
_, err := zorm.InsertSlice(ctx, demoSlice)
//If the returned err is not nil, the transaction will be rolled back.
return nil, err
})
//Mark test failed.
if err != nil {
t.Errorf("错误:%v", err)
}
}
//TestInsertEntityMap 04.Test to save the Entity Map object for scenarios where it is not convenient to use struct, using Map as a carrier
func TestInsertEntityMap(t *testing.T) {
// You need to manually start the transaction. If the error returned by the anonymous function is not nil, the transaction will be rolled back.
//If the global DefaultTxOptions configuration does not meet the requirements, you can set the isolation level of the transaction before the zorm.Transaction transaction method, such as ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}), if txOptions is nil , Use the global DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
//To create an Entity Map, you need to pass in the table name.
entityMap := zorm.NewEntityMap(demoStructTableName)
//Set the primary key name.
entityMap.PkColumnName = "id"
//If it is an auto-increasing sequence, set the value of the sequence.
//entityMap.PkSequence = "mySequence"
//Set Set the field value of the database
//If the primary key is auto-increment or sequence, don't entity Map.Set the value of the primary key.
entityMap.Set("id", zorm.FuncGenerateStringID())
entityMap.Set("userName", "entityMap-userName")
entityMap.Set("password", "entityMap-password")
entityMap.Set("createTime", time.Now())
entityMap.Set("active", 1)
//carried out
_, err := zorm.InsertEntityMap(ctx, entityMap)
//If the returned err is not nil, the transaction will be rolled back
return nil, err
})
//Mark test failed
if err != nil {
t.Errorf("error:%v", err)
}
}
//TestQueryRow 05.Test query a struct object
func TestQueryRow(t *testing.T) {
//Declare a pointer to an object to carry the returned data.
demo := &demoStruct{}
//Finder for constructing query.
finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
//finder = zorm.NewSelectFinder(demoStructTableName, "id,userName") // select id,userName from t_demo
//finder = zorm.NewFinder().Append("SELECT * FROM " + demoStructTableName) // select * from t_demo
// finder.Append The first parameter is the statement, and the following parameters are the corresponding values.
// The order of the values must be correct. Use the statement uniformly? Zorm will handle the difference in the database
finder.Append("WHERE id=? and active in(?)", "41b2aa4f-379a-4319-8af9-08472b6e514e", []int{0, 1})
//Execute query
has,err := zorm.QueryRow(ctx, finder, demo)
if err != nil { //Mark test failed
t.Errorf("error:%v", err)
}
if has { //数据库存在数据
//Print result
fmt.Println(demo)
}
}
//TestQueryRowMap 06.Test query map receiving results, used in scenarios that are not suitable for struct, more flexible
func TestQueryRowMap(t *testing.T) {
//Finder for constructing query.
finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
//finder.Append: The first parameter is the statement, and the following parameters are the corresponding values.
//The order of the values must be correct. Use the statement uniformly? Zorm will handle the difference in the database
finder.Append("WHERE id=? and active in(?)", "41b2aa4f-379a-4319-8af9-08472b6e514e", []int{0, 1})
//Execute query
resultMap, err := zorm.QueryRowMap(ctx, finder)
if err != nil { //Mark test failed
t.Errorf("error:%v", err)
}
//Print result
fmt.Println(resultMap)
}
//TestQuery 07.Test query object list
func TestQuery(t *testing.T) {
//Create a slice to receive the result
list := make([]*demoStruct, 0)
//Finder for constructing query
finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
//Create a paging object. After the query is completed, the page object can be directly used by the front-end paging component.
page := zorm.NewPage()
page.PageNo = 1 //Query page 1, default is 1
page.PageSize = 20 //20 items per page, the default is 20
//Execute query.如果想不分页,查询所有数据,page传入nil
err := zorm.Query(ctx, finder, &list, page)
if err != nil { //Mark test failed
t.Errorf("error:%v", err)
}
//Print result
fmt.Println("Total number:", page.TotalCount, " List:", list)
}
//TestQueryMap 08.Test query map list, used in scenarios where struct is not convenient, a record is a map object.
func TestQueryMap(t *testing.T) {
//Finder for constructing query.
finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
//Create a paging object. After the query is completed, the page object can be directly used by the front-end paging component。
page := zorm.NewPage()
//Execute query
listMap, err := zorm.QueryMap(ctx, finder, page)
if err != nil { //Mark test failed
t.Errorf("error:%v", err)
}
//Print result.如果不想分页,查询所有数据,page传入nil
fmt.Println("Total number:", page.TotalCount, " List:", listMap)
}
//TestUpdateNotZeroValue 09.Update the struct object, only update fields that are not zero. The primary key must have a value.
func TestUpdateNotZeroValue(t *testing.T) {
// You need to manually start the transaction. If the error returned by the anonymous function is not nil,
// the transaction will be rolled back.
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
//Declare a pointer to an object to update data
demo := &demoStruct{}
demo.Id = "41b2aa4f-379a-4319-8af9-08472b6e514e"
demo.UserName = "UpdateNotZeroValue"
//Update "sql":"UPDATE t_demo SET userName=? WHERE id=?","args":["UpdateNotZeroValue","41b2aa4f-379a-4319-8af9-08472b6e514e"]
_, err := zorm.UpdateNotZeroValue(ctx, demo)
//If the returned err is not nil, the transaction will be rolled back.
return nil, err
})
if err != nil {
//Mark test failed
t.Errorf("error:%v", err)
}
}
//TestUpdate 10.Update the struct object, update all fields. The primary key must have a value.
func TestUpdate(t *testing.T) {
// You need to manually start the transaction.
// If the error returned by the anonymous function is not nil, the transaction will be rolled back.
//If the global DefaultTxOptions configuration does not meet the requirements, you can set the isolation level of the transaction before the zorm.Transaction transaction method, such as ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}), if txOptions is nil , Use the global DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
//Declare a pointer to an object to update data.
demo := &demoStruct{}
demo.Id = "41b2aa4f-379a-4319-8af9-08472b6e514e"
demo.UserName = "TestUpdate"
_, err := zorm.Update(ctx, demo)
//If the returned err is not nil, the transaction will be rolled back.
return nil, err
})
if err != nil {
//Mark test failed
t.Errorf("error:%v", err)
}
}
//TestUpdateFinder 11.Through finder update, zorm is the most flexible way, you can write any update statement,
// or even manually write insert statement
func TestUpdateFinder(t *testing.T) {
//You need to manually start the transaction. If the error returned by the anonymous function is not nil, the transaction will be rolled back.
//If the global DefaultTxOptions configuration does not meet the requirements, you can set the isolation level of the transaction before the zorm.Transaction transaction method, such as ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}), if txOptions is nil , Use the global DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
finder := zorm.NewUpdateFinder(demoStructTableName) // UPDATE t_demo SET
//finder = zorm.NewDeleteFinder(demoStructTableName) // DELETE FROM t_demo
//finder = zorm.NewFinder().Append("UPDATE").Append(demoStructTableName).Append("SET") // UPDATE t_demo SET
finder.Append("userName=?,active=?", "TestUpdateFinder", 1).Append("WHERE id=?", "41b2aa4f-379a-4319-8af9-08472b6e514e")
//Update "sql":"UPDATE t_demo SET userName=?,active=? WHERE id=?","args":["TestUpdateFinder",1,"41b2aa4f-379a-4319-8af9-08472b6e514e"]
_, err := zorm.UpdateFinder(ctx, finder)
//If the returned err is not nil, the transaction will be rolled back.
return nil, err
})
if err != nil { //Mark test failed
t.Errorf("error:%v", err)
}
}
//TestUpdateEntityMap 12.Update an Entity Map, the primary key must have a value
func TestUpdateEntityMap(t *testing.T) {
//You need to manually start the transaction.
//If the error returned by the anonymous function is not nil, the transaction will be rolled back.
//If the global DefaultTxOptions configuration does not meet the requirements, you can set the isolation level of the transaction before the zorm.Transaction transaction method, such as ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}), if txOptions is nil , Use the global DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
//To create an Entity Map, you need to pass in the table name.
entityMap := zorm.NewEntityMap(demoStructTableName)
//Set the primary key name.
entityMap.PkColumnName = "id"
//Set Set the field value of the database, the primary key must have a value.
entityMap.Set("id", "41b2aa4f-379a-4319-8af9-08472b6e514e")
entityMap.Set("userName", "TestUpdateEntityMap")
//Update "sql":"UPDATE t_demo SET userName=? WHERE id=?","args":["TestUpdateEntityMap","41b2aa4f-379a-4319-8af9-08472b6e514e"]
_, err := zorm.UpdateEntityMap(ctx, entityMap)
//If the returned err is not nil, the transaction will be rolled back.
return nil, err
})
if err != nil {
//Mark test failed
t.Errorf("error:%v", err)
}
}
//TestDelete 13.To delete a struct object, the primary key must have a value.
func TestDelete(t *testing.T) {
//You need to manually start the transaction. If the error returned by the anonymous function is not nil, the transaction will be rolled back.
//If the global DefaultTxOptions configuration does not meet the requirements, you can set the isolation level of the transaction before the zorm.Transaction transaction method, such as ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}), if txOptions is nil , Use the global DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
demo := &demoStruct{}
demo.Id = "ae9987ac-0467-4fe2-a260-516c89292684"
//delete "sql":"DELETE FROM t_demo WHERE id=?","args":["ae9987ac-0467-4fe2-a260-516c89292684"]
_, err := zorm.Delete(ctx, demo)
//If the returned err is not nil, the transaction will be rolled back.
return nil, err
})
if err != nil {
//Mark test failed
t.Errorf("error:%v", err)
}
}
//TestProc 14.Test call stored procedure
func TestProc(t *testing.T) {
demo := &demoStruct{}
finder := zorm.NewFinder().Append("call testproc(?) ", "u_10001")
zorm.QueryRow(ctx, finder, demo)
fmt.Println(demo)
}
//TestFunc 15.Test call custom function.
func TestFunc(t *testing.T) {
userName := ""
finder := zorm.NewFinder().Append("select testfunc(?) ", "u_10001")
zorm.QueryRow(ctx, finder, &userName)
fmt.Println(userName)
}
//TestOther 16.Some other instructions. Thank you very much for seeing this line.
func TestOther(t *testing.T) {
//Scenario 1. Multiple databases. Through the db Dao of the corresponding database, call the Bind Context DB Connection function,
//bind the connection of this database to the returned ctx, and then pass the ctx to the zorm function.
newCtx, err := dbDao.BindContextDBConnection(ctx)
if err != nil {
//Mark test failed
t.Errorf("error:%v", err)
}
finder := zorm.NewSelectFinder(demoStructTableName)
//Pass the newly generated new Ctx to the function of zorm.
list, _ := zorm.QueryRowMap(newCtx, finder, nil)
fmt.Println(list)
//Scenario 2. Read-write separation of a single database.
//Set the strategy function for read-write separation.
zorm.FuncReadWriteStrategy = myReadWriteStrategy
//Scenario 3. If there are multiple databases,
//each database is also separated from reading and writing, and processed according to scenario 1.
}
//Strategies for the separation of read and write of a single database rwType=0 read,rwType=1 write
func myReadWriteStrategy(rwType int) *zorm.DBDao {
//According to your own business scenario, return the required read and write dao, and call this function every time you need a database connection
return dbDao
}
//---------------------------------//
//To implement the interface of CustomDriverValueConver,extend the custom type, such as text type of dm database, the mapped type is dm.DmClob type , cannot use string type to receive directly.
type CustomDMText struct{}
//GetDriverValue according to the database column type and entity class field type, return driver.Value Instance. If the return value is nil, no type replacement is performed and the default method is used.
func (dmtext CustomDMText) GetDriverValue(columnType *sql.ColumnType, structFieldType *reflect.Type, finder *zorm.Finder) (driver.Value, error) {
return &dm.DmClob{}, nil
}
//ConverDriverValue database column type, entity class field type, GetDriverValue returned driver.Value New value, return the pointer according to the receiving type value, pointer, pointer!!!!
func (dmtext CustomDMText) ConverDriverValue(columnType *sql.ColumnType, structFieldType *reflect.Type, tempDriverValue driver.Value, finder *zorm.Finder) (interface{}, error) {
//Type conversion
dmClob, isok := tempDriverValue.(*dm.DmClob)
if !isok {
return tempDriverValue, errors.New("Conversion to *dm.DmClob type failed")
}
//Get the length
dmlen, errLength := dmClob.GetLength()
if errLength != nil {
return dmClob, errLength
}
//Convert int64 to int type
strInt64 := strconv.FormatInt(dmlen, 10)
dmlenInt, errAtoi := strconv.Atoi(strInt64)
if errAtoi != nil {
return dmClob, errAtoi
}
//Read string
str, errReadString := dmClob.ReadString(1, dmlenInt)
return &str, errReadString
}
//zorm.CustomDriverValueMap for configuration driver.Value and the corresponding processing relationship, key is the string of drier.Value. For example *dm.DmClob
//It is usually added in the init method
zorm.CustomDriverValueMap["*dm.DmClob"] = CustomDMText{}
```
## Distributed transaction
Implement distributed transactions based on seata-golang.
### Proxy mode
```golang
//DataSourceConfig configuration DefaultTxOptions
//DefaultTxOptions: &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false},
// Introduce the dependency package of the V1 version, refer to the official example of V2
import (
"github.com/opentrx/mysql"
"github.com/transaction-wg/seata-golang/pkg/client"
"github.com/transaction-wg/seata-golang/pkg/client/config"
"github.com/transaction-wg/seata-golang/pkg/client/rm"
"github.com/transaction-wg/seata-golang/pkg/client/tm"
seataContext "github.com/transaction-wg/seata-golang/pkg/client/context"
)
//Configuration file path
var configPath = "./conf/client.yml"
func main() {
//Initial configuration
conf := config.InitConf(configPath)
//Initialize the RPC client
client.NewRpcClient()
//Register mysql driver
mysql.InitDataResourceManager()
mysql.RegisterResource(config.GetATConfig().DSN)
//sqlDB, err := sql.Open("mysql", config.GetATConfig().DSN)
//Subsequent normal initialization of zorm must be placed after the initialization of seata mysql!!!
//................//
//tm registration transaction service, refer to the official example. (Global hosting is mainly to remove the proxy, zero intrusion to the business)
tm.Implement(svc.ProxySvc)
//................//
//Get the rootContext of seata
rootContext := seataContext.NewRootContext(ctx)
//rootContext := ctx.(*seataContext.RootContext)
//Create seata transaction
seataTx := tm.GetCurrentOrCreate(rootContext)
//Start transaction
seataTx.BeginWithTimeoutAndName(int32(6000), "transaction name", rootContext)
//Get the XID after the transaction is opened. It can be passed through the header of gin, or passed in other ways
xid:=rootContext.GetXID()
// Accept the passed XID and bind it to the local ctx
ctx =context.WithValue(ctx,mysql.XID,xid)
}
```
### Global hosting mode
```golang
//Do not use proxy mode, global hosting, do not modify business code, zero intrusion to achieve distributed transactions
//tm.Implement(svc.ProxySvc)
// It is recommended to put the following code in a separate file
//................//
// ZormSeataGlobalTransaction wraps *tm.DefaultGlobalTransaction of seata, and implements the zorm.ISeataGlobalTransaction interface
type ZormSeataGlobalTransaction struct {
*tm.DefaultGlobalTransaction
}
// MyFuncSeataGlobalTransaction zorm adapts the function of seata distributed transaction, configure zorm.DataSourceConfig.FuncSeataGlobalTransaction=MyFuncSeataGlobalTransaction
func MyFuncSeataGlobalTransaction(ctx context.Context) (zorm.ISeataGlobalTransaction, context.Context, error) {
//Get the rootContext of seata
rootContext := seataContext.NewRootContext(ctx)
//Create seata transaction
seataTx := tm.GetCurrentOrCreate(rootContext)
//Use the zorm.ISeataGlobalTransaction interface object to wrap the seata transaction and isolate the seata-golang dependency
seataGlobalTransaction := ZormSeataGlobalTransaction{seataTx}
return seataGlobalTransaction, rootContext, nil
}
//Implement the zorm.ISeataGlobalTransaction interface
func (gtx ZormSeataGlobalTransaction) SeataBegin(ctx context.Context) error {
rootContext := ctx.(*seataContext.RootContext)
return gtx.BeginWithTimeout(int32(6000), rootContext)
}
func (gtx ZormSeataGlobalTransaction) SeataCommit(ctx context.Context) error {
rootContext := ctx.(*seataContext.RootContext)
return gtx.Commit(rootContext)
}
func (gtx ZormSeataGlobalTransaction) SeataRollback(ctx context.Context) error {
rootContext := ctx.(*seataContext.RootContext)
return gtx.Rollback(rootContext)
}
func (gtx ZormSeataGlobalTransaction) GetSeataXID(ctx context.Context) string {
rootContext := ctx.(*seataContext.RootContext)
return rootContext.GetXID()
}
//................//
```
## Performance stress test
Test code:https://github.com/alphayan/goormbenchmark
Index description
Total time, average number of nanoseconds per time, average memory allocated per time, average number of memory allocated per time.
The update performance of zorm, gorm, and xorm is equivalent. The read performance of zorm is twice as fast as that of gorm and xorm.
```
2000 times - Insert
zorm: 9.05s 4524909 ns/op 2146 B/op 33 allocs/op
gorm: 9.60s 4800617 ns/op 5407 B/op 119 allocs/op
xorm: 12.63s 6315205 ns/op 2365 B/op 56 allocs/op
2000 times - BulkInsert 100 row
xorm: 23.89s 11945333 ns/op 253812 B/op 4250 allocs/op
gorm: Don't support bulk insert - https://github.com/jinzhu/gorm/issues/255
zorm: Don't support bulk insert
2000 times - Update
xorm: 0.39s 195846 ns/op 2529 B/op 87 allocs/op
zorm: 0.51s 253577 ns/op 2232 B/op 32 allocs/op
gorm: 0.73s 366905 ns/op 9157 B/op 226 allocs/op
2000 times - Read
zorm: 0.28s 141890 ns/op 1616 B/op 43 allocs/op
gorm: 0.45s 223720 ns/op 5931 B/op 138 allocs/op
xorm: 0.55s 276055 ns/op 8648 B/op 227 allocs/op
2000 times - MultiRead limit 1000
zorm: 13.93s 6967146 ns/op 694286 B/op 23054 allocs/op
gorm: 26.40s 13201878 ns/op 2392826 B/op 57031 allocs/op
xorm: 30.77s 15382967 ns/op 1637098 B/op 72088 allocs/op
```

@ -0,0 +1,766 @@
## 介绍
![zorm logo](zorm-logo.png)
go(golang)轻量级ORM,零依赖,零侵入分布式事务,支持达梦(dm),金仓(kingbase),神通(shentong),南大通用(gbase),mysql,postgresql,oracle,mssql,sqlite,clickhouse数据库.
源码地址:https://gitee.com/chunanyong/zorm
官网:[https://zorm.cn](https://zorm.cn)
交流QQ群[727723736]() 添加进入社区群聊,问题交流,技术探讨
社区微信: [LAUV927]()
```
go get gitee.com/chunanyong/zorm
```
* 基于原生sql语句编写,是[springrain](https://gitee.com/chunanyong/springrain)的精简和优化.
* [代码生成器](https://gitee.com/zhou-a-xing/wsgt)
* 代码精简,主体2500行,零依赖4000行,注释详细,方便定制修改.
* <font color=red>支持事务传播,这是zorm诞生的主要原因</font>
* 支持mysql,postgresql,oracle,mssql,sqlite,clickhouse,dm(达梦),kingbase(金仓),shentong(神通),gbase(南通),clickhouse数据库
* 支持多库和读写分离
* 更新性能zorm,gorm,xorm相当. 读取性能zorm比gorm,xorm快50%
* 不支持联合主键,变通认为无主键,业务控制实现(艰难取舍)
* 集成seata-golang,支持全局托管,不修改业务代码,零侵入分布式事务
* 支持clickhouse,更新,删除语句使用SQL92标准语法.clickhouse-go官方驱动不支持批量insert语法,建议使用https://github.com/mailru/go-clickhouse
zorm生产环境使用参考: [UserStructService.go](https://gitee.com/chunanyong/readygo/tree/master/permission/permservice)
## 源码仓库说明
我主导的开源项目主库都在gitee,github上留有项目说明,引导跳转到gitee,这样也造成了项目star增长缓慢,毕竟github社区更加强大.
**开源没有国界,开发者却有自己的祖国.**
严格意义上,github是受美国法律管辖的 https://www.infoq.cn/article/SA72SsSeZBpUSH_ZH8XB
尽我所能,支持国内开源社区,不喜勿喷,谢谢!
## 支持国产数据库
### 达梦(dm)
配置zorm.DataSourceConfig的 DriverName:dm ,DBType:dm
达梦数据库驱动: [https://gitee.com/chunanyong/dm](https://gitee.com/chunanyong/dm)
达梦的text类型会映射为dm.DmClob,string不能接收,需要实现zorm.CustomDriverValueConver接口,自定义扩展处理
### 人大金仓(kingbase)
配置zorm.DataSourceConfig的 DriverName:kingbase ,DBType:kingbase
金仓驱动说明: [https://help.kingbase.com.cn/doc-view-8108.html](https://help.kingbase.com.cn/doc-view-8108.html)
金仓kingbase 8核心是基于postgresql 9.6,可以使用 [https://github.com/lib/pq](https://github.com/lib/pq) 进行测试,生产环境建议使用官方驱动.
注意修改 data/kingbase.conf中 ```ora_input_emptystr_isnull = false```,因为golang没有null值,一般数据库都是not null,golang的string默认是'',如果这个设置为true,数据库就会把值设置为null,和字段属性not null 冲突,因此报错.
### 神舟通用(shentong)
建议使用官方驱动,配置zorm.DataSourceConfig的 DriverName:aci ,DBType:shentong
### 南大通用(gbase)
~~暂时还未找到官方golang驱动,配置zorm.DataSourceConfig的 DriverName:gbase ,DBType:gbase~~
暂时先使用odbc驱动,DriverName:odbc ,DBType:gbase
## 测试用例
https://gitee.com/chunanyong/readygo/blob/master/test/testzorm/BaseDao_test.go
```go
// zorm 使用原生的sql语句,没有对sql语法做限制.语句使用Finder作为载体
// 占位符统一使用?,zorm会根据数据库类型,自动替换占位符,例如postgresql数据库把?替换成$1,$2...
// zorm使用 ctx context.Context 参数实现事务传播,ctx从web层传递进来即可,例如gin的c.Request.Context()
// zorm的事务操作需要显式使用zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {})开启
```
## 数据库脚本和实体类
https://gitee.com/chunanyong/readygo/blob/master/test/testzorm/demoStruct.go
生成实体类或手动编写,建议使用代码生成器 https://gitee.com/zhou-a-xing/wsgt
```go
package testzorm
import (
"time"
"gitee.com/chunanyong/zorm"
)
//建表语句
/*
DROP TABLE IF EXISTS `t_demo`;
CREATE TABLE `t_demo` (
`id` varchar(50) NOT NULL COMMENT '主键',
`userName` varchar(30) NOT NULL COMMENT '姓名',
`password` varchar(50) NOT NULL COMMENT '密码',
`createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
`active` int COMMENT '是否有效(0否,1是)',
PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COMMENT = '例子' ;
*/
//demoStructTableName 表名常量,方便直接调用
const demoStructTableName = "t_demo"
// demoStruct 例子
type demoStruct struct {
//引入默认的struct,隔离IEntityStruct的方法改动
zorm.EntityStruct
//Id 主键
Id string `column:"id"`
//UserName 姓名
UserName string `column:"userName"`
//Password 密码
Password string `column:"password"`
//CreateTime <no value>
CreateTime time.Time `column:"createTime"`
//Active 是否有效(0否,1是)
//Active int `column:"active"`
//------------------数据库字段结束,自定义字段写在下面---------------//
//如果查询的字段在column tag中没有找到,就会根据名称(不区分大小写,支持 _ 下划线转驼峰)映射到struct的属性上
//模拟自定义的字段Active
Active int
}
//GetTableName 获取表名称
//IEntityStruct 接口的方法,实体类需要实现!!!
func (entity *demoStruct) GetTableName() string {
return demoStructTableName
}
//GetPKColumnName 获取数据库表的主键字段名称.因为要兼容Map,只能是数据库的字段名称
//不支持联合主键,变通认为无主键,业务控制实现(艰难取舍)
//如果没有主键,也需要实现这个方法, return "" 即可
//IEntityStruct 接口的方法,实体类需要实现!!!
func (entity *demoStruct) GetPKColumnName() string {
//如果没有主键
//return ""
return "id"
}
//newDemoStruct 创建一个默认对象
func newDemoStruct() demoStruct {
demo := demoStruct{
//如果Id=="",保存时zorm会调用zorm.FuncGenerateStringID(),默认时间戳+随机数,也可以自己定义实现方式,例如 zorm.FuncGenerateStringID=funcmyId
Id: zorm.FuncGenerateStringID(),
UserName: "defaultUserName",
Password: "defaultPassword",
Active: 1,
CreateTime: time.Now(),
}
return demo
}
```
## 测试用例即文档
```go
// testzorm 使用原生的sql语句,没有对sql语法做限制.语句使用Finder作为载体
// 占位符统一使用?,zorm会根据数据库类型,自动替换占位符,例如postgresql数据库把?替换成$1,$2...
// zorm使用 ctx context.Context 参数实现事务传播,ctx从web层传递进来即可,例如gin的c.Request.Context()
// zorm的事务操作需要显式使用zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {})开启
package testzorm
import (
"context"
"fmt"
"testing"
"time"
"gitee.com/chunanyong/zorm"
//00.引入数据库驱动
_ "github.com/go-sql-driver/mysql"
)
//dbDao 代表一个数据库,如果有多个数据库,就对应声明多个DBDao
var dbDao *zorm.DBDao
// ctx默认应该有 web层传入,例如gin的c.Request.Context().这里只是模拟
var ctx = context.Background()
//01.初始化DBDao
func init() {
//自定义zorm日志输出
//zorm.LogCallDepth = 4 //日志调用的层级
//zorm.FuncLogError = myFuncLogError //记录异常日志的函数
//zorm.FuncLogPanic = myFuncLogPanic //记录panic日志,默认使用defaultLogError实现
//zorm.FuncPrintSQL = myFuncPrintSQL //打印sql的函数
//自定义日志输出格式,把FuncPrintSQL函数重新赋值
//log.SetFlags(log.LstdFlags)
//zorm.FuncPrintSQL = zorm.FuncPrintSQL
//dbDaoConfig 数据库的配置.这里只是模拟,生产应该是读取配置配置文件,构造DataSourceConfig
dbDaoConfig := zorm.DataSourceConfig{
//DSN 数据库的连接字符串
DSN: "root:root@tcp(127.0.0.1:3306)/readygo?charset=utf8&parseTime=true",
//数据库驱动名称:mysql,postgres,oci8,sqlserver,sqlite3,clickhouse,dm,kingbase,aci 和DBType对应,处理数据库有多个驱动
DriverName: "mysql",
//数据库类型(方言判断依据):mysql,postgresql,oracle,mssql,sqlite,clickhouse,dm,kingbase,shentong 和 DriverName 对应,处理数据库有多个驱动
DBType: "mysql",
//MaxOpenConns 数据库最大连接数 默认50
MaxOpenConns: 50,
//MaxIdleConns 数据库最大空闲连接数 默认50
MaxIdleConns: 50,
//ConnMaxLifetimeSecond 连接存活秒时间. 默认600(10分钟)后连接被销毁重建.避免数据库主动断开连接,造成死连接.MySQL默认wait_timeout 28800秒(8小时)
ConnMaxLifetimeSecond: 600,
//PrintSQL 打印SQL.会使用FuncPrintSQL记录SQL
PrintSQL: true,
//DefaultTxOptions 事务隔离级别的默认配置,默认为nil
//DefaultTxOptions: nil,
//如果是使用seata-golang分布式事务,建议使用默认配置
//DefaultTxOptions: &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false},
//FuncSeataGlobalTransaction seata-golang分布式的适配函数,返回ISeataGlobalTransaction接口的实现
//FuncSeataGlobalTransaction : MyFuncSeataGlobalTransaction,
//使用现有的数据库连接,优先级高于DSN
//SQLDB : nil,
}
// 根据dbDaoConfig创建dbDao, 一个数据库只执行一次,第一个执行的数据库为 defaultDao,后续zorm.xxx方法,默认使用的就是defaultDao
dbDao, _ = zorm.NewDBDao(&dbDaoConfig)
}
//TestInsert 02.测试保存Struct对象
func TestInsert(t *testing.T) {
//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,
//例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}),如果txOptions为nil,使用全局DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
//创建一个demo对象
demo := newDemoStruct()
//保存对象,参数是对象指针.如果主键是自增,会赋值到对象的主键属性
_, err := zorm.Insert(ctx, &demo)
//如果返回的err不是nil,事务就会回滚
return nil, err
})
//标记测试失败
if err != nil {
t.Errorf("错误:%v", err)
}
}
//TestInsertSlice 03.测试批量保存Struct对象的Slice
//如果是自增主键,无法对Struct对象里的主键属性赋值
func TestInsertSlice(t *testing.T) {
//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,
//例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}),如果txOptions为nil,使用全局DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
//slice存放的类型是zorm.IEntityStruct!!!,golang目前没有泛型,使用IEntityStruct接口,兼容Struct实体类
demoSlice := make([]zorm.IEntityStruct, 0)
//创建对象1
demo1 := newDemoStruct()
demo1.UserName = "demo1"
//创建对象2
demo2 := newDemoStruct()
demo2.UserName = "demo2"
demoSlice = append(demoSlice, &demo1, &demo2)
//批量保存对象,如果主键是自增,无法保存自增的ID到对象里.
_, err := zorm.InsertSlice(ctx, demoSlice)
//如果返回的err不是nil,事务就会回滚
return nil, err
})
//标记测试失败
if err != nil {
t.Errorf("错误:%v", err)
}
}
//TestInsertEntityMap 04.测试保存EntityMap对象,用于不方便使用struct的场景,使用Map作为载体
func TestInsertEntityMap(t *testing.T) {
//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,
//例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}),如果txOptions为nil,使用全局DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
//创建一个EntityMap,需要传入表名
entityMap := zorm.NewEntityMap(demoStructTableName)
//设置主键名称
entityMap.PkColumnName = "id"
//如果是自增序列,设置序列的值
//entityMap.PkSequence = "mySequence"
//Set 设置数据库的字段值
//如果主键是自增或者序列,不要entityMap.Set主键的值
entityMap.Set("id", zorm.FuncGenerateStringID())
entityMap.Set("userName", "entityMap-userName")
entityMap.Set("password", "entityMap-password")
entityMap.Set("createTime", time.Now())
entityMap.Set("active", 1)
//执行
_, err := zorm.InsertEntityMap(ctx, entityMap)
//如果返回的err不是nil,事务就会回滚
return nil, err
})
//标记测试失败
if err != nil {
t.Errorf("错误:%v", err)
}
}
//TestQueryRow 05.测试查询一个struct对象
func TestQueryRow(t *testing.T) {
//声明一个对象的指针,用于承载返回的数据
demo := &demoStruct{}
//构造查询用的finder
finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
//finder = zorm.NewSelectFinder(demoStructTableName, "id,userName") // select id,userName from t_demo
//finder = zorm.NewFinder().Append("SELECT * FROM " + demoStructTableName) // select * from t_demo
//finder默认启用了sql注入检查,禁止语句中拼接 ' 单引号,可以设置 finder.InjectionCheck = false 解开限制
//finder.Append 第一个参数是语句,后面的参数是对应的值,值的顺序要正确.语句统一使用?,zorm会处理数据库的差异
//in (?) 参数必须有()括号,不能 in ?
finder.Append("WHERE id=? and active in(?)", "20210630163227149563000042432429", []int{0, 1})
//执行查询,has为true表示数据库有数据
has, err := zorm.QueryRow(ctx, finder, demo)
if err != nil { //标记测试失败
t.Errorf("错误:%v", err)
}
//打印结果
fmt.Println(demo)
}
//TestQueryRowMap 06.测试查询map接收结果,用于不太适合struct的场景,比较灵活
func TestQueryRowMap(t *testing.T) {
//构造查询用的finder
finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
//finder.Append 第一个参数是语句,后面的参数是对应的值,值的顺序要正确.语句统一使用?,zorm会处理数据库的差异
//in (?) 参数必须有()括号,不能 in ?
finder.Append("WHERE id=? and active in(?)", "20210630163227149563000042432429", []int{0, 1})
//执行查询
resultMap, err := zorm.QueryRowMap(ctx, finder)
if err != nil { //标记测试失败
t.Errorf("错误:%v", err)
}
//打印结果
fmt.Println(resultMap)
}
//TestQuery 07.测试查询对象列表
func TestQuery(t *testing.T) {
//创建用于接收结果的slice
list := make([]*demoStruct, 0)
//构造查询用的finder
finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
//创建分页对象,查询完成后,page对象可以直接给前端分页组件使用
page := zorm.NewPage()
page.PageNo = 2 //查询第1页,默认是1
page.PageSize = 2 //每页20条,默认是20
//执行查询
err := zorm.Query(ctx, finder, &list, page)
if err != nil { //标记测试失败
t.Errorf("错误:%v", err)
}
//打印结果
fmt.Println("总条数:", page.TotalCount, " 列表:", list)
}
//TestQueryMap 08.测试查询map列表,用于不方便使用struct的场景,一条记录是一个map对象
func TestQueryMap(t *testing.T) {
//构造查询用的finder
finder := zorm.NewSelectFinder(demoStructTableName) // select * from t_demo
//创建分页对象,查询完成后,page对象可以直接给前端分页组件使用
page := zorm.NewPage()
page.PageNo = 1 //查询第1页,默认是1
page.PageSize = 2 //每页20条,默认是20
//执行查询
listMap, err := zorm.QueryMap(ctx, finder, page)
if err != nil { //标记测试失败
t.Errorf("错误:%v", err)
}
//打印结果
fmt.Println("总条数:", page.TotalCount, " 列表:", listMap)
}
//TestUpdateNotZeroValue 09.更新struct对象,只更新不为零值的字段.主键必须有值
func TestUpdateNotZeroValue(t *testing.T) {
//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,
//例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}),如果txOptions为nil,使用全局DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
//声明一个对象的指针,用于更新数据
demo := &demoStruct{}
demo.Id = "20210630163227149563000042432429"
demo.UserName = "UpdateNotZeroValue"
//更新 "sql":"UPDATE t_demo SET userName=? WHERE id=?","args":["UpdateNotZeroValue","41b2aa4f-379a-4319-8af9-08472b6e514e"]
_, err := zorm.UpdateNotZeroValue(ctx, demo)
//如果返回的err不是nil,事务就会回滚
return nil, err
})
if err != nil { //标记测试失败
t.Errorf("错误:%v", err)
}
}
//TestUpdate 10.更新struct对象,更新所有字段.主键必须有值
func TestUpdate(t *testing.T) {
//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,
//例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}),如果txOptions为nil,使用全局DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
//声明一个对象的指针,用于更新数据
demo := &demoStruct{}
demo.Id = "20210630163227149563000042432429"
demo.UserName = "TestUpdate"
_, err := zorm.Update(ctx, demo)
//如果返回的err不是nil,事务就会回滚
return nil, err
})
if err != nil { //标记测试失败
t.Errorf("错误:%v", err)
}
}
//TestUpdateFinder 11.通过finder更新,zorm最灵活的方式,可以编写任何更新语句,甚至手动编写insert语句
func TestUpdateFinder(t *testing.T) {
//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,
//例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}),如果txOptions为nil,使用全局DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
finder := zorm.NewUpdateFinder(demoStructTableName) // UPDATE t_demo SET
//finder = zorm.NewDeleteFinder(demoStructTableName) // DELETE FROM t_demo
//finder = zorm.NewFinder().Append("UPDATE").Append(demoStructTableName).Append("SET") // UPDATE t_demo SET
finder.Append("userName=?,active=?", "TestUpdateFinder", 1).Append("WHERE id=?", "20210630163227149563000042432429")
//更新 "sql":"UPDATE t_demo SET userName=?,active=? WHERE id=?","args":["TestUpdateFinder",1,"41b2aa4f-379a-4319-8af9-08472b6e514e"]
_, err := zorm.UpdateFinder(ctx, finder)
//如果返回的err不是nil,事务就会回滚
return nil, err
})
if err != nil { //标记测试失败
t.Errorf("错误:%v", err)
}
}
//TestUpdateEntityMap 12.更新一个EntityMap,主键必须有值
func TestUpdateEntityMap(t *testing.T) {
//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,
//例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}),如果txOptions为nil,使用全局DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
//创建一个EntityMap,需要传入表名
entityMap := zorm.NewEntityMap(demoStructTableName)
//设置主键名称
entityMap.PkColumnName = "id"
//Set 设置数据库的字段值,主键必须有值
entityMap.Set("id", "20210630163227149563000042432429")
entityMap.Set("userName", "TestUpdateEntityMap")
//更新 "sql":"UPDATE t_demo SET userName=? WHERE id=?","args":["TestUpdateEntityMap","41b2aa4f-379a-4319-8af9-08472b6e514e"]
_, err := zorm.UpdateEntityMap(ctx, entityMap)
//如果返回的err不是nil,事务就会回滚
return nil, err
})
if err != nil { //标记测试失败
t.Errorf("错误:%v", err)
}
}
//TestDelete 13.删除一个struct对象,主键必须有值
func TestDelete(t *testing.T) {
//需要手动开启事务,匿名函数返回的error如果不是nil,事务就会回滚
//如果全局DefaultTxOptions配置不满足需求,可以在zorm.Transaction事务方法前设置事务的隔离级别,
//例如 ctx, _ := dbDao.BindContextTxOptions(ctx, &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false}),如果txOptions为nil,使用全局DefaultTxOptions
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
demo := &demoStruct{}
demo.Id = "20210630163227149563000042432429"
//删除 "sql":"DELETE FROM t_demo WHERE id=?","args":["ae9987ac-0467-4fe2-a260-516c89292684"]
_, err := zorm.Delete(ctx, demo)
//如果返回的err不是nil,事务就会回滚
return nil, err
})
if err != nil { //标记测试失败
t.Errorf("错误:%v", err)
}
}
//TestProc 14.测试调用存储过程
func TestProc(t *testing.T) {
demo := &demoStruct{}
finder := zorm.NewFinder().Append("call testproc(?) ", "u_10001")
zorm.QueryRow(ctx, finder, demo)
fmt.Println(demo)
}
//TestFunc 15.测试调用自定义函数
func TestFunc(t *testing.T) {
userName := ""
finder := zorm.NewFinder().Append("select testfunc(?) ", "u_10001")
zorm.QueryRow(ctx, finder, &userName)
fmt.Println(userName)
}
//TestOther 16.其他的一些说明.非常感谢您能看到这一行
func TestOther(t *testing.T) {
//场景1.多个数据库.通过对应数据库的dbDao,调用BindContextDBConnection函数,把这个数据库的连接绑定到返回的ctx上,然后把ctx传递到zorm的函数即可.
newCtx, err := dbDao.BindContextDBConnection(ctx)
if err != nil { //标记测试失败
t.Errorf("错误:%v", err)
}
finder := zorm.NewSelectFinder(demoStructTableName)
//把新产生的newCtx传递到zorm的函数
list, _ := zorm.QueryMap(newCtx, finder, nil)
fmt.Println(list)
//场景2.单个数据库的读写分离.设置读写分离的策略函数.
zorm.FuncReadWriteStrategy = myReadWriteStrategy
//场景3.如果是多个数据库,每个数据库还读写分离,按照 场景1 处理
}
//单个数据库的读写分离的策略 rwType=0 read,rwType=1 write
func myReadWriteStrategy(rwType int) *zorm.DBDao {
//根据自己的业务场景,返回需要的读写dao,每次需要数据库的连接的时候,会调用这个函数
return dbDao
}
//---------------------------------//
//实现CustomDriverValueConver接口,扩展自定义类型,例如 达梦数据库text类型,映射出来的是dm.DmClob类型,无法使用string类型直接接收
type CustomDMText struct{}
//GetDriverValue 根据数据库列类型,实体类属性类型,Finder对象,返回driver.Value的实例
//如果无法获取到structFieldType,例如Map查询,会传入nil
//如果返回值为nil,接口扩展逻辑无效,使用原生的方式接收数据库字段值
func (dmtext CustomDMText) GetDriverValue(columnType *sql.ColumnType, structFieldType *reflect.Type, finder *zorm.Finder) (driver.Value, error) {
return &dm.DmClob{}, nil
}
//ConverDriverValue 数据库列类型,实体类属性类型,GetDriverValue返回的driver.Value的临时接收值,Finder对象
//如果无法获取到structFieldType,例如Map查询,会传入nil
//返回符合接收类型值的指针,指针,指针!!!!
func (dmtext CustomDMText) ConverDriverValue(columnType *sql.ColumnType, structFieldType *reflect.Type, tempDriverValue driver.Value, finder *zorm.Finder) (interface{}, error) {
//类型转换
dmClob, isok := tempDriverValue.(*dm.DmClob)
if !isok {
return tempDriverValue, errors.New("转换至*dm.DmClob类型失败")
}
//获取长度
dmlen, errLength := dmClob.GetLength()
if errLength != nil {
return dmClob, errLength
}
//int64转成int类型
strInt64 := strconv.FormatInt(dmlen, 10)
dmlenInt, errAtoi := strconv.Atoi(strInt64)
if errAtoi != nil {
return dmClob, errAtoi
}
//读取字符串
str, errReadString := dmClob.ReadString(1, dmlenInt)
return &str, errReadString
}
//CustomDriverValueMap 用于配置driver.Value和对应的处理关系,key是 drier.Value 的字符串,例如 *dm.DmClob
//一般是放到init方法里进行添加
zorm.CustomDriverValueMap["*dm.DmClob"] = CustomDMText{}
```
## 分布式事务
基于seata-golang实现分布式事务.
### proxy模式
```golang
//DataSourceConfig 配置 DefaultTxOptions
//DefaultTxOptions: &sql.TxOptions{Isolation: sql.LevelDefault, ReadOnly: false},
// 引入V1版本的依赖包,V2的参考官方例子
import (
"github.com/opentrx/mysql"
"github.com/transaction-wg/seata-golang/pkg/client"
"github.com/transaction-wg/seata-golang/pkg/client/config"
"github.com/transaction-wg/seata-golang/pkg/client/rm"
"github.com/transaction-wg/seata-golang/pkg/client/tm"
seataContext "github.com/transaction-wg/seata-golang/pkg/client/context"
)
//配置文件路径
var configPath = "./conf/client.yml"
func main() {
//初始化配置
conf := config.InitConf(configPath)
//初始化RPC客户端
client.NewRpcClient()
//注册mysql驱动
mysql.InitDataResourceManager()
mysql.RegisterResource(config.GetATConfig().DSN)
//sqlDB, err := sql.Open("mysql", config.GetATConfig().DSN)
//后续正常初始化zorm,一定要放到seata mysql 初始化后面!!!
//................//
//tm注册事务服务,参照官方例子.(全局托管主要是去掉proxy,对业务零侵入)
tm.Implement(svc.ProxySvc)
//................//
//获取seata的rootContext
//rootContext := seataContext.NewRootContext(ctx)
//rootContext := ctx.(*seataContext.RootContext)
//创建seata事务
//seataTx := tm.GetCurrentOrCreate(rootContext)
//开始事务
//seataTx.BeginWithTimeoutAndName(int32(6000), "事务名称", rootContext)
//事务开启之后获取XID.可以通过gin的header传递,或者其他方式传递
//xid:=rootContext.GetXID()
// 如果使用的gin框架,获取到ctx
// ctx := c.Request.Context()
// 接受传递过来的XID,绑定到本地ctx
//ctx =context.WithValue(ctx,mysql.XID,xid)
}
```
### 全局托管模式
```golang
//不使用proxy代理模式,全局托管,不修改业务代码,零侵入实现分布式事务
//tm.Implement(svc.ProxySvc)
// 分布式事务示例代码
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
// 获取当前分布式事务的XID.不用考虑怎么来的,如果是分布式事务环境,会自动设置值
// xid := ctx.Value("XID").(string)
// 把xid传递到第三方应用
// req.Header.Set("XID", xid)
// 如果返回的err不是nil,本地事务和分布式事务就会回滚
return nil, err
})
///----------第三方应用-------///
// 第三方应用开启事务前,ctx需要绑定XID,例如使用了gin框架
// 接受传递过来的XID,绑定到本地ctx
// xid:=c.Request.Header.Get("XID")
// 获取到ctx
// ctx := c.Request.Context()
// ctx = context.WithValue(ctx,"XID",xid)
// ctx绑定XID之后,调用业务事务
_, err := zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
// 业务代码......
// 如果返回的err不是nil,本地事务和分布式事务就会回滚
return nil, err
})
// 建议以下代码放到单独的文件里
//................//
// ZormSeataGlobalTransaction 包装seata的*tm.DefaultGlobalTransaction,实现zorm.ISeataGlobalTransaction接口
type ZormSeataGlobalTransaction struct {
*tm.DefaultGlobalTransaction
}
// MyFuncSeataGlobalTransaction zorm适配seata分布式事务的函数
// 重要!!!!需要配置zorm.DataSourceConfig.FuncSeataGlobalTransaction=MyFuncSeataGlobalTransaction 重要!!!
func MyFuncSeataGlobalTransaction(ctx context.Context) (zorm.ISeataGlobalTransaction, context.Context, error) {
//获取seata的rootContext
rootContext := seataContext.NewRootContext(ctx)
//创建seata事务
seataTx := tm.GetCurrentOrCreate(rootContext)
//使用zorm.ISeataGlobalTransaction接口对象包装seata事务,隔离seata-golang依赖
seataGlobalTransaction := ZormSeataGlobalTransaction{seataTx}
return seataGlobalTransaction, rootContext, nil
}
//实现zorm.ISeataGlobalTransaction接口
func (gtx ZormSeataGlobalTransaction) SeataBegin(ctx context.Context) error {
rootContext := ctx.(*seataContext.RootContext)
return gtx.BeginWithTimeout(int32(6000), rootContext)
}
func (gtx ZormSeataGlobalTransaction) SeataCommit(ctx context.Context) error {
rootContext := ctx.(*seataContext.RootContext)
return gtx.Commit(rootContext)
}
func (gtx ZormSeataGlobalTransaction) SeataRollback(ctx context.Context) error {
rootContext := ctx.(*seataContext.RootContext)
//如果是Participant角色,修改为Launcher角色,允许分支事务提交全局事务.
if gtx.Role != tm.Launcher {
gtx.Role = tm.Launcher
}
return gtx.Rollback(rootContext)
}
func (gtx ZormSeataGlobalTransaction) GetSeataXID(ctx context.Context) string {
rootContext := ctx.(*seataContext.RootContext)
return rootContext.GetXID()
}
//................//
```
## 性能压测
测试代码:https://github.com/springrain/goormbenchmark
zorm 1.2.x 版本实现了基础功能,读性能比gorm和xorm快一倍.随着功能持续增加,造成性能下降,目前读性能只快了50%.
zorm会持续优化改进性能.

@ -54,14 +54,19 @@ type DataSourceConfig struct {
//FuncSeataGlobalTransaction seata-golang分布式的适配函数,返回ISeataGlobalTransaction接口的实现
FuncSeataGlobalTransaction func(ctx context.Context) (ISeataGlobalTransaction, context.Context, error)
//使用现有的数据库连接,优先级高于DSN
SQLDB *sql.DB
}
// newDataSource 创建一个新的datasource,内部调用,避免外部直接使用datasource
// newDAtaSource Create a new datasource and call it internally to avoid direct external use of the datasource
func newDataSource(config *DataSourceConfig) (*dataSource, error) {
if config.DSN == "" {
return nil, errors.New("DSN cannot be empty")
if config == nil {
return nil, errors.New("config cannot be nil")
}
if config.DriverName == "" {
return nil, errors.New("DriverName cannot be empty")
}
@ -70,16 +75,20 @@ func newDataSource(config *DataSourceConfig) (*dataSource, error) {
}
var db *sql.DB
var errSQLOpen error
//if config.MockSQLDB == nil {
db, errSQLOpen = sql.Open(config.DriverName, config.DSN)
if errSQLOpen != nil {
errSQLOpen = fmt.Errorf("newDataSource-->open数据库打开失败:%w", errSQLOpen)
FuncLogError(errSQLOpen)
return nil, errSQLOpen
if config.SQLDB == nil { //没有已经存在的数据库连接,使用DSN初始化
if config.DSN == "" {
return nil, errors.New("DSN cannot be empty")
}
db, errSQLOpen = sql.Open(config.DriverName, config.DSN)
if errSQLOpen != nil {
errSQLOpen = fmt.Errorf("newDataSource-->open数据库打开失败:%w", errSQLOpen)
FuncLogError(errSQLOpen)
return nil, errSQLOpen
}
} else { //使用已经存在的数据库连接
db = config.SQLDB
}
// } else {
// db = config.MockSQLDB
// }
if config.MaxOpenConns == 0 {
config.MaxOpenConns = 50

@ -155,7 +155,7 @@ func wrapInsertSQLNOreBuild(dbType string, typeOf *reflect.Type, entity IEntityS
i = i - 1
continue
} else if (pktype == "string") && (pkValue.(string) == "") { //主键是字符串类型,并且值为"",赋值id
} else if (pktype == "string") && reflect.ValueOf(pkValue).IsZero() { //主键是字符串类型,并且值为"",赋值id
//生成主键字符串
//Generate primary key string
id := FuncGenerateStringID()
@ -168,7 +168,7 @@ func wrapInsertSQLNOreBuild(dbType string, typeOf *reflect.Type, entity IEntityS
//If it is a number type and the value is 0,
//it is considered to be a database self-increment,
//delete the primary key information from the array, and let the database generate itself.
} else if (pktype == "int" && pkValue.(int) == 0) || (pktype == "int64" && pkValue.(int64) == 0) {
} else if (pktype == "int" || pktype == "int64") && reflect.ValueOf(pkValue).IsZero() {
//标记是自增主键
//Mark is auto-incrementing primary key
autoIncrement = 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

@ -800,18 +800,33 @@ var awsPartition = partition{
endpointKey{
Region: "eu-central-1",
}: endpoint{},
endpointKey{
Region: "eu-north-1",
}: endpoint{},
endpointKey{
Region: "eu-west-1",
}: endpoint{},
endpointKey{
Region: "eu-west-2",
}: endpoint{},
endpointKey{
Region: "eu-west-3",
}: endpoint{},
endpointKey{
Region: "me-south-1",
}: endpoint{},
endpointKey{
Region: "sa-east-1",
}: endpoint{},
endpointKey{
Region: "us-east-1",
}: endpoint{},
endpointKey{
Region: "us-east-2",
}: endpoint{},
endpointKey{
Region: "us-west-1",
}: endpoint{},
endpointKey{
Region: "us-west-2",
}: endpoint{},
@ -2005,6 +2020,76 @@ var awsPartition = partition{
}: endpoint{},
},
},
"appconfig": service{
Endpoints: serviceEndpoints{
endpointKey{
Region: "af-south-1",
}: endpoint{},
endpointKey{
Region: "ap-east-1",
}: endpoint{},
endpointKey{
Region: "ap-northeast-1",
}: endpoint{},
endpointKey{
Region: "ap-northeast-2",
}: endpoint{},
endpointKey{
Region: "ap-northeast-3",
}: endpoint{},
endpointKey{
Region: "ap-south-1",
}: endpoint{},
endpointKey{
Region: "ap-southeast-1",
}: endpoint{},
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
endpointKey{
Region: "ap-southeast-3",
}: endpoint{},
endpointKey{
Region: "ca-central-1",
}: endpoint{},
endpointKey{
Region: "eu-central-1",
}: endpoint{},
endpointKey{
Region: "eu-north-1",
}: endpoint{},
endpointKey{
Region: "eu-south-1",
}: endpoint{},
endpointKey{
Region: "eu-west-1",
}: endpoint{},
endpointKey{
Region: "eu-west-2",
}: endpoint{},
endpointKey{
Region: "eu-west-3",
}: endpoint{},
endpointKey{
Region: "me-south-1",
}: endpoint{},
endpointKey{
Region: "sa-east-1",
}: endpoint{},
endpointKey{
Region: "us-east-1",
}: endpoint{},
endpointKey{
Region: "us-east-2",
}: endpoint{},
endpointKey{
Region: "us-west-1",
}: endpoint{},
endpointKey{
Region: "us-west-2",
}: endpoint{},
},
},
"appconfigdata": service{
Endpoints: serviceEndpoints{
endpointKey{
@ -2578,6 +2663,9 @@ var awsPartition = partition{
},
Deprecated: boxedTrue,
},
endpointKey{
Region: "us-east-2",
}: endpoint{},
endpointKey{
Region: "us-west-2",
}: endpoint{},
@ -6258,6 +6346,76 @@ var awsPartition = partition{
}: endpoint{},
},
},
"dlm": service{
Endpoints: serviceEndpoints{
endpointKey{
Region: "af-south-1",
}: endpoint{},
endpointKey{
Region: "ap-east-1",
}: endpoint{},
endpointKey{
Region: "ap-northeast-1",
}: endpoint{},
endpointKey{
Region: "ap-northeast-2",
}: endpoint{},
endpointKey{
Region: "ap-northeast-3",
}: endpoint{},
endpointKey{
Region: "ap-south-1",
}: endpoint{},
endpointKey{
Region: "ap-southeast-1",
}: endpoint{},
endpointKey{
Region: "ap-southeast-2",
}: endpoint{},
endpointKey{
Region: "ap-southeast-3",
}: endpoint{},
endpointKey{
Region: "ca-central-1",
}: endpoint{},
endpointKey{
Region: "eu-central-1",
}: endpoint{},
endpointKey{
Region: "eu-north-1",
}: endpoint{},
endpointKey{
Region: "eu-south-1",
}: endpoint{},
endpointKey{
Region: "eu-west-1",
}: endpoint{},
endpointKey{
Region: "eu-west-2",
}: endpoint{},
endpointKey{
Region: "eu-west-3",
}: endpoint{},
endpointKey{
Region: "me-south-1",
}: endpoint{},
endpointKey{
Region: "sa-east-1",
}: endpoint{},
endpointKey{
Region: "us-east-1",
}: endpoint{},
endpointKey{
Region: "us-east-2",
}: endpoint{},
endpointKey{
Region: "us-west-1",
}: endpoint{},
endpointKey{
Region: "us-west-2",
}: endpoint{},
},
},
"dms": service{
Endpoints: serviceEndpoints{
endpointKey{
@ -12196,6 +12354,9 @@ var awsPartition = partition{
},
"kinesisvideo": service{
Endpoints: serviceEndpoints{
endpointKey{
Region: "af-south-1",
}: endpoint{},
endpointKey{
Region: "ap-east-1",
}: endpoint{},
@ -15131,6 +15292,14 @@ var awsPartition = partition{
},
"oidc": service{
Endpoints: serviceEndpoints{
endpointKey{
Region: "ap-east-1",
}: endpoint{
Hostname: "oidc.ap-east-1.amazonaws.com",
CredentialScope: credentialScope{
Region: "ap-east-1",
},
},
endpointKey{
Region: "ap-northeast-1",
}: endpoint{
@ -15235,6 +15404,14 @@ var awsPartition = partition{
Region: "eu-west-3",
},
},
endpointKey{
Region: "me-south-1",
}: endpoint{
Hostname: "oidc.me-south-1.amazonaws.com",
CredentialScope: credentialScope{
Region: "me-south-1",
},
},
endpointKey{
Region: "sa-east-1",
}: endpoint{
@ -15840,6 +16017,14 @@ var awsPartition = partition{
},
"portal.sso": service{
Endpoints: serviceEndpoints{
endpointKey{
Region: "ap-east-1",
}: endpoint{
Hostname: "portal.sso.ap-east-1.amazonaws.com",
CredentialScope: credentialScope{
Region: "ap-east-1",
},
},
endpointKey{
Region: "ap-northeast-1",
}: endpoint{
@ -15944,6 +16129,14 @@ var awsPartition = partition{
Region: "eu-west-3",
},
},
endpointKey{
Region: "me-south-1",
}: endpoint{
Hostname: "portal.sso.me-south-1.amazonaws.com",
CredentialScope: credentialScope{
Region: "me-south-1",
},
},
endpointKey{
Region: "sa-east-1",
}: endpoint{
@ -24113,6 +24306,16 @@ var awscnPartition = partition{
}: endpoint{},
},
},
"appconfig": service{
Endpoints: serviceEndpoints{
endpointKey{
Region: "cn-north-1",
}: endpoint{},
endpointKey{
Region: "cn-northwest-1",
}: endpoint{},
},
},
"appconfigdata": service{
Endpoints: serviceEndpoints{
endpointKey{
@ -24455,6 +24658,16 @@ var awscnPartition = partition{
}: endpoint{},
},
},
"dlm": service{
Endpoints: serviceEndpoints{
endpointKey{
Region: "cn-north-1",
}: endpoint{},
endpointKey{
Region: "cn-northwest-1",
}: endpoint{},
},
},
"dms": service{
Endpoints: serviceEndpoints{
endpointKey{
@ -26073,6 +26286,46 @@ var awsusgovPartition = partition{
}: endpoint{},
},
},
"appconfig": service{
Endpoints: serviceEndpoints{
endpointKey{
Region: "fips-us-gov-east-1",
}: endpoint{
Hostname: "appconfig.us-gov-east-1.amazonaws.com",
CredentialScope: credentialScope{
Region: "us-gov-east-1",
},
Deprecated: boxedTrue,
},
endpointKey{
Region: "fips-us-gov-west-1",
}: endpoint{
Hostname: "appconfig.us-gov-west-1.amazonaws.com",
CredentialScope: credentialScope{
Region: "us-gov-west-1",
},
Deprecated: boxedTrue,
},
endpointKey{
Region: "us-gov-east-1",
}: endpoint{},
endpointKey{
Region: "us-gov-east-1",
Variant: fipsVariant,
}: endpoint{
Hostname: "appconfig.us-gov-east-1.amazonaws.com",
},
endpointKey{
Region: "us-gov-west-1",
}: endpoint{},
endpointKey{
Region: "us-gov-west-1",
Variant: fipsVariant,
}: endpoint{
Hostname: "appconfig.us-gov-west-1.amazonaws.com",
},
},
},
"appconfigdata": service{
Endpoints: serviceEndpoints{
endpointKey{
@ -26899,6 +27152,16 @@ var awsusgovPartition = partition{
},
},
},
"dlm": service{
Endpoints: serviceEndpoints{
endpointKey{
Region: "us-gov-east-1",
}: endpoint{},
endpointKey{
Region: "us-gov-west-1",
}: endpoint{},
},
},
"dms": service{
Defaults: endpointDefaults{
defaultKey{}: endpoint{},
@ -30649,6 +30912,16 @@ var awsisoPartition = partition{
}: endpoint{},
},
},
"appconfig": service{
Endpoints: serviceEndpoints{
endpointKey{
Region: "us-iso-east-1",
}: endpoint{},
endpointKey{
Region: "us-iso-west-1",
}: endpoint{},
},
},
"appconfigdata": service{
Endpoints: serviceEndpoints{
endpointKey{
@ -30946,6 +31219,9 @@ var awsisoPartition = partition{
endpointKey{
Region: "us-iso-east-1",
}: endpoint{},
endpointKey{
Region: "us-iso-west-1",
}: endpoint{},
},
},
"events": service{
@ -31393,6 +31669,13 @@ var awsisobPartition = partition{
},
},
},
"appconfig": service{
Endpoints: serviceEndpoints{
endpointKey{
Region: "us-isob-east-1",
}: endpoint{},
},
},
"application-autoscaling": service{
Defaults: endpointDefaults{
defaultKey{}: endpoint{

@ -5,4 +5,4 @@ package aws
const SDKName = "aws-sdk-go"
// SDKVersion is the version of this SDK
const SDKVersion = "1.44.51"
const SDKVersion = "1.44.53"

@ -0,0 +1,29 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (darwin || freebsd || netbsd || openbsd) && gc
// +build darwin freebsd netbsd openbsd
// +build gc
#include "textflag.h"
// System call support for RISCV64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)

@ -0,0 +1,63 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build riscv64 && freebsd
// +build riscv64,freebsd
package unix
import (
"syscall"
"unsafe"
)
func setTimespec(sec, nsec int64) Timespec {
return Timespec{Sec: sec, Nsec: nsec}
}
func setTimeval(sec, usec int64) Timeval {
return Timeval{Sec: sec, Usec: usec}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
k.Ident = uint64(fd)
k.Filter = int16(mode)
k.Flags = uint16(flags)
}
func (iov *Iovec) SetLen(length int) {
iov.Len = uint64(length)
}
func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
func (msghdr *Msghdr) SetIovlen(length int) {
msghdr.Iovlen = int32(length)
}
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
var writtenOut uint64 = 0
_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
written = int(writtenOut)
if e1 != 0 {
err = e1
}
return
}
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint64(countin)}
err = ptrace(PT_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
return int(ioDesc.Len), err
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,394 @@
// go run mksysnum.go https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12
// Code generated by the command above; see README.md. DO NOT EDIT.
//go:build riscv64 && freebsd
// +build riscv64,freebsd
package unix
const (
// SYS_NOSYS = 0; // { int nosys(void); } syscall nosys_args int
SYS_EXIT = 1 // { void sys_exit(int rval); } exit sys_exit_args void
SYS_FORK = 2 // { int fork(void); }
SYS_READ = 3 // { ssize_t read(int fd, void *buf, size_t nbyte); }
SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, size_t nbyte); }
SYS_OPEN = 5 // { int open(char *path, int flags, int mode); }
SYS_CLOSE = 6 // { int close(int fd); }
SYS_WAIT4 = 7 // { int wait4(int pid, int *status, int options, struct rusage *rusage); }
SYS_LINK = 9 // { int link(char *path, char *link); }
SYS_UNLINK = 10 // { int unlink(char *path); }
SYS_CHDIR = 12 // { int chdir(char *path); }
SYS_FCHDIR = 13 // { int fchdir(int fd); }
SYS_CHMOD = 15 // { int chmod(char *path, int mode); }
SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); }
SYS_BREAK = 17 // { caddr_t break(char *nsize); }
SYS_GETPID = 20 // { pid_t getpid(void); }
SYS_MOUNT = 21 // { int mount(char *type, char *path, int flags, caddr_t data); }
SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); }
SYS_SETUID = 23 // { int setuid(uid_t uid); }
SYS_GETUID = 24 // { uid_t getuid(void); }
SYS_GETEUID = 25 // { uid_t geteuid(void); }
SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, caddr_t addr, int data); }
SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, int flags); }
SYS_SENDMSG = 28 // { int sendmsg(int s, struct msghdr *msg, int flags); }
SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, size_t len, int flags, struct sockaddr * __restrict from, __socklen_t * __restrict fromlenaddr); }
SYS_ACCEPT = 30 // { int accept(int s, struct sockaddr * __restrict name, __socklen_t * __restrict anamelen); }
SYS_GETPEERNAME = 31 // { int getpeername(int fdes, struct sockaddr * __restrict asa, __socklen_t * __restrict alen); }
SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, struct sockaddr * __restrict asa, __socklen_t * __restrict alen); }
SYS_ACCESS = 33 // { int access(char *path, int amode); }
SYS_CHFLAGS = 34 // { int chflags(const char *path, u_long flags); }
SYS_FCHFLAGS = 35 // { int fchflags(int fd, u_long flags); }
SYS_SYNC = 36 // { int sync(void); }
SYS_KILL = 37 // { int kill(int pid, int signum); }
SYS_GETPPID = 39 // { pid_t getppid(void); }
SYS_DUP = 41 // { int dup(u_int fd); }
SYS_GETEGID = 43 // { gid_t getegid(void); }
SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, size_t offset, u_int scale); }
SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, int facs, int pid); }
SYS_GETGID = 47 // { gid_t getgid(void); }
SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int namelen); }
SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); }
SYS_ACCT = 51 // { int acct(char *path); }
SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, stack_t *oss); }
SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, caddr_t data); }
SYS_REBOOT = 55 // { int reboot(int opt); }
SYS_REVOKE = 56 // { int revoke(char *path); }
SYS_SYMLINK = 57 // { int symlink(char *path, char *link); }
SYS_READLINK = 58 // { ssize_t readlink(char *path, char *buf, size_t count); }
SYS_EXECVE = 59 // { int execve(char *fname, char **argv, char **envv); }
SYS_UMASK = 60 // { int umask(int newmask); }
SYS_CHROOT = 61 // { int chroot(char *path); }
SYS_MSYNC = 65 // { int msync(void *addr, size_t len, int flags); }
SYS_VFORK = 66 // { int vfork(void); }
SYS_SBRK = 69 // { int sbrk(int incr); }
SYS_SSTK = 70 // { int sstk(int incr); }
SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); }
SYS_MPROTECT = 74 // { int mprotect(void *addr, size_t len, int prot); }
SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, int behav); }
SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, char *vec); }
SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, gid_t *gidset); }
SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, gid_t *gidset); }
SYS_GETPGRP = 81 // { int getpgrp(void); }
SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); }
SYS_SETITIMER = 83 // { int setitimer(u_int which, struct itimerval *itv, struct itimerval *oitv); }
SYS_SWAPON = 85 // { int swapon(char *name); }
SYS_GETITIMER = 86 // { int getitimer(u_int which, struct itimerval *itv); }
SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); }
SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); }
SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); }
SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv); }
SYS_FSYNC = 95 // { int fsync(int fd); }
SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, int prio); }
SYS_SOCKET = 97 // { int socket(int domain, int type, int protocol); }
SYS_CONNECT = 98 // { int connect(int s, caddr_t name, int namelen); }
SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); }
SYS_BIND = 104 // { int bind(int s, caddr_t name, int namelen); }
SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, caddr_t val, int valsize); }
SYS_LISTEN = 106 // { int listen(int s, int backlog); }
SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, struct timezone *tzp); }
SYS_GETRUSAGE = 117 // { int getrusage(int who, struct rusage *rusage); }
SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, caddr_t val, int *avalsize); }
SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, u_int iovcnt); }
SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, u_int iovcnt); }
SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, struct timezone *tzp); }
SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); }
SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); }
SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); }
SYS_SETREGID = 127 // { int setregid(int rgid, int egid); }
SYS_RENAME = 128 // { int rename(char *from, char *to); }
SYS_FLOCK = 131 // { int flock(int fd, int how); }
SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); }
SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, int flags, caddr_t to, int tolen); }
SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); }
SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, int protocol, int *rsv); }
SYS_MKDIR = 136 // { int mkdir(char *path, int mode); }
SYS_RMDIR = 137 // { int rmdir(char *path); }
SYS_UTIMES = 138 // { int utimes(char *path, struct timeval *tptr); }
SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, struct timeval *olddelta); }
SYS_SETSID = 147 // { int setsid(void); }
SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, caddr_t arg); }
SYS_NLM_SYSCALL = 154 // { int nlm_syscall(int debug_level, int grace_period, int addr_count, char **addrs); }
SYS_NFSSVC = 155 // { int nfssvc(int flag, caddr_t argp); }
SYS_LGETFH = 160 // { int lgetfh(char *fname, struct fhandle *fhp); }
SYS_GETFH = 161 // { int getfh(char *fname, struct fhandle *fhp); }
SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); }
SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, struct rtprio *rtp); }
SYS_SEMSYS = 169 // { int semsys(int which, int a2, int a3, int a4, int a5); }
SYS_MSGSYS = 170 // { int msgsys(int which, int a2, int a3, int a4, int a5, int a6); }
SYS_SHMSYS = 171 // { int shmsys(int which, int a2, int a3, int a4); }
SYS_SETFIB = 175 // { int setfib(int fibnum); }
SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); }
SYS_SETGID = 181 // { int setgid(gid_t gid); }
SYS_SETEGID = 182 // { int setegid(gid_t egid); }
SYS_SETEUID = 183 // { int seteuid(uid_t euid); }
SYS_PATHCONF = 191 // { int pathconf(char *path, int name); }
SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); }
SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, struct rlimit *rlp); } getrlimit __getrlimit_args int
SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, struct rlimit *rlp); } setrlimit __setrlimit_args int
SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); } __sysctl sysctl_args int
SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); }
SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); }
SYS_UNDELETE = 205 // { int undelete(char *path); }
SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); }
SYS_GETPGID = 207 // { int getpgid(pid_t pid); }
SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, int timeout); }
SYS_SEMGET = 221 // { int semget(key_t key, int nsems, int semflg); }
SYS_SEMOP = 222 // { int semop(int semid, struct sembuf *sops, size_t nsops); }
SYS_MSGGET = 225 // { int msgget(key_t key, int msgflg); }
SYS_MSGSND = 226 // { int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); }
SYS_MSGRCV = 227 // { ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); }
SYS_SHMAT = 228 // { int shmat(int shmid, const void *shmaddr, int shmflg); }
SYS_SHMDT = 230 // { int shmdt(const void *shmaddr); }
SYS_SHMGET = 231 // { int shmget(key_t key, size_t size, int shmflg); }
SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, struct timespec *tp); }
SYS_CLOCK_SETTIME = 233 // { int clock_settime(clockid_t clock_id, const struct timespec *tp); }
SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, struct timespec *tp); }
SYS_KTIMER_CREATE = 235 // { int ktimer_create(clockid_t clock_id, struct sigevent *evp, int *timerid); }
SYS_KTIMER_DELETE = 236 // { int ktimer_delete(int timerid); }
SYS_KTIMER_SETTIME = 237 // { int ktimer_settime(int timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue); }
SYS_KTIMER_GETTIME = 238 // { int ktimer_gettime(int timerid, struct itimerspec *value); }
SYS_KTIMER_GETOVERRUN = 239 // { int ktimer_getoverrun(int timerid); }
SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, struct timespec *rmtp); }
SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); }
SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate(struct ffclock_estimate *cest); }
SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate(struct ffclock_estimate *cest); }
SYS_CLOCK_NANOSLEEP = 244 // { int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp, struct timespec *rmtp); }
SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id, int which, clockid_t *clock_id); }
SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); }
SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, int inherit); }
SYS_RFORK = 251 // { int rfork(int flags); }
SYS_ISSETUGID = 253 // { int issetugid(void); }
SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); }
SYS_AIO_READ = 255 // { int aio_read(struct aiocb *aiocbp); }
SYS_AIO_WRITE = 256 // { int aio_write(struct aiocb *aiocbp); }
SYS_LIO_LISTIO = 257 // { int lio_listio(int mode, struct aiocb* const *acb_list, int nent, struct sigevent *sig); }
SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); }
SYS_LUTIMES = 276 // { int lutimes(char *path, struct timeval *tptr); }
SYS_PREADV = 289 // { ssize_t preadv(int fd, struct iovec *iovp, u_int iovcnt, off_t offset); }
SYS_PWRITEV = 290 // { ssize_t pwritev(int fd, struct iovec *iovp, u_int iovcnt, off_t offset); }
SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, int flags); }
SYS_MODNEXT = 300 // { int modnext(int modid); }
SYS_MODSTAT = 301 // { int modstat(int modid, struct module_stat* stat); }
SYS_MODFNEXT = 302 // { int modfnext(int modid); }
SYS_MODFIND = 303 // { int modfind(const char *name); }
SYS_KLDLOAD = 304 // { int kldload(const char *file); }
SYS_KLDUNLOAD = 305 // { int kldunload(int fileid); }
SYS_KLDFIND = 306 // { int kldfind(const char *file); }
SYS_KLDNEXT = 307 // { int kldnext(int fileid); }
SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct kld_file_stat *stat); }
SYS_KLDFIRSTMOD = 309 // { int kldfirstmod(int fileid); }
SYS_GETSID = 310 // { int getsid(pid_t pid); }
SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, uid_t suid); }
SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, gid_t sgid); }
SYS_AIO_RETURN = 314 // { ssize_t aio_return(struct aiocb *aiocbp); }
SYS_AIO_SUSPEND = 315 // { int aio_suspend(struct aiocb * const * aiocbp, int nent, const struct timespec *timeout); }
SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, struct aiocb *aiocbp); }
SYS_AIO_ERROR = 317 // { int aio_error(struct aiocb *aiocbp); }
SYS_YIELD = 321 // { int yield(void); }
SYS_MLOCKALL = 324 // { int mlockall(int how); }
SYS_MUNLOCKALL = 325 // { int munlockall(void); }
SYS___GETCWD = 326 // { int __getcwd(char *buf, size_t buflen); }
SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, const struct sched_param *param); }
SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct sched_param *param); }
SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param); }
SYS_SCHED_GETSCHEDULER = 330 // { int sched_getscheduler (pid_t pid); }
SYS_SCHED_YIELD = 331 // { int sched_yield (void); }
SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); }
SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); }
SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, struct timespec *interval); }
SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); }
SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, void *data); }
SYS_JAIL = 338 // { int jail(struct jail *jail); }
SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, const sigset_t *set, sigset_t *oset); }
SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); }
SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); }
SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout); }
SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set, siginfo_t *info); }
SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); }
SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); }
SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); }
SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, acl_type_t type, struct acl *aclp); }
SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, acl_type_t type); }
SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, acl_type_t type); }
SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); }
SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); }
SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, const char *filename, int attrnamespace, const char *attrname); }
SYS_EXTATTR_SET_FILE = 356 // { ssize_t extattr_set_file(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); }
SYS_EXTATTR_GET_FILE = 357 // { ssize_t extattr_get_file(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); }
SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, int attrnamespace, const char *attrname); }
SYS_AIO_WAITCOMPLETE = 359 // { ssize_t aio_waitcomplete(struct aiocb **aiocbp, struct timespec *timeout); }
SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); }
SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); }
SYS_KQUEUE = 362 // { int kqueue(void); }
SYS_EXTATTR_SET_FD = 371 // { ssize_t extattr_set_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); }
SYS_EXTATTR_GET_FD = 372 // { ssize_t extattr_get_fd(int fd, int attrnamespace, const char *attrname, void *data, size_t nbytes); }
SYS_EXTATTR_DELETE_FD = 373 // { int extattr_delete_fd(int fd, int attrnamespace, const char *attrname); }
SYS___SETUGID = 374 // { int __setugid(int flag); }
SYS_EACCESS = 376 // { int eaccess(char *path, int amode); }
SYS_NMOUNT = 378 // { int nmount(struct iovec *iovp, unsigned int iovcnt, int flags); }
SYS___MAC_GET_PROC = 384 // { int __mac_get_proc(struct mac *mac_p); }
SYS___MAC_SET_PROC = 385 // { int __mac_set_proc(struct mac *mac_p); }
SYS___MAC_GET_FD = 386 // { int __mac_get_fd(int fd, struct mac *mac_p); }
SYS___MAC_GET_FILE = 387 // { int __mac_get_file(const char *path_p, struct mac *mac_p); }
SYS___MAC_SET_FD = 388 // { int __mac_set_fd(int fd, struct mac *mac_p); }
SYS___MAC_SET_FILE = 389 // { int __mac_set_file(const char *path_p, struct mac *mac_p); }
SYS_KENV = 390 // { int kenv(int what, const char *name, char *value, int len); }
SYS_LCHFLAGS = 391 // { int lchflags(const char *path, u_long flags); }
SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, int count); }
SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr, off_t *sbytes, int flags); }
SYS_MAC_SYSCALL = 394 // { int mac_syscall(const char *policy, int call, void *arg); }
SYS_KSEM_CLOSE = 400 // { int ksem_close(semid_t id); }
SYS_KSEM_POST = 401 // { int ksem_post(semid_t id); }
SYS_KSEM_WAIT = 402 // { int ksem_wait(semid_t id); }
SYS_KSEM_TRYWAIT = 403 // { int ksem_trywait(semid_t id); }
SYS_KSEM_INIT = 404 // { int ksem_init(semid_t *idp, unsigned int value); }
SYS_KSEM_OPEN = 405 // { int ksem_open(semid_t *idp, const char *name, int oflag, mode_t mode, unsigned int value); }
SYS_KSEM_UNLINK = 406 // { int ksem_unlink(const char *name); }
SYS_KSEM_GETVALUE = 407 // { int ksem_getvalue(semid_t id, int *val); }
SYS_KSEM_DESTROY = 408 // { int ksem_destroy(semid_t id); }
SYS___MAC_GET_PID = 409 // { int __mac_get_pid(pid_t pid, struct mac *mac_p); }
SYS___MAC_GET_LINK = 410 // { int __mac_get_link(const char *path_p, struct mac *mac_p); }
SYS___MAC_SET_LINK = 411 // { int __mac_set_link(const char *path_p, struct mac *mac_p); }
SYS_EXTATTR_SET_LINK = 412 // { ssize_t extattr_set_link(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); }
SYS_EXTATTR_GET_LINK = 413 // { ssize_t extattr_get_link(const char *path, int attrnamespace, const char *attrname, void *data, size_t nbytes); }
SYS_EXTATTR_DELETE_LINK = 414 // { int extattr_delete_link(const char *path, int attrnamespace, const char *attrname); }
SYS___MAC_EXECVE = 415 // { int __mac_execve(char *fname, char **argv, char **envv, struct mac *mac_p); }
SYS_SIGACTION = 416 // { int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); }
SYS_SIGRETURN = 417 // { int sigreturn(const struct __ucontext *sigcntxp); }
SYS_GETCONTEXT = 421 // { int getcontext(struct __ucontext *ucp); }
SYS_SETCONTEXT = 422 // { int setcontext(const struct __ucontext *ucp); }
SYS_SWAPCONTEXT = 423 // { int swapcontext(struct __ucontext *oucp, const struct __ucontext *ucp); }
SYS_SWAPOFF = 424 // { int swapoff(const char *name); }
SYS___ACL_GET_LINK = 425 // { int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); }
SYS___ACL_SET_LINK = 426 // { int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); }
SYS___ACL_DELETE_LINK = 427 // { int __acl_delete_link(const char *path, acl_type_t type); }
SYS___ACL_ACLCHECK_LINK = 428 // { int __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); }
SYS_SIGWAIT = 429 // { int sigwait(const sigset_t *set, int *sig); }
SYS_THR_CREATE = 430 // { int thr_create(ucontext_t *ctx, long *id, int flags); }
SYS_THR_EXIT = 431 // { void thr_exit(long *state); }
SYS_THR_SELF = 432 // { int thr_self(long *id); }
SYS_THR_KILL = 433 // { int thr_kill(long id, int sig); }
SYS_JAIL_ATTACH = 436 // { int jail_attach(int jid); }
SYS_EXTATTR_LIST_FD = 437 // { ssize_t extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes); }
SYS_EXTATTR_LIST_FILE = 438 // { ssize_t extattr_list_file(const char *path, int attrnamespace, void *data, size_t nbytes); }
SYS_EXTATTR_LIST_LINK = 439 // { ssize_t extattr_list_link(const char *path, int attrnamespace, void *data, size_t nbytes); }
SYS_KSEM_TIMEDWAIT = 441 // { int ksem_timedwait(semid_t id, const struct timespec *abstime); }
SYS_THR_SUSPEND = 442 // { int thr_suspend(const struct timespec *timeout); }
SYS_THR_WAKE = 443 // { int thr_wake(long id); }
SYS_KLDUNLOADF = 444 // { int kldunloadf(int fileid, int flags); }
SYS_AUDIT = 445 // { int audit(const void *record, u_int length); }
SYS_AUDITON = 446 // { int auditon(int cmd, void *data, u_int length); }
SYS_GETAUID = 447 // { int getauid(uid_t *auid); }
SYS_SETAUID = 448 // { int setauid(uid_t *auid); }
SYS_GETAUDIT = 449 // { int getaudit(struct auditinfo *auditinfo); }
SYS_SETAUDIT = 450 // { int setaudit(struct auditinfo *auditinfo); }
SYS_GETAUDIT_ADDR = 451 // { int getaudit_addr(struct auditinfo_addr *auditinfo_addr, u_int length); }
SYS_SETAUDIT_ADDR = 452 // { int setaudit_addr(struct auditinfo_addr *auditinfo_addr, u_int length); }
SYS_AUDITCTL = 453 // { int auditctl(char *path); }
SYS__UMTX_OP = 454 // { int _umtx_op(void *obj, int op, u_long val, void *uaddr1, void *uaddr2); }
SYS_THR_NEW = 455 // { int thr_new(struct thr_param *param, int param_size); }
SYS_SIGQUEUE = 456 // { int sigqueue(pid_t pid, int signum, void *value); }
SYS_KMQ_OPEN = 457 // { int kmq_open(const char *path, int flags, mode_t mode, const struct mq_attr *attr); }
SYS_KMQ_SETATTR = 458 // { int kmq_setattr(int mqd, const struct mq_attr *attr, struct mq_attr *oattr); }
SYS_KMQ_TIMEDRECEIVE = 459 // { int kmq_timedreceive(int mqd, char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct timespec *abs_timeout); }
SYS_KMQ_TIMEDSEND = 460 // { int kmq_timedsend(int mqd, const char *msg_ptr, size_t msg_len, unsigned msg_prio, const struct timespec *abs_timeout); }
SYS_KMQ_NOTIFY = 461 // { int kmq_notify(int mqd, const struct sigevent *sigev); }
SYS_KMQ_UNLINK = 462 // { int kmq_unlink(const char *path); }
SYS_ABORT2 = 463 // { int abort2(const char *why, int nargs, void **args); }
SYS_THR_SET_NAME = 464 // { int thr_set_name(long id, const char *name); }
SYS_AIO_FSYNC = 465 // { int aio_fsync(int op, struct aiocb *aiocbp); }
SYS_RTPRIO_THREAD = 466 // { int rtprio_thread(int function, lwpid_t lwpid, struct rtprio *rtp); }
SYS_SCTP_PEELOFF = 471 // { int sctp_peeloff(int sd, uint32_t name); }
SYS_SCTP_GENERIC_SENDMSG = 472 // { int sctp_generic_sendmsg(int sd, caddr_t msg, int mlen, caddr_t to, __socklen_t tolen, struct sctp_sndrcvinfo *sinfo, int flags); }
SYS_SCTP_GENERIC_SENDMSG_IOV = 473 // { int sctp_generic_sendmsg_iov(int sd, struct iovec *iov, int iovlen, caddr_t to, __socklen_t tolen, struct sctp_sndrcvinfo *sinfo, int flags); }
SYS_SCTP_GENERIC_RECVMSG = 474 // { int sctp_generic_recvmsg(int sd, struct iovec *iov, int iovlen, struct sockaddr *from, __socklen_t *fromlenaddr, struct sctp_sndrcvinfo *sinfo, int *msg_flags); }
SYS_PREAD = 475 // { ssize_t pread(int fd, void *buf, size_t nbyte, off_t offset); }
SYS_PWRITE = 476 // { ssize_t pwrite(int fd, const void *buf, size_t nbyte, off_t offset); }
SYS_MMAP = 477 // { caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, off_t pos); }
SYS_LSEEK = 478 // { off_t lseek(int fd, off_t offset, int whence); }
SYS_TRUNCATE = 479 // { int truncate(char *path, off_t length); }
SYS_FTRUNCATE = 480 // { int ftruncate(int fd, off_t length); }
SYS_THR_KILL2 = 481 // { int thr_kill2(pid_t pid, long id, int sig); }
SYS_SHM_OPEN = 482 // { int shm_open(const char *path, int flags, mode_t mode); }
SYS_SHM_UNLINK = 483 // { int shm_unlink(const char *path); }
SYS_CPUSET = 484 // { int cpuset(cpusetid_t *setid); }
SYS_CPUSET_SETID = 485 // { int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid); }
SYS_CPUSET_GETID = 486 // { int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id, cpusetid_t *setid); }
SYS_CPUSET_GETAFFINITY = 487 // { int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, cpuset_t *mask); }
SYS_CPUSET_SETAFFINITY = 488 // { int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id, size_t cpusetsize, const cpuset_t *mask); }
SYS_FACCESSAT = 489 // { int faccessat(int fd, char *path, int amode, int flag); }
SYS_FCHMODAT = 490 // { int fchmodat(int fd, char *path, mode_t mode, int flag); }
SYS_FCHOWNAT = 491 // { int fchownat(int fd, char *path, uid_t uid, gid_t gid, int flag); }
SYS_FEXECVE = 492 // { int fexecve(int fd, char **argv, char **envv); }
SYS_FUTIMESAT = 494 // { int futimesat(int fd, char *path, struct timeval *times); }
SYS_LINKAT = 495 // { int linkat(int fd1, char *path1, int fd2, char *path2, int flag); }
SYS_MKDIRAT = 496 // { int mkdirat(int fd, char *path, mode_t mode); }
SYS_MKFIFOAT = 497 // { int mkfifoat(int fd, char *path, mode_t mode); }
SYS_OPENAT = 499 // { int openat(int fd, char *path, int flag, mode_t mode); }
SYS_READLINKAT = 500 // { ssize_t readlinkat(int fd, char *path, char *buf, size_t bufsize); }
SYS_RENAMEAT = 501 // { int renameat(int oldfd, char *old, int newfd, char *new); }
SYS_SYMLINKAT = 502 // { int symlinkat(char *path1, int fd, char *path2); }
SYS_UNLINKAT = 503 // { int unlinkat(int fd, char *path, int flag); }
SYS_POSIX_OPENPT = 504 // { int posix_openpt(int flags); }
SYS_GSSD_SYSCALL = 505 // { int gssd_syscall(char *path); }
SYS_JAIL_GET = 506 // { int jail_get(struct iovec *iovp, unsigned int iovcnt, int flags); }
SYS_JAIL_SET = 507 // { int jail_set(struct iovec *iovp, unsigned int iovcnt, int flags); }
SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); }
SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); }
SYS___SEMCTL = 510 // { int __semctl(int semid, int semnum, int cmd, union semun *arg); }
SYS_MSGCTL = 511 // { int msgctl(int msqid, int cmd, struct msqid_ds *buf); }
SYS_SHMCTL = 512 // { int shmctl(int shmid, int cmd, struct shmid_ds *buf); }
SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); }
SYS___CAP_RIGHTS_GET = 515 // { int __cap_rights_get(int version, int fd, cap_rights_t *rightsp); }
SYS_CAP_ENTER = 516 // { int cap_enter(void); }
SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); }
SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); }
SYS_PDKILL = 519 // { int pdkill(int fd, int signum); }
SYS_PDGETPID = 520 // { int pdgetpid(int fd, pid_t *pidp); }
SYS_PSELECT = 522 // { int pselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, const struct timespec *ts, const sigset_t *sm); }
SYS_GETLOGINCLASS = 523 // { int getloginclass(char *namebuf, size_t namelen); }
SYS_SETLOGINCLASS = 524 // { int setloginclass(const char *namebuf); }
SYS_RCTL_GET_RACCT = 525 // { int rctl_get_racct(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); }
SYS_RCTL_GET_RULES = 526 // { int rctl_get_rules(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); }
SYS_RCTL_GET_LIMITS = 527 // { int rctl_get_limits(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); }
SYS_RCTL_ADD_RULE = 528 // { int rctl_add_rule(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); }
SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, size_t inbuflen, void *outbufp, size_t outbuflen); }
SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, off_t offset, off_t len); }
SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, off_t len, int advice); }
SYS_WAIT6 = 532 // { int wait6(idtype_t idtype, id_t id, int *status, int options, struct __wrusage *wrusage, siginfo_t *info); }
SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, cap_rights_t *rightsp); }
SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, const u_long *cmds, size_t ncmds); }
SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, u_long *cmds, size_t maxcmds); }
SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, uint32_t fcntlrights); }
SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, uint32_t *fcntlrightsp); }
SYS_BINDAT = 538 // { int bindat(int fd, int s, caddr_t name, int namelen); }
SYS_CONNECTAT = 539 // { int connectat(int fd, int s, caddr_t name, int namelen); }
SYS_CHFLAGSAT = 540 // { int chflagsat(int fd, const char *path, u_long flags, int atflag); }
SYS_ACCEPT4 = 541 // { int accept4(int s, struct sockaddr * __restrict name, __socklen_t * __restrict anamelen, int flags); }
SYS_PIPE2 = 542 // { int pipe2(int *fildes, int flags); }
SYS_AIO_MLOCK = 543 // { int aio_mlock(struct aiocb *aiocbp); }
SYS_PROCCTL = 544 // { int procctl(idtype_t idtype, id_t id, int com, void *data); }
SYS_PPOLL = 545 // { int ppoll(struct pollfd *fds, u_int nfds, const struct timespec *ts, const sigset_t *set); }
SYS_FUTIMENS = 546 // { int futimens(int fd, struct timespec *times); }
SYS_UTIMENSAT = 547 // { int utimensat(int fd, char *path, struct timespec *times, int flag); }
SYS_FDATASYNC = 550 // { int fdatasync(int fd); }
SYS_FSTAT = 551 // { int fstat(int fd, struct stat *sb); }
SYS_FSTATAT = 552 // { int fstatat(int fd, char *path, struct stat *buf, int flag); }
SYS_FHSTAT = 553 // { int fhstat(const struct fhandle *u_fhp, struct stat *sb); }
SYS_GETDIRENTRIES = 554 // { ssize_t getdirentries(int fd, char *buf, size_t count, off_t *basep); }
SYS_STATFS = 555 // { int statfs(char *path, struct statfs *buf); }
SYS_FSTATFS = 556 // { int fstatfs(int fd, struct statfs *buf); }
SYS_GETFSSTAT = 557 // { int getfsstat(struct statfs *buf, long bufsize, int mode); }
SYS_FHSTATFS = 558 // { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); }
SYS_MKNODAT = 559 // { int mknodat(int fd, char *path, mode_t mode, dev_t dev); }
SYS_KEVENT = 560 // { int kevent(int fd, struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout); }
SYS_CPUSET_GETDOMAIN = 561 // { int cpuset_getdomain(cpulevel_t level, cpuwhich_t which, id_t id, size_t domainsetsize, domainset_t *mask, int *policy); }
SYS_CPUSET_SETDOMAIN = 562 // { int cpuset_setdomain(cpulevel_t level, cpuwhich_t which, id_t id, size_t domainsetsize, domainset_t *mask, int policy); }
SYS_GETRANDOM = 563 // { int getrandom(void *buf, size_t buflen, unsigned int flags); }
SYS_GETFHAT = 564 // { int getfhat(int fd, char *path, struct fhandle *fhp, int flags); }
SYS_FHLINK = 565 // { int fhlink(struct fhandle *fhp, const char *to); }
SYS_FHLINKAT = 566 // { int fhlinkat(struct fhandle *fhp, int tofd, const char *to,); }
SYS_FHREADLINK = 567 // { int fhreadlink(struct fhandle *fhp, char *buf, size_t bufsize); }
SYS___SYSCTLBYNAME = 570 // { int __sysctlbyname(const char *name, size_t namelen, void *old, size_t *oldlenp, void *new, size_t newlen); }
SYS_CLOSE_RANGE = 575 // { int close_range(u_int lowfd, u_int highfd, int flags); }
)

@ -0,0 +1,626 @@
// cgo -godefs -- -fsigned-char types_freebsd.go | go run mkpost.go
// Code generated by the command above; see README.md. DO NOT EDIT.
//go:build riscv64 && freebsd
// +build riscv64,freebsd
package unix
const (
SizeofPtr = 0x8
SizeofShort = 0x2
SizeofInt = 0x4
SizeofLong = 0x8
SizeofLongLong = 0x8
)
type (
_C_short int16
_C_int int32
_C_long int64
_C_long_long int64
)
type Timespec struct {
Sec int64
Nsec int64
}
type Timeval struct {
Sec int64
Usec int64
}
type Time_t int64
type Rusage struct {
Utime Timeval
Stime Timeval
Maxrss int64
Ixrss int64
Idrss int64
Isrss int64
Minflt int64
Majflt int64
Nswap int64
Inblock int64
Oublock int64
Msgsnd int64
Msgrcv int64
Nsignals int64
Nvcsw int64
Nivcsw int64
}
type Rlimit struct {
Cur int64
Max int64
}
type _Gid_t uint32
const (
_statfsVersion = 0x20140518
_dirblksiz = 0x400
)
type Stat_t struct {
Dev uint64
Ino uint64
Nlink uint64
Mode uint16
_0 int16
Uid uint32
Gid uint32
_1 int32
Rdev uint64
Atim Timespec
Mtim Timespec
Ctim Timespec
Btim Timespec
Size int64
Blocks int64
Blksize int32
Flags uint32
Gen uint64
Spare [10]uint64
}
type Statfs_t struct {
Version uint32
Type uint32
Flags uint64
Bsize uint64
Iosize uint64
Blocks uint64
Bfree uint64
Bavail int64
Files uint64
Ffree int64
Syncwrites uint64
Asyncwrites uint64
Syncreads uint64
Asyncreads uint64
Spare [10]uint64
Namemax uint32
Owner uint32
Fsid Fsid
Charspare [80]int8
Fstypename [16]byte
Mntfromname [1024]byte
Mntonname [1024]byte
}
type Flock_t struct {
Start int64
Len int64
Pid int32
Type int16
Whence int16
Sysid int32
_ [4]byte
}
type Dirent struct {
Fileno uint64
Off int64
Reclen uint16
Type uint8
Pad0 uint8
Namlen uint16
Pad1 uint16
Name [256]int8
}
type Fsid struct {
Val [2]int32
}
const (
PathMax = 0x400
)
const (
FADV_NORMAL = 0x0
FADV_RANDOM = 0x1
FADV_SEQUENTIAL = 0x2
FADV_WILLNEED = 0x3
FADV_DONTNEED = 0x4
FADV_NOREUSE = 0x5
)
type RawSockaddrInet4 struct {
Len uint8
Family uint8
Port uint16
Addr [4]byte /* in_addr */
Zero [8]int8
}
type RawSockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type RawSockaddrUnix struct {
Len uint8
Family uint8
Path [104]int8
}
type RawSockaddrDatalink struct {
Len uint8
Family uint8
Index uint16
Type uint8
Nlen uint8
Alen uint8
Slen uint8
Data [46]int8
}
type RawSockaddr struct {
Len uint8
Family uint8
Data [14]int8
}
type RawSockaddrAny struct {
Addr RawSockaddr
Pad [92]int8
}
type _Socklen uint32
type Xucred struct {
Version uint32
Uid uint32
Ngroups int16
Groups [16]uint32
_ *byte
}
type Linger struct {
Onoff int32
Linger int32
}
type Iovec struct {
Base *byte
Len uint64
}
type IPMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type IPMreqn struct {
Multiaddr [4]byte /* in_addr */
Address [4]byte /* in_addr */
Ifindex int32
}
type IPv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type Msghdr struct {
Name *byte
Namelen uint32
Iov *Iovec
Iovlen int32
Control *byte
Controllen uint32
Flags int32
}
type Cmsghdr struct {
Len uint32
Level int32
Type int32
}
type Inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
type IPv6MTUInfo struct {
Addr RawSockaddrInet6
Mtu uint32
}
type ICMPv6Filter struct {
Filt [8]uint32
}
const (
SizeofSockaddrInet4 = 0x10
SizeofSockaddrInet6 = 0x1c
SizeofSockaddrAny = 0x6c
SizeofSockaddrUnix = 0x6a
SizeofSockaddrDatalink = 0x36
SizeofXucred = 0x58
SizeofLinger = 0x8
SizeofIovec = 0x10
SizeofIPMreq = 0x8
SizeofIPMreqn = 0xc
SizeofIPv6Mreq = 0x14
SizeofMsghdr = 0x30
SizeofCmsghdr = 0xc
SizeofInet6Pktinfo = 0x14
SizeofIPv6MTUInfo = 0x20
SizeofICMPv6Filter = 0x20
)
const (
PTRACE_TRACEME = 0x0
PTRACE_CONT = 0x7
PTRACE_KILL = 0x8
)
type PtraceLwpInfoStruct struct {
Lwpid int32
Event int32
Flags int32
Sigmask Sigset_t
Siglist Sigset_t
Siginfo __Siginfo
Tdname [20]int8
Child_pid int32
Syscall_code uint32
Syscall_narg uint32
}
type __Siginfo struct {
Signo int32
Errno int32
Code int32
Pid int32
Uid uint32
Status int32
Addr *byte
Value [8]byte
_ [40]byte
}
type Sigset_t struct {
Val [4]uint32
}
type Reg struct {
Ra uint64
Sp uint64
Gp uint64
Tp uint64
T [7]uint64
S [12]uint64
A [8]uint64
Sepc uint64
Sstatus uint64
}
type FpReg struct {
X [32][2]uint64
Fcsr uint64
}
type FpExtendedPrecision struct{}
type PtraceIoDesc struct {
Op int32
Offs *byte
Addr *byte
Len uint64
}
type Kevent_t struct {
Ident uint64
Filter int16
Flags uint16
Fflags uint32
Data int64
Udata *byte
Ext [4]uint64
}
type FdSet struct {
Bits [16]uint64
}
const (
sizeofIfMsghdr = 0xa8
SizeofIfMsghdr = 0xa8
sizeofIfData = 0x98
SizeofIfData = 0x98
SizeofIfaMsghdr = 0x14
SizeofIfmaMsghdr = 0x10
SizeofIfAnnounceMsghdr = 0x18
SizeofRtMsghdr = 0x98
SizeofRtMetrics = 0x70
)
type ifMsghdr struct {
Msglen uint16
Version uint8
Type uint8
Addrs int32
Flags int32
Index uint16
_ uint16
Data ifData
}
type IfMsghdr struct {
Msglen uint16
Version uint8
Type uint8
Addrs int32
Flags int32
Index uint16
Data IfData
}
type ifData struct {
Type uint8
Physical uint8
Addrlen uint8
Hdrlen uint8
Link_state uint8
Vhid uint8
Datalen uint16
Mtu uint32
Metric uint32
Baudrate uint64
Ipackets uint64
Ierrors uint64
Opackets uint64
Oerrors uint64
Collisions uint64
Ibytes uint64
Obytes uint64
Imcasts uint64
Omcasts uint64
Iqdrops uint64
Oqdrops uint64
Noproto uint64
Hwassist uint64
_ [8]byte
_ [16]byte
}
type IfData struct {
Type uint8
Physical uint8
Addrlen uint8
Hdrlen uint8
Link_state uint8
Spare_char1 uint8
Spare_char2 uint8
Datalen uint8
Mtu uint64
Metric uint64
Baudrate uint64
Ipackets uint64
Ierrors uint64
Opackets uint64
Oerrors uint64
Collisions uint64
Ibytes uint64
Obytes uint64
Imcasts uint64
Omcasts uint64
Iqdrops uint64
Noproto uint64
Hwassist uint64
Epoch int64
Lastchange Timeval
}
type IfaMsghdr struct {
Msglen uint16
Version uint8
Type uint8
Addrs int32
Flags int32
Index uint16
_ uint16
Metric int32
}
type IfmaMsghdr struct {
Msglen uint16
Version uint8
Type uint8
Addrs int32
Flags int32
Index uint16
_ uint16
}
type IfAnnounceMsghdr struct {
Msglen uint16
Version uint8
Type uint8
Index uint16
Name [16]int8
What uint16
}
type RtMsghdr struct {
Msglen uint16
Version uint8
Type uint8
Index uint16
_ uint16
Flags int32
Addrs int32
Pid int32
Seq int32
Errno int32
Fmask int32
Inits uint64
Rmx RtMetrics
}
type RtMetrics struct {
Locks uint64
Mtu uint64
Hopcount uint64
Expire uint64
Recvpipe uint64
Sendpipe uint64
Ssthresh uint64
Rtt uint64
Rttvar uint64
Pksent uint64
Weight uint64
Nhidx uint64
Filler [2]uint64
}
const (
SizeofBpfVersion = 0x4
SizeofBpfStat = 0x8
SizeofBpfZbuf = 0x18
SizeofBpfProgram = 0x10
SizeofBpfInsn = 0x8
SizeofBpfHdr = 0x20
SizeofBpfZbufHeader = 0x20
)
type BpfVersion struct {
Major uint16
Minor uint16
}
type BpfStat struct {
Recv uint32
Drop uint32
}
type BpfZbuf struct {
Bufa *byte
Bufb *byte
Buflen uint64
}
type BpfProgram struct {
Len uint32
Insns *BpfInsn
}
type BpfInsn struct {
Code uint16
Jt uint8
Jf uint8
K uint32
}
type BpfHdr struct {
Tstamp Timeval
Caplen uint32
Datalen uint32
Hdrlen uint16
_ [6]byte
}
type BpfZbufHeader struct {
Kernel_gen uint32
Kernel_len uint32
User_gen uint32
_ [5]uint32
}
type Termios struct {
Iflag uint32
Oflag uint32
Cflag uint32
Lflag uint32
Cc [20]uint8
Ispeed uint32
Ospeed uint32
}
type Winsize struct {
Row uint16
Col uint16
Xpixel uint16
Ypixel uint16
}
const (
AT_FDCWD = -0x64
AT_EACCESS = 0x100
AT_SYMLINK_NOFOLLOW = 0x200
AT_SYMLINK_FOLLOW = 0x400
AT_REMOVEDIR = 0x800
)
type PollFd struct {
Fd int32
Events int16
Revents int16
}
const (
POLLERR = 0x8
POLLHUP = 0x10
POLLIN = 0x1
POLLINIGNEOF = 0x2000
POLLNVAL = 0x20
POLLOUT = 0x4
POLLPRI = 0x2
POLLRDBAND = 0x80
POLLRDNORM = 0x40
POLLWRBAND = 0x100
POLLWRNORM = 0x4
)
type CapRights struct {
Rights [2]uint64
}
type Utsname struct {
Sysname [256]byte
Nodename [256]byte
Release [256]byte
Version [256]byte
Machine [256]byte
}
const SizeofClockinfo = 0x14
type Clockinfo struct {
Hz int32
Tick int32
Spare int32
Stathz int32
Profhz int32
}

@ -45,6 +45,7 @@ func (bb *baseBuilder) Build(cc balancer.ClientConn, opt balancer.BuildOptions)
scStates: make(map[balancer.SubConn]connectivity.State),
csEvltr: &balancer.ConnectivityStateEvaluator{},
config: bb.config,
state: connectivity.Connecting,
}
// Initialize picker to a picker that always returns
// ErrNoSubConnAvailable, because when state of a SubConn changes, we
@ -134,6 +135,9 @@ func (b *baseBalancer) UpdateClientConnState(s balancer.ClientConnState) error {
b.ResolverError(errors.New("produced zero addresses"))
return balancer.ErrBadResolverState
}
b.regeneratePicker()
b.cc.UpdateState(balancer.State{ConnectivityState: b.state, Picker: b.picker})
return nil
}

@ -146,6 +146,10 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *
cc.safeConfigSelector.UpdateConfigSelector(&defaultConfigSelector{nil})
cc.ctx, cc.cancel = context.WithCancel(context.Background())
for _, opt := range extraDialOptions {
opt.apply(&cc.dopts)
}
for _, opt := range opts {
opt.apply(&cc.dopts)
}

@ -35,6 +35,15 @@ import (
"google.golang.org/grpc/stats"
)
func init() {
internal.AddExtraDialOptions = func(opt ...DialOption) {
extraDialOptions = append(extraDialOptions, opt...)
}
internal.ClearExtraDialOptions = func() {
extraDialOptions = nil
}
}
// dialOptions configure a Dial call. dialOptions are set by the DialOption
// values passed to Dial.
type dialOptions struct {
@ -70,6 +79,8 @@ type DialOption interface {
apply(*dialOptions)
}
var extraDialOptions []DialOption
// EmptyDialOption does not alter the dial configuration. It can be embedded in
// another structure to build custom dial options.
//
@ -380,7 +391,7 @@ func WithDialer(f func(string, time.Duration) (net.Conn, error)) DialOption {
// all the RPCs and underlying network connections in this ClientConn.
func WithStatsHandler(h stats.Handler) DialOption {
return newFuncDialOption(func(o *dialOptions) {
o.copts.StatsHandler = h
o.copts.StatsHandlers = append(o.copts.StatsHandlers, h)
})
}

@ -193,6 +193,8 @@ func (gsb *Balancer) ExitIdle() {
ei.ExitIdle()
return
}
gsb.mu.Lock()
defer gsb.mu.Unlock()
for sc := range balToUpdate.subconns {
sc.Connect()
}

@ -42,14 +42,14 @@ var binLogger Logger
var grpclogLogger = grpclog.Component("binarylog")
// SetLogger sets the binarg logger.
// SetLogger sets the binary logger.
//
// Only call this at init time.
func SetLogger(l Logger) {
binLogger = l
}
// GetLogger gets the binarg logger.
// GetLogger gets the binary logger.
//
// Only call this at init time.
func GetLogger() Logger {

@ -77,7 +77,7 @@ var (
// environment variable
// "GRPC_XDS_EXPERIMENTAL_ENABLE_AGGREGATE_AND_LOGICAL_DNS_CLUSTER" to
// "true".
XDSAggregateAndDNS = strings.EqualFold(os.Getenv(aggregateAndDNSSupportEnv), "true")
XDSAggregateAndDNS = !strings.EqualFold(os.Getenv(aggregateAndDNSSupportEnv), "false")
// XDSRBAC indicates whether xDS configured RBAC HTTP Filter is enabled,
// which can be disabled by setting the environment variable

@ -63,6 +63,76 @@ var (
// xDS-enabled server invokes this method on a grpc.Server when a particular
// listener moves to "not-serving" mode.
DrainServerTransports interface{} // func(*grpc.Server, string)
// AddExtraServerOptions adds an array of ServerOption that will be
// effective globally for newly created servers. The priority will be: 1.
// user-provided; 2. this method; 3. default values.
AddExtraServerOptions interface{} // func(opt ...ServerOption)
// ClearExtraServerOptions clears the array of extra ServerOption. This
// method is useful in testing and benchmarking.
ClearExtraServerOptions func()
// AddExtraDialOptions adds an array of DialOption that will be effective
// globally for newly created client channels. The priority will be: 1.
// user-provided; 2. this method; 3. default values.
AddExtraDialOptions interface{} // func(opt ...DialOption)
// ClearExtraDialOptions clears the array of extra DialOption. This
// method is useful in testing and benchmarking.
ClearExtraDialOptions func()
// NewXDSResolverWithConfigForTesting creates a new xds resolver builder using
// the provided xds bootstrap config instead of the global configuration from
// the supported environment variables. The resolver.Builder is meant to be
// used in conjunction with the grpc.WithResolvers DialOption.
//
// Testing Only
//
// This function should ONLY be used for testing and may not work with some
// other features, including the CSDS service.
NewXDSResolverWithConfigForTesting interface{} // func([]byte) (resolver.Builder, error)
// RegisterRLSClusterSpecifierPluginForTesting registers the RLS Cluster
// Specifier Plugin for testing purposes, regardless of the XDSRLS environment
// variable.
//
// TODO: Remove this function once the RLS env var is removed.
RegisterRLSClusterSpecifierPluginForTesting func()
// UnregisterRLSClusterSpecifierPluginForTesting unregisters the RLS Cluster
// Specifier Plugin for testing purposes. This is needed because there is no way
// to unregister the RLS Cluster Specifier Plugin after registering it solely
// for testing purposes using RegisterRLSClusterSpecifierPluginForTesting().
//
// TODO: Remove this function once the RLS env var is removed.
UnregisterRLSClusterSpecifierPluginForTesting func()
// RegisterRBACHTTPFilterForTesting registers the RBAC HTTP Filter for testing
// purposes, regardless of the RBAC environment variable.
//
// TODO: Remove this function once the RBAC env var is removed.
RegisterRBACHTTPFilterForTesting func()
// UnregisterRBACHTTPFilterForTesting unregisters the RBAC HTTP Filter for
// testing purposes. This is needed because there is no way to unregister the
// HTTP Filter after registering it solely for testing purposes using
// RegisterRBACHTTPFilterForTesting().
//
// TODO: Remove this function once the RBAC env var is removed.
UnregisterRBACHTTPFilterForTesting func()
// RegisterOutlierDetectionBalancerForTesting registers the Outlier
// Detection Balancer for testing purposes, regardless of the Outlier
// Detection environment variable.
//
// TODO: Remove this function once the Outlier Detection env var is removed.
RegisterOutlierDetectionBalancerForTesting func()
// UnregisterOutlierDetectionBalancerForTesting unregisters the Outlier
// Detection Balancer for testing purposes. This is needed because there is
// no way to unregister the Outlier Detection Balancer after registering it
// solely for testing purposes using
// RegisterOutlierDetectionBalancerForTesting().
//
// TODO: Remove this function once the Outlier Detection env var is removed.
UnregisterOutlierDetectionBalancerForTesting func()
)
// HealthChecker defines the signature of the client-side LB channel health checking function.

@ -49,7 +49,7 @@ import (
// NewServerHandlerTransport returns a ServerTransport handling gRPC
// from inside an http.Handler. It requires that the http Server
// supports HTTP/2.
func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats stats.Handler) (ServerTransport, error) {
func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats []stats.Handler) (ServerTransport, error) {
if r.ProtoMajor != 2 {
return nil, errors.New("gRPC requires HTTP/2")
}
@ -138,7 +138,7 @@ type serverHandlerTransport struct {
// TODO make sure this is consistent across handler_server and http2_server
contentSubtype string
stats stats.Handler
stats []stats.Handler
}
func (ht *serverHandlerTransport) Close() {
@ -228,10 +228,10 @@ func (ht *serverHandlerTransport) WriteStatus(s *Stream, st *status.Status) erro
})
if err == nil { // transport has not been closed
if ht.stats != nil {
// Note: The trailer fields are compressed with hpack after this call returns.
// No WireLength field is set here.
ht.stats.HandleRPC(s.Context(), &stats.OutTrailer{
// Note: The trailer fields are compressed with hpack after this call returns.
// No WireLength field is set here.
for _, sh := range ht.stats {
sh.HandleRPC(s.Context(), &stats.OutTrailer{
Trailer: s.trailer.Copy(),
})
}
@ -314,10 +314,10 @@ func (ht *serverHandlerTransport) WriteHeader(s *Stream, md metadata.MD) error {
})
if err == nil {
if ht.stats != nil {
for _, sh := range ht.stats {
// Note: The header fields are compressed with hpack after this call returns.
// No WireLength field is set here.
ht.stats.HandleRPC(s.Context(), &stats.OutHeader{
sh.HandleRPC(s.Context(), &stats.OutHeader{
Header: md.Copy(),
Compression: s.sendCompress,
})
@ -369,14 +369,14 @@ func (ht *serverHandlerTransport) HandleStreams(startStream func(*Stream), trace
}
ctx = metadata.NewIncomingContext(ctx, ht.headerMD)
s.ctx = peer.NewContext(ctx, pr)
if ht.stats != nil {
s.ctx = ht.stats.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method})
for _, sh := range ht.stats {
s.ctx = sh.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method})
inHeader := &stats.InHeader{
FullMethod: s.method,
RemoteAddr: ht.RemoteAddr(),
Compression: s.recvCompress,
}
ht.stats.HandleRPC(s.ctx, inHeader)
sh.HandleRPC(s.ctx, inHeader)
}
s.trReader = &transportReader{
reader: &recvBufferReader{ctx: s.ctx, ctxDone: s.ctx.Done(), recv: s.buf, freeBuffer: func(*bytes.Buffer) {}},

@ -90,7 +90,7 @@ type http2Client struct {
kp keepalive.ClientParameters
keepaliveEnabled bool
statsHandler stats.Handler
statsHandlers []stats.Handler
initialWindowSize int32
@ -311,7 +311,7 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts
isSecure: isSecure,
perRPCCreds: perRPCCreds,
kp: kp,
statsHandler: opts.StatsHandler,
statsHandlers: opts.StatsHandlers,
initialWindowSize: initialWindowSize,
onPrefaceReceipt: onPrefaceReceipt,
nextID: 1,
@ -341,15 +341,15 @@ func newHTTP2Client(connectCtx, ctx context.Context, addr resolver.Address, opts
updateFlowControl: t.updateFlowControl,
}
}
if t.statsHandler != nil {
t.ctx = t.statsHandler.TagConn(t.ctx, &stats.ConnTagInfo{
for _, sh := range t.statsHandlers {
t.ctx = sh.TagConn(t.ctx, &stats.ConnTagInfo{
RemoteAddr: t.remoteAddr,
LocalAddr: t.localAddr,
})
connBegin := &stats.ConnBegin{
Client: true,
}
t.statsHandler.HandleConn(t.ctx, connBegin)
sh.HandleConn(t.ctx, connBegin)
}
t.channelzID, err = channelz.RegisterNormalSocket(t, opts.ChannelzParentID, fmt.Sprintf("%s -> %s", t.localAddr, t.remoteAddr))
if err != nil {
@ -773,24 +773,27 @@ func (t *http2Client) NewStream(ctx context.Context, callHdr *CallHdr) (*Stream,
return nil, &NewStreamError{Err: ErrConnClosing, AllowTransparentRetry: true}
}
}
if t.statsHandler != nil {
if len(t.statsHandlers) != 0 {
header, ok := metadata.FromOutgoingContext(ctx)
if ok {
header.Set("user-agent", t.userAgent)
} else {
header = metadata.Pairs("user-agent", t.userAgent)
}
// Note: The header fields are compressed with hpack after this call returns.
// No WireLength field is set here.
outHeader := &stats.OutHeader{
Client: true,
FullMethod: callHdr.Method,
RemoteAddr: t.remoteAddr,
LocalAddr: t.localAddr,
Compression: callHdr.SendCompress,
Header: header,
for _, sh := range t.statsHandlers {
// Note: The header fields are compressed with hpack after this call returns.
// No WireLength field is set here.
// Note: Creating a new stats object to prevent pollution.
outHeader := &stats.OutHeader{
Client: true,
FullMethod: callHdr.Method,
RemoteAddr: t.remoteAddr,
LocalAddr: t.localAddr,
Compression: callHdr.SendCompress,
Header: header,
}
sh.HandleRPC(s.ctx, outHeader)
}
t.statsHandler.HandleRPC(s.ctx, outHeader)
}
return s, nil
}
@ -916,11 +919,11 @@ func (t *http2Client) Close(err error) {
for _, s := range streams {
t.closeStream(s, err, false, http2.ErrCodeNo, st, nil, false)
}
if t.statsHandler != nil {
for _, sh := range t.statsHandlers {
connEnd := &stats.ConnEnd{
Client: true,
}
t.statsHandler.HandleConn(t.ctx, connEnd)
sh.HandleConn(t.ctx, connEnd)
}
}
@ -1432,7 +1435,7 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
close(s.headerChan)
}
if t.statsHandler != nil {
for _, sh := range t.statsHandlers {
if isHeader {
inHeader := &stats.InHeader{
Client: true,
@ -1440,14 +1443,14 @@ func (t *http2Client) operateHeaders(frame *http2.MetaHeadersFrame) {
Header: metadata.MD(mdata).Copy(),
Compression: s.recvCompress,
}
t.statsHandler.HandleRPC(s.ctx, inHeader)
sh.HandleRPC(s.ctx, inHeader)
} else {
inTrailer := &stats.InTrailer{
Client: true,
WireLength: int(frame.Header().Length),
Trailer: metadata.MD(mdata).Copy(),
}
t.statsHandler.HandleRPC(s.ctx, inTrailer)
sh.HandleRPC(s.ctx, inTrailer)
}
}

@ -82,7 +82,7 @@ type http2Server struct {
// updates, reset streams, and various settings) to the controller.
controlBuf *controlBuffer
fc *trInFlow
stats stats.Handler
stats []stats.Handler
// Keepalive and max-age parameters for the server.
kp keepalive.ServerParameters
// Keepalive enforcement policy.
@ -257,7 +257,7 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
fc: &trInFlow{limit: uint32(icwz)},
state: reachable,
activeStreams: make(map[uint32]*Stream),
stats: config.StatsHandler,
stats: config.StatsHandlers,
kp: kp,
idle: time.Now(),
kep: kep,
@ -272,13 +272,13 @@ func NewServerTransport(conn net.Conn, config *ServerConfig) (_ ServerTransport,
updateFlowControl: t.updateFlowControl,
}
}
if t.stats != nil {
t.ctx = t.stats.TagConn(t.ctx, &stats.ConnTagInfo{
for _, sh := range t.stats {
t.ctx = sh.TagConn(t.ctx, &stats.ConnTagInfo{
RemoteAddr: t.remoteAddr,
LocalAddr: t.localAddr,
})
connBegin := &stats.ConnBegin{}
t.stats.HandleConn(t.ctx, connBegin)
sh.HandleConn(t.ctx, connBegin)
}
t.channelzID, err = channelz.RegisterNormalSocket(t, config.ChannelzParentID, fmt.Sprintf("%s -> %s", t.remoteAddr, t.localAddr))
if err != nil {
@ -570,8 +570,8 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
t.adjustWindow(s, uint32(n))
}
s.ctx = traceCtx(s.ctx, s.method)
if t.stats != nil {
s.ctx = t.stats.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method})
for _, sh := range t.stats {
s.ctx = sh.TagRPC(s.ctx, &stats.RPCTagInfo{FullMethodName: s.method})
inHeader := &stats.InHeader{
FullMethod: s.method,
RemoteAddr: t.remoteAddr,
@ -580,7 +580,7 @@ func (t *http2Server) operateHeaders(frame *http2.MetaHeadersFrame, handle func(
WireLength: int(frame.Header().Length),
Header: metadata.MD(mdata).Copy(),
}
t.stats.HandleRPC(s.ctx, inHeader)
sh.HandleRPC(s.ctx, inHeader)
}
s.ctxDone = s.ctx.Done()
s.wq = newWriteQuota(defaultWriteQuota, s.ctxDone)
@ -996,14 +996,14 @@ func (t *http2Server) writeHeaderLocked(s *Stream) error {
t.closeStream(s, true, http2.ErrCodeInternal, false)
return ErrHeaderListSizeLimitViolation
}
if t.stats != nil {
for _, sh := range t.stats {
// Note: Headers are compressed with hpack after this call returns.
// No WireLength field is set here.
outHeader := &stats.OutHeader{
Header: s.header.Copy(),
Compression: s.sendCompress,
}
t.stats.HandleRPC(s.Context(), outHeader)
sh.HandleRPC(s.Context(), outHeader)
}
return nil
}
@ -1064,10 +1064,10 @@ func (t *http2Server) WriteStatus(s *Stream, st *status.Status) error {
// Send a RST_STREAM after the trailers if the client has not already half-closed.
rst := s.getState() == streamActive
t.finishStream(s, rst, http2.ErrCodeNo, trailingHeader, true)
if t.stats != nil {
for _, sh := range t.stats {
// Note: The trailer fields are compressed with hpack after this call returns.
// No WireLength field is set here.
t.stats.HandleRPC(s.Context(), &stats.OutTrailer{
sh.HandleRPC(s.Context(), &stats.OutTrailer{
Trailer: s.trailer.Copy(),
})
}
@ -1222,9 +1222,9 @@ func (t *http2Server) Close() {
for _, s := range streams {
s.cancel()
}
if t.stats != nil {
for _, sh := range t.stats {
connEnd := &stats.ConnEnd{}
t.stats.HandleConn(t.ctx, connEnd)
sh.HandleConn(t.ctx, connEnd)
}
}

@ -322,8 +322,6 @@ type bufWriter struct {
batchSize int
conn net.Conn
err error
onFlush func()
}
func newBufWriter(conn net.Conn, batchSize int) *bufWriter {
@ -360,9 +358,6 @@ func (w *bufWriter) Flush() error {
if w.offset == 0 {
return nil
}
if w.onFlush != nil {
w.onFlush()
}
_, w.err = w.conn.Write(w.buf[:w.offset])
w.offset = 0
return w.err

@ -523,7 +523,7 @@ type ServerConfig struct {
ConnectionTimeout time.Duration
Credentials credentials.TransportCredentials
InTapHandle tap.ServerInHandle
StatsHandler stats.Handler
StatsHandlers []stats.Handler
KeepaliveParams keepalive.ServerParameters
KeepalivePolicy keepalive.EnforcementPolicy
InitialWindowSize int32
@ -553,8 +553,8 @@ type ConnectOptions struct {
CredsBundle credentials.Bundle
// KeepaliveParams stores the keepalive parameters.
KeepaliveParams keepalive.ClientParameters
// StatsHandler stores the handler for stats.
StatsHandler stats.Handler
// StatsHandlers stores the handler for stats.
StatsHandlers []stats.Handler
// InitialWindowSize sets the initial window size for a stream.
InitialWindowSize int32
// InitialConnWindowSize sets the initial window size for a connection.

@ -28,25 +28,40 @@ type addressMapEntry struct {
// Multiple accesses may not be performed concurrently. Must be created via
// NewAddressMap; do not construct directly.
type AddressMap struct {
m map[string]addressMapEntryList
// The underlying map is keyed by an Address with fields that we don't care
// about being set to their zero values. The only fields that we care about
// are `Addr`, `ServerName` and `Attributes`. Since we need to be able to
// distinguish between addresses with same `Addr` and `ServerName`, but
// different `Attributes`, we cannot store the `Attributes` in the map key.
//
// The comparison operation for structs work as follows:
// Struct values are comparable if all their fields are comparable. Two
// struct values are equal if their corresponding non-blank fields are equal.
//
// The value type of the map contains a slice of addresses which match the key
// in their `Addr` and `ServerName` fields and contain the corresponding value
// associated with them.
m map[Address]addressMapEntryList
}
func toMapKey(addr *Address) Address {
return Address{Addr: addr.Addr, ServerName: addr.ServerName}
}
type addressMapEntryList []*addressMapEntry
// NewAddressMap creates a new AddressMap.
func NewAddressMap() *AddressMap {
return &AddressMap{m: make(map[string]addressMapEntryList)}
return &AddressMap{m: make(map[Address]addressMapEntryList)}
}
// find returns the index of addr in the addressMapEntry slice, or -1 if not
// present.
func (l addressMapEntryList) find(addr Address) int {
if len(l) == 0 {
return -1
}
for i, entry := range l {
if entry.addr.ServerName == addr.ServerName &&
entry.addr.Attributes.Equal(addr.Attributes) {
// Attributes are the only thing to match on here, since `Addr` and
// `ServerName` are already equal.
if entry.addr.Attributes.Equal(addr.Attributes) {
return i
}
}
@ -55,7 +70,8 @@ func (l addressMapEntryList) find(addr Address) int {
// Get returns the value for the address in the map, if present.
func (a *AddressMap) Get(addr Address) (value interface{}, ok bool) {
entryList := a.m[addr.Addr]
addrKey := toMapKey(&addr)
entryList := a.m[addrKey]
if entry := entryList.find(addr); entry != -1 {
return entryList[entry].value, true
}
@ -64,17 +80,19 @@ func (a *AddressMap) Get(addr Address) (value interface{}, ok bool) {
// Set updates or adds the value to the address in the map.
func (a *AddressMap) Set(addr Address, value interface{}) {
entryList := a.m[addr.Addr]
addrKey := toMapKey(&addr)
entryList := a.m[addrKey]
if entry := entryList.find(addr); entry != -1 {
a.m[addr.Addr][entry].value = value
entryList[entry].value = value
return
}
a.m[addr.Addr] = append(a.m[addr.Addr], &addressMapEntry{addr: addr, value: value})
a.m[addrKey] = append(entryList, &addressMapEntry{addr: addr, value: value})
}
// Delete removes addr from the map.
func (a *AddressMap) Delete(addr Address) {
entryList := a.m[addr.Addr]
addrKey := toMapKey(&addr)
entryList := a.m[addrKey]
entry := entryList.find(addr)
if entry == -1 {
return
@ -85,7 +103,7 @@ func (a *AddressMap) Delete(addr Address) {
copy(entryList[entry:], entryList[entry+1:])
entryList = entryList[:len(entryList)-1]
}
a.m[addr.Addr] = entryList
a.m[addrKey] = entryList
}
// Len returns the number of entries in the map.
@ -107,3 +125,14 @@ func (a *AddressMap) Keys() []Address {
}
return ret
}
// Values returns a slice of all current map values.
func (a *AddressMap) Values() []interface{} {
ret := make([]interface{}, 0, a.Len())
for _, entryList := range a.m {
for _, entry := range entryList {
ret = append(ret, entry.value)
}
}
return ret
}

@ -73,6 +73,12 @@ func init() {
internal.DrainServerTransports = func(srv *Server, addr string) {
srv.drainServerTransports(addr)
}
internal.AddExtraServerOptions = func(opt ...ServerOption) {
extraServerOptions = opt
}
internal.ClearExtraServerOptions = func() {
extraServerOptions = nil
}
}
var statusOK = status.New(codes.OK, "")
@ -150,7 +156,7 @@ type serverOptions struct {
chainUnaryInts []UnaryServerInterceptor
chainStreamInts []StreamServerInterceptor
inTapHandle tap.ServerInHandle
statsHandler stats.Handler
statsHandlers []stats.Handler
maxConcurrentStreams uint32
maxReceiveMessageSize int
maxSendMessageSize int
@ -174,6 +180,7 @@ var defaultServerOptions = serverOptions{
writeBufferSize: defaultWriteBufSize,
readBufferSize: defaultReadBufSize,
}
var extraServerOptions []ServerOption
// A ServerOption sets options such as credentials, codec and keepalive parameters, etc.
type ServerOption interface {
@ -435,7 +442,7 @@ func InTapHandle(h tap.ServerInHandle) ServerOption {
// StatsHandler returns a ServerOption that sets the stats handler for the server.
func StatsHandler(h stats.Handler) ServerOption {
return newFuncServerOption(func(o *serverOptions) {
o.statsHandler = h
o.statsHandlers = append(o.statsHandlers, h)
})
}
@ -560,6 +567,9 @@ func (s *Server) stopServerWorkers() {
// started to accept requests yet.
func NewServer(opt ...ServerOption) *Server {
opts := defaultServerOptions
for _, o := range extraServerOptions {
o.apply(&opts)
}
for _, o := range opt {
o.apply(&opts)
}
@ -867,7 +877,7 @@ func (s *Server) newHTTP2Transport(c net.Conn) transport.ServerTransport {
ConnectionTimeout: s.opts.connectionTimeout,
Credentials: s.opts.creds,
InTapHandle: s.opts.inTapHandle,
StatsHandler: s.opts.statsHandler,
StatsHandlers: s.opts.statsHandlers,
KeepaliveParams: s.opts.keepaliveParams,
KeepalivePolicy: s.opts.keepalivePolicy,
InitialWindowSize: s.opts.initialWindowSize,
@ -963,7 +973,7 @@ var _ http.Handler = (*Server)(nil)
// Notice: This API is EXPERIMENTAL and may be changed or removed in a
// later release.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
st, err := transport.NewServerHandlerTransport(w, r, s.opts.statsHandler)
st, err := transport.NewServerHandlerTransport(w, r, s.opts.statsHandlers)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
@ -1076,8 +1086,10 @@ func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Str
return status.Errorf(codes.ResourceExhausted, "grpc: trying to send message larger than max (%d vs. %d)", len(payload), s.opts.maxSendMessageSize)
}
err = t.Write(stream, hdr, payload, opts)
if err == nil && s.opts.statsHandler != nil {
s.opts.statsHandler.HandleRPC(stream.Context(), outPayload(false, msg, data, payload, time.Now()))
if err == nil {
for _, sh := range s.opts.statsHandlers {
sh.HandleRPC(stream.Context(), outPayload(false, msg, data, payload, time.Now()))
}
}
return err
}
@ -1124,13 +1136,13 @@ func chainUnaryInterceptors(interceptors []UnaryServerInterceptor) UnaryServerIn
}
func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.Stream, info *serviceInfo, md *MethodDesc, trInfo *traceInfo) (err error) {
sh := s.opts.statsHandler
if sh != nil || trInfo != nil || channelz.IsOn() {
shs := s.opts.statsHandlers
if len(shs) != 0 || trInfo != nil || channelz.IsOn() {
if channelz.IsOn() {
s.incrCallsStarted()
}
var statsBegin *stats.Begin
if sh != nil {
for _, sh := range shs {
beginTime := time.Now()
statsBegin = &stats.Begin{
BeginTime: beginTime,
@ -1161,7 +1173,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
trInfo.tr.Finish()
}
if sh != nil {
for _, sh := range shs {
end := &stats.End{
BeginTime: statsBegin.BeginTime,
EndTime: time.Now(),
@ -1243,7 +1255,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
}
var payInfo *payloadInfo
if sh != nil || binlog != nil {
if len(shs) != 0 || binlog != nil {
payInfo = &payloadInfo{}
}
d, err := recvAndDecompress(&parser{r: stream}, stream, dc, s.opts.maxReceiveMessageSize, payInfo, decomp)
@ -1260,7 +1272,7 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
if err := s.getCodec(stream.ContentSubtype()).Unmarshal(d, v); err != nil {
return status.Errorf(codes.Internal, "grpc: error unmarshalling request: %v", err)
}
if sh != nil {
for _, sh := range shs {
sh.HandleRPC(stream.Context(), &stats.InPayload{
RecvTime: time.Now(),
Payload: v,
@ -1418,16 +1430,18 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
if channelz.IsOn() {
s.incrCallsStarted()
}
sh := s.opts.statsHandler
shs := s.opts.statsHandlers
var statsBegin *stats.Begin
if sh != nil {
if len(shs) != 0 {
beginTime := time.Now()
statsBegin = &stats.Begin{
BeginTime: beginTime,
IsClientStream: sd.ClientStreams,
IsServerStream: sd.ServerStreams,
}
sh.HandleRPC(stream.Context(), statsBegin)
for _, sh := range shs {
sh.HandleRPC(stream.Context(), statsBegin)
}
}
ctx := NewContextWithServerTransportStream(stream.Context(), stream)
ss := &serverStream{
@ -1439,10 +1453,10 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
maxReceiveMessageSize: s.opts.maxReceiveMessageSize,
maxSendMessageSize: s.opts.maxSendMessageSize,
trInfo: trInfo,
statsHandler: sh,
statsHandler: shs,
}
if sh != nil || trInfo != nil || channelz.IsOn() {
if len(shs) != 0 || trInfo != nil || channelz.IsOn() {
// See comment in processUnaryRPC on defers.
defer func() {
if trInfo != nil {
@ -1456,7 +1470,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
ss.mu.Unlock()
}
if sh != nil {
if len(shs) != 0 {
end := &stats.End{
BeginTime: statsBegin.BeginTime,
EndTime: time.Now(),
@ -1464,7 +1478,9 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
if err != nil && err != io.EOF {
end.Error = toRPCErr(err)
}
sh.HandleRPC(stream.Context(), end)
for _, sh := range shs {
sh.HandleRPC(stream.Context(), end)
}
}
if channelz.IsOn() {

@ -374,9 +374,9 @@ func (cs *clientStream) newAttemptLocked(isTransparent bool) (*csAttempt, error)
ctx := newContextWithRPCInfo(cs.ctx, cs.callInfo.failFast, cs.callInfo.codec, cs.cp, cs.comp)
method := cs.callHdr.Method
sh := cs.cc.dopts.copts.StatsHandler
var beginTime time.Time
if sh != nil {
shs := cs.cc.dopts.copts.StatsHandlers
for _, sh := range shs {
ctx = sh.TagRPC(ctx, &stats.RPCTagInfo{FullMethodName: method, FailFast: cs.callInfo.failFast})
beginTime = time.Now()
begin := &stats.Begin{
@ -414,12 +414,12 @@ func (cs *clientStream) newAttemptLocked(isTransparent bool) (*csAttempt, error)
}
return &csAttempt{
ctx: ctx,
beginTime: beginTime,
cs: cs,
dc: cs.cc.dopts.dc,
statsHandler: sh,
trInfo: trInfo,
ctx: ctx,
beginTime: beginTime,
cs: cs,
dc: cs.cc.dopts.dc,
statsHandlers: shs,
trInfo: trInfo,
}, nil
}
@ -536,8 +536,8 @@ type csAttempt struct {
// and cleared when the finish method is called.
trInfo *traceInfo
statsHandler stats.Handler
beginTime time.Time
statsHandlers []stats.Handler
beginTime time.Time
// set for newStream errors that may be transparently retried
allowTransparentRetry bool
@ -960,8 +960,8 @@ func (a *csAttempt) sendMsg(m interface{}, hdr, payld, data []byte) error {
}
return io.EOF
}
if a.statsHandler != nil {
a.statsHandler.HandleRPC(a.ctx, outPayload(true, m, data, payld, time.Now()))
for _, sh := range a.statsHandlers {
sh.HandleRPC(a.ctx, outPayload(true, m, data, payld, time.Now()))
}
if channelz.IsOn() {
a.t.IncrMsgSent()
@ -971,7 +971,7 @@ func (a *csAttempt) sendMsg(m interface{}, hdr, payld, data []byte) error {
func (a *csAttempt) recvMsg(m interface{}, payInfo *payloadInfo) (err error) {
cs := a.cs
if a.statsHandler != nil && payInfo == nil {
if len(a.statsHandlers) != 0 && payInfo == nil {
payInfo = &payloadInfo{}
}
@ -1008,8 +1008,8 @@ func (a *csAttempt) recvMsg(m interface{}, payInfo *payloadInfo) (err error) {
}
a.mu.Unlock()
}
if a.statsHandler != nil {
a.statsHandler.HandleRPC(a.ctx, &stats.InPayload{
for _, sh := range a.statsHandlers {
sh.HandleRPC(a.ctx, &stats.InPayload{
Client: true,
RecvTime: time.Now(),
Payload: m,
@ -1068,7 +1068,7 @@ func (a *csAttempt) finish(err error) {
ServerLoad: balancerload.Parse(tr),
})
}
if a.statsHandler != nil {
for _, sh := range a.statsHandlers {
end := &stats.End{
Client: true,
BeginTime: a.beginTime,
@ -1076,7 +1076,7 @@ func (a *csAttempt) finish(err error) {
Trailer: tr,
Error: err,
}
a.statsHandler.HandleRPC(a.ctx, end)
sh.HandleRPC(a.ctx, end)
}
if a.trInfo != nil && a.trInfo.tr != nil {
if err == nil {
@ -1445,7 +1445,7 @@ type serverStream struct {
maxSendMessageSize int
trInfo *traceInfo
statsHandler stats.Handler
statsHandler []stats.Handler
binlog binarylog.MethodLogger
// serverHeaderBinlogged indicates whether server header has been logged. It
@ -1555,8 +1555,10 @@ func (ss *serverStream) SendMsg(m interface{}) (err error) {
Message: data,
})
}
if ss.statsHandler != nil {
ss.statsHandler.HandleRPC(ss.s.Context(), outPayload(false, m, data, payload, time.Now()))
if len(ss.statsHandler) != 0 {
for _, sh := range ss.statsHandler {
sh.HandleRPC(ss.s.Context(), outPayload(false, m, data, payload, time.Now()))
}
}
return nil
}
@ -1590,7 +1592,7 @@ func (ss *serverStream) RecvMsg(m interface{}) (err error) {
}
}()
var payInfo *payloadInfo
if ss.statsHandler != nil || ss.binlog != nil {
if len(ss.statsHandler) != 0 || ss.binlog != nil {
payInfo = &payloadInfo{}
}
if err := recv(ss.p, ss.codec, ss.s, ss.dc, m, ss.maxReceiveMessageSize, payInfo, ss.decomp); err != nil {
@ -1605,15 +1607,17 @@ func (ss *serverStream) RecvMsg(m interface{}) (err error) {
}
return toRPCErr(err)
}
if ss.statsHandler != nil {
ss.statsHandler.HandleRPC(ss.s.Context(), &stats.InPayload{
RecvTime: time.Now(),
Payload: m,
// TODO truncate large payload.
Data: payInfo.uncompressedBytes,
WireLength: payInfo.wireLength + headerLen,
Length: len(payInfo.uncompressedBytes),
})
if len(ss.statsHandler) != 0 {
for _, sh := range ss.statsHandler {
sh.HandleRPC(ss.s.Context(), &stats.InPayload{
RecvTime: time.Now(),
Payload: m,
// TODO truncate large payload.
Data: payInfo.uncompressedBytes,
WireLength: payInfo.wireLength + headerLen,
Length: len(payInfo.uncompressedBytes),
})
}
}
if ss.binlog != nil {
ss.binlog.Log(&binarylog.ClientMessage{

@ -19,4 +19,4 @@
package grpc
// Version is the current grpc version.
const Version = "1.47.0"
const Version = "1.48.0"

12
vendor/modules.txt vendored

@ -1,4 +1,4 @@
# gitee.com/chunanyong/zorm v1.5.5
# gitee.com/chunanyong/zorm v1.5.6
## explicit; go 1.13
gitee.com/chunanyong/zorm
gitee.com/chunanyong/zorm/decimal
@ -9,7 +9,7 @@ github.com/aliyun/aliyun-oss-go-sdk/oss
## explicit; go 1.16
github.com/allegro/bigcache/v3
github.com/allegro/bigcache/v3/queue
# github.com/aws/aws-sdk-go v1.44.51
# github.com/aws/aws-sdk-go v1.44.53
## explicit; go 1.11
github.com/aws/aws-sdk-go/aws
github.com/aws/aws-sdk-go/aws/arn
@ -481,7 +481,7 @@ golang.org/x/net/trace
## explicit
golang.org/x/sync/errgroup
golang.org/x/sync/singleflight
# golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d
# golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e
## explicit; go 1.17
golang.org/x/sys/cpu
golang.org/x/sys/internal/unsafeheader
@ -516,11 +516,11 @@ golang.org/x/text/width
# golang.org/x/time v0.0.0-20220609170525-579cf78fd858
## explicit
golang.org/x/time/rate
# google.golang.org/genproto v0.0.0-20220708155623-50e5f4832e73
# google.golang.org/genproto v0.0.0-20220712132514-bdd2acd4974d
## explicit; go 1.15
google.golang.org/genproto/googleapis/api/annotations
google.golang.org/genproto/googleapis/rpc/status
# google.golang.org/grpc v1.47.0
# google.golang.org/grpc v1.48.0
## explicit; go 1.14
google.golang.org/grpc
google.golang.org/grpc/attributes
@ -641,7 +641,7 @@ gorm.io/gorm/logger
gorm.io/gorm/migrator
gorm.io/gorm/schema
gorm.io/gorm/utils
# xorm.io/builder v0.3.11
# xorm.io/builder v0.3.12
## explicit; go 1.11
xorm.io/builder
# xorm.io/xorm v1.3.1

185
vendor/xorm.io/builder/cond_in.go generated vendored

@ -38,132 +38,198 @@ func (condIn condIn) WriteTo(w Writer) error {
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[int8]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []int16:
vals := condIn.vals[0].([]int16)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[int16]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []int:
vals := condIn.vals[0].([]int)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[int]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []int32:
vals := condIn.vals[0].([]int32)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[int32]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []int64:
vals := condIn.vals[0].([]int64)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[int64]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []uint8:
vals := condIn.vals[0].([]uint8)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[uint8]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []uint16:
vals := condIn.vals[0].([]uint16)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[uint16]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []uint:
vals := condIn.vals[0].([]uint)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[uint]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []uint32:
vals := condIn.vals[0].([]uint32)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[uint32]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []uint64:
vals := condIn.vals[0].([]uint64)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[uint64]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []string:
vals := condIn.vals[0].([]string)
if len(vals) <= 0 {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[string]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []interface{}:
vals := condIn.vals[0].([]interface{})
@ -205,15 +271,38 @@ func (condIn condIn) WriteTo(w Writer) error {
return condIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", l)
trackMap := make(map[interface{}]bool, l)
for i := 0; i < l; i++ {
val := v.Index(i).Interface()
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
} else {
// Using a map for better efficiency
trackMap := make(map[interface{}]bool, len(condIn.vals))
for i := 0; i < l; i++ {
w.Append(v.Index(i).Interface())
i := 0
for in, val := range condIn.vals {
if _, exists := trackMap[val]; exists {
// This sets empty values to nil, they get sliced off later.
condIn.vals[in] = nil
continue
}
trackMap[val] = true
condIn.vals[i] = val
i++
}
} else {
// Here we slice the slice to only contain those values we defined as correct.
condIn.vals = condIn.vals[:i]
questionMark := strings.Repeat("?,", len(condIn.vals))
if _, err := fmt.Fprintf(w, "%s IN (%s)", condIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err

@ -35,132 +35,198 @@ func (condNotIn condNotIn) WriteTo(w Writer) error {
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[int8]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []int16:
vals := condNotIn.vals[0].([]int16)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[int16]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []int:
vals := condNotIn.vals[0].([]int)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[int]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []int32:
vals := condNotIn.vals[0].([]int32)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[int32]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []int64:
vals := condNotIn.vals[0].([]int64)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[int64]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []uint8:
vals := condNotIn.vals[0].([]uint8)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[uint8]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []uint16:
vals := condNotIn.vals[0].([]uint16)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[uint16]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []uint:
vals := condNotIn.vals[0].([]uint)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[uint]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []uint32:
vals := condNotIn.vals[0].([]uint32)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[uint32]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []uint64:
vals := condNotIn.vals[0].([]uint64)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[uint64]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []string:
vals := condNotIn.vals[0].([]string)
if len(vals) <= 0 {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", len(vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
// We're using this map to track if a parameter was already added to the condition to not add the same multiple times.
trackMap := make(map[string]bool, len(vals))
for _, val := range vals {
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
case []interface{}:
vals := condNotIn.vals[0].([]interface{})
@ -202,15 +268,38 @@ func (condNotIn condNotIn) WriteTo(w Writer) error {
return condNotIn.handleBlank(w)
}
questionMark := strings.Repeat("?,", l)
trackMap := make(map[interface{}]bool, l)
for i := 0; i < l; i++ {
val := v.Index(i).Interface()
if _, exists := trackMap[val]; exists {
continue
}
w.Append(val)
trackMap[val] = true
}
questionMark := strings.Repeat("?,", len(trackMap))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err
}
} else {
// Using a map for better efficiency
trackMap := make(map[interface{}]bool, len(condNotIn.vals))
for i := 0; i < l; i++ {
w.Append(v.Index(i).Interface())
i := 0
for in, val := range condNotIn.vals {
if _, exists := trackMap[val]; exists {
// This sets empty values to nil, they get sliced off later.
condNotIn.vals[in] = nil
continue
}
trackMap[val] = true
condNotIn.vals[i] = val
i++
}
} else {
// Here we slice the slice to only contain those values we defined as correct.
condNotIn.vals = condNotIn.vals[:i]
questionMark := strings.Repeat("?,", len(condNotIn.vals))
if _, err := fmt.Fprintf(w, "%s NOT IN (%s)", condNotIn.col, questionMark[:len(questionMark)-1]); err != nil {
return err

Loading…
Cancel
Save