88 "github.com/tetratelabs/wazero"
99 "github.com/tetratelabs/wazero/api"
1010
11+ "github.com/ncruces/go-sqlite3"
1112 "github.com/ncruces/go-sqlite3/internal/util"
1213)
1314
2930// [CREATE]: https://sqlite.org/lang_createtable.html
3031// [ALTER TABLE]: https://sqlite.org/lang_altertable.html
3132func ParseTable (sql string ) (_ * Table , err error ) {
33+ if len (sql ) > 8192 {
34+ return nil , sqlite3 .TOOBIG
35+ }
36+
3237 once .Do (func () {
3338 ctx := context .Background ()
3439 cfg := wazero .NewRuntimeConfigInterpreter ()
@@ -81,6 +86,7 @@ type Table struct {
8186 IsWithoutRowID bool
8287 IsStrict bool
8388 Columns []Column
89+ Constraints []TableConstraint
8490 Type StatementType
8591 CurrentName string
8692 NewName string
@@ -96,9 +102,16 @@ func (t *Table) load(mod api.Module, ptr uint32, sql string) {
96102 t .IsWithoutRowID = loadBool (mod , ptr + 26 )
97103 t .IsStrict = loadBool (mod , ptr + 27 )
98104
99- t .Columns = loadSlice (mod , ptr + 28 , func (ptr uint32 , ret * Column ) {
105+ t .Columns = loadSlice (mod , ptr + 28 , func (ptr uint32 , ret * Column ) uint32 {
106+ p , _ := mod .Memory ().ReadUint32Le (ptr )
107+ ret .load (mod , p , sql )
108+ return 4
109+ })
110+
111+ t .Constraints = loadSlice (mod , ptr + 36 , func (ptr uint32 , ret * TableConstraint ) uint32 {
100112 p , _ := mod .Memory ().ReadUint32Le (ptr )
101113 ret .load (mod , p , sql )
114+ return 4
102115 })
103116
104117 t .Type = loadEnum [StatementType ](mod , ptr + 44 )
@@ -159,6 +172,47 @@ func (c *Column) load(mod api.Module, ptr uint32, sql string) {
159172 c .GeneratedType = loadEnum [GenType ](mod , ptr + 96 )
160173}
161174
175+ // TableConstraint holds metadata about a table key constraint.
176+ type TableConstraint struct {
177+ Type ConstraintType
178+ Name string
179+ // Type is TABLECONSTRAINT_PRIMARYKEY or TABLECONSTRAINT_UNIQUE
180+ IndexedColumns []IdxColumn
181+ ConflictClause ConflictClause
182+ IsAutoIncrement bool
183+ // Type is TABLECONSTRAINT_CHECK
184+ Expr string
185+ // Type is TABLECONSTRAINT_FOREIGNKEY
186+ ForeignKeyNames []string
187+ ForeignKeyClause * ForeignKey
188+ }
189+
190+ func (c * TableConstraint ) load (mod api.Module , ptr uint32 , sql string ) {
191+ c .Type = loadEnum [ConstraintType ](mod , ptr + 0 )
192+ c .Name = loadString (mod , ptr + 4 , sql )
193+ switch c .Type {
194+ case TABLECONSTRAINT_PRIMARYKEY , TABLECONSTRAINT_UNIQUE :
195+ c .IndexedColumns = loadSlice (mod , ptr + 12 , func (ptr uint32 , ret * IdxColumn ) uint32 {
196+ ret .load (mod , ptr , sql )
197+ return 20
198+ })
199+ c .ConflictClause = loadEnum [ConflictClause ](mod , ptr + 20 )
200+ c .IsAutoIncrement = loadBool (mod , ptr + 24 )
201+ case TABLECONSTRAINT_CHECK :
202+ c .Expr = loadString (mod , ptr + 12 , sql )
203+ case TABLECONSTRAINT_FOREIGNKEY :
204+ c .ForeignKeyNames = loadSlice (mod , ptr + 12 , func (ptr uint32 , ret * string ) uint32 {
205+ * ret = loadString (mod , ptr , sql )
206+ return 8
207+ })
208+ if ptr , _ := mod .Memory ().ReadUint32Le (ptr + 20 ); ptr != 0 {
209+ c .ForeignKeyClause = & ForeignKey {}
210+ c .ForeignKeyClause .load (mod , ptr , sql )
211+ }
212+ }
213+ }
214+
215+ // ForeignKey holds metadata about a foreign key constraint.
162216type ForeignKey struct {
163217 Table string
164218 Columns []string
@@ -171,8 +225,9 @@ type ForeignKey struct {
171225func (f * ForeignKey ) load (mod api.Module , ptr uint32 , sql string ) {
172226 f .Table = loadString (mod , ptr + 0 , sql )
173227
174- f .Columns = loadSlice (mod , ptr + 8 , func (ptr uint32 , ret * string ) {
228+ f .Columns = loadSlice (mod , ptr + 8 , func (ptr uint32 , ret * string ) uint32 {
175229 * ret = loadString (mod , ptr , sql )
230+ return 8
176231 })
177232
178233 f .OnDelete = loadEnum [FKAction ](mod , ptr + 16 )
@@ -181,6 +236,19 @@ func (f *ForeignKey) load(mod api.Module, ptr uint32, sql string) {
181236 f .Deferrable = loadEnum [FKDefType ](mod , ptr + 32 )
182237}
183238
239+ // IdxColumn holds metadata about an indexed column.
240+ type IdxColumn struct {
241+ Name string
242+ CollateName string
243+ Order OrderClause
244+ }
245+
246+ func (c * IdxColumn ) load (mod api.Module , ptr uint32 , sql string ) {
247+ c .Name = loadString (mod , ptr + 0 , sql )
248+ c .CollateName = loadString (mod , ptr + 8 , sql )
249+ c .Order = loadEnum [OrderClause ](mod , ptr + 16 )
250+ }
251+
184252func loadString (mod api.Module , ptr uint32 , sql string ) string {
185253 off , _ := mod .Memory ().ReadUint32Le (ptr + 0 )
186254 if off == 0 {
@@ -190,16 +258,15 @@ func loadString(mod api.Module, ptr uint32, sql string) string {
190258 return sql [off - sqlp : off + len - sqlp ]
191259}
192260
193- func loadSlice [T any ](mod api.Module , ptr uint32 , fn func (uint32 , * T )) []T {
261+ func loadSlice [T any ](mod api.Module , ptr uint32 , fn func (uint32 , * T ) uint32 ) []T {
194262 ref , _ := mod .Memory ().ReadUint32Le (ptr + 4 )
195263 if ref == 0 {
196264 return nil
197265 }
198266 len , _ := mod .Memory ().ReadUint32Le (ptr + 0 )
199267 ret := make ([]T , len )
200268 for i := range ret {
201- fn (ref , & ret [i ])
202- ref += 4
269+ ref += fn (ref , & ret [i ])
203270 }
204271 return ret
205272}
0 commit comments