99
1010 _ "github.com/go-sql-driver/mysql"
1111 "github.com/jackc/pgx/v5/pgxpool"
12- _ "github.com/ncruces/go-sqlite3/driver "
12+ "github.com/ncruces/go-sqlite3"
1313 _ "github.com/ncruces/go-sqlite3/embed"
1414
1515 "github.com/sqlc-dev/sqlc/internal/engine/dolphin"
@@ -42,21 +42,21 @@ func (g *PostgreSQLColumnGetter) GetColumnNames(ctx context.Context, query strin
4242 return columns , nil
4343}
4444
45- // SQLColumnGetter implements ColumnGetter for MySQL and SQLite using database/sql.
46- type SQLColumnGetter struct {
45+ // MySQLColumnGetter implements ColumnGetter for MySQL using database/sql.
46+ type MySQLColumnGetter struct {
4747 db * sql.DB
4848}
4949
50- func (g * SQLColumnGetter ) GetColumnNames (ctx context.Context , query string ) ([]string , error ) {
50+ func (g * MySQLColumnGetter ) GetColumnNames (ctx context.Context , query string ) ([]string , error ) {
5151 // Prepare the statement to validate the query and get column metadata
5252 stmt , err := g .db .PrepareContext (ctx , query )
5353 if err != nil {
5454 return nil , err
5555 }
5656 defer stmt .Close ()
5757
58- // Execute with LIMIT 0 workaround by wrapping in a subquery to get column names
59- // without fetching actual data. We need to execute to get column metadata from database/sql .
58+ // Execute to get column metadata from database/sql.
59+ // database/sql doesn't expose column names from prepared statements directly .
6060 rows , err := stmt .QueryContext (ctx )
6161 if err != nil {
6262 return nil , err
@@ -66,6 +66,29 @@ func (g *SQLColumnGetter) GetColumnNames(ctx context.Context, query string) ([]s
6666 return rows .Columns ()
6767}
6868
69+ // SQLiteColumnGetter implements ColumnGetter for SQLite using the native ncruces/go-sqlite3 API.
70+ type SQLiteColumnGetter struct {
71+ conn * sqlite3.Conn
72+ }
73+
74+ func (g * SQLiteColumnGetter ) GetColumnNames (ctx context.Context , query string ) ([]string , error ) {
75+ // Prepare the statement - this gives us column metadata without executing
76+ stmt , _ , err := g .conn .Prepare (query )
77+ if err != nil {
78+ return nil , err
79+ }
80+ defer stmt .Close ()
81+
82+ // Get column names from the prepared statement
83+ count := stmt .ColumnCount ()
84+ columns := make ([]string , count )
85+ for i := 0 ; i < count ; i ++ {
86+ columns [i ] = stmt .ColumnName (i )
87+ }
88+
89+ return columns , nil
90+ }
91+
6992func TestExpandPostgreSQL (t * testing.T ) {
7093 // Skip if no database connection available
7194 uri := os .Getenv ("POSTGRESQL_SERVER_URI" )
@@ -251,7 +274,7 @@ func TestExpandMySQL(t *testing.T) {
251274 parser := dolphin .NewParser ()
252275
253276 // Create the expander
254- colGetter := & SQLColumnGetter {db : db }
277+ colGetter := & MySQLColumnGetter {db : db }
255278 exp := New (colGetter , parser , parser )
256279
257280 tests := []struct {
@@ -317,15 +340,15 @@ func TestExpandMySQL(t *testing.T) {
317340func TestExpandSQLite (t * testing.T ) {
318341 ctx := context .Background ()
319342
320- // Create an in-memory SQLite database
321- db , err := sql .Open ("sqlite3" , ":memory:" )
343+ // Create an in-memory SQLite database using native API
344+ conn , err := sqlite3 .Open (":memory:" )
322345 if err != nil {
323346 t .Fatalf ("could not open SQLite: %v" , err )
324347 }
325- defer db .Close ()
348+ defer conn .Close ()
326349
327350 // Create a test table
328- _ , err = db . ExecContext ( ctx , `
351+ err = conn . Exec ( `
329352 CREATE TABLE authors (
330353 id INTEGER PRIMARY KEY AUTOINCREMENT,
331354 name TEXT NOT NULL,
@@ -339,8 +362,8 @@ func TestExpandSQLite(t *testing.T) {
339362 // Create the parser which also implements format.Dialect
340363 parser := sqlite .NewParser ()
341364
342- // Create the expander
343- colGetter := & SQLColumnGetter { db : db }
365+ // Create the expander using native SQLite column getter
366+ colGetter := & SQLiteColumnGetter { conn : conn }
344367 exp := New (colGetter , parser , parser )
345368
346369 tests := []struct {
0 commit comments