11using System . Data ;
22using System . Data . Common ;
33using System . Diagnostics . CodeAnalysis ;
4+ using SharpCoreDB . Interfaces ;
45
56namespace SharpCoreDB . Data . Provider ;
67
@@ -139,6 +140,16 @@ public override int ExecuteNonQuery()
139140 else
140141 db . ExecuteSQL ( CommandText ! ) ;
141142
143+ // ? CRITICAL FIX: Flush data after non-query commands to ensure persistence!
144+ // Without this, INSERT/UPDATE/DELETE data only lives in memory until connection close.
145+ var commandUpper = CommandText ! . Trim ( ) . ToUpperInvariant ( ) ;
146+ if ( commandUpper . StartsWith ( "INSERT" ) ||
147+ commandUpper . StartsWith ( "UPDATE" ) ||
148+ commandUpper . StartsWith ( "DELETE" ) )
149+ {
150+ db . Flush ( ) ;
151+ }
152+
142153 // SharpCoreDB doesn't return rows affected, return -1 as per ADO.NET convention
143154 return - 1 ;
144155 }
@@ -160,6 +171,13 @@ protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
160171 var db = Connection ! . DbInstance ! ;
161172 var parameters = BuildParameterDictionary ( ) ;
162173
174+ // ? FIX: Intercept SQLite system table queries and redirect to IMetadataProvider
175+ var commandTextUpper = CommandText ! . ToUpperInvariant ( ) . Trim ( ) ;
176+ if ( commandTextUpper . Contains ( "SQLITE_MASTER" ) || commandTextUpper . Contains ( "SQLITE_SCHEMA" ) )
177+ {
178+ return ExecuteSystemTableQuery ( commandTextUpper , behavior ) ;
179+ }
180+
163181 List < Dictionary < string , object > > results ;
164182 if ( parameters . Count > 0 )
165183 results = db . ExecuteQuery ( CommandText ! , parameters ) ;
@@ -174,6 +192,148 @@ protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
174192 }
175193 }
176194
195+ /// <summary>
196+ /// Executes queries against SQLite system tables (sqlite_master) by redirecting to IMetadataProvider.
197+ /// </summary>
198+ private DbDataReader ExecuteSystemTableQuery ( string commandTextUpper , CommandBehavior behavior )
199+ {
200+ #if DEBUG
201+ System . Diagnostics . Debug . WriteLine ( $ "[ExecuteSystemTableQuery] Query: { CommandText } ") ;
202+ System . Diagnostics . Debug . WriteLine ( $ "[ExecuteSystemTableQuery] Command (upper): { commandTextUpper } ") ;
203+ #endif
204+
205+ try
206+ {
207+ var db = Connection ! . DbInstance ! ;
208+
209+ // Check if this is a table list query
210+ if ( commandTextUpper . Contains ( "SELECT" ) && commandTextUpper . Contains ( "NAME" ) )
211+ {
212+ #if DEBUG
213+ System . Diagnostics . Debug . WriteLine ( $ "[ExecuteSystemTableQuery] Detected table list query") ;
214+ System . Diagnostics . Debug . WriteLine ( $ "[ExecuteSystemTableQuery] Database type: { db . GetType ( ) . Name } ") ;
215+ System . Diagnostics . Debug . WriteLine ( $ "[ExecuteSystemTableQuery] IMetadataProvider: { db is IMetadataProvider } ") ;
216+ #endif
217+
218+ // Redirect to IMetadataProvider.GetTables()
219+ if ( db is IMetadataProvider metadata )
220+ {
221+ var tables = metadata . GetTables ( ) ;
222+
223+ #if DEBUG
224+ System . Diagnostics . Debug . WriteLine ( $ "[ExecuteSystemTableQuery] GetTables() returned { tables ? . Count ?? 0 } tables") ;
225+ #endif
226+
227+ // Convert to the format expected by SQLite queries
228+ var results = new List < Dictionary < string , object > > ( ) ;
229+
230+ if ( tables != null && tables . Count > 0 )
231+ {
232+ foreach ( var table in tables )
233+ {
234+ #if DEBUG
235+ System . Diagnostics . Debug . WriteLine ( $ "[ExecuteSystemTableQuery] Table: { table . Name } , Type: { table . Type } ") ;
236+ #endif
237+ results . Add ( new Dictionary < string , object >
238+ {
239+ [ "name" ] = table . Name ?? string . Empty ,
240+ [ "type" ] = table . Type ?? "TABLE"
241+ } ) ;
242+ }
243+ }
244+
245+ #if DEBUG
246+ System . Diagnostics . Debug . WriteLine ( $ "[ExecuteSystemTableQuery] Returning { results . Count } rows") ;
247+ #endif
248+
249+ // Return empty result set if no tables (this is valid - new database)
250+ return new SharpCoreDBDataReader ( results , behavior ) ;
251+ }
252+ else
253+ {
254+ #if DEBUG
255+ System . Diagnostics . Debug . WriteLine ( $ "[ExecuteSystemTableQuery] ERROR: Database does not implement IMetadataProvider!") ;
256+ #endif
257+ }
258+ }
259+
260+ // Check if this is a column list query (pragma_table_info or similar)
261+ if ( commandTextUpper . Contains ( "PRAGMA" ) || commandTextUpper . Contains ( "TABLE_INFO" ) )
262+ {
263+ // Extract table name from query (simplified parsing)
264+ var tableName = ExtractTableNameFromPragma ( CommandText ! ) ;
265+
266+ if ( ! string . IsNullOrEmpty ( tableName ) && db is IMetadataProvider metadata )
267+ {
268+ var columns = metadata . GetColumns ( tableName ) ;
269+
270+ var results = new List < Dictionary < string , object > > ( ) ;
271+ foreach ( var column in columns )
272+ {
273+ results . Add ( new Dictionary < string , object >
274+ {
275+ [ "cid" ] = column . Ordinal ,
276+ [ "name" ] = column . Name ,
277+ [ "type" ] = column . DataType ,
278+ [ "notnull" ] = ! column . IsNullable ? 1 : 0 ,
279+ [ "dflt_value" ] = DBNull . Value ,
280+ [ "pk" ] = 0
281+ } ) ;
282+ }
283+
284+ return new SharpCoreDBDataReader ( results , behavior ) ;
285+ }
286+ }
287+
288+ // Fallback: Return empty result set for unsupported system queries
289+ // This is valid - don't throw an exception
290+ return new SharpCoreDBDataReader ( [ ] , behavior ) ;
291+ }
292+ catch ( Exception ex )
293+ {
294+ // Log the error but return empty result set instead of crashing
295+ System . Diagnostics . Debug . WriteLine ( $ "[SharpCoreDB] System table query failed: { ex . Message } ") ;
296+ return new SharpCoreDBDataReader ( [ ] , behavior ) ;
297+ }
298+ }
299+
300+ /// <summary>
301+ /// Extracts table name from PRAGMA table_info() or similar queries.
302+ /// </summary>
303+ private static string ? ExtractTableNameFromPragma ( string sql )
304+ {
305+ try
306+ {
307+ // Simple regex to extract table name from PRAGMA table_info('tablename')
308+ var match = System . Text . RegularExpressions . Regex . Match (
309+ sql ,
310+ @"table_info\s*\(\s*['""]?(\w+)['""]?\s*\)" ,
311+ System . Text . RegularExpressions . RegexOptions . IgnoreCase ) ;
312+
313+ if ( match . Success && match . Groups . Count > 1 )
314+ {
315+ return match . Groups [ 1 ] . Value ;
316+ }
317+
318+ // Try to extract from SELECT * FROM pragma_table_info('tablename')
319+ match = System . Text . RegularExpressions . Regex . Match (
320+ sql ,
321+ @"pragma_table_info\s*\(\s*['""]?(\w+)['""]?\s*\)" ,
322+ System . Text . RegularExpressions . RegexOptions . IgnoreCase ) ;
323+
324+ if ( match . Success && match . Groups . Count > 1 )
325+ {
326+ return match . Groups [ 1 ] . Value ;
327+ }
328+ }
329+ catch
330+ {
331+ // Ignore parsing errors
332+ }
333+
334+ return null ;
335+ }
336+
177337 /// <summary>
178338 /// Executes a SQL statement and returns the first column of the first row.
179339 /// </summary>
@@ -224,6 +384,17 @@ public override async Task<int> ExecuteNonQueryAsync(CancellationToken cancellat
224384 else
225385 await db . ExecuteSQLAsync ( CommandText ! , cancellationToken ) ;
226386
387+ // ? CRITICAL FIX: Flush data after non-query commands to ensure persistence!
388+ // Without this, INSERT/UPDATE/DELETE data only lives in memory until connection close.
389+ // This is essential for data durability - we want data on disk IMMEDIATELY.
390+ var commandUpper = CommandText ! . Trim ( ) . ToUpperInvariant ( ) ;
391+ if ( commandUpper . StartsWith ( "INSERT" ) ||
392+ commandUpper . StartsWith ( "UPDATE" ) ||
393+ commandUpper . StartsWith ( "DELETE" ) )
394+ {
395+ db . Flush ( ) ;
396+ }
397+
227398 return - 1 ;
228399 }
229400 catch ( Exception ex )
@@ -280,6 +451,13 @@ protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBeha
280451 var db = Connection ! . DbInstance ! ;
281452 var parameters = BuildParameterDictionary ( ) ;
282453
454+ // ? FIX: Intercept SQLite system table queries and redirect to IMetadataProvider
455+ var commandTextUpper = CommandText ! . ToUpperInvariant ( ) . Trim ( ) ;
456+ if ( commandTextUpper . Contains ( "SQLITE_MASTER" ) || commandTextUpper . Contains ( "SQLITE_SCHEMA" ) )
457+ {
458+ return ExecuteSystemTableQuery ( commandTextUpper , behavior ) ;
459+ }
460+
283461 // ExecuteQuery doesn't have async version, so use Task.Run
284462 var results = await Task . Run ( ( ) =>
285463 {
0 commit comments