@@ -12,60 +12,50 @@ import (
12
12
)
13
13
14
14
const (
15
- _NONE = iota
16
- _MEMORY
17
- _SYNTAX
18
- _UNSUPPORTEDSQL
19
-
20
- codeptr = 4
21
- baseptr = 8
15
+ errp = 4
16
+ sqlp = 8
22
17
)
23
18
24
19
var (
25
20
//go:embed parse/sql3parse_table.wasm
26
- binary []byte
27
- ctx context.Context
28
- once sync.Once
29
- runtime wazero.Runtime
30
- module wazero.CompiledModule
21
+ binary []byte
22
+ once sync.Once
23
+ runtime wazero.Runtime
24
+ compiled wazero.CompiledModule
31
25
)
32
26
33
- // Table holds metadata about a table.
34
- type Table struct {
35
- mod api.Module
36
- ptr uint32
37
- sql string
38
- }
39
-
40
27
// Parse parses a [CREATE] or [ALTER TABLE] command.
41
28
//
42
29
// [CREATE]: https://sqlite.org/lang_createtable.html
43
30
// [ALTER TABLE]: https://sqlite.org/lang_altertable.html
44
31
func Parse (sql string ) (_ * Table , err error ) {
45
32
once .Do (func () {
46
- ctx = context .Background ()
47
- cfg := wazero .NewRuntimeConfigInterpreter (). WithDebugInfoEnabled ( false )
33
+ ctx : = context .Background ()
34
+ cfg := wazero .NewRuntimeConfigInterpreter ()
48
35
runtime = wazero .NewRuntimeWithConfig (ctx , cfg )
49
- module , err = runtime .CompileModule (ctx , binary )
36
+ compiled , err = runtime .CompileModule (ctx , binary )
50
37
})
51
38
if err != nil {
52
39
return nil , err
53
40
}
54
41
55
- mod , err := runtime .InstantiateModule (ctx , module , wazero .NewModuleConfig ().WithName ("" ))
42
+ ctx := context .Background ()
43
+ mod , err := runtime .InstantiateModule (ctx , compiled , wazero .NewModuleConfig ().WithName ("" ))
56
44
if err != nil {
57
45
return nil , err
58
46
}
47
+ defer mod .Close (ctx )
59
48
60
- if buf , ok := mod .Memory ().Read (baseptr , uint32 (len (sql ))); ok {
49
+ if buf , ok := mod .Memory ().Read (sqlp , uint32 (len (sql ))); ok {
61
50
copy (buf , sql )
62
51
}
63
- r , err := mod .ExportedFunction ("sql3parse_table" ).Call (ctx , baseptr , uint64 (len (sql )), codeptr )
52
+
53
+ r , err := mod .ExportedFunction ("sql3parse_table" ).Call (ctx , sqlp , uint64 (len (sql )), errp )
64
54
if err != nil {
65
55
return nil , err
66
56
}
67
57
68
- c , _ := mod .Memory ().ReadUint32Le (codeptr )
58
+ c , _ := mod .Memory ().ReadUint32Le (errp )
69
59
switch c {
70
60
case _MEMORY :
71
61
panic (util .OOMErr )
@@ -74,68 +64,146 @@ func Parse(sql string) (_ *Table, err error) {
74
64
case _UNSUPPORTEDSQL :
75
65
return nil , util .ErrorString ("sql3parse: unsupported SQL" )
76
66
}
77
- if r [0 ] == 0 {
78
- return nil , nil
79
- }
80
- return & Table {
81
- sql : sql ,
82
- mod : mod ,
83
- ptr : uint32 (r [0 ]),
84
- }, nil
67
+
68
+ var tab Table
69
+ tab .load (mod , uint32 (r [0 ]), sql )
70
+ return & tab , nil
85
71
}
86
72
87
- // Close closes a table handle.
88
- func (t * Table ) Close () error {
89
- mod := t .mod
90
- t .mod = nil
91
- return mod .Close (ctx )
73
+ // Table holds metadata about a table.
74
+ type Table struct {
75
+ Name string
76
+ Schema string
77
+ Comment string
78
+ IsTemporary bool
79
+ IsIfNotExists bool
80
+ IsWithoutRowID bool
81
+ IsStrict bool
82
+ Columns []Column
83
+ Type StatementType
84
+ CurrentName string
85
+ NewName string
92
86
}
93
87
94
- // NumColumns returns the number of columns of the table.
95
- func (t * Table ) NumColumns () int {
96
- r , err := t .mod .ExportedFunction ("sql3table_num_columns" ).Call (ctx , uint64 (t .ptr ))
97
- if err != nil {
98
- panic (err )
99
- }
100
- return int (int32 (r [0 ]))
88
+ func (t * Table ) load (mod api.Module , ptr uint32 , sql string ) {
89
+ t .Name = loadString (mod , ptr + 0 , sql )
90
+ t .Schema = loadString (mod , ptr + 8 , sql )
91
+ t .Comment = loadString (mod , ptr + 16 , sql )
92
+
93
+ t .IsTemporary = loadBool (mod , ptr + 24 )
94
+ t .IsIfNotExists = loadBool (mod , ptr + 25 )
95
+ t .IsWithoutRowID = loadBool (mod , ptr + 26 )
96
+ t .IsStrict = loadBool (mod , ptr + 27 )
97
+
98
+ t .Columns = loadSlice (mod , ptr + 28 , func (ptr uint32 , res * Column ) {
99
+ p , _ := mod .Memory ().ReadUint32Le (ptr )
100
+ res .load (mod , p , sql )
101
+ })
102
+
103
+ t .Type = loadEnum [StatementType ](mod , ptr + 44 )
104
+ t .CurrentName = loadString (mod , ptr + 48 , sql )
105
+ t .NewName = loadString (mod , ptr + 56 , sql )
101
106
}
102
107
103
- // Column returns data for the ith column of the table.
104
- //
105
- // https://sqlite.org/lang_createtable.html#column_definitions
106
- func (t * Table ) Column (i int ) Column {
107
- r , err := t .mod .ExportedFunction ("sql3table_get_column" ).Call (ctx , uint64 (t .ptr ), uint64 (i ))
108
- if err != nil {
109
- panic (err )
110
- }
111
- return Column {
112
- tab : t ,
113
- ptr : uint32 (r [0 ]),
108
+ // Column holds metadata about a column.
109
+ type Column struct {
110
+ Name string
111
+ Type string
112
+ Length string
113
+ ConstraintName string
114
+ Comment string
115
+ IsPrimaryKey bool
116
+ IsAutoIncrement bool
117
+ IsNotNull bool
118
+ IsUnique bool
119
+ PKOrder OrderClause
120
+ PKConflictClause ConflictClause
121
+ NotNullConflictClause ConflictClause
122
+ UniqueConflictClause ConflictClause
123
+ CheckExpr string
124
+ DefaultExpr string
125
+ CollateName string
126
+ ForeignKeyClause * ForeignKey
127
+ }
128
+
129
+ func (c * Column ) load (mod api.Module , ptr uint32 , sql string ) {
130
+ c .Name = loadString (mod , ptr + 0 , sql )
131
+ c .Type = loadString (mod , ptr + 8 , sql )
132
+ c .Length = loadString (mod , ptr + 16 , sql )
133
+ c .ConstraintName = loadString (mod , ptr + 24 , sql )
134
+ c .Comment = loadString (mod , ptr + 32 , sql )
135
+
136
+ c .IsPrimaryKey = loadBool (mod , ptr + 40 )
137
+ c .IsAutoIncrement = loadBool (mod , ptr + 41 )
138
+ c .IsNotNull = loadBool (mod , ptr + 42 )
139
+ c .IsUnique = loadBool (mod , ptr + 43 )
140
+
141
+ c .PKOrder = loadEnum [OrderClause ](mod , ptr + 44 )
142
+ c .PKConflictClause = loadEnum [ConflictClause ](mod , ptr + 48 )
143
+ c .NotNullConflictClause = loadEnum [ConflictClause ](mod , ptr + 52 )
144
+ c .UniqueConflictClause = loadEnum [ConflictClause ](mod , ptr + 56 )
145
+
146
+ c .CheckExpr = loadString (mod , ptr + 60 , sql )
147
+ c .DefaultExpr = loadString (mod , ptr + 68 , sql )
148
+ c .CollateName = loadString (mod , ptr + 76 , sql )
149
+
150
+ if ptr , _ := mod .Memory ().ReadUint32Le (ptr + 84 ); ptr != 0 {
151
+ c .ForeignKeyClause = & ForeignKey {}
152
+ c .ForeignKeyClause .load (mod , ptr , sql )
114
153
}
115
154
}
116
155
117
- func (t * Table ) string (ptr uint32 ) string {
118
- if ptr == 0 {
156
+ type ForeignKey struct {
157
+ Table string
158
+ Columns []string
159
+ OnDelete FKAction
160
+ OnUpdate FKAction
161
+ Match string
162
+ Deferrable FKDefType
163
+ }
164
+
165
+ func (f * ForeignKey ) load (mod api.Module , ptr uint32 , sql string ) {
166
+ f .Table = loadString (mod , ptr + 0 , sql )
167
+
168
+ f .Columns = loadSlice (mod , ptr + 8 , func (ptr uint32 , res * string ) {
169
+ * res = loadString (mod , ptr , sql )
170
+ })
171
+
172
+ f .OnDelete = loadEnum [FKAction ](mod , ptr + 16 )
173
+ f .OnUpdate = loadEnum [FKAction ](mod , ptr + 20 )
174
+ f .Match = loadString (mod , ptr + 24 , sql )
175
+ f .Deferrable = loadEnum [FKDefType ](mod , ptr + 32 )
176
+ }
177
+
178
+ func loadString (mod api.Module , ptr uint32 , sql string ) string {
179
+ off , _ := mod .Memory ().ReadUint32Le (ptr + 0 )
180
+ if off == 0 {
119
181
return ""
120
182
}
121
- off , _ := t .mod .Memory ().ReadUint32Le (ptr + 0 )
122
- len , _ := t .mod .Memory ().ReadUint32Le (ptr + 4 )
123
- return t .sql [off - baseptr : off + len - baseptr ]
183
+ len , _ := mod .Memory ().ReadUint32Le (ptr + 4 )
184
+ return sql [off - sqlp : off + len - sqlp ]
124
185
}
125
186
126
- // Column holds metadata about a column.
127
- type Column struct {
128
- tab * Table
129
- ptr uint32
187
+ func loadSlice [T any ](mod api.Module , ptr uint32 , fn func (uint32 , * T )) []T {
188
+ ref , _ := mod .Memory ().ReadUint32Le (ptr + 4 )
189
+ if ref == 0 {
190
+ return nil
191
+ }
192
+ len , _ := mod .Memory ().ReadUint32Le (ptr + 0 )
193
+ res := make ([]T , len )
194
+ for i := range res {
195
+ fn (ref , & res [i ])
196
+ ref += 4
197
+ }
198
+ return res
130
199
}
131
200
132
- // Type returns the declared type of a column.
133
- //
134
- // https://sqlite.org/lang_createtable.html#column_data_types
135
- func (c Column ) Type () string {
136
- r , err := c .tab .mod .ExportedFunction ("sql3column_type" ).Call (ctx , uint64 (c .ptr ))
137
- if err != nil {
138
- panic (err )
139
- }
140
- return c .tab .string (uint32 (r [0 ]))
201
+ func loadEnum [T ~ uint32 ](mod api.Module , ptr uint32 ) T {
202
+ val , _ := mod .Memory ().ReadUint32Le (ptr )
203
+ return T (val )
204
+ }
205
+
206
+ func loadBool (mod api.Module , ptr uint32 ) bool {
207
+ val , _ := mod .Memory ().ReadByte (ptr )
208
+ return val != 0
141
209
}
0 commit comments