@@ -32,18 +32,45 @@ export async function getDuckDBColumnTypes(
3232 tableName : string
3333) : Promise < DuckDBColumnDesc [ ] > {
3434 const quotedTableName = quoteTableName ( tableName ) ;
35- const resDescribe = await connection . query ( `DESCRIBE ${ quotedTableName } ` ) ;
36-
3735 const duckDbTypes : DuckDBColumnDesc [ ] = [ ] ;
38- const numRows = resDescribe . numRows ;
39- for ( let i = 0 ; i < numRows ; ++ i ) {
40- const columnName = resDescribe . getChildAt ( 0 ) ?. get ( i ) ;
41- const columnType = resDescribe . getChildAt ( 1 ) ?. get ( i ) ;
42-
43- duckDbTypes . push ( {
44- name : columnName ,
45- type : columnType
46- } ) ;
36+ try {
37+ // PRAGMA table_info is less likely to bind/execute view SQL than DESCRIBE,
38+ // so it avoids triggering remote access (e.g., S3) for view-backed schemas.
39+ const resInfo = await connection . query (
40+ `PRAGMA table_info(${ quotedTableName } )`
41+ ) ;
42+ const numRows = resInfo . numRows ;
43+ const columnNames = resInfo . getChild ( 'name' ) ;
44+ const columnTypes = resInfo . getChild ( 'type' ) ;
45+ for ( let i = 0 ; i < numRows ; ++ i ) {
46+ duckDbTypes . push ( {
47+ name : columnNames ?. get ( i ) ,
48+ type : columnTypes ?. get ( i )
49+ } ) ;
50+ }
51+ } catch ( primaryError ) {
52+ try {
53+ const resDescribe = await connection . query ( `DESCRIBE ${ quotedTableName } ` ) ;
54+ const numRows = resDescribe . numRows ;
55+ for ( let i = 0 ; i < numRows ; ++ i ) {
56+ const columnName = resDescribe . getChildAt ( 0 ) ?. get ( i ) ;
57+ const columnType = resDescribe . getChildAt ( 1 ) ?. get ( i ) ;
58+
59+ duckDbTypes . push ( {
60+ name : columnName ,
61+ type : columnType
62+ } ) ;
63+ }
64+ } catch ( fallbackError ) {
65+ const error = new Error (
66+ `[DuckDB] Failed to load column types for ${ tableName } (PRAGMA + DESCRIBE).`
67+ ) ;
68+ ( error as Error & { cause ?: unknown } ) . cause = {
69+ primaryError,
70+ fallbackError
71+ } ;
72+ throw error ;
73+ }
4774 }
4875
4976 return duckDbTypes ;
0 commit comments