|
7 | 7 | // This driver requires a file: URI always be used to open a database. |
8 | 8 | // For details see https://sqlite.org/c3ref/open.html#urifilenames. |
9 | 9 | // |
10 | | -// |
11 | | -// Initializing connections or tracing |
| 10 | +// # Initializing connections or tracing |
12 | 11 | // |
13 | 12 | // If you want to do initial configuration of a connection, or enable |
14 | 13 | // tracing, use the Connector function: |
|
18 | 17 | // } |
19 | 18 | // db, err = sql.OpenDB(sqlite.Connector(sqliteURI, connInitFunc, nil)) |
20 | 19 | // |
21 | | -// |
22 | | -// Memory Mode |
| 20 | +// # Memory Mode |
23 | 21 | // |
24 | 22 | // In-memory databases are popular for tests. |
25 | 23 | // Use the "memdb" VFS (*not* the legacy in-memory modes) to be compatible |
|
29 | 27 | // |
30 | 28 | // Use a different dbname for each memory database opened. |
31 | 29 | // |
32 | | -// |
33 | | -// Binding Types |
| 30 | +// # Binding Types |
34 | 31 | // |
35 | 32 | // SQLite is flexible about type conversions, and so is this driver. |
36 | 33 | // Almost all "basic" Go types (int, float64, string) are accepted and |
|
39 | 36 | // Values that implement encoding.TextMarshaler or json.Marshaler are |
40 | 37 | // stored in SQLite in their marshaled form. |
41 | 38 | // |
42 | | -// |
43 | | -// Binding Time |
| 39 | +// # Binding Time |
44 | 40 | // |
45 | 41 | // While SQLite3 has no strict time datatype, it does have a series of built-in |
46 | 42 | // functions that operate on timestamps that expect columns to be in one of many |
|
50 | 46 | // shortest timestamp format that can accurately represent the time.Time. |
51 | 47 | // The supported formats are: |
52 | 48 | // |
53 | | -// 2. YYYY-MM-DD HH:MM |
54 | | -// 3. YYYY-MM-DD HH:MM:SS |
55 | | -// 4. YYYY-MM-DD HH:MM:SS.SSS |
| 49 | +// 2. YYYY-MM-DD HH:MM |
| 50 | +// 3. YYYY-MM-DD HH:MM:SS |
| 51 | +// 4. YYYY-MM-DD HH:MM:SS.SSS |
56 | 52 | // |
57 | 53 | // If the time.Time is not UTC (strongly consider storing times in UTC!), |
58 | 54 | // we follow SQLite's norm of appending "[+-]HH:MM" to the above formats. |
|
62 | 58 | // in the link above. If you want to do that, pass the result of time.Time.Unix |
63 | 59 | // to the driver. |
64 | 60 | // |
65 | | -// |
66 | | -// Reading Time |
| 61 | +// # Reading Time |
67 | 62 | // |
68 | 63 | // In general, time is hard to extract from SQLite as a time.Time. |
69 | 64 | // If a column is defined as DATE or DATETIME, then text data is parsed |
@@ -280,12 +275,24 @@ func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, e |
280 | 275 | // Raw is so ConnInitFunc can cast to SQLConn. |
281 | 276 | func (c *conn) Raw(fn func(interface{}) error) error { return fn(c) } |
282 | 277 |
|
| 278 | +type readOnlyKey struct{} |
| 279 | + |
| 280 | +// ReadOnly applies the query_only pragma to the connection. |
| 281 | +func ReadOnly(ctx context.Context) context.Context { |
| 282 | + return context.WithValue(ctx, readOnlyKey{}, true) |
| 283 | +} |
| 284 | + |
| 285 | +// IsReadOnly reports whether the context has the ReadOnly key. |
| 286 | +func IsReadOnly(ctx context.Context) bool { |
| 287 | + return ctx.Value(readOnlyKey{}) != nil |
| 288 | +} |
| 289 | + |
283 | 290 | func (c *conn) txInit(ctx context.Context) error { |
284 | 291 | if c.txState != txStateInit { |
285 | 292 | return nil |
286 | 293 | } |
287 | 294 | c.txState = txStateBegun |
288 | | - if c.readOnly { |
| 295 | + if c.readOnly || IsReadOnly(ctx) { |
289 | 296 | if err := c.execInternal(ctx, "BEGIN"); err != nil { |
290 | 297 | return err |
291 | 298 | } |
|
0 commit comments