Skip to content

Commit fb5d946

Browse files
author
LoneWandererProductions
committed
Fix stupid bug in Sqlite Wrapper
1 parent 5148fa1 commit fb5d946

2 files changed

Lines changed: 76 additions & 51 deletions

File tree

SQLiteHelper/SqliteExecute.cs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -917,10 +917,10 @@ private bool ExecuteNonQuery(string sqlQuery, bool suppress)
917917
/// <param name="checking">Shall we check the input</param>
918918
/// <returns>Success Status</returns>
919919
private bool ExecuteInsertQuery(
920-
string sqlQuery,
921-
IReadOnlyCollection<TableSet> table,
922-
Dictionary<string, TableColumns> tableInfo,
923-
bool checking)
920+
string sqlQuery,
921+
IReadOnlyCollection<TableSet> table,
922+
Dictionary<string, TableColumns> tableInfo,
923+
bool checking)
924924
{
925925
// Establish connection
926926
using var conn = GetConn();
@@ -932,50 +932,49 @@ private bool ExecuteInsertQuery(
932932
// Begin transaction
933933
using var tr = conn.BeginTransaction();
934934

935-
936935
try
937936
{
938937
using var cmd = conn.CreateCommand();
939938
cmd.Transaction = tr;
940939
cmd.CommandTimeout = SqliteConnectionConfig.TimeOut;
941940
cmd.CommandText = sqlQuery;
942941

943-
var checkCount = 0;
944-
var paramCache = new Dictionary<int, SQLiteParameter>();
945-
942+
// Syntax Checker initialization
946943
var syntax = new SqliteSyntax(SetMessage);
947944

945+
// Cache parameters to reuse objects (Optimization)
946+
var paramCache = new Dictionary<int, SQLiteParameter>();
947+
948948
foreach (var row in table)
949949
{
950+
// Syntax Check Logic
950951
if (checking)
951952
{
952-
if (checkCount >= tableInfo.Count)
953-
{
954-
checkCount = 0;
955-
}
956-
957-
var convert = tableInfo.ElementAt(checkCount).Value;
958-
if (!syntax.AdvancedSyntaxCheck(tableInfo, table, row, convert))
953+
// Pass the full schema (tableInfo) and the full batch (table)
954+
// The Syntax class now handles the column iteration internally.
955+
if (!syntax.AdvancedSyntaxCheck(tableInfo, row, table))
959956
{
960957
return false;
961958
}
962-
963-
checkCount++;
964959
}
965960

966-
cmd.Parameters.Clear(); // Ensure no leftover parameters
961+
// Clear parameters for the new row
962+
cmd.Parameters.Clear();
967963

968964
for (var i = 0; i < row.Row.Count; i++)
969965
{
970966
if (!paramCache.TryGetValue(i, out var param))
971967
{
968+
// Create parameter if it doesn't exist
972969
param = new SQLiteParameter($"{SqliteHelperResources.Param}{i}", row.Row[i]);
973970
cmd.Parameters.Add(param);
974971
paramCache[i] = param;
975972
}
976973
else
977974
{
975+
// Reuse parameter object, just update value and re-add to command
978976
param.Value = row.Row[i];
977+
cmd.Parameters.Add(param);
979978
}
980979
}
981980

@@ -986,7 +985,8 @@ private bool ExecuteInsertQuery(
986985

987986
_message = new MessageItem
988987
{
989-
Message = $"{SqliteHelperResources.SuccessExecutedLog}{sqlQuery}", Level = 2
988+
Message = $"{SqliteHelperResources.SuccessExecutedLog}{sqlQuery}",
989+
Level = 2
990990
};
991991
OnError(_message);
992992

@@ -1003,7 +1003,6 @@ private bool ExecuteInsertQuery(
10031003
return false;
10041004
}
10051005

1006-
10071006
/// <summary>
10081007
/// Update Table
10091008
/// </summary>

SqliteHelper/SqliteSyntax.cs

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@
22
* COPYRIGHT: See COPYING in the top level directory
33
* PROJECT: SqliteHelper
44
* FILE: SqliteHelper/SqLiteDataTypes.cs
5-
* PURPOSE: Enums of Types Sqlite Supports
5+
* PURPOSE: Enums of Types Sqlite Supports and Syntax Checking
66
* PROGRAMER: Peter Geinitz (Wayfarer)
77
*/
88

99
using System;
10-
using System.Collections;
1110
using System.Collections.Generic;
1211
using System.Linq;
1312

1413
namespace SqliteHelper
1514
{
15+
/// <summary>
16+
/// Handles syntax checking and data validation for SQLite operations
17+
/// </summary>
1618
internal sealed class SqliteSyntax
1719
{
1820
/// <summary>
@@ -35,35 +37,49 @@ public SqliteSyntax(EventHandler<MessageItem> setMessage = null)
3537
}
3638

3739
/// <summary>
38-
/// Basic sanity checks
40+
/// Basic sanity checks.
41+
/// Refactored to check the Entire Row against the Entire Schema.
3942
/// </summary>
4043
/// <param name="tableInfo">Headers, Data Type and Constraints of the table</param>
41-
/// <param name="table">Table Collection</param>
42-
/// <param name="row">Table Collection</param>
43-
/// <param name="convert">Table Collection</param>
44+
/// <param name="row">The specific Row we are checking</param>
45+
/// <param name="batch">The full batch of rows (needed for uniqueness checks within the batch)</param>
4446
/// <returns>true if no errors were found</returns>
45-
internal bool AdvancedSyntaxCheck(ICollection tableInfo, IEnumerable<TableSet> table, TableSet row,
46-
TableColumns convert)
47+
internal bool AdvancedSyntaxCheck(
48+
Dictionary<string, TableColumns> tableInfo,
49+
TableSet row,
50+
IEnumerable<TableSet> batch)
4751
{
48-
if (tableInfo.Count != table.First().Row.Count)
52+
// Sanity Check: Do the column counts match?
53+
if (tableInfo.Count != row.Row.Count)
4954
{
5055
LogError(SqliteHelperResources.ErrorMoreElementsToAddThanRows);
5156
return false;
5257
}
5358

54-
foreach (var rows in row.Row)
59+
// Convert dictionary values to a list to access by index
60+
// (Assuming order matches Insert logic)
61+
var schemaColumns = tableInfo.Values.ToList();
62+
63+
// Loop through each column in the row
64+
for (int i = 0; i < row.Row.Count; i++)
5565
{
56-
if (!CheckNullability(rows, convert))
66+
var value = row.Row[i];
67+
var definition = schemaColumns[i];
68+
69+
// Check Nullability
70+
if (!CheckNullability(value, definition))
5771
{
5872
return false;
5973
}
6074

61-
if (!CheckTypeCompatibility(rows, convert))
75+
// Check Data Type
76+
if (!CheckTypeCompatibility(value, definition))
6277
{
6378
return false;
6479
}
6580

66-
if (!CheckUniqueness(row, convert))
81+
// Check Uniqueness (Primary Key / Unique Constraint)
82+
if (!CheckBatchUniqueness(value, i, definition, batch))
6783
{
6884
return false;
6985
}
@@ -75,58 +91,68 @@ internal bool AdvancedSyntaxCheck(ICollection tableInfo, IEnumerable<TableSet> t
7591
/// <summary>
7692
/// Checks the nullability.
7793
/// </summary>
78-
/// <param name="rows">The rows.</param>
79-
/// <param name="convert">The convert.</param>
94+
/// <param name="value">The value to check.</param>
95+
/// <param name="convert">The column definition.</param>
8096
/// <returns>Condition fulfilled</returns>
81-
private bool CheckNullability(object rows, TableColumns convert)
97+
private bool CheckNullability(string value, TableColumns convert)
8298
{
83-
if (rows != null || convert.NotNull)
99+
// Logic Fix: Valid if value exists OR if the column allows nulls (NOT NotNull).
100+
if (!string.IsNullOrEmpty(value) || !convert.NotNull)
84101
{
85102
return true;
86103
}
87104

88-
LogError(SqliteHelperResources.ErrorNotNullAble);
105+
LogError($"{SqliteHelperResources.ErrorNotNullAble} (Column: {convert.RowId})");
89106
return false;
90107
}
91108

92109
/// <summary>
93110
/// Checks the type compatibility.
94111
/// </summary>
95-
/// <param name="rows">The rows.</param>
96-
/// <param name="convert">The convert.</param>
112+
/// <param name="value">The value string.</param>
113+
/// <param name="convert">The column definition.</param>
97114
/// <returns>Condition fulfilled</returns>
98-
private bool CheckTypeCompatibility(string rows, TableColumns convert)
115+
private bool CheckTypeCompatibility(string value, TableColumns convert)
99116
{
100-
var check = SqliteProcessing.CheckConvert(convert.DataType, rows);
117+
// If empty and nullable, skip type check
118+
if (string.IsNullOrEmpty(value)) return true;
119+
120+
var check = SqliteProcessing.CheckConvert(convert.DataType, value);
101121
if (check)
102122
{
103123
return true;
104124
}
105125

106-
LogError($"{SqliteHelperResources.ErrorWrongType} - Value: {rows}, Expected Type: {convert.DataType}");
126+
LogError($"{SqliteHelperResources.ErrorWrongType} - Value: {value}, Expected Type: {convert.DataType}");
107127
return false;
108128
}
109129

110130
/// <summary>
111-
/// Checks the uniqueness.
131+
/// Checks the uniqueness within the current batch.
112132
/// </summary>
113-
/// <param name="row">The row.</param>
114-
/// <param name="convert">The convert.</param>
115-
/// <returns></returns>
116-
private bool CheckUniqueness(TableSet row, TableColumns convert)
133+
/// <param name="value">The value to check.</param>
134+
/// <param name="columnIndex">Index of the column.</param>
135+
/// <param name="convert">The column definition.</param>
136+
/// <param name="batch">The full batch of rows.</param>
137+
/// <returns>True if unique in batch</returns>
138+
private bool CheckBatchUniqueness(string value, int columnIndex, TableColumns convert, IEnumerable<TableSet> batch)
117139
{
140+
// Only check if it is a Primary Key or explicitly Unique
118141
if (!convert.PrimaryKey && !convert.Unique)
119142
{
120143
return true;
121144
}
122145

123-
var isUnique = row.Row.Distinct().Count() == row.Row.Count;
124-
if (isUnique)
146+
// Check if this value appears more than once in this specific column index across the batch
147+
// Note: This does not check the Database itself, only the data we are about to insert.
148+
int count = batch.Count(r => r.Row.Count > columnIndex && r.Row[columnIndex] == value);
149+
150+
if (count <= 1)
125151
{
126152
return true;
127153
}
128154

129-
LogError(SqliteHelperResources.ErrorNotUnique);
155+
LogError($"{SqliteHelperResources.ErrorNotUnique} (Duplicate found in batch: {value})");
130156
return false;
131157
}
132158

0 commit comments

Comments
 (0)