Skip to content

Commit fd866bb

Browse files
committed
2 parents b49cdc5 + 50b9184 commit fd866bb

File tree

1 file changed

+73
-55
lines changed

1 file changed

+73
-55
lines changed

SQL.md

Lines changed: 73 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
# `database/sql` driver for `YDB`
22

3-
Package `ydb-go-sdk` provides usage `database/sql` API also.
4-
`database/sql` driver implementation use `ydb-go-sdk` native driver API's.
3+
In addition to native YDB Go driver APIs, package `ydb-go-sdk` provides standard APIs for `database/sql`.
4+
It allows to use "regular" Go facilities to access YDB databases.
5+
Behind the scene, `database/sql` APIs are implemented using the native interfaces.
6+
57

68
## Table of contents
79
1. [Initialization of `database/sql` driver](#init)
810
* [Configure driver with `ydb.Connector` (recommended way)](#init-connector)
9-
* [Configure driver only with data source name (connection string)](#init-dsn)
10-
2. [About session pool](#session-pool)
11-
3. [Execute queries](#queries)
12-
* [On database object](#queries-db)
13-
* [With transaction](#queries-tx)
11+
* [Configure driver with data source name or connection string](#init-dsn)
12+
2. [Session pooling](#session-pool)
13+
3. [Query execution](#queries)
14+
* [Queries on database object](#queries-db)
15+
* [Queries on transaction object](#queries-tx)
1416
4. [Query modes (DDL, DML, DQL, etc.)](#query-modes)
1517
5. [Retry helpers for `YDB` `database/sql` driver](#retry)
1618
* [Over `sql.Conn` object](#retry-conn)
1719
* [Over `sql.Tx`](#retry-tx)
1820
6. [Query args types](#arg-types)
1921
7. [Get native driver from `*sql.DB`](#unwrap)
20-
8. [Logging SDK's events](#logs)
21-
9. [Add metrics about SDK's events](#metrics)
22-
10. [Add `Jaeger` traces about driver events](#jaeger)
2322

2423
## Initialization of `database/sql` driver <a name="init"></a>
2524

@@ -48,7 +47,8 @@ func main() {
4847
db := sql.OpenDB(connector)
4948
}
5049
```
51-
### Configure driver only with data source name (connection string) <a name="init-dsn"></a>
50+
51+
### Configure driver with data source name or connection string <a name="init-dsn"></a>
5252
```go
5353
import (
5454
"database/sql"
@@ -65,23 +65,24 @@ Data source name parameters:
6565
* static credentials with authority part of URI, like `grpcs://root:password@localhost:2135/local`
6666
* `query_mode=scripting` - you can redefine default [DML](https://en.wikipedia.org/wiki/Data_manipulation_language) query mode
6767

68-
## About session pool <a name="session-pool"></a>
68+
## Session pooling <a name="session-pool"></a>
6969

70-
Native driver `ydb-go-sdk/v3` implements internal session pool, which uses with `db.Table().Do()` or `db.Table().DoTx()` methods.
71-
Internal session pool configures with options like `ydb.WithSessionPoolSizeLimit()` and other.
72-
Unlike session pool in native driver, `database/sql` contains another session pool, which configures with `*sql.DB.SetMaxOpenConns` and `*sql.DB.SetMaxIdleConns`.
73-
Lifetime of `YDB` session depends on driver configuration and predefined errors, such as `sql.driver.ErrBadConn`.
74-
`YDB` driver for `database/sql` transform internal `YDB` errors into `sql.driver.ErrBadConn` depending on result of internal error check (delete session on error or not and other).
75-
In most cases this behaviour of `database/sql` driver implementation for specific RDBMS completes queries without result errors.
76-
But some errors on unfortunate cases may be get on client-side.
77-
That's why querying must be wrapped with retry helpers, such as `retry.Do` or `retry.DoTx` (see more about retry helpers in [retry section](#retry)).
70+
Native driver `ydb-go-sdk/v3` implements the internal session pool, which uses with `db.Table().Do()` or `db.Table().DoTx()` methods.
71+
Internal session pool is configured with options like `ydb.WithSessionPoolSizeLimit()` and other.
72+
Unlike the session pool in the native driver, `database/sql` contains a different implementation of the session pool, which is configured with `*sql.DB.SetMaxOpenConns` and `*sql.DB.SetMaxIdleConns`.
73+
Lifetime of a `YDB` session depends on driver configuration and error occurance, such as `sql.driver.ErrBadConn`.
74+
`YDB` driver for `database/sql` includes the logic to transform the internal `YDB` error codes into `sql.driver.ErrBadConn` and other retryable and non-retryable error types.
7875

79-
## Execute queries <a name="queries"></a>
76+
In most cases the implementation of `database/sql` driver for YDB allows to complete queries without user-visible errors.
77+
But some errors need to be handled on the client side, by re-running not a single operation, but a complete transaction.
78+
Therefore the transaction logic needs to be wrapped with retry helpers, such as `retry.Do` or `retry.DoTx` (see more about retry helpers in the [retry section](#retry)).
8079

81-
### On database object <a name="queries-db"></a>
80+
## Query execution <a name="queries"></a>
81+
82+
### Queries on database object <a name="queries-db"></a>
8283
```go
8384
rows, err := db.QueryContext(ctx,
84-
"SELECT series_id, title, release_date FROM /full/path/of/table/series;"
85+
"SELECT series_id, title, release_date FROM `/full/path/of/table/series`;"
8586
)
8687
if err != nil {
8788
log.Fatal(err)
@@ -104,19 +105,23 @@ if err = rows.Err(); err != nil { // always check final rows err
104105
}
105106
```
106107

107-
### With transaction <a name="queries-tx"></a>
108-
Supports only `default` transaction options which mapped to `YDB` `SerializableReadWrite` transaction settings.
108+
### Queries on transaction object <a name="queries-tx"></a>
109+
Query execution on transaction object supports only `default` transaction options
110+
which are mapped to `YDB` `SerializableReadWrite` transaction settings.
111+
112+
`YDB`'s `OnlineReadOnly` and `StaleReadOnly` transaction settings are not compatible
113+
with interactive transactions such as `database/sql`'s `*sql.Tx`.
114+
That's why `ydb-go-sdk` implements read-only `sql.LevelSnapshot` with fake transaction
115+
(temporary, until `YDB` starts to support true snapshot isolation mode).
109116

110-
`YDB`'s `OnlineReadOnly` and `StaleReadOnly` transaction settings are not compatible with interactive transactions such as `database/sql`'s `*sql.Tx`.
111-
That's why `ydb-go-sdk` implements read-only `sql.LevelSnapshot` with fake transaction (temporary, while `YDB` main clusters are supports true snapshot isolation mode)
112117
```go
113118
tx, err := db.BeginTx(ctx, sql.TxOptions{})
114119
if err != nil {
115120
log.Fatal(err)
116121
}
117122
defer tx.Rollback()
118123
rows, err := tx.QueryContext(ctx,
119-
"SELECT series_id, title, release_date FROM /full/path/of/table/series;"
124+
"SELECT series_id, title, release_date FROM `/full/path/of/table/series`;"
120125
)
121126
if err != nil {
122127
log.Fatal(err)
@@ -141,48 +146,56 @@ if err = tx.Commit(); err != nil {
141146
log.Fatal(err)
142147
}
143148
```
149+
144150
## Query modes (DDL, DML, DQL, etc.) <a name="query-modes"></a>
145-
The `YDB` server API is currently requires to select a specific method by specific request type. For example, [DDL](https://en.wikipedia.org/wiki/Data_definition_language) must be called with `table.session.ExecuteSchemeQuery`, [DML](https://en.wikipedia.org/wiki/Data_manipulation_language) must be called with `table.session.Execute`, [DQL](https://en.wikipedia.org/wiki/Data_query_language) may be called with `table.session.Execute` or `table.session.StreamExecuteScanQuery` etc. `YDB` have a `scripting` service also, which provides different query types with single method, but not supports transactions.
151+
Currently the `YDB` server APIs require the use of a proper GRPC service method depending on the specific request type.
152+
In particular, [DDL](https://en.wikipedia.org/wiki/Data_definition_language) must be called through `table.session.ExecuteSchemeQuery`,
153+
[DML](https://en.wikipedia.org/wiki/Data_manipulation_language) needs `table.session.Execute`, and
154+
[DQL](https://en.wikipedia.org/wiki/Data_query_language) should be passed via `table.session.Execute` or `table.session.StreamExecuteScanQuery`.
155+
`YDB` also has a so-called "scripting" service, which supports different query types within a single method,
156+
but without support for transactions.
146157

147-
That's why needs to select query mode on client side currently.
158+
Unfortunately, this leads to the need to choose the proper query mode on the application side.
148159

149-
`YDB` team have a roadmap goal to implements a single method for executing different query types.
160+
`YDB` team has a roadmap goal to implement a single universal service method for executing
161+
different query types and without the limitations of the "scripting" service method.
150162

151-
`database/sql` driver implementation for `YDB` supports next query modes:
163+
`database/sql` driver implementation for `YDB` supports the following query modes:
152164
* `ydb.DataQueryMode` - default query mode, for lookup [DQL](https://en.wikipedia.org/wiki/Data_query_language) queries and [DML](https://en.wikipedia.org/wiki/Data_manipulation_language) queries.
153-
* `ydb.ExplainQueryMode` - for gettting plan and [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) of some query
154-
* `ydb.ScanQueryMode` - for strong [OLAP](https://en.wikipedia.org/wiki/Online_analytical_processing) scenarious, [DQL-only](https://en.wikipedia.org/wiki/Data_query_language) queries. Read more about scan queries in [ydb.tech](https://ydb.tech/en/docs/concepts/scan_query)
165+
* `ydb.ExplainQueryMode` - for gettting plan and [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) of the query
166+
* `ydb.ScanQueryMode` - for heavy [OLAP](https://en.wikipedia.org/wiki/Online_analytical_processing) style scenarious, with [DQL-only](https://en.wikipedia.org/wiki/Data_query_language) queries. Read more about scan queries in [ydb.tech](https://ydb.tech/en/docs/concepts/scan_query)
155167
* `ydb.SchemeQueryMode` - for [DDL](https://en.wikipedia.org/wiki/Data_definition_language) queries
156-
* `ydb.ScriptingQueryMode` - for [DDL](https://en.wikipedia.org/wiki/Data_definition_language), [DML](https://en.wikipedia.org/wiki/Data_manipulation_language), [DQL](https://en.wikipedia.org/wiki/Data_query_language) queries (not a [TCL](https://en.wikipedia.org/wiki/SQL#Transaction_controls)). Be careful: queries executes longer than with other query modes and consumes bigger server-side resources
168+
* `ydb.ScriptingQueryMode` - for [DDL](https://en.wikipedia.org/wiki/Data_definition_language), [DML](https://en.wikipedia.org/wiki/Data_manipulation_language), [DQL](https://en.wikipedia.org/wiki/Data_query_language) queries (not a [TCL](https://en.wikipedia.org/wiki/SQL#Transaction_controls)). Be careful: queries execute longer than with other query modes, and consume more server-side resources
157169

158-
Example for changing default query mode:
170+
Example for changing the default query mode:
159171
```go
160172
res, err = db.ExecContext(ydb.WithQueryMode(ctx, ydb.SchemeQueryMode),
161173
"DROP TABLE `/full/path/to/table/series`",
162174
)
163175
```
164176

165-
## Specify `YDB` transaction control <a name="tx-control"></a>
177+
## Changing the transaction control mode <a name="tx-control"></a>
166178

167-
Default `YDB`'s transaction control is a `SerializableReadWrite`.
168-
Default transaction control outside interactive transactions may be changed with context:
179+
Default `YDB`'s transaction control mode is a `SerializableReadWrite`.
180+
Default transaction control mode can be changed outside of interactive transactions by updating the context object:
169181
```
170182
ctx := ydb.WithTxControl(ctx, table.OnlineReadOnlyTxControl())
171183
```
172184

173185
## Retry helpers for `YDB` `database/sql` driver <a name="retry"></a>
174186

175187
`YDB` is a distributed `RDBMS` with non-stop 24/7 releases flow.
176-
It means some nodes may be not available for queries.
177-
Also network errors may be occurred.
178-
That's why some queries may be complete with errors.
188+
It means some nodes may be unavailable for queries at some point in time.
189+
Network errors may also occur.
190+
That's why some queries may complete with errors.
179191
Most of those errors are transient.
180-
`ydb-go-sdk`'s "knows" what to do on specific error: retry or not, with or without backoff, with or whithout deleting session, etc.
181-
`ydb-go-sdk` provides retry helpers which can work either with plain database connection object, or with interactive transaction object.
192+
`ydb-go-sdk`'s "knows" what to do on specific error: retry or not, with or without backoff, with or without the need to re-establish the session, etc.
193+
`ydb-go-sdk` provides retry helpers which can work either with the database connection object, or with the transaction object.
182194

183-
### Over `sql.Conn` object <a name="retry-conn"></a>
195+
### Retries over `sql.Conn` object <a name="retry-conn"></a>
184196

185-
`retry.Do` helper allow custom lambda, which must return error for processing or nil if retry operation is ok.
197+
`retry.Do` helper accepts custom lambda, which must return error if it happens during the processing,
198+
or nil if the operation succeeds.
186199
```
187200
import (
188201
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
@@ -200,11 +213,15 @@ err := retry.Do(context.TODO(), db, func(ctx context.Context, cc *sql.Conn) erro
200213
201214
```
202215

203-
### Over `sql.Tx` <a name="retry-tx"></a>
216+
### Retries over `sql.Tx` <a name="retry-tx"></a>
217+
218+
`retry.DoTx` helper accepts custom lambda, which must return error if it happens during processing,
219+
or nil if the operation succeeds.
204220

205-
`retry.DoTx` helper allow custom lambda, which must return error for processing or nil if retry operation is ok.
221+
`tx` object is a prepared transaction object.
222+
223+
The logic within the custom lambda does not need the explicit commit or rollback at the end - `retry.DoTx` does it automatically.
206224

207-
`tx` object is a prepared transaction object which not requires commit or rollback at the end - `retry.DoTx` do it automatically.
208225
```
209226
import (
210227
"github.com/ydb-platform/ydb-go-sdk/v3/retry"
@@ -226,10 +243,10 @@ err := retry.DoTx(context.TODO(), db, func(ctx context.Context, tx *sql.Tx) erro
226243
}))
227244
```
228245

229-
## Query args types <a name="arg-types"></a>
246+
## Specifying query parameters <a name="arg-types"></a>
230247

231-
`database/sql` driver for `YDB` supports next types of query args:
232-
* multiple `sql.NamedArg` (uniform `database/sql` arg)
248+
`database/sql` driver for `YDB` supports the following types of query parameters:
249+
* multiple `sql.NamedArg` arguments (standard `database/sql` query parameters)
233250
```
234251
rows, err := cc.QueryContext(ctx, `
235252
DECLARE $seasonTitle AS Utf8;
@@ -240,7 +257,7 @@ err := retry.DoTx(context.TODO(), db, func(ctx context.Context, tx *sql.Tx) erro
240257
sql.Named("views", uint64(1000)),
241258
)
242259
```
243-
* multiple native for `ydb-go-sdk` `table.ParameterOption` which constructs from `table.ValueParam("name", value)`
260+
* multiple native `ydb-go-sdk` `table.ParameterOption` arguments which are constructed with `table.ValueParam("name", value)`
244261
```
245262
rows, err := cc.QueryContext(ctx, `
246263
DECLARE $seasonTitle AS Utf8;
@@ -251,7 +268,7 @@ err := retry.DoTx(context.TODO(), db, func(ctx context.Context, tx *sql.Tx) erro
251268
table.ValueParam("views", types.Uint64Value((1000)),
252269
)
253270
```
254-
* single native for `ydb-go-sdk` `*table.QueryParameters` which constructs from `table.NewQueryParameters(parameterOptions...)`
271+
* single native `ydb-go-sdk` `*table.QueryParameters` argument which are constructed with `table.NewQueryParameters(parameterOptions...)`
255272
```
256273
rows, err := cc.QueryContext(ctx, `
257274
DECLARE $seasonTitle AS Utf8;
@@ -264,7 +281,8 @@ err := retry.DoTx(context.TODO(), db, func(ctx context.Context, tx *sql.Tx) erro
264281
),
265282
)
266283
```
267-
## Get native driver from `*sql.DB` <a name="unwrap"></a>
284+
285+
## Accessing the native driver from `*sql.DB` <a name="unwrap"></a>
268286

269287
```go
270288
db, err := sql.Open("ydb", "grpcs://localhost:2135/local")

0 commit comments

Comments
 (0)