Преглед изворни кода

Fixes to problems with DbReload

Kenric Nugteren пре 2 недеља
родитељ
комит
11b190c5cf
3 измењених фајлова са 154 додато и 85 уклоњено
  1. 41 23
      DbReload/DbReload/MainViewModel.cs
  2. 57 53
      DbReload/DbReload/MainWindow.xaml
  3. 56 9
      DbReload/DbReload/SqlTokenizer.cs

+ 41 - 23
DbReload/DbReload/MainViewModel.cs

@@ -1,5 +1,7 @@
+using System.Collections.ObjectModel;
 using System.Data.SQLite;
 using System.IO;
+using System.Reflection;
 using System.Windows.Threading;
 using CommunityToolkit.Mvvm.ComponentModel;
 using CommunityToolkit.Mvvm.Input;
@@ -9,15 +11,16 @@ namespace DbReload;
 
 public partial class MainViewModel : ObservableObject
 {
-    [ObservableProperty] private string _sqLiteFile = "";
-    [ObservableProperty] private string[] _logFiles = [];
+    [ObservableProperty] private string _sqLiteFile = "C:\\Development\\data\\_test\\test.dbs";
+    [ObservableProperty] private string[] _logFiles = Directory.GetFiles("C:\\Windows\\System32\\config\\systemprofile\\AppData\\Roaming\\PRSServer\\PRSDatabase", "*.sql");
     [ObservableProperty] private string _progress = "";
+    [ObservableProperty] private List<string> _log = new();
 
     [RelayCommand]
     private void CreateSQLiteFile()
     {
         OpenFileDialog dlg = new OpenFileDialog();
-        dlg.Filter = "SQLite Files (*.db)|*.db";
+        dlg.Filter = "SQLite Files (*.db,*.dbs)|*.db;*.dbs";
         if (dlg.ShowDialog() == true)
             SqLiteFile = dlg.FileName;
     }
@@ -31,13 +34,14 @@ public partial class MainViewModel : ObservableObject
         if (dlg.ShowDialog() == true)
             LogFiles = dlg.FileNames;
     }
-
-    private SQLiteConnection _connection;
     
     [RelayCommand]
     private async Task Go()
     {
         Progress = "Opening Database File";
+
+        Log.Clear();
+
         var sb = new SQLiteConnectionStringBuilder();
         sb.DataSource = SqLiteFile;
         sb.Version = 3;
@@ -46,40 +50,54 @@ public partial class MainViewModel : ObservableObject
         
         var conn = sb.ToString();
 
-        _connection = new SQLiteConnection(conn);
-        _connection.BusyTimeout = Convert.ToInt32(TimeSpan.FromMinutes(2).TotalMilliseconds);
+        using var connection = new SQLiteConnection(conn);
+        connection.BusyTimeout = Convert.ToInt32(TimeSpan.FromMinutes(2).TotalMilliseconds);
+        connection.Update += _connection_Update;
+        connection.Trace += _connection_Trace;
 
-        _connection.Open();
-        var command = new SQLiteCommand(_connection);
+        connection.Open();
+        using var command = new SQLiteCommand(connection);
         var ordered = LogFiles.OrderBy(x => x);
         foreach (var logfile in ordered)
         {
             Progress = $"Opening {Path.GetFileName(logfile)}";
-            var text = await File.ReadAllTextAsync(logfile);
-            //var statements = text.Split(";\r\n");
-            //int i = 0;
-            //foreach (var line in statements)
-            //{
-            //    await Dispatcher.CurrentDispatcher.BeginInvoke(() =>
-            //    {
-            //        Progress = "Processing {Path.GetFileName(logfile)} ({i}/{lines.Length})";
-            //    });
+            var text = await File.ReadAllTextAsync(logfile).ConfigureAwait(false);
+            var statements = SqlTokenizer.SplitStatements(text);
+            int i = 0;
+            foreach (var line in statements)
+            {
+                Progress = $"Processing {Path.GetFileName(logfile)} ({i}/{statements.Count})";
                 
-                command.CommandText = text;
+                command.CommandText = line;
                 try
                 {
-                    command.ExecuteNonQuery();
+                    await command.ExecuteNonQueryAsync();
                 }
                 catch (Exception e)
                 {
+                    Log.Add($"{Path.GetFileName(logfile)}: \"{e.Message}\" in \"{line}\"");
                     Console.WriteLine(e);
                     //throw;
                 }
                 
-            //    i++;
-            //}    
+                i++;
+            }
         }
 
+        var logFile = Path.Combine(
+            Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location) ?? "",
+            "log.txt");
+        await File.AppendAllLinesAsync(logFile, new string[] { "", $"Reload at {DateTime.Now:yyyy-MM-dd hh\\:mm\\:ss}" }.Concat(Log));
+
+        Progress = "Done";
+    }
+
+    private void _connection_Update(object sender, UpdateEventArgs e)
+    {
+    }
+
+    private void _connection_Trace(object sender, TraceEventArgs e)
+    {
+        Console.WriteLine(e.Statement);
     }
-    
 }

+ 57 - 53
DbReload/DbReload/MainWindow.xaml

@@ -6,63 +6,67 @@
         xmlns:local="clr-namespace:DbReload"
         mc:Ignorable="d"
         Title="MainWindow" Height="450" Width="800">
-        <Window.DataContext>
-            <local:MainViewModel />
-        </Window.DataContext>
-                                                   
-        <Grid>
-           <Grid.RowDefinitions>
-               <RowDefinition Height="Auto" />
-               <RowDefinition Height="*" />
-               <RowDefinition Height="Auto" />
-           </Grid.RowDefinitions>
-           <Grid.ColumnDefinitions>
-               <ColumnDefinition Width="Auto"/>
-               <ColumnDefinition Width="*"/>
-               <ColumnDefinition Width="Auto"/>
-           </Grid.ColumnDefinitions>        
-           
-           <Label
-               Grid.Row="0"
+    <Window.DataContext>
+        <local:MainViewModel />
+    </Window.DataContext>
+    <Grid Margin="4">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="*" />
+            <RowDefinition Height="Auto" />
+        </Grid.RowDefinitions>
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="Auto"/>
+            <ColumnDefinition Width="*"/>
+            <ColumnDefinition Width="Auto"/>
+        </Grid.ColumnDefinitions>        
+        
+        <Label Grid.Row="0"
                Grid.Column="0"
                Content="SQLite File" />
-           <TextBox
-               Grid.Row="0"
-               Grid.Column="1"
-               IsReadOnly="True"
-               Text="{Binding SqLiteFile}" />
-           <Button 
-               Grid.Row="0"
-               Grid.Column="2"
-               Content="Select"
-               Command="{Binding CreateSQLiteFileCommand}"/>
-           
-           <Label
-               Grid.Row="1"
+        <TextBox Grid.Row="0"
+                 Grid.Column="1"
+                 IsReadOnly="True"
+                 Text="{Binding SqLiteFile}"
+                 VerticalContentAlignment="Center"
+                 Background="LightYellow"
+                 Margin="0,0,4,4"/>
+        <Button Grid.Row="0"
+                Grid.Column="2"
+                Content="Select"
+                Command="{Binding CreateSQLiteFileCommand}"
+                Margin="0,0,0,4"
+                Padding="5"/>
+        
+        <Label Grid.Row="1"
                Grid.Column="0"
                Content="Log Folder" />
-           <ListBox
-               Grid.Row="1"
-               Grid.Column="1"
-               ItemsSource="{Binding LogFiles}" />
-           <Button 
-               Grid.Row="1"
-               Grid.Column="2"
-               Content="Select"
-               Command="{Binding SelectLogFilesCommand}"/>
-           
-           <Label
-               Grid.Row="2"
+        <ListBox Grid.Row="1"
+                 Grid.Column="1"
+                 ItemsSource="{Binding LogFiles}"
+                 Background="LightYellow"
+                 Margin="0,0,4,4"/>
+        <Button Grid.Row="1"
+                Grid.Column="2"
+                Content="Select"
+                Command="{Binding SelectLogFilesCommand}"
+                Margin="0,0,0,4"
+                Padding="5"/>
+        
+        <Label Grid.Row="2"
                Grid.Column="0"
                Content="Progress" />
-           <TextBox
-               Grid.Row="2"
-               Grid.Column="1"
-               Text="{Binding Progress}" />
-           <Button 
-               Grid.Row="2"
-               Grid.Column="2"
-               Content="Go!"
-               Command="{Binding GoCommand}"/>    
-       </Grid>
+        <TextBox Grid.Row="2"
+                 Grid.Column="1"
+                 Text="{Binding Progress}"
+                 VerticalContentAlignment="Center"
+                 IsReadOnly="True"
+                 Background="WhiteSmoke"
+                 Margin="0,0,4,0"/>
+        <Button Grid.Row="2"
+                Grid.Column="2"
+                Content="Go!"
+                Command="{Binding GoCommand}"
+                Padding="5"/>
+    </Grid>
 </Window>

+ 56 - 9
DbReload/DbReload/SqlTokenizer.cs

@@ -11,6 +11,8 @@ public static class SqlTokenizer
         var results = new List<string>();
         var sb = new StringBuilder(sql.Length);
 
+        int nested = 0;
+
         int i = 0;
         while (i < sql.Length)
         {
@@ -19,13 +21,22 @@ public static class SqlTokenizer
             // 1) Statement terminator (only when not in any special mode)
             if (c == ';')
             {
-                if (keepTerminator) sb.Append(c);
+                if(nested == 0)
+                {
+                    if (keepTerminator) sb.Append(c);
 
-                var stmt = sb.ToString().Trim();
-                if (stmt.Length > 0) results.Add(stmt);
+                    var stmt = sb.ToString().Trim();
+                    if (stmt.Length > 0) results.Add(stmt);
 
-                sb.Clear();
-                i++;
+                    sb.Clear();
+                    i++;
+                }
+                else
+                {
+                    // Don't do anything; we're still in a BEGIN block.
+                    sb.Append(c);
+                    i++;
+                }
                 continue;
             }
 
@@ -57,11 +68,47 @@ public static class SqlTokenizer
                 continue;
             }
 
-            // 6) PostgreSQL dollar-quoted string: $tag$ ... $tag$ or $$ ... $$
-            if (c == '$')
+            // // 6) PostgreSQL dollar-quoted string: $tag$ ... $tag$ or $$ ... $$
+            // if (c == '$')
+            // {
+            //     if (TryConsumeDollarQuoted(sql, ref i, sb))
+            //         continue;
+            // }
+
+            // CASE statement
+            if(c == 'C' && i + 3 < sql.Length
+                && sql[i + 1] == 'A'
+                && sql[i + 2] == 'S'
+                && sql[i + 3] == 'E')
             {
-                if (TryConsumeDollarQuoted(sql, ref i, sb))
-                    continue;
+                ++nested;
+                sb.Append("CASE");
+                i += 4;
+                continue;
+            }
+
+            // BEGIN statement
+            if(c == 'B' && i + 4 < sql.Length
+                && sql[i + 1] == 'E'
+                && sql[i + 2] == 'G'
+                && sql[i + 3] == 'I'
+                && sql[i + 4] == 'N')
+            {
+                ++nested;
+                sb.Append("BEGIN");
+                i += 5;
+                continue;
+            }
+
+            // END statement
+            if(c == 'E' && i + 2 < sql.Length
+                && sql[i + 1] == 'N'
+                && sql[i + 2] == 'D')
+            {
+                --nested;
+                sb.Append("END");
+                i += 3;
+                continue;
             }
 
             // Default: copy char