diff --git a/FAnsi.sln.DotSettings b/FAnsi.sln.DotSettings
new file mode 100644
index 00000000..a44f51d4
--- /dev/null
+++ b/FAnsi.sln.DotSettings
@@ -0,0 +1,6 @@
+
+ DB
+ FROM
+ SELECT
+ SQL
+ WHERE
\ No newline at end of file
diff --git a/FAnsiSql/DatabaseOperationArgs.cs b/FAnsiSql/DatabaseOperationArgs.cs
index 433709e6..ccbbd556 100644
--- a/FAnsiSql/DatabaseOperationArgs.cs
+++ b/FAnsiSql/DatabaseOperationArgs.cs
@@ -49,8 +49,9 @@ public DatabaseOperationArgs(IManagedTransaction transactionIfAny, int timeoutIn
///
public int ExecuteNonQuery(DbCommand cmd)
{
- return Execute(cmd, ()=>cmd.ExecuteNonQueryAsync(CancellationToken));
+ return Execute(cmd, () => cmd.ExecuteNonQueryAsync(CancellationToken));
}
+
///
/// Sets the timeout and cancellation on then runs with the
/// (if any) and blocks till the call completes.
diff --git a/FAnsiSql/Discovery/BulkCopy.cs b/FAnsiSql/Discovery/BulkCopy.cs
index 1d7c6b10..807aaded 100644
--- a/FAnsiSql/Discovery/BulkCopy.cs
+++ b/FAnsiSql/Discovery/BulkCopy.cs
@@ -149,8 +149,20 @@ protected void ConvertStringTypesToHardTypes(DataTable dt)
//if the DataColumn is part of the Primary Key of the DataTable (in memory)
//then we need to update the primary key to include the new column not the old one
- if (dt.PrimaryKey != null && dt.PrimaryKey.Contains(dataColumn))
- dt.PrimaryKey = dt.PrimaryKey.Except(new[] { dataColumn }).Union(new[] { newColumn }).ToArray();
+ if (dt.PrimaryKey != null)
+ {
+ var modified = false;
+ // Need to invoke the PrimaryKey setter to update the internal state of the DataTable, can't just modify existing array!
+ var newKey = Array.ConvertAll(dt.PrimaryKey, c =>
+ {
+ if (c != dataColumn) return c;
+
+ modified = true;
+ return newColumn;
+ });
+ if (modified)
+ dt.PrimaryKey = newKey;
+ }
var oldOrdinal = dataColumn.Ordinal;
diff --git a/FAnsiSql/Discovery/ConnectionStringDefaults/ConnectionStringKeywordAccumulator.cs b/FAnsiSql/Discovery/ConnectionStringDefaults/ConnectionStringKeywordAccumulator.cs
index 60467eb2..dc7171f6 100644
--- a/FAnsiSql/Discovery/ConnectionStringDefaults/ConnectionStringKeywordAccumulator.cs
+++ b/FAnsiSql/Discovery/ConnectionStringDefaults/ConnectionStringKeywordAccumulator.cs
@@ -86,8 +86,6 @@ public void AddOrUpdateKeyword(string keyword, string value, ConnectionStringKey
}
//now iterate all the keys we had before and add those too, if the key count doesn't change for any of them we know it's a duplicate semantically
- if (_builder.Keys == null) return null;
-
foreach (var current in _keywords)
{
var keysBefore = _builder.Keys.Count;
diff --git a/FAnsiSql/Discovery/DatabaseColumnRequest.cs b/FAnsiSql/Discovery/DatabaseColumnRequest.cs
index ab864f9d..75e9d8e7 100644
--- a/FAnsiSql/Discovery/DatabaseColumnRequest.cs
+++ b/FAnsiSql/Discovery/DatabaseColumnRequest.cs
@@ -59,7 +59,7 @@ public sealed class DatabaseColumnRequest(string columnName, DatabaseTypeRequest
///
public string? Collation { get; set; }
- public DatabaseColumnRequest(string columnName, string explicitDbType, bool allowNulls = true) : this(columnName, (DatabaseTypeRequest?)null, allowNulls)
+ public DatabaseColumnRequest(string columnName, string? explicitDbType, bool allowNulls = true) : this(columnName, (DatabaseTypeRequest?)null, allowNulls)
{
ExplicitDbType = explicitDbType;
}
@@ -69,7 +69,8 @@ public DatabaseColumnRequest(string columnName, string explicitDbType, bool allo
///
///
///
- public string GetSQLDbType(ITypeTranslater typeTranslater) => ExplicitDbType??typeTranslater.GetSQLDBTypeForCSharpType(TypeRequested);
+ public string GetSQLDbType(ITypeTranslater typeTranslater) =>
+ ExplicitDbType ?? typeTranslater.GetSQLDBTypeForCSharpType(TypeRequested);
public string GetRuntimeName() => ColumnName;
}
\ No newline at end of file
diff --git a/FAnsiSql/Discovery/DiscoveredColumn.cs b/FAnsiSql/Discovery/DiscoveredColumn.cs
index 9a6f963a..61b115e5 100644
--- a/FAnsiSql/Discovery/DiscoveredColumn.cs
+++ b/FAnsiSql/Discovery/DiscoveredColumn.cs
@@ -1,4 +1,5 @@
-using FAnsi.Discovery.QuerySyntax;
+using System;
+using FAnsi.Discovery.QuerySyntax;
using FAnsi.Naming;
using TypeGuesser;
@@ -57,14 +58,13 @@ public sealed class DiscoveredColumn(DiscoveredTable table, string name, bool al
///
public string? Format { get; set; }
- private readonly string _name = name;
private readonly IQuerySyntaxHelper _querySyntaxHelper = table.Database.Server.GetQuerySyntaxHelper();
///
/// The unqualified name of the column e.g. "MyCol"
///
///
- public string GetRuntimeName() => _querySyntaxHelper.GetRuntimeName(_name);
+ public string GetRuntimeName() => _querySyntaxHelper.GetRuntimeName(name);
///
/// The fully qualified name of the column e.g. [MyDb].dbo.[MyTable].[MyCol] or `MyDb`.`MyCol`
@@ -86,7 +86,7 @@ public string GetFullyQualifiedName() => _querySyntaxHelper.EnsureFullyQualified
/// Returns the name of the column
///
///
- public override string ToString() => _name;
+ public override string ToString() => name;
///
/// Generates a primed with the of this column. This can be used to inspect new
@@ -100,7 +100,7 @@ public string GetFullyQualifiedName() => _querySyntaxHelper.EnsureFullyQualified
///
///
///
- private bool Equals(DiscoveredColumn other) => string.Equals(_name, other._name) && Equals(Table, other.Table);
+ private bool Equals(DiscoveredColumn other) => string.Equals(name, other.ToString()) && Equals(Table, other.Table);
///
/// Based on column name and Table
@@ -120,17 +120,11 @@ public override bool Equals(object? obj)
/// Based on column name and Table
///
///
- public override int GetHashCode()
- {
- unchecked
- {
- return ((_name?.GetHashCode() ?? 0) * 397) ^ (Table?.GetHashCode() ?? 0);
- }
- }
+ public override int GetHashCode() => HashCode.Combine(name, Table);
///
/// Returns the wrapped e.g. "[MyCol]" name of the column including escaping e.g. if you wanted to name a column "][nquisitor" (which would return "[]][nquisitor]"). Use to return the full name including table/database/schema.
///
///
- public string? GetWrappedName() => Table.GetQuerySyntaxHelper().EnsureWrapped(GetRuntimeName());
+ public string GetWrappedName() => Table.GetQuerySyntaxHelper().EnsureWrapped(GetRuntimeName());
}
\ No newline at end of file
diff --git a/FAnsiSql/Discovery/DiscoveredDataType.cs b/FAnsiSql/Discovery/DiscoveredDataType.cs
index 5d6c1e25..c3de7903 100644
--- a/FAnsiSql/Discovery/DiscoveredDataType.cs
+++ b/FAnsiSql/Discovery/DiscoveredDataType.cs
@@ -81,7 +81,7 @@ public DiscoveredDataType(DbDataReader r, string sqlType, DiscoveredColumn? colu
public void Resize(int newSize, IManagedTransaction? managedTransaction = null)
{
var toReplace = GetLengthIfString();
-
+
if(newSize == toReplace)
return;
@@ -120,7 +120,7 @@ public void Resize(int numberOfDigitsBeforeDecimalPoint, int numberOfDigitsAfter
var newDataType = _column?.Table.GetQuerySyntaxHelper()
.TypeTranslater.GetSQLDBTypeForCSharpType(new DatabaseTypeRequest(typeof(decimal), null,
new DecimalSize(numberOfDigitsBeforeDecimalPoint, numberOfDigitsAfterDecimalPoint))) ??
- throw new InvalidOperationException($"Failed to calculate new DB type");
+ throw new InvalidOperationException("Failed to calculate new DB type");
AlterTypeTo(newDataType, managedTransaction);
}
@@ -155,7 +155,7 @@ public void AlterTypeTo(string newType, IManagedTransaction? managedTransaction
}
}
- SQLType = newType;
+ SQLType = newType;
}
///
diff --git a/FAnsiSql/Discovery/DiscoveredDatabase.cs b/FAnsiSql/Discovery/DiscoveredDatabase.cs
index 2cc2230b..5c1bbb83 100644
--- a/FAnsiSql/Discovery/DiscoveredDatabase.cs
+++ b/FAnsiSql/Discovery/DiscoveredDatabase.cs
@@ -84,7 +84,7 @@ public IEnumerable DiscoverTableValuedFunctions(I
/// Returns the wrapped e.g. "[MyDatabase]" name of the database including escaping e.g. if you wanted to name a database "][nquisitor" (which would return "[]][nquisitor]").
///
///
- public string? GetWrappedName() => _querySyntaxHelper.EnsureWrapped(GetRuntimeName());
+ public string GetWrappedName() => _querySyntaxHelper.EnsureWrapped(GetRuntimeName());
///
/// Creates an expectation (See ) that there is a table with the given name in the database.
@@ -127,7 +127,7 @@ public DiscoveredTable ExpectTable(string tableName, string? schema = null, Tabl
///
public bool Exists(IManagedTransaction? transaction = null)
{
- return Server.DiscoverDatabases().Any(db => db.GetRuntimeName()?.Equals(GetRuntimeName(), StringComparison.InvariantCultureIgnoreCase) == true);
+ return Server.DiscoverDatabases().Any(db => db.GetRuntimeName().Equals(GetRuntimeName(), StringComparison.InvariantCultureIgnoreCase));
}
///
@@ -303,11 +303,5 @@ public override bool Equals(object? obj)
/// Based on Server and database name
///
///
- public override int GetHashCode()
- {
- unchecked
- {
- return ((Server != null ? Server.GetHashCode() : 0) * 397) ^ (_database != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(_database) : 0);
- }
- }
+ public override int GetHashCode() => HashCode.Combine(Server, _database);
}
\ No newline at end of file
diff --git a/FAnsiSql/Discovery/DiscoveredDatabaseHelper.cs b/FAnsiSql/Discovery/DiscoveredDatabaseHelper.cs
index 59640def..bf0a23e9 100644
--- a/FAnsiSql/Discovery/DiscoveredDatabaseHelper.cs
+++ b/FAnsiSql/Discovery/DiscoveredDatabaseHelper.cs
@@ -19,7 +19,7 @@ namespace FAnsi.Discovery;
/// DBMS specific implementation of all functionality that relates to interacting with existing databases (dropping databases, creating tables, finding stored procedures etc). For
/// database creation see
///
-public abstract class DiscoveredDatabaseHelper:IDiscoveredDatabaseHelper
+public abstract class DiscoveredDatabaseHelper : IDiscoveredDatabaseHelper
{
public abstract IEnumerable ListTables(DiscoveredDatabase parent, IQuerySyntaxHelper querySyntaxHelper, DbConnection connection,
string database, bool includeViews, DbTransaction? transaction = null);
@@ -41,7 +41,7 @@ public DiscoveredTable CreateTable(CreateTableArgs args)
? args.ExplicitColumnDefinitions.ToList()
: [];
- if(args.DataTable != null)
+ if (args.DataTable != null)
{
ThrowIfObjectColumns(args.DataTable);
@@ -50,7 +50,7 @@ public DiscoveredTable CreateTable(CreateTableArgs args)
foreach (DataColumn column in args.DataTable.Columns)
{
//do we have an explicit overriding column definition?
- var overriding = customRequests.SingleOrDefault(c => c.ColumnName.Equals(column.ColumnName,StringComparison.CurrentCultureIgnoreCase));
+ var overriding = customRequests.SingleOrDefault(c => c.ColumnName.Equals(column.ColumnName, StringComparison.CurrentCultureIgnoreCase));
//yes
if (overriding != null)
@@ -84,7 +84,7 @@ public DiscoveredTable CreateTable(CreateTableArgs args)
var guesser = GetGuesser(column);
guesser.Culture = args.Culture;
- CopySettings(guesser,args);
+ CopySettings(guesser, args);
guesser.AdjustToCompensateForValues(column);
@@ -92,9 +92,9 @@ public DiscoveredTable CreateTable(CreateTableArgs args)
if (column.GetDoNotReType())
guesser.Guess.CSharpType = column.DataType;
- typeDictionary.Add(column.ColumnName,guesser);
+ typeDictionary.Add(column.ColumnName, guesser);
- columns.Add(new DatabaseColumnRequest(column.ColumnName, guesser.Guess, column.AllowDBNull) { IsPrimaryKey = args.DataTable.PrimaryKey.Contains(column)});
+ columns.Add(new DatabaseColumnRequest(column.ColumnName, guesser.Guess, column.AllowDBNull) { IsPrimaryKey = args.DataTable.PrimaryKey.Contains(column) });
}
}
}
@@ -123,7 +123,7 @@ public DiscoveredTable CreateTable(CreateTableArgs args)
var tbl = args.Database.ExpectTable(args.TableName, args.Schema);
//unless we are being asked to create it empty then upload the DataTable to it
- if(args.DataTable != null && !args.CreateEmpty)
+ if (args is { DataTable: not null, CreateEmpty: false })
{
using var bulk = tbl.BeginBulkInsert(args.Culture);
bulk.DateTimeDecider.Settings.ExplicitDateFormats = args.GuessSettings.ExplicitDateFormats;
@@ -153,7 +153,7 @@ public void ThrowIfObjectColumns(DataTable dt)
{
var objCol = dt.Columns.Cast().FirstOrDefault(static c => c.DataType == typeof(object));
- if(objCol != null)
+ if (objCol != null)
throw new NotSupportedException(
string.Format(
FAnsiStrings.DataTable_Column__0__was_of_DataType__1___this_is_not_allowed___Use_String_for_untyped_data,
@@ -174,7 +174,7 @@ public virtual string GetCreateTableSql(DiscoveredDatabase database, string tabl
bool cascadeDelete, string? schema)
{
if (string.IsNullOrWhiteSpace(tableName))
- throw new ArgumentNullException(nameof(tableName),FAnsiStrings.DiscoveredDatabaseHelper_GetCreateTableSql_Table_name_cannot_be_null);
+ throw new ArgumentNullException(nameof(tableName), FAnsiStrings.DiscoveredDatabaseHelper_GetCreateTableSql_Table_name_cannot_be_null);
var bodySql = new StringBuilder();
@@ -204,7 +204,7 @@ public virtual string GetCreateTableSql(DiscoveredDatabase database, string tabl
var pks = columns.Where(static c => c.IsPrimaryKey).ToArray();
if (pks.Length != 0)
- bodySql.Append(GetPrimaryKeyDeclarationSql(tableName, pks,syntaxHelper));
+ bodySql.Append(GetPrimaryKeyDeclarationSql(tableName, pks, syntaxHelper));
if (foreignKeyPairs != null)
{
@@ -227,7 +227,7 @@ public virtual string GetCreateTableSql(DiscoveredDatabase database, string tabl
///
///
///
- protected virtual string GetCreateTableSqlLineForColumn(DatabaseColumnRequest col, string datatype, IQuerySyntaxHelper syntaxHelper) => $"{syntaxHelper.EnsureWrapped(col.ColumnName)} {datatype} {(col.Default != MandatoryScalarFunctions.None ? $"default {syntaxHelper.GetScalarFunctionSql(col.Default)}" : "")} {(string.IsNullOrWhiteSpace(col.Collation) ? "" : $"COLLATE {col.Collation}")} {(col.AllowNulls && !col.IsPrimaryKey ? " NULL" : " NOT NULL")} {(col.IsAutoIncrement ? syntaxHelper.GetAutoIncrementKeywordIfAny() : "")}";
+ protected virtual string GetCreateTableSqlLineForColumn(DatabaseColumnRequest col, string datatype, IQuerySyntaxHelper syntaxHelper) => $"{syntaxHelper.EnsureWrapped(col.ColumnName)} {datatype} {(col.Default != MandatoryScalarFunctions.None ? $"default {syntaxHelper.GetScalarFunctionSql(col.Default)}" : "")} {(string.IsNullOrWhiteSpace(col.Collation) ? "" : $"COLLATE {col.Collation}")} {(col is { AllowNulls: true, IsPrimaryKey: false } ? " NULL" : " NOT NULL")} {(col.IsAutoIncrement ? syntaxHelper.GetAutoIncrementKeywordIfAny() : "")}";
public virtual string GetForeignKeyConstraintSql(string foreignTable, IQuerySyntaxHelper syntaxHelper,
Dictionary foreignKeyPairs, bool cascadeDelete, string? constraintName)
@@ -273,7 +273,7 @@ public void ExecuteBatchNonQuery(string sql, DbConnection conn, DbTransaction? t
ExecuteBatchNonQuery(sql, conn, transaction, out _, timeout);
}
- private static readonly string[] separator = ["\n", "\r"];
+ private static readonly string[] Separator = ["\n", "\r"];
///
/// Executes the given SQL against the database + sends GO delimited statements as separate batches
@@ -306,11 +306,11 @@ public void ExecuteBatchNonQuery(string sql, DbConnection conn, DbTransaction? t
sql += "\nGO"; // make sure last batch is executed.
try
{
- foreach (var line in sql.Split(separator, StringSplitOptions.RemoveEmptyEntries))
+ foreach (var line in sql.Split(Separator, StringSplitOptions.RemoveEmptyEntries))
{
lineNumber++;
- if (line.Trim().Equals("GO",StringComparison.CurrentCultureIgnoreCase))
+ if (line.Trim().Equals("GO", StringComparison.CurrentCultureIgnoreCase))
{
var executeSql = sqlBatch.ToString();
if (string.IsNullOrWhiteSpace(executeSql))
diff --git a/FAnsiSql/Discovery/DiscoveredServer.cs b/FAnsiSql/Discovery/DiscoveredServer.cs
index 35a4bab5..3be1439c 100644
--- a/FAnsiSql/Discovery/DiscoveredServer.cs
+++ b/FAnsiSql/Discovery/DiscoveredServer.cs
@@ -377,14 +377,10 @@ public DiscoveredDatabase CreateDatabase(string newDatabaseName)
///
///
///
- private bool Equals(DiscoveredServer other)
- {
- if (Builder == null || other.Builder == null)
- return Equals(Builder, other.Builder) && DatabaseType == other.DatabaseType;
-
+ private bool Equals(DiscoveredServer other) =>
//server is the same if they are pointed at the same server
- return string.Equals(Builder.ConnectionString, other.Builder.ConnectionString, StringComparison.OrdinalIgnoreCase) && DatabaseType == other.DatabaseType;
- }
+ DatabaseType == other.DatabaseType &&
+ string.Equals(Builder.ConnectionString, other.Builder.ConnectionString, StringComparison.OrdinalIgnoreCase);
///
/// Equality based on Builder.ConnectionString and DatabaseType
diff --git a/FAnsiSql/Discovery/DiscoveredTable.cs b/FAnsiSql/Discovery/DiscoveredTable.cs
index abd83e05..6bb01b06 100644
--- a/FAnsiSql/Discovery/DiscoveredTable.cs
+++ b/FAnsiSql/Discovery/DiscoveredTable.cs
@@ -171,7 +171,7 @@ public DataTable GetDataTable(DatabaseOperationArgs args, int topX = int.MaxValu
{
var col = dt.Columns.Add(c.GetRuntimeName());
col.AllowDBNull = c.AllowNulls;
- col.DataType = c.DataType.GetCSharpDataType();
+ col.DataType = c.DataType?.GetCSharpDataType();
}
Helper.FillDataTableWithTopX(args, this, topX, dt);
@@ -441,15 +441,15 @@ public int Insert(Dictionary toInsert, CultureInfo? cu
var syntaxHelper = GetQuerySyntaxHelper();
var server = Database.Server;
- var _parameterNames = syntaxHelper.GetParameterNamesFor(toInsert.Keys.ToArray(), static c => c.GetRuntimeName());
+ var parameterNames = syntaxHelper.GetParameterNamesFor(toInsert.Keys.ToArray(), static c => c.GetRuntimeName());
using var connection = Database.Server.GetManagedConnection(transaction);
var sql =
- $"INSERT INTO {GetFullyQualifiedName()}({string.Join(",", toInsert.Keys.Select(c => syntaxHelper.EnsureWrapped(c.GetRuntimeName())))}) VALUES ({string.Join(",", toInsert.Keys.Select(c => _parameterNames[c]))})";
+ $"INSERT INTO {GetFullyQualifiedName()}({string.Join(",", toInsert.Keys.Select(c => syntaxHelper.EnsureWrapped(c.GetRuntimeName())))}) VALUES ({string.Join(",", toInsert.Keys.Select(c => parameterNames[c]))})";
using var cmd = server.Helper.GetCommand(sql, connection.Connection, connection.Transaction);
foreach (var p in toInsert
- .Select(kvp => new { kvp, parameter = server.Helper.GetParameter(_parameterNames[kvp.Key]) })
+ .Select(kvp => new { kvp, parameter = server.Helper.GetParameter(parameterNames[kvp.Key]) })
.Select(t =>
GetQuerySyntaxHelper().GetParameter(t.parameter, t.kvp.Key, t.kvp.Value, culture)))
cmd.Parameters.Add(p);
@@ -545,16 +545,7 @@ public override bool Equals(object? obj)
/// Based on table name, schema, database and TableType
///
///
- public override int GetHashCode()
- {
- unchecked
- {
- var hashCode = StringComparer.OrdinalIgnoreCase.GetHashCode(GetSchemaWithDefaultForNull() ?? string.Empty);
- hashCode = (hashCode * 397) ^ (Database != null ? Database.GetHashCode() : 0);
- hashCode = (hashCode * 397) ^ (int)TableType;
- return hashCode;
- }
- }
+ public override int GetHashCode() => HashCode.Combine(TableName, GetSchemaWithDefaultForNull(), Database, TableType);
public DiscoveredRelationship AddForeignKey(DiscoveredColumn foreignKey, DiscoveredColumn primaryKey, bool cascadeDeletes, string? constraintName = null, DatabaseOperationArgs? args = null) => AddForeignKey(new Dictionary { { foreignKey, primaryKey } }, cascadeDeletes, constraintName, args);
diff --git a/FAnsiSql/Discovery/DiscoveredTableHelper.cs b/FAnsiSql/Discovery/DiscoveredTableHelper.cs
index d9740a6d..cb7252a9 100644
--- a/FAnsiSql/Discovery/DiscoveredTableHelper.cs
+++ b/FAnsiSql/Discovery/DiscoveredTableHelper.cs
@@ -76,7 +76,7 @@ public string ScriptTableCreation(DiscoveredTable table, bool dropPrimaryKeys, b
foreach (var c in table.DiscoverColumns())
{
- var sqlType = c.DataType.SQLType;
+ var sqlType = c.DataType?.SQLType;
if (c.IsAutoIncrement && convertIdentityToInt)
sqlType = "int";
@@ -90,7 +90,7 @@ public string ScriptTableCreation(DiscoveredTable table, bool dropPrimaryKeys, b
var fromtt = table.Database.Server.GetQuerySyntaxHelper().TypeTranslater;
var tott = toCreateTable?.Database.Server.GetQuerySyntaxHelper().TypeTranslater ?? throw new InvalidOperationException($"Unable to retrieve type translator for {toCreateTable}");
- sqlType = fromtt.TranslateSQLDBType(c.DataType.SQLType, tott);
+ sqlType = fromtt.TranslateSQLDBType(c.DataType?.SQLType, tott);
}
var colRequest = new DatabaseColumnRequest(c.GetRuntimeName(), sqlType, c.AllowNulls || dropNullability)
@@ -99,7 +99,7 @@ public string ScriptTableCreation(DiscoveredTable table, bool dropPrimaryKeys, b
IsAutoIncrement = c.IsAutoIncrement && !convertIdentityToInt
};
- colRequest.AllowNulls = colRequest.AllowNulls && !colRequest.IsAutoIncrement;
+ colRequest.AllowNulls = colRequest is { AllowNulls: true, IsAutoIncrement: false };
//if there is a collation
if (!string.IsNullOrWhiteSpace(c.Collation) && (toCreateTable == null || !isToDifferentDatabaseType))
diff --git a/FAnsiSql/Discovery/IDiscoveredTableHelper.cs b/FAnsiSql/Discovery/IDiscoveredTableHelper.cs
index 5dabb0ac..f5681d61 100644
--- a/FAnsiSql/Discovery/IDiscoveredTableHelper.cs
+++ b/FAnsiSql/Discovery/IDiscoveredTableHelper.cs
@@ -15,6 +15,7 @@ public interface IDiscoveredTableHelper
{
///
/// The table to fetch records from
+ /// How many results to retrieve
string GetTopXSqlForTable(IHasFullyQualifiedNameToo table, int topX);
IEnumerable DiscoverColumns(DiscoveredTable discoveredTable, IManagedConnection connection, string database);
diff --git a/FAnsiSql/Discovery/QuerySyntax/Aggregation/AggregateCustomLineCollection.cs b/FAnsiSql/Discovery/QuerySyntax/Aggregation/AggregateCustomLineCollection.cs
index 73d13341..de6e6a0d 100644
--- a/FAnsiSql/Discovery/QuerySyntax/Aggregation/AggregateCustomLineCollection.cs
+++ b/FAnsiSql/Discovery/QuerySyntax/Aggregation/AggregateCustomLineCollection.cs
@@ -28,37 +28,42 @@ private void Validate()
//if we have any axis bits
if (Axis == null && AxisSelect == null && AxisGroupBy == null) return;
//we must have all the axis bits
- if(AxisSelect == null || AxisGroupBy is null or null)
+ if (AxisSelect == null || AxisGroupBy == null)
throw new AggregateCustomLineCollectionException(FAnsiStrings.AggregateCustomLineCollection_Validate_AggregateCustomLineCollection_is_missing_some__but_not_all__Axis_components);
}
///
/// The single aggregate function line e.g. "count(distinct chi) as Fish,"
///
- public CustomLine? CountSelect => Lines.SingleOrDefault(static l => l.Role == CustomLineRole.CountFunction && l.LocationToInsert == QueryComponent.QueryTimeColumn);
+ public CustomLine? CountSelect => Lines.SingleOrDefault(static l =>
+ l is { Role: CustomLineRole.CountFunction, LocationToInsert: QueryComponent.QueryTimeColumn });
///
/// The (optional) single line of SELECT SQL which is the Axis join column e.g. "[MyDb]..[mytbl].[AdmissionDate] as Admt,"
///
- public CustomLine? AxisSelect => Lines.SingleOrDefault(static l => l.Role == CustomLineRole.Axis && l.LocationToInsert == QueryComponent.QueryTimeColumn);
+ public CustomLine? AxisSelect => Lines.SingleOrDefault(static l =>
+ l is { Role: CustomLineRole.Axis, LocationToInsert: QueryComponent.QueryTimeColumn });
///
/// The (optional) single line of GROUP BY SQL which matches exactly the SQL of
///
- public CustomLine? AxisGroupBy => Lines.SingleOrDefault(static l => l.LocationToInsert == QueryComponent.GroupBy && l.Role == CustomLineRole.Axis);
+ public CustomLine? AxisGroupBy => Lines.SingleOrDefault(static l =>
+ l is { LocationToInsert: QueryComponent.GroupBy, Role: CustomLineRole.Axis });
///
/// The (optional) single line of SELECT SQL which is the dynamic pivot column e.g. "[MyDb]..[mytbl].[Healthboard] as hb,"
///
- public CustomLine? PivotSelect => Lines.SingleOrDefault(static l => l.Role == CustomLineRole.Pivot && l.LocationToInsert == QueryComponent.QueryTimeColumn);
+ public CustomLine? PivotSelect => Lines.SingleOrDefault(static l =>
+ l is { Role: CustomLineRole.Pivot, LocationToInsert: QueryComponent.QueryTimeColumn });
///
/// The (optional) single line of ORDER BY SQL which restricts which records are returned when doing a dynamic pivot e.g. only dynamic pivot on the
/// top 5 drugs ordered by SUM of prescriptions
///
- public CustomLine? TopXOrderBy => Lines.SingleOrDefault(static l => l.LocationToInsert == QueryComponent.OrderBy && l.Role == CustomLineRole.TopX);
+ public CustomLine? TopXOrderBy => Lines.SingleOrDefault(static l =>
+ l is { LocationToInsert: QueryComponent.OrderBy, Role: CustomLineRole.TopX });
///
/// Returns all concatenated SQL for all between the inclusive boundaries from/to
diff --git a/FAnsiSql/Discovery/QuerySyntax/Aggregation/AggregateHelper.cs b/FAnsiSql/Discovery/QuerySyntax/Aggregation/AggregateHelper.cs
index fa2de438..9a25c488 100644
--- a/FAnsiSql/Discovery/QuerySyntax/Aggregation/AggregateHelper.cs
+++ b/FAnsiSql/Discovery/QuerySyntax/Aggregation/AggregateHelper.cs
@@ -4,7 +4,7 @@
namespace FAnsi.Discovery.QuerySyntax.Aggregation;
-public abstract class AggregateHelper:IAggregateHelper
+public abstract class AggregateHelper : IAggregateHelper
{
public string BuildAggregate(List queryLines, IQueryAxis? axisIfAny)
{
@@ -20,7 +20,7 @@ public string BuildAggregate(List queryLines, IQueryAxis? axisIfAny)
//pivot (no axis)
if (lines.AxisSelect == null)
- return BuildPivotOnlyAggregate(lines,GetPivotOnlyNonPivotColumn(lines));
+ return BuildPivotOnlyAggregate(lines, GetPivotOnlyNonPivotColumn(lines));
//pivot and axis
return BuildPivotAndAxisAggregate(lines);
@@ -28,8 +28,8 @@ public string BuildAggregate(List queryLines, IQueryAxis? axisIfAny)
private static CustomLine GetPivotOnlyNonPivotColumn(AggregateCustomLineCollection query)
{
- var nonPivotColumn = query.Lines.Where(static l => l.LocationToInsert == QueryComponent.QueryTimeColumn && l.Role == CustomLineRole.None).ToArray();
- if(nonPivotColumn.Length != 1)
+ var nonPivotColumn = query.Lines.Where(static l => l is { LocationToInsert: QueryComponent.QueryTimeColumn, Role: CustomLineRole.None }).ToArray();
+ if (nonPivotColumn.Length != 1)
throw new Exception("Pivot is only valid when there are 3 SELECT columns, an aggregate (e.g. count(*)), a pivot and a final column");
return nonPivotColumn[0];
@@ -48,7 +48,7 @@ private static CustomLine GetPivotOnlyNonPivotColumn(AggregateCustomLineCollecti
///
protected abstract string BuildAxisAggregate(AggregateCustomLineCollection query);
- protected abstract string BuildPivotOnlyAggregate(AggregateCustomLineCollection query,CustomLine nonPivotColumn);
+ protected abstract string BuildPivotOnlyAggregate(AggregateCustomLineCollection query, CustomLine nonPivotColumn);
protected abstract string BuildPivotAndAxisAggregate(AggregateCustomLineCollection query);
@@ -60,21 +60,25 @@ private static CustomLine GetPivotOnlyNonPivotColumn(AggregateCustomLineCollecti
///
///
///
- protected void WrapAxisColumnWithDatePartFunction(AggregateCustomLineCollection query, string axisColumnAlias)
+ protected void WrapAxisColumnWithDatePartFunction(AggregateCustomLineCollection query, string? axisColumnAlias)
{
- if(string.IsNullOrWhiteSpace(axisColumnAlias))
- throw new ArgumentNullException(nameof(axisColumnAlias));
+ ArgumentException.ThrowIfNullOrWhiteSpace(axisColumnAlias, nameof(axisColumnAlias));
+ if (query.Axis?.AxisIncrement == null)
+ throw new InvalidOperationException("No axis increment in query");
- var axisGroupBy = query.AxisGroupBy;
- var axisColumnWithoutAlias = query.AxisSelect.GetTextWithoutAlias(query.SyntaxHelper);
+ var axisGroupBy = query.AxisGroupBy ??
+ throw new InvalidOperationException("No axis grouping in query");
+ var axisColumnWithoutAlias = query.AxisSelect?.GetTextWithoutAlias(query.SyntaxHelper) ??
+ throw new InvalidOperationException("No axis column in query");
- var axisColumnEndedWithComma = query.AxisSelect.Text.EndsWith(',');
- query.AxisSelect.Text =
- $"{GetDatePartOfColumn(query.Axis?.AxisIncrement ?? throw new InvalidOperationException("No axis in query"), axisColumnWithoutAlias)} AS {axisColumnAlias}{(axisColumnEndedWithComma ? "," : "")}";
+ var axisColumnEndedWithComma = query.AxisSelect?.Text.EndsWith(',') == true;
+ if (query.AxisSelect != null)
+ query.AxisSelect.Text =
+ $"{GetDatePartOfColumn(query.Axis.AxisIncrement, axisColumnWithoutAlias)} AS {axisColumnAlias}{(axisColumnEndedWithComma ? "," : "")}";
var groupByEndedWithComma = axisGroupBy.Text.EndsWith(',');
axisGroupBy.Text = GetDatePartOfColumn(query.Axis.AxisIncrement, axisColumnWithoutAlias) + (groupByEndedWithComma ? "," : "");
}
- public abstract string GetDatePartOfColumn(AxisIncrement increment, string columnSql);
+ public abstract string GetDatePartOfColumn(AxisIncrement? axisIncrement, string columnSql);
}
\ No newline at end of file
diff --git a/FAnsiSql/Discovery/QuerySyntax/IQuerySyntaxHelper.cs b/FAnsiSql/Discovery/QuerySyntax/IQuerySyntaxHelper.cs
index c97cfc98..9d7d99b6 100644
--- a/FAnsiSql/Discovery/QuerySyntax/IQuerySyntaxHelper.cs
+++ b/FAnsiSql/Discovery/QuerySyntax/IQuerySyntaxHelper.cs
@@ -90,7 +90,7 @@ public interface IQuerySyntaxHelper
///
///
///
- string Escape(string sql);
+ string? Escape(string? sql);
TopXResponse HowDoWeAchieveTopX(int x);
string GetParameterDeclaration(string proposedNewParameterName, DatabaseTypeRequest request);
@@ -138,7 +138,7 @@ public interface IQuerySyntaxHelper
///
///
/// If was badly formed, blank etc
- void SplitLineIntoOuterMostMethodAndContents(string lineToSplit, out string method, out string contents);
+ void SplitLineIntoOuterMostMethodAndContents(string? lineToSplit, out string method, out string contents);
///
/// The SQL that would be valid for a CREATE TABLE statement that would result in a given column becoming auto increment e.g. "IDENTITY(1,1)"
diff --git a/FAnsiSql/Discovery/QuerySyntax/QueryComponent.cs b/FAnsiSql/Discovery/QuerySyntax/QueryComponent.cs
index e7014a6f..86e3288a 100644
--- a/FAnsiSql/Discovery/QuerySyntax/QueryComponent.cs
+++ b/FAnsiSql/Discovery/QuerySyntax/QueryComponent.cs
@@ -14,5 +14,4 @@ public enum QueryComponent
Having,
OrderBy,
Postfix //after everything else in the query (including WHERE containers and any ORDER BYs)
-
}
\ No newline at end of file
diff --git a/FAnsiSql/Discovery/QuerySyntaxHelper.cs b/FAnsiSql/Discovery/QuerySyntaxHelper.cs
index ee6ed770..ca99917d 100644
--- a/FAnsiSql/Discovery/QuerySyntaxHelper.cs
+++ b/FAnsiSql/Discovery/QuerySyntaxHelper.cs
@@ -64,7 +64,7 @@ public abstract partial class QuerySyntaxHelper(
public ITypeTranslater TypeTranslater { get; private set; } = translater;
- private readonly Dictionary factories = [];
+ private readonly Dictionary _factories = [];
public IAggregateHelper AggregateHelper { get; private set; } = aggregateHelper;
public IUpdateHelper UpdateHelper { get; set; } = updateHelper;
@@ -89,7 +89,7 @@ public static HashSet GetAllParameterNamesFromQuery(string query)
if (string.IsNullOrWhiteSpace(query))
return [];
- var toReturn = new HashSet(ParameterNameRegex.Matches(query).Cast().Select(static match => match.Groups[1].Value.Trim()), StringComparer.InvariantCultureIgnoreCase);
+ var toReturn = new HashSet(ParameterNameRegex.Matches(query).Select(static match => match.Groups[1].Value.Trim()), StringComparer.InvariantCultureIgnoreCase);
return toReturn;
}
@@ -178,7 +178,7 @@ public virtual string EnsureFullyQualified(string? databaseName, string? schema,
: //table valued functions do not support database name being in the column level selection list area of sql queries
$"{EnsureFullyQualified(databaseName, schema, tableName)}.{EnsureWrapped(GetRuntimeName(columnName))}";
- public virtual string Escape(string sql) => string.IsNullOrWhiteSpace(sql) ? sql : sql.Replace("'", "''");
+ public virtual string? Escape([NotNullIfNotNull(nameof(sql))] string? sql) => string.IsNullOrWhiteSpace(sql) ? sql : sql.Replace("'", "''");
public abstract TopXResponse HowDoWeAchieveTopX(int x);
public virtual string GetParameterDeclaration(string proposedNewParameterName, DatabaseTypeRequest request) => GetParameterDeclaration(proposedNewParameterName, TypeTranslater.GetSQLDBTypeForCSharpType(request));
@@ -224,7 +224,7 @@ public virtual bool SplitLineIntoSelectSQLAndAlias(string lineToSplit, out strin
public abstract string GetScalarFunctionSql(MandatoryScalarFunctions function);
///
- public void SplitLineIntoOuterMostMethodAndContents(string lineToSplit, out string method, out string contents)
+ public void SplitLineIntoOuterMostMethodAndContents(string? lineToSplit, out string method, out string contents)
{
if (string.IsNullOrWhiteSpace(lineToSplit))
throw new ArgumentException(
@@ -262,11 +262,7 @@ public static string MakeHeaderNameSensible(string header)
//replace anything that isn't a digit, letter or underscore with emptiness (except spaces - these will go but first...)
//also accept anything above ASCII 256
- var r = HeaderNameCharRegex();
-
- var adjustedHeader = r.Replace(header, "");
-
- var sb = new StringBuilder(adjustedHeader);
+ var sb = new StringBuilder(HeaderNameCharRegex().Replace(header, ""));
//Camel case after spaces
for (var i = 0; i < sb.Length; i++)
@@ -275,13 +271,10 @@ public static string MakeHeaderNameSensible(string header)
//and that character is a lower case letter
sb[i + 1] = char.ToUpper(sb[i + 1]);
- adjustedHeader = sb.ToString().Replace(" ", "");
+ sb.Replace(" ", "");
//if it starts with a digit (illegal) put an underscore before it
- if (StartsDigitsRe().IsMatch(adjustedHeader))
- adjustedHeader = $"_{adjustedHeader}";
-
- return adjustedHeader;
+ return char.IsAsciiDigit(sb[0]) ? $"_{sb}" : sb.ToString();
}
public string GetSensibleEntityNameFromString(string? potentiallyDodgyName)
@@ -302,7 +295,7 @@ public string GetSensibleEntityNameFromString(string? potentiallyDodgyName)
public abstract string GetAutoIncrementKeywordIfAny();
public abstract Dictionary GetSQLFunctionsDictionary();
- public bool IsBasicallyNull(object value)
+ public bool IsBasicallyNull(object? value)
{
if (value is string stringValue)
return string.IsNullOrWhiteSpace(stringValue);
@@ -328,18 +321,18 @@ public DbParameter GetParameter(DbParameter p, DiscoveredColumn discoveredColumn
{
culture ??= CultureInfo.InvariantCulture;
- if (!factories.ContainsKey(culture))
- factories.Add(culture, new TypeDeciderFactory(culture));
+ if (!_factories.ContainsKey(culture))
+ _factories.Add(culture, new TypeDeciderFactory(culture));
var tt = TypeTranslater;
- p.DbType = tt.GetDbTypeForSQLDBType(discoveredColumn.DataType.SQLType);
- var cSharpType = tt.GetCSharpTypeForSQLDBType(discoveredColumn.DataType.SQLType);
+ p.DbType = tt.GetDbTypeForSQLDBType(discoveredColumn.DataType?.SQLType);
+ var cSharpType = tt.GetCSharpTypeForSQLDBType(discoveredColumn.DataType?.SQLType);
if (IsBasicallyNull(value))
p.Value = DBNull.Value;
- else if (value is string strVal && factories[culture].IsSupported(cSharpType)) //if the input is a string and it's for a hard type e.g. TimeSpan
+ else if (value is string strVal && _factories[culture].IsSupported(cSharpType)) //if the input is a string and it's for a hard type e.g. TimeSpan
{
- var decider = factories[culture].Create(cSharpType);
+ var decider = _factories[culture].Create(cSharpType);
var o = decider.Parse(strVal);
if (o is DateTime d) o = FormatDateTimeForDbParameter(d);
@@ -444,7 +437,7 @@ public bool IsValidColumnName(string columnName, [NotNullWhen(false)] out string
protected virtual object FormatTimespanForDbParameter(TimeSpan timeSpan) => timeSpan;
#region Equality Members
- protected bool Equals(QuerySyntaxHelper other)
+ protected bool Equals(QuerySyntaxHelper? other)
{
if (other == null)
return false;
@@ -473,7 +466,7 @@ public Dictionary GetParameterNamesFor(T[] columns, Func GetParameterNamesFor(T[] columns, Func
///
///
- string GetSQLDBTypeForCSharpType(DatabaseTypeRequest request);
+ string GetSQLDBTypeForCSharpType(DatabaseTypeRequest? request);
///
/// Returns the System.Data.DbType (e.g. DbType.String) for the specified proprietary database type (e.g. "varchar(max)")
@@ -29,7 +29,7 @@ public interface ITypeTranslater
///
///
///
- DbType GetDbTypeForSQLDBType(string sqlType);
+ DbType GetDbTypeForSQLDBType(string? sqlType);
///
@@ -80,5 +80,5 @@ public interface ITypeTranslater
///
///
///
- string TranslateSQLDBType(string sqlType, ITypeTranslater destinationTypeTranslater);
+ string? TranslateSQLDBType(string? sqlType, ITypeTranslater destinationTypeTranslater);
}
\ No newline at end of file
diff --git a/FAnsiSql/Discovery/TypeTranslation/TypeTranslater.cs b/FAnsiSql/Discovery/TypeTranslation/TypeTranslater.cs
index 939df941..4cbc8e3f 100644
--- a/FAnsiSql/Discovery/TypeTranslation/TypeTranslater.cs
+++ b/FAnsiSql/Discovery/TypeTranslation/TypeTranslater.cs
@@ -53,8 +53,10 @@ protected TypeTranslater(Regex dateRegex, int maxStringWidthBeforeMax, int strin
StringWidthWhenNotSupplied = stringWidthWhenNotSupplied;
}
- public string GetSQLDBTypeForCSharpType(DatabaseTypeRequest request)
+ public string GetSQLDBTypeForCSharpType(DatabaseTypeRequest? request)
{
+ ArgumentNullException.ThrowIfNull(request);
+
var t = request.CSharpType;
if (t == typeof(bool) || t == typeof(bool?))
@@ -62,7 +64,7 @@ public string GetSQLDBTypeForCSharpType(DatabaseTypeRequest request)
if (t == typeof(byte))
return GetByteDataType();
-
+
if (t == typeof(short) || t == typeof(short) || t == typeof(ushort) || t == typeof(short?) || t == typeof(ushort?))
return GetSmallIntDataType();
@@ -98,7 +100,7 @@ public string GetSQLDBTypeForCSharpType(DatabaseTypeRequest request)
private static string GetByteDataType() => "tinyint";
- private static string GetFloatingPointDataType(DecimalSize decimalSize)
+ private static string GetFloatingPointDataType(DecimalSize? decimalSize)
{
if (decimalSize == null || decimalSize.IsEmpty)
return "decimal(20,10)";
@@ -115,7 +117,7 @@ protected string GetStringDataType(int? maxExpectedStringWidth)
if (maxExpectedStringWidth > MaxStringWidthBeforeMax)
return GetStringDataTypeWithUnlimitedWidth();
-
+
return GetStringDataTypeImpl(maxExpectedStringWidth.Value);
}
@@ -131,7 +133,7 @@ private string GetUnicodeStringDataType(int? maxExpectedStringWidth)
if (maxExpectedStringWidth > MaxStringWidthBeforeMax)
return GetUnicodeStringDataTypeWithUnlimitedWidth();
-
+
return GetUnicodeStringDataTypeImpl(maxExpectedStringWidth.Value);
}
@@ -210,8 +212,13 @@ public Type GetCSharpTypeForSQLDBType(string? sqlType) =>
public bool IsSupportedSQLDBType(string sqlType) => TryGetCSharpTypeForSQLDBType(sqlType) != null;
///
- public DbType GetDbTypeForSQLDBType(string sqlType)
+ public DbType GetDbTypeForSQLDBType(string? sqlType)
{
+ if (string.IsNullOrWhiteSpace(sqlType))
+ throw new TypeNotMappedException(string.Format(
+ FAnsiStrings
+ .TypeTranslater_GetCSharpTypeForSQLDBType_No_CSharp_type_mapping_exists_for_SQL_type___0____TypeTranslater_was___1___,
+ sqlType, GetType().Name));
if (IsBit(sqlType))
return DbType.Boolean;
@@ -233,13 +240,13 @@ public DbType GetDbTypeForSQLDBType(string sqlType)
if (IsString(sqlType))
return DbType.String;
-
+
if (IsDate(sqlType))
return DbType.DateTime;
if (IsTime(sqlType))
return DbType.Time;
-
+
if (IsByteArray(sqlType))
return DbType.Object;
@@ -252,7 +259,7 @@ public DbType GetDbTypeForSQLDBType(string sqlType)
sqlType, GetType().Name));
}
- public virtual DatabaseTypeRequest GetDataTypeRequestForSQLDBType(string sqlType)
+ public virtual DatabaseTypeRequest GetDataTypeRequestForSQLDBType(string? sqlType)
{
var cSharpType = GetCSharpTypeForSQLDBType(sqlType);
@@ -269,11 +276,10 @@ public virtual DatabaseTypeRequest GetDataTypeRequestForSQLDBType(string sqlType
if (cSharpType == typeof(TimeSpan))
lengthIfString = GetStringLengthForTimeSpan();
-
+
var request = new DatabaseTypeRequest(cSharpType, lengthIfString, digits);
- if (cSharpType == typeof(string))
- request.Unicode = IsUnicode(sqlType);
+ if (cSharpType == typeof(string) && sqlType != null) request.Unicode = IsUnicode(sqlType);
return request;
}
@@ -284,20 +290,20 @@ public virtual DatabaseTypeRequest GetDataTypeRequestForSQLDBType(string sqlType
///
///
///
- private static bool IsUnicode(string sqlType) => sqlType != null && sqlType.StartsWith("n", StringComparison.CurrentCultureIgnoreCase);
+ private static bool IsUnicode(string sqlType) => sqlType.StartsWith("n", StringComparison.OrdinalIgnoreCase);
public virtual Guesser GetGuesserFor(DiscoveredColumn discoveredColumn) => GetGuesserFor(discoveredColumn, 0);
protected Guesser GetGuesserFor(DiscoveredColumn discoveredColumn, int extraLengthPerNonAsciiCharacter)
{
- var reqType = GetDataTypeRequestForSQLDBType(discoveredColumn.DataType.SQLType);
+ var reqType = GetDataTypeRequestForSQLDBType(discoveredColumn.DataType?.SQLType);
return new Guesser(reqType)
{
ExtraLengthPerNonAsciiCharacter = extraLengthPerNonAsciiCharacter
};
}
- public virtual int GetLengthIfString(string sqlType)
+ public virtual int GetLengthIfString(string? sqlType)
{
if (string.IsNullOrWhiteSpace(sqlType))
return -1;
@@ -315,7 +321,7 @@ public virtual int GetLengthIfString(string sqlType)
return -1;
}
- public DecimalSize? GetDigitsBeforeAndAfterDecimalPointIfDecimal(string sqlType)
+ public DecimalSize? GetDigitsBeforeAndAfterDecimalPointIfDecimal(string? sqlType)
{
if (string.IsNullOrWhiteSpace(sqlType))
return null;
@@ -328,7 +334,7 @@ public virtual int GetLengthIfString(string sqlType)
return new DecimalSize(precision - scale, scale);
}
- public string TranslateSQLDBType(string sqlType, ITypeTranslater destinationTypeTranslater)
+ public string TranslateSQLDBType(string? sqlType, ITypeTranslater destinationTypeTranslater)
{
//e.g. data_type is datetime2 (i.e. Sql Server), this returns System.DateTime
var requested = GetDataTypeRequestForSQLDBType(sqlType);
diff --git a/FAnsiSql/Implementation/ImplementationManager.cs b/FAnsiSql/Implementation/ImplementationManager.cs
index 2df7a1d7..705296b6 100644
--- a/FAnsiSql/Implementation/ImplementationManager.cs
+++ b/FAnsiSql/Implementation/ImplementationManager.cs
@@ -62,7 +62,7 @@ public static IImplementation GetImplementation(DbConnection connection)
.ImplementationManager_GetImplementation_No_implementation_found_for_ADO_Net_object_of_Type__0_,
connection.GetType()));
}
- private static IImplementation GetImplementation(Func condition, string errorIfNotFound) => Instance?._implementations.FirstOrDefault(condition)??throw new ImplementationNotFoundException(errorIfNotFound);
+ private static IImplementation GetImplementation(Func condition, string errorIfNotFound) => Instance._implementations.FirstOrDefault(condition)??throw new ImplementationNotFoundException(errorIfNotFound);
///
/// Returns all currently loaded implementations or null if no implementations have been loaded
diff --git a/FAnsiSql/Implementations/MicrosoftSQL/Aggregation/MicrosoftSQLAggregateHelper.cs b/FAnsiSql/Implementations/MicrosoftSQL/Aggregation/MicrosoftSQLAggregateHelper.cs
index 46b294ff..9b2c879c 100644
--- a/FAnsiSql/Implementations/MicrosoftSQL/Aggregation/MicrosoftSQLAggregateHelper.cs
+++ b/FAnsiSql/Implementations/MicrosoftSQL/Aggregation/MicrosoftSQLAggregateHelper.cs
@@ -47,7 +47,7 @@ SELECT @currentDate
///
///
///
- public override string GetDatePartOfColumn(AxisIncrement increment, string columnSql) =>
+ public override string GetDatePartOfColumn(AxisIncrement? increment, string columnSql) =>
increment switch
{
AxisIncrement.Day =>
@@ -90,10 +90,12 @@ public string GetDatePartBasedEqualsBetweenColumns(AxisIncrement increment, stri
protected override string BuildAxisAggregate(AggregateCustomLineCollection query)
{
- var countAlias = query.CountSelect.GetAliasFromText(query.SyntaxHelper);
- var axisColumnAlias = query.AxisSelect.GetAliasFromText(query.SyntaxHelper) ?? "joinDt";
+ ArgumentNullException.ThrowIfNull(query.Axis);
- WrapAxisColumnWithDatePartFunction(query,axisColumnAlias);
+ var countAlias = query.CountSelect?.GetAliasFromText(query.SyntaxHelper);
+ var axisColumnAlias = query.AxisSelect?.GetAliasFromText(query.SyntaxHelper) ?? "joinDt";
+
+ WrapAxisColumnWithDatePartFunction(query, axisColumnAlias);
return string.Format(
@@ -130,6 +132,7 @@ ORDER BY
protected override string BuildPivotAndAxisAggregate(AggregateCustomLineCollection query)
{
+ ArgumentNullException.ThrowIfNull(query.Axis);
var syntaxHelper = query.SyntaxHelper;
var part1 = GetPivotPart1(query, out var pivotAlias, out var countAlias, out var axisColumnAlias);
@@ -246,21 +249,21 @@ ORDER BY
return part1 + part2;
}
- private string GetPivotPart1(AggregateCustomLineCollection query, out string pivotAlias, out string countAlias, out string? axisColumnAlias)
+ private string GetPivotPart1(AggregateCustomLineCollection query, out string? pivotAlias, out string? countAlias, out string? axisColumnAlias)
{
var syntaxHelper = query.SyntaxHelper;
//find the pivot column e.g. 'hb_extract AS Healthboard'
var pivotSelectLine = query.PivotSelect;
- var pivotSqlWithoutAlias = pivotSelectLine.GetTextWithoutAlias(syntaxHelper);
- pivotAlias = pivotSelectLine.GetAliasFromText(syntaxHelper);
+ var pivotSqlWithoutAlias = pivotSelectLine?.GetTextWithoutAlias(syntaxHelper);
+ pivotAlias = pivotSelectLine?.GetAliasFromText(syntaxHelper);
//ensure it has an RHS
if (string.IsNullOrWhiteSpace(pivotAlias))
pivotAlias = syntaxHelper.GetRuntimeName(pivotSqlWithoutAlias);
- var countSqlWithoutAlias = query.CountSelect.GetTextWithoutAlias(syntaxHelper);
- countAlias = query.CountSelect.GetAliasFromText(syntaxHelper);
+ var countSqlWithoutAlias = query.CountSelect?.GetTextWithoutAlias(syntaxHelper);
+ countAlias = query.CountSelect?.GetAliasFromText(syntaxHelper);
var axisColumnWithoutAlias = query.AxisSelect?.GetTextWithoutAlias(query.SyntaxHelper);
axisColumnAlias = query.AxisSelect?.GetAliasFromText(query.SyntaxHelper) ?? "joinDt";
diff --git a/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftQuerySyntaxHelper.cs b/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftQuerySyntaxHelper.cs
index 612a6fdf..c76b22df 100644
--- a/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftQuerySyntaxHelper.cs
+++ b/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftQuerySyntaxHelper.cs
@@ -87,7 +87,7 @@ 3617 when string.IsNullOrWhiteSpace(sqlE.Message) => true,
///
///
///
- private string? GetRuntimeNameWithDoubledClosingSquareBrackets(string s) => GetRuntimeName(s)?.Replace("]", "]]");
+ private string GetRuntimeNameWithDoubledClosingSquareBrackets(string s) => GetRuntimeName(s).Replace("]", "]]");
public override string EnsureFullyQualified(string? databaseName, string? schema, string tableName)
{
diff --git a/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLBulkCopy.cs b/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLBulkCopy.cs
index d41ec3a5..2a8cf64f 100644
--- a/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLBulkCopy.cs
+++ b/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLBulkCopy.cs
@@ -121,33 +121,35 @@ private Exception AttemptLineByLineInsert(Exception e, SqlBulkCopy insert, DataT
foreach (DataRow dr in dt.Rows)
try
{
- investigationOneLineAtATime.WriteToServer(new[] { dr }); //try one line
+ investigationOneLineAtATime.WriteToServer([dr]); //try one line
line++;
}
catch (Exception exception)
{
- if (BcpColIdToString(investigationOneLineAtATime, exception as SqlException, out var result, out var badMapping))
- {
- if (badMapping is null || !dt.Columns.Contains(badMapping.SourceColumn))
- return new Exception(
- string.Format(
- SR
- .MicrosoftSQLBulkCopy_AttemptLineByLineInsert_BulkInsert_failed_on_data_row__0___1_,
- line, result), e);
-
- var sourceValue = dr[badMapping.SourceColumn];
- var destColumn = TargetTableColumns.SingleOrDefault(c =>c.GetRuntimeName().Equals(badMapping.DestinationColumn));
-
- if (destColumn != null)
- return new FileLoadException(
- string.Format(SR.MicrosoftSQLBulkCopy_AttemptLineByLineInsert_BulkInsert_failed_on_data_row__0__the_complaint_was_about_source_column____1____which_had_value____2____destination_data_type_was____3____4__5_, line, badMapping.SourceColumn, sourceValue, destColumn.DataType, Environment.NewLine, result), exception);
-
- return new Exception(string.Format(SR.MicrosoftSQLBulkCopy_AttemptLineByLineInsert_BulkInsert_failed_on_data_row__0___1_, line, result), e);
- }
-
- return new FileLoadException(
- string.Format(SR.MicrosoftSQLBulkCopy_AttemptLineByLineInsert_Second_Pass_Exception__Failed_to_load_data_row__0__the_following_values_were_rejected_by_the_database___1__2__3_, line, Environment.NewLine, string.Join(Environment.NewLine,dr.ItemArray), firstPass),
- exception);
+ if (!BcpColIdToString(investigationOneLineAtATime, exception as SqlException, out var result,
+ out var badMapping))
+ return new FileLoadException(
+ string.Format(
+ SR
+ .MicrosoftSQLBulkCopy_AttemptLineByLineInsert_Second_Pass_Exception__Failed_to_load_data_row__0__the_following_values_were_rejected_by_the_database___1__2__3_,
+ line, Environment.NewLine, string.Join(Environment.NewLine, dr.ItemArray), firstPass),
+ exception);
+
+ if (badMapping is null || !dt.Columns.Contains(badMapping.SourceColumn))
+ return new Exception(
+ string.Format(
+ SR
+ .MicrosoftSQLBulkCopy_AttemptLineByLineInsert_BulkInsert_failed_on_data_row__0___1_,
+ line, result), e);
+
+ var sourceValue = dr[badMapping.SourceColumn];
+ var destColumn = TargetTableColumns.SingleOrDefault(c =>c.GetRuntimeName().Equals(badMapping.DestinationColumn));
+
+ if (destColumn != null)
+ return new FileLoadException(
+ string.Format(SR.MicrosoftSQLBulkCopy_AttemptLineByLineInsert_BulkInsert_failed_on_data_row__0__the_complaint_was_about_source_column____1____which_had_value____2____destination_data_type_was____3____4__5_, line, badMapping.SourceColumn, sourceValue, destColumn.DataType, Environment.NewLine, result), exception);
+
+ return new Exception(string.Format(SR.MicrosoftSQLBulkCopy_AttemptLineByLineInsert_BulkInsert_failed_on_data_row__0___1_, line, result), e);
}
//it worked... how!?
diff --git a/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLColumnHelper.cs b/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLColumnHelper.cs
index ba167349..6f741bbf 100644
--- a/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLColumnHelper.cs
+++ b/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLColumnHelper.cs
@@ -22,7 +22,7 @@ public string GetTopXSqlForColumn(IHasRuntimeName database, IHasFullyQualifiedNa
public string GetAlterColumnToSql(DiscoveredColumn column, string newType, bool allowNulls)
{
- if (column.DataType.SQLType != "bit" || newType == "bit")
+ if (column.DataType?.SQLType != "bit" || newType == "bit")
return
$"ALTER TABLE {column.Table.GetFullyQualifiedName()} ALTER COLUMN {column.GetWrappedName()} {newType} {(allowNulls ? "NULL" : "NOT NULL")}";
diff --git a/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLDatabaseHelper.cs b/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLDatabaseHelper.cs
index 52a00495..3d88e93f 100644
--- a/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLDatabaseHelper.cs
+++ b/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLDatabaseHelper.cs
@@ -51,23 +51,20 @@ public override IEnumerable ListTables(DiscoveredDatabase paren
public override IEnumerable ListTableValuedFunctions(DiscoveredDatabase parent, IQuerySyntaxHelper querySyntaxHelper, DbConnection connection, string database, DbTransaction? transaction = null)
{
- using (DbCommand cmd = new SqlCommand(
- $"use {querySyntaxHelper.EnsureWrapped(database)};select name,\r\n (select name from sys.schemas s where s.schema_id = o.schema_id) as schema_name\r\n from sys.objects o\r\nWHERE type_desc = 'SQL_INLINE_TABLE_VALUED_FUNCTION' OR type_desc = 'SQL_TABLE_VALUED_FUNCTION' OR type_desc ='CLR_TABLE_VALUED_FUNCTION'", (SqlConnection)connection))
+ using DbCommand cmd = new SqlCommand(
+ $"use {querySyntaxHelper.EnsureWrapped(database)};select name,\r\n (select name from sys.schemas s where s.schema_id = o.schema_id) as schema_name\r\n from sys.objects o\r\nWHERE type_desc = 'SQL_INLINE_TABLE_VALUED_FUNCTION' OR type_desc = 'SQL_TABLE_VALUED_FUNCTION' OR type_desc ='CLR_TABLE_VALUED_FUNCTION'", (SqlConnection)connection);
+ cmd.Transaction = transaction;
+ using var r = cmd.ExecuteReader();
+ while (r.Read())
{
- cmd.Transaction = transaction;
-
- using var r = cmd.ExecuteReader();
- while (r.Read())
- {
- var schema = r["schema_name"] as string;
-
- if (string.Equals("dbo", schema))
- schema = null;
- var name = r["name"].ToString();
- if (name != null)
- yield return new DiscoveredTableValuedFunction(parent, name, querySyntaxHelper, schema);
- }
+ var schema = r["schema_name"] as string;
+
+ if (string.Equals("dbo", schema))
+ schema = null;
+ var name = r["name"].ToString();
+ if (name != null)
+ yield return new DiscoveredTableValuedFunction(parent, name, querySyntaxHelper, schema);
}
}
@@ -89,7 +86,7 @@ public override IEnumerable ListStoredprocedures(DbCo
public override void DropDatabase(DiscoveredDatabase database)
{
- var userIsCurrentlyInDatabase = database.Server.GetCurrentDatabase().GetRuntimeName().Equals(database.GetRuntimeName());
+ var userIsCurrentlyInDatabase = database.Server.GetCurrentDatabase()?.GetRuntimeName().Equals(database.GetRuntimeName()) == true;
var serverConnectionBuilder = new SqlConnectionStringBuilder(database.Server.Builder.ConnectionString);
if (userIsCurrentlyInDatabase)
@@ -168,7 +165,7 @@ INNER JOIN sys.[databases] d
WHERE d.[name] = 'master' AND type = 0
""";
- string dataFolder;
+ string? dataFolder;
// Create a new server so we don't mutate database.Server and cause a whole lot of side-effects in other code, e.g. attachers
var server = database.Server;
@@ -194,12 +191,12 @@ INNER JOIN sys.[databases] d
// detach!
sql = $@"EXEC sys.sp_detach_db '{dbLiteralName}';";
- using(var cmd = new SqlCommand(sql, con))
+ using (var cmd = new SqlCommand(sql, con))
cmd.ExecuteNonQuery();
// get data-files path from SQL Server
- using(var cmd = new SqlCommand(getDefaultSqlServerDatabaseDirectory, con))
- dataFolder = (string)cmd.ExecuteScalar();
+ using (var cmd = new SqlCommand(getDefaultSqlServerDatabaseDirectory, con))
+ dataFolder = cmd.ExecuteScalar() as string;
return dataFolder == null ? null : new DirectoryInfo(dataFolder);
}
diff --git a/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLTableHelper.cs b/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLTableHelper.cs
index f4d8c2fd..9485caf1 100644
--- a/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLTableHelper.cs
+++ b/FAnsiSql/Implementations/MicrosoftSQL/MicrosoftSQLTableHelper.cs
@@ -40,7 +40,8 @@ public override IEnumerable DiscoverColumns(DiscoveredTable di
? $"{discoveredTable.GetRuntimeName()}.{r["COLUMN_NAME"]}"
: r["COLUMN_NAME"].ToString();
- var toAdd = new DiscoveredColumn(discoveredTable, columnName, isNullable)
+ var toAdd = new DiscoveredColumn(discoveredTable,
+ columnName ?? throw new InvalidOperationException("Anonymous column found"), isNullable)
{
IsAutoIncrement = Convert.ToBoolean(r["is_identity"]),
Collation = r["collation_name"] as string
@@ -56,7 +57,7 @@ public override IEnumerable DiscoverColumns(DiscoveredTable di
///
///
///
- private static string? GetObjectName(DiscoveredTable table)
+ private static string GetObjectName(DiscoveredTable table)
{
var syntax = table.GetQuerySyntaxHelper();
@@ -160,7 +161,9 @@ public override void CreatePrimaryKey(DatabaseOperationArgs args, DiscoveredTabl
{
using var connection = args.GetManagedConnection(table);
var columnHelper = GetColumnHelper();
- foreach (var alterSql in discoverColumns.Where(static dc => dc.AllowNulls).Select(col => columnHelper.GetAlterColumnToSql(col, col.DataType.SQLType, false)))
+ foreach (var alterSql in discoverColumns.Where(static dc => dc.AllowNulls).Select(col =>
+ columnHelper.GetAlterColumnToSql(col,
+ col.DataType?.SQLType ?? throw new InvalidOperationException("Missing type"), false)))
{
using var alterCmd = table.GetCommand(alterSql, connection.Connection, connection.Transaction);
args.ExecuteNonQuery(alterCmd);
@@ -249,7 +252,9 @@ public override DiscoveredRelationship[] DiscoverRelationships(DiscoveredTable t
toReturn.Add(current.Name, current);
}
- current.AddKeys(r["PKCOLUMN_NAME"].ToString(), r["FKCOLUMN_NAME"].ToString(), transaction);
+ current.AddKeys(
+ r["PKCOLUMN_NAME"].ToString() ?? throw new InvalidOperationException("Unnamed primary key column"),
+ r["FKCOLUMN_NAME"].ToString() ?? throw new InvalidOperationException("Unnamed foreign key column"), transaction);
}
}
diff --git a/FAnsiSql/Implementations/MySql/Aggregation/MySqlAggregateHelper.cs b/FAnsiSql/Implementations/MySql/Aggregation/MySqlAggregateHelper.cs
index 7fed9fb3..bb3d3caa 100644
--- a/FAnsiSql/Implementations/MySql/Aggregation/MySqlAggregateHelper.cs
+++ b/FAnsiSql/Implementations/MySql/Aggregation/MySqlAggregateHelper.cs
@@ -8,21 +8,28 @@ namespace FAnsi.Implementations.MySql.Aggregation;
public sealed class MySqlAggregateHelper : AggregateHelper
{
public static readonly MySqlAggregateHelper Instance = new();
- private MySqlAggregateHelper() { }
- private static string GetDateAxisTableDeclaration(IQueryAxis axis)
+
+ private MySqlAggregateHelper()
+ {
+ }
+
+ private static string GetDateAxisTableDeclaration(IQueryAxis? axis)
{
+ ArgumentNullException.ThrowIfNull(axis);
+
//if the axis is days then there are likely to be thousands of them but if we start adding thousands of years
//mysql date falls over with overflow exceptions
var thousands =
- axis.AxisIncrement == AxisIncrement.Day ?
- """
- JOIN
- (SELECT 0 thousands
- UNION ALL SELECT 1000 UNION ALL SELECT 2000 UNION ALL SELECT 3000
- UNION ALL SELECT 4000 UNION ALL SELECT 5000 UNION ALL SELECT 6000
- UNION ALL SELECT 7000 UNION ALL SELECT 8000 UNION ALL SELECT 9000
- ) thousands
- """ : "";
+ axis.AxisIncrement == AxisIncrement.Day
+ ? """
+ JOIN
+ (SELECT 0 thousands
+ UNION ALL SELECT 1000 UNION ALL SELECT 2000 UNION ALL SELECT 3000
+ UNION ALL SELECT 4000 UNION ALL SELECT 5000 UNION ALL SELECT 6000
+ UNION ALL SELECT 7000 UNION ALL SELECT 8000 UNION ALL SELECT 9000
+ ) thousands
+ """
+ : "";
var plusThousands = axis.AxisIncrement == AxisIncrement.Day ? "+ thousands" : "";
@@ -68,7 +75,7 @@ UNION ALL SELECT 700 UNION ALL SELECT 800 UNION ALL SELECT 900
""";
}
- public override string GetDatePartOfColumn(AxisIncrement increment, string columnSql)
+ public override string GetDatePartOfColumn(AxisIncrement? increment, string columnSql)
{
return increment switch
{
@@ -85,8 +92,8 @@ public override string GetDatePartOfColumn(AxisIncrement increment, string colum
protected override string BuildAxisAggregate(AggregateCustomLineCollection query)
{
- var countAlias = query.CountSelect.GetAliasFromText(query.SyntaxHelper);
- var axisColumnAlias = query.AxisSelect.GetAliasFromText(query.SyntaxHelper) ?? "joinDt";
+ var countAlias = query.CountSelect?.GetAliasFromText(query.SyntaxHelper);
+ var axisColumnAlias = query.AxisSelect?.GetAliasFromText(query.SyntaxHelper) ?? "joinDt";
WrapAxisColumnWithDatePartFunction(query, axisColumnAlias);
@@ -114,7 +121,7 @@ ORDER BY
string.Join(Environment.NewLine, query.Lines.Where(static c => c.LocationToInsert < QueryComponent.SELECT)),
GetDateAxisTableDeclaration(query.Axis),
- GetDatePartOfColumn(query.Axis.AxisIncrement, "dateAxis.dt"),
+ GetDatePartOfColumn(query.Axis?.AxisIncrement, "dateAxis.dt"),
countAlias,
//the entire query
@@ -126,6 +133,9 @@ ORDER BY
protected override string BuildPivotAndAxisAggregate(AggregateCustomLineCollection query)
{
+ ArgumentNullException.ThrowIfNull(query.Axis);
+ ArgumentNullException.ThrowIfNull(query.AxisSelect);
+
var axisColumnWithoutAlias = query.AxisSelect.GetTextWithoutAlias(query.SyntaxHelper);
var part1 = GetPivotPart1(query);
@@ -168,11 +178,11 @@ ORDER BY
string.Join(Environment.NewLine, query.Lines.Where(static l => l.LocationToInsert < QueryComponent.SELECT)),
GetDateAxisTableDeclaration(query.Axis),
part1,
- query.SyntaxHelper.Escape(GetDatePartOfColumn(query.Axis.AxisIncrement, "dateAxis.dt")),
+ query.SyntaxHelper.Escape(GetDatePartOfColumn(query.Axis?.AxisIncrement, "dateAxis.dt")),
string.Join(Environment.NewLine, query.Lines.Where(static c => c.LocationToInsert == QueryComponent.SELECT)),
//the from including all table joins and where but no calendar table join
- query.SyntaxHelper.Escape(GetDatePartOfColumn(query.Axis.AxisIncrement, axisColumnWithoutAlias)),
+ query.SyntaxHelper.Escape(GetDatePartOfColumn(query.Axis?.AxisIncrement, axisColumnWithoutAlias)),
//the order by (should be count so that heavy populated columns come first)
string.Join(Environment.NewLine, query.Lines.Where(static c => c.LocationToInsert is >= QueryComponent.FROM and <= QueryComponent.WHERE).Select(x => query.SyntaxHelper.Escape(x.Text)))
@@ -231,9 +241,9 @@ ORDER BY
///
private static string GetPivotPart1(AggregateCustomLineCollection query)
{
- var pivotSqlWithoutAlias = query.PivotSelect.GetTextWithoutAlias(query.SyntaxHelper);
+ var pivotSqlWithoutAlias = query.PivotSelect?.GetTextWithoutAlias(query.SyntaxHelper);
- var countSqlWithoutAlias = query.CountSelect.GetTextWithoutAlias(query.SyntaxHelper);
+ var countSqlWithoutAlias = query.CountSelect?.GetTextWithoutAlias(query.SyntaxHelper);
query.SyntaxHelper.SplitLineIntoOuterMostMethodAndContents(countSqlWithoutAlias, out var aggregateMethod,
out var aggregateParameter);
@@ -258,13 +268,15 @@ private static string GetPivotPart1(AggregateCustomLineCollection query)
//theres an explicit topX so order by it verbatim instead
var topXOrderByLine =
- query.Lines.SingleOrDefault(static c => c.LocationToInsert == QueryComponent.OrderBy && c.Role == CustomLineRole.TopX);
+ query.Lines.SingleOrDefault(static c => c is
+ { LocationToInsert: QueryComponent.OrderBy, Role: CustomLineRole.TopX });
if (topXOrderByLine != null)
orderBy = topXOrderByLine.Text;
//if theres a topX limit postfix line (See MySqlQuerySyntaxHelper.HowDoWeAchieveTopX) add that too
var topXLimitLine =
- query.Lines.SingleOrDefault(static c => c.LocationToInsert == QueryComponent.Postfix && c.Role == CustomLineRole.TopX);
+ query.Lines.SingleOrDefault(static c => c is
+ { LocationToInsert: QueryComponent.Postfix, Role: CustomLineRole.TopX });
var topXLimitSqlIfAny = topXLimitLine != null ? topXLimitLine.Text : "";
var havingSqlIfAny = string.Join(Environment.NewLine,
diff --git a/FAnsiSql/Implementations/MySql/MySqlBulkCopy.cs b/FAnsiSql/Implementations/MySql/MySqlBulkCopy.cs
index 39b41da0..7d561c43 100644
--- a/FAnsiSql/Implementations/MySql/MySqlBulkCopy.cs
+++ b/FAnsiSql/Implementations/MySql/MySqlBulkCopy.cs
@@ -39,7 +39,7 @@ public override int UploadImpl(DataTable dt)
var sb = new StringBuilder(commandPrefix, 1 << 22);
- var matches = matchedColumns.Keys.Select(column => (matchedColumns[column].DataType.SQLType, column.Ordinal)).ToArray();
+ var matches = matchedColumns.Keys.Select(column => (matchedColumns[column].DataType?.SQLType, column.Ordinal)).ToArray();
foreach (DataRow dr in dt.Rows)
{
sb.Append('(');
@@ -71,30 +71,42 @@ public override int UploadImpl(DataTable dt)
return affected;
}
- private string ConstructIndividualValue(string dataType, object value)
+ private string ConstructIndividualValue(string? dataType, object? value)
{
- dataType = dataType.ToUpper();
- dataType = BracketsRe().Replace(dataType, "").Trim();
-
- if (value is DateTime valueDateTime)
- switch (dataType)
+ if (value is DateTime valueDateTime && dataType is { Length: > 0 })
+ {
+ var dt = dataType.AsSpan().Trim();
+ switch (dt[0])
{
- case "DATE":
- return $"'{valueDateTime:yyyy-MM-dd}'";
- case "TIMESTAMP" or "DATETIME":
- return $"'{valueDateTime:yyyy-MM-dd HH:mm:ss}'";
- case "TIME":
- return $"'{valueDateTime:HH:mm:ss}'";
+ case 'd':
+ case 'D':
+ if (dt.Equals("date", StringComparison.OrdinalIgnoreCase))
+ return $"'{valueDateTime:yyyy-MM-dd}'";
+ if (dt.Equals("datetime", StringComparison.OrdinalIgnoreCase))
+ return $"'{valueDateTime:yyyy-MM-dd HH:mm:ss}'";
+
+ break;
+
+ case 't':
+ case 'T':
+ if (dt.Equals("time", StringComparison.OrdinalIgnoreCase))
+ return $"'{valueDateTime:HH:mm:ss}'";
+ if (dt.Equals("timestamp", StringComparison.OrdinalIgnoreCase))
+ return $"'{valueDateTime:yyyy-MM-dd HH:mm:ss}'";
+
+ break;
}
+ }
if (value == null || value == DBNull.Value)
return "NULL";
- return ConstructIndividualValue(dataType, value.ToString());
+ return ConstructIndividualValue(dataType, value.ToString() ?? "NULL");
}
- private string ConstructIndividualValue(string dataType, string value)
+ private string ConstructIndividualValue(string? dataType, string value)
{
+ dataType = BracketsRe().Replace(dataType?.ToUpper() ?? "", "").Trim();
return dataType switch
{
"BIT" => value,
diff --git a/FAnsiSql/Implementations/MySql/MySqlDatabaseHelper.cs b/FAnsiSql/Implementations/MySql/MySqlDatabaseHelper.cs
index 41b96ce3..e20b5d79 100644
--- a/FAnsiSql/Implementations/MySql/MySqlDatabaseHelper.cs
+++ b/FAnsiSql/Implementations/MySql/MySqlDatabaseHelper.cs
@@ -3,7 +3,6 @@
using System.Data;
using System.Data.Common;
using System.IO;
-using System.Linq;
using FAnsi.Discovery;
using FAnsi.Discovery.QuerySyntax;
using MySqlConnector;
@@ -14,7 +13,7 @@ public sealed class MySqlDatabaseHelper : DiscoveredDatabaseHelper
{
public override IEnumerable ListTableValuedFunctions(DiscoveredDatabase parent, IQuerySyntaxHelper querySyntaxHelper,
DbConnection connection, string database, DbTransaction? transaction = null) =>
- Enumerable.Empty();
+ [];
public override DiscoveredStoredprocedure[] ListStoredprocedures(DbConnectionStringBuilder builder, string database) => throw new NotImplementedException();
diff --git a/FAnsiSql/Implementations/MySql/MySqlQuerySyntaxHelper.cs b/FAnsiSql/Implementations/MySql/MySqlQuerySyntaxHelper.cs
index f2712105..56f308ea 100644
--- a/FAnsiSql/Implementations/MySql/MySqlQuerySyntaxHelper.cs
+++ b/FAnsiSql/Implementations/MySql/MySqlQuerySyntaxHelper.cs
@@ -21,7 +21,7 @@ public sealed class MySqlQuerySyntaxHelper : QuerySyntaxHelper
public override string CloseQualifier => "`";
- private MySqlQuerySyntaxHelper() : base(MySqlTypeTranslater.Instance, MySqlAggregateHelper.Instance,MySqlUpdateHelper.Instance,DatabaseType.MySql)//no specific type translation required
+ private MySqlQuerySyntaxHelper() : base(MySqlTypeTranslater.Instance, MySqlAggregateHelper.Instance, MySqlUpdateHelper.Instance, DatabaseType.MySql)//no specific type translation required
{
}
@@ -34,7 +34,7 @@ private MySqlQuerySyntaxHelper() : base(MySqlTypeTranslater.Instance, MySqlAggre
///
///
///
- private string? GetRuntimeNameWithDoubledBackticks(string s) => GetRuntimeName(s)?.Replace("`", "``");
+ private string GetRuntimeNameWithDoubledBackticks(string s) => GetRuntimeName(s).Replace("`", "``");
protected override string UnescapeWrappedNameBody(string name) => name.Replace("``", "`");
@@ -47,32 +47,32 @@ public override string EnsureFullyQualified(string? databaseName, string? schema
return $"{EnsureWrapped(databaseName)}{DatabaseTableSeparator}{EnsureWrapped(tableName)}";
}
- public override TopXResponse HowDoWeAchieveTopX(int x) => new($"LIMIT {x}",QueryComponent.Postfix);
+ public override TopXResponse HowDoWeAchieveTopX(int x) => new($"LIMIT {x}", QueryComponent.Postfix);
public override string GetParameterDeclaration(string proposedNewParameterName, string sqlType) =>
//MySql doesn't require parameter declaration you just start using it like javascript
$"/* {proposedNewParameterName} */";
- public override string Escape(string sql)
+ public override string Escape(string? sql)
{
// https://dev.mysql.com/doc/refman/8.0/en/string-literals.html
- var r = new StringBuilder(sql.Length);
- foreach (var c in sql)
+ var r = new StringBuilder(sql?.Length ?? 0);
+ foreach (var c in sql ?? "")
r.Append(c switch
{
- '\0' => "\\0",
+ '\0' => "\\0",
'\'' => "\\'",
'"' => "\"",
- '\b' => "\\b",
- '\n' => "\\n",
- '\r' => "\\r",
- '\t' => "\\t",
- '\u001a' => "\\Z",
+ '\b' => "\\b",
+ '\n' => "\\n",
+ '\r' => "\\r",
+ '\t' => "\\t",
+ '\u001a' => "\\Z",
'\\' => "\\",
// Pattern matching only:
// '%' => "\\%",
// '_' => "\\_",
- _ => $"{c}"
+ _ => $"{c}"
});
return r.ToString();
}
diff --git a/FAnsiSql/Implementations/MySql/MySqlTableHelper.cs b/FAnsiSql/Implementations/MySql/MySqlTableHelper.cs
index 08e87340..ed078f6e 100644
--- a/FAnsiSql/Implementations/MySql/MySqlTableHelper.cs
+++ b/FAnsiSql/Implementations/MySql/MySqlTableHelper.cs
@@ -72,7 +72,7 @@ public override IEnumerable DiscoverColumns(DiscoveredTable di
r.Close();
}
- private static bool YesNoToBool(object o)
+ private static bool YesNoToBool(object? o)
{
if (o is bool b)
return b;
diff --git a/FAnsiSql/Implementations/MySql/MySqlTypeTranslater.cs b/FAnsiSql/Implementations/MySql/MySqlTypeTranslater.cs
index 7b98a5c9..eb4c2aa7 100644
--- a/FAnsiSql/Implementations/MySql/MySqlTypeTranslater.cs
+++ b/FAnsiSql/Implementations/MySql/MySqlTypeTranslater.cs
@@ -23,15 +23,39 @@ private MySqlTypeTranslater() : base(DateRe(), 4000, 4000)
LongRegex = LongRe();
}
- public override int GetLengthIfString(string sqlType) =>
- sqlType.ToUpperInvariant() switch
+ public override int GetLengthIfString(string? sqlType)
+ {
+ if (!(sqlType?.Length > 0))
+ return sqlType != null && AlsoStringRegex.IsMatch(sqlType) ? int.MaxValue : base.GetLengthIfString(sqlType);
+
+ switch (sqlType[0])
{
- "TINYTEXT" => 1 << 8,
- "TEXT" => 1 << 16,
- "MEDIUMTEXT" => 1 << 24,
- "LONGTEXT" => int.MaxValue, // Should be 1<<32 but that overflows...
- _ => AlsoStringRegex.IsMatch(sqlType) ? int.MaxValue : base.GetLengthIfString(sqlType)
- };
+ case 'l':
+ case 'L':
+ if (sqlType.Equals("longtext", StringComparison.OrdinalIgnoreCase))
+ return int.MaxValue;
+
+ break;
+
+ case 'm':
+ case 'M':
+ if (sqlType.Equals("mediumtext", StringComparison.OrdinalIgnoreCase))
+ return 1 << 24;
+
+ break;
+
+ case 't':
+ case 'T':
+ if (sqlType.Equals("text", StringComparison.OrdinalIgnoreCase))
+ return 1 << 16;
+ if (sqlType.Equals("tinytext", StringComparison.OrdinalIgnoreCase))
+ return 1 << 8;
+
+ break;
+ }
+
+ return AlsoStringRegex.IsMatch(sqlType) ? int.MaxValue : base.GetLengthIfString(sqlType);
+ }
public override string GetStringDataTypeWithUnlimitedWidth() => "longtext";
diff --git a/FAnsiSql/Implementations/Oracle/Aggregation/OracleAggregateHelper.cs b/FAnsiSql/Implementations/Oracle/Aggregation/OracleAggregateHelper.cs
index 56b362f1..f1f254b0 100644
--- a/FAnsiSql/Implementations/Oracle/Aggregation/OracleAggregateHelper.cs
+++ b/FAnsiSql/Implementations/Oracle/Aggregation/OracleAggregateHelper.cs
@@ -11,7 +11,7 @@ public sealed class OracleAggregateHelper : AggregateHelper
private OracleAggregateHelper() {}
protected override IQuerySyntaxHelper GetQuerySyntaxHelper() => OracleQuerySyntaxHelper.Instance;
- public override string GetDatePartOfColumn(AxisIncrement increment, string columnSql) =>
+ public override string GetDatePartOfColumn(AxisIncrement? increment, string columnSql) =>
increment switch
{
AxisIncrement.Day => columnSql,
@@ -29,11 +29,11 @@ private static string GetDateAxisTableDeclaration(IQueryAxis axis)
var startDateSql =
//is it a date in some format or other?
- DateTime.TryParse(axis.StartDate.Trim('\'', '"'), out var start)
+ DateTime.TryParse(axis.StartDate?.Trim('\'', '"'), out var start)
? $"to_date('{start:yyyyMMdd}','yyyymmdd')"
: $"to_date(to_char({axis.StartDate}, 'YYYYMMDD'), 'yyyymmdd')"; //assume its some Oracle specific syntax that results in a date
- var endDateSql = DateTime.TryParse(axis.EndDate.Trim('\'', '"'), out var end)
+ var endDateSql = DateTime.TryParse(axis.EndDate?.Trim('\'', '"'), out var end)
? $"to_date('{end:yyyyMMdd}','yyyymmdd')"
: $"to_date(to_char({axis.EndDate}, 'YYYYMMDD'), 'yyyymmdd')"; //assume its some Oracle specific syntax that results in a date e.g. CURRENT_TIMESTAMP
@@ -81,6 +81,8 @@ from dual
protected override string BuildAxisAggregate(AggregateCustomLineCollection query)
{
+ ArgumentNullException.ThrowIfNull(query.Axis);
+
//we are trying to produce something like this:
/*
with calendar as (
@@ -100,8 +102,8 @@ group by
dt
order by dt*/
- var countAlias = query.CountSelect.GetAliasFromText(query.SyntaxHelper);
- var axisColumnAlias = query.AxisSelect.GetAliasFromText(query.SyntaxHelper) ?? "joinDt";
+ var countAlias = query.CountSelect?.GetAliasFromText(query.SyntaxHelper);
+ var axisColumnAlias = query.AxisSelect?.GetAliasFromText(query.SyntaxHelper) ?? "joinDt";
WrapAxisColumnWithDatePartFunction(query, axisColumnAlias);
diff --git a/FAnsiSql/Implementations/Oracle/OracleBulkCopy.cs b/FAnsiSql/Implementations/Oracle/OracleBulkCopy.cs
index 2ba62fa7..a598c16d 100644
--- a/FAnsiSql/Implementations/Oracle/OracleBulkCopy.cs
+++ b/FAnsiSql/Implementations/Oracle/OracleBulkCopy.cs
@@ -44,8 +44,12 @@ public override int UploadImpl(DataTable dt)
foreach (var (dataColumn, discoveredColumn) in mapping)
{
var p = _server.AddParameterWithValueToCommand(parameterNames[dataColumn], cmd, DBNull.Value);
+ if (discoveredColumn.DataType?.SQLType == null)
+ continue;
+
p.DbType = tt.GetDbTypeForSQLDBType(discoveredColumn.DataType.SQLType);
+ // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (p.DbType)
{
case DbType.DateTime:
diff --git a/FAnsiSql/Implementations/Oracle/OracleQuerySyntaxHelper.cs b/FAnsiSql/Implementations/Oracle/OracleQuerySyntaxHelper.cs
index 62aaa3d0..2f3007c9 100644
--- a/FAnsiSql/Implementations/Oracle/OracleQuerySyntaxHelper.cs
+++ b/FAnsiSql/Implementations/Oracle/OracleQuerySyntaxHelper.cs
@@ -31,7 +31,9 @@ private OracleQuerySyntaxHelper() : base(OracleTypeTranslater.Instance, OracleAg
{
var answer = base.GetRuntimeName(s);
- return string.IsNullOrWhiteSpace(answer) ? s :
+ return string.IsNullOrWhiteSpace(answer)
+ ? s
+ :
//upper it because oracle loves uppercase stuff
answer.Trim('"').ToUpper();
}
@@ -82,9 +84,7 @@ protected override object FormatTimespanForDbParameter(TimeSpan timeSpan) =>
//Value must be a DateTime even if DBParameter is of Type DbType.Time
Convert.ToDateTime(timeSpan.ToString());
- private static readonly HashSet ReservedWords = new(new[]
- {
-
+ private static readonly HashSet ReservedWords = new([
"ACCESS",
"ACCOUNT",
"ACTIVATE",
@@ -565,6 +565,6 @@ protected override object FormatTimespanForDbParameter(TimeSpan timeSpan) =>
"XID",
"YEAR",
"ZONE"
- }, StringComparer.CurrentCultureIgnoreCase);
+ ], StringComparer.CurrentCultureIgnoreCase);
}
\ No newline at end of file
diff --git a/FAnsiSql/Implementations/Oracle/OracleTypeTranslater.cs b/FAnsiSql/Implementations/Oracle/OracleTypeTranslater.cs
index 87e9deff..efc6986e 100644
--- a/FAnsiSql/Implementations/Oracle/OracleTypeTranslater.cs
+++ b/FAnsiSql/Implementations/Oracle/OracleTypeTranslater.cs
@@ -59,7 +59,9 @@ protected override bool IsString(string sqlType) =>
protected override bool IsFloatingPoint(string sqlType) => base.IsFloatingPoint(sqlType) || AlsoFloatingPointRegex.IsMatch(sqlType);
- public override int GetLengthIfString(string sqlType) => AlsoStringRegex.IsMatch(sqlType) ? int.MaxValue : base.GetLengthIfString(sqlType);
+ public override int GetLengthIfString(string? sqlType) => sqlType != null && AlsoStringRegex.IsMatch(sqlType)
+ ? int.MaxValue
+ : base.GetLengthIfString(sqlType);
protected override bool IsSmallInt(string sqlType) =>
//yup you ask for one of these, you will get a NUMBER(38) https://docs.oracle.com/cd/A58617_01/server.804/a58241/ch5.htm
diff --git a/FAnsiSql/Implementations/PostgreSql/Aggregation/PostgreSqlAggregateHelper.cs b/FAnsiSql/Implementations/PostgreSql/Aggregation/PostgreSqlAggregateHelper.cs
index 2bf0d2cc..bbe31990 100644
--- a/FAnsiSql/Implementations/PostgreSql/Aggregation/PostgreSqlAggregateHelper.cs
+++ b/FAnsiSql/Implementations/PostgreSql/Aggregation/PostgreSqlAggregateHelper.cs
@@ -22,10 +22,10 @@ protected override string BuildAxisAggregate(AggregateCustomLineCollection query
_ => throw new ArgumentOutOfRangeException(nameof(query),$"Invalid AxisIncrement {query.Axis?.AxisIncrement}")
};
- var countAlias = query.CountSelect.GetAliasFromText(query.SyntaxHelper);
- var axisColumnAlias = query.AxisSelect.GetAliasFromText(query.SyntaxHelper) ?? "joinDt";
+ var countAlias = query.CountSelect?.GetAliasFromText(query.SyntaxHelper);
+ var axisColumnAlias = query.AxisSelect?.GetAliasFromText(query.SyntaxHelper) ?? "joinDt";
- WrapAxisColumnWithDatePartFunction(query,axisColumnAlias);
+ WrapAxisColumnWithDatePartFunction(query, axisColumnAlias);
var sql =
string.Format("""
@@ -63,7 +63,7 @@ ORDER BY
protected override string BuildPivotAndAxisAggregate(AggregateCustomLineCollection query) => throw new NotImplementedException();
- public override string GetDatePartOfColumn(AxisIncrement increment, string columnSql) =>
+ public override string GetDatePartOfColumn(AxisIncrement? increment, string columnSql) =>
increment switch
{
AxisIncrement.Day => $"{columnSql}::date",
diff --git a/FAnsiSql/Implementations/PostgreSql/PostgreSqlDatabaseHelper.cs b/FAnsiSql/Implementations/PostgreSql/PostgreSqlDatabaseHelper.cs
index 00f29bee..75150317 100644
--- a/FAnsiSql/Implementations/PostgreSql/PostgreSqlDatabaseHelper.cs
+++ b/FAnsiSql/Implementations/PostgreSql/PostgreSqlDatabaseHelper.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Data.Common;
using System.IO;
-using System.Linq;
using FAnsi.Discovery;
using FAnsi.Discovery.QuerySyntax;
using Npgsql;
@@ -77,11 +76,11 @@ public override IEnumerable ListTables(DiscoveredDatabase paren
public override IEnumerable ListTableValuedFunctions(DiscoveredDatabase parent, IQuerySyntaxHelper querySyntaxHelper,
DbConnection connection, string database, DbTransaction? transaction = null) =>
- Enumerable.Empty();
+ [];
public override DiscoveredStoredprocedure[]
ListStoredprocedures(DbConnectionStringBuilder builder, string database) =>
- Array.Empty();
+ [];
public override IDiscoveredTableHelper GetTableHelper() => PostgreSqlTableHelper.Instance;
@@ -120,7 +119,7 @@ FROM pg_stat_activity
protected override string GetCreateTableSqlLineForColumn(DatabaseColumnRequest col, string datatype, IQuerySyntaxHelper syntaxHelper) =>
//Collations generally have to be in quotes (unless maybe they are very weird user generated ones?)
- $"{syntaxHelper.EnsureWrapped(col.ColumnName)} {datatype} {(col.Default != MandatoryScalarFunctions.None ? $"default {syntaxHelper.GetScalarFunctionSql(col.Default)}" : "")} {(string.IsNullOrWhiteSpace(col.Collation) ? "" : $"COLLATE \"{col.Collation.Trim('"')}\"")} {(col.AllowNulls && !col.IsPrimaryKey ? " NULL" : " NOT NULL")} {(col.IsAutoIncrement ? syntaxHelper.GetAutoIncrementKeywordIfAny() : "")}";
+ $"{syntaxHelper.EnsureWrapped(col.ColumnName)} {datatype} {(col.Default != MandatoryScalarFunctions.None ? $"default {syntaxHelper.GetScalarFunctionSql(col.Default)}" : "")} {(string.IsNullOrWhiteSpace(col.Collation) ? "" : $"COLLATE \"{col.Collation.Trim('"')}\"")} {(col is { AllowNulls: true, IsPrimaryKey: false } ? " NULL" : " NOT NULL")} {(col.IsAutoIncrement ? syntaxHelper.GetAutoIncrementKeywordIfAny() : "")}";
public override DirectoryInfo Detach(DiscoveredDatabase database) => throw new NotImplementedException();
diff --git a/FAnsiSql/Implementations/PostgreSql/PostgreSqlServerHelper.cs b/FAnsiSql/Implementations/PostgreSql/PostgreSqlServerHelper.cs
index c65ffe55..7374ef75 100644
--- a/FAnsiSql/Implementations/PostgreSql/PostgreSqlServerHelper.cs
+++ b/FAnsiSql/Implementations/PostgreSql/PostgreSqlServerHelper.cs
@@ -47,7 +47,7 @@ public override void CreateDatabase(DbConnectionStringBuilder builder, IHasRunti
public override string? GetExplicitPasswordIfAny(DbConnectionStringBuilder builder) => ((NpgsqlConnectionStringBuilder)builder).Password;
- public override Version? GetVersion(DiscoveredServer server)
+ public override Version GetVersion(DiscoveredServer server)
{
using var con = new NpgsqlConnection(server.Builder.ConnectionString);
con.Open();
diff --git a/FAnsiSql/Implementations/PostgreSql/PostgreSqlSyntaxHelper.cs b/FAnsiSql/Implementations/PostgreSql/PostgreSqlSyntaxHelper.cs
index b87ab6c8..9a5a1bdf 100644
--- a/FAnsiSql/Implementations/PostgreSql/PostgreSqlSyntaxHelper.cs
+++ b/FAnsiSql/Implementations/PostgreSql/PostgreSqlSyntaxHelper.cs
@@ -45,7 +45,7 @@ protected override object FormatDateTimeForDbParameter(DateTime dateTime) =>
///
///
///
- private string? GetRuntimeNameWithDoubledDoubleQuotes(string s) => GetRuntimeName(s)?.Replace("\"", "\"\"");
+ private string GetRuntimeNameWithDoubledDoubleQuotes(string s) => GetRuntimeName(s).Replace("\"", "\"\"");
protected override string UnescapeWrappedNameBody(string name) => name.Replace("\"\"", "\"");
diff --git a/FAnsiSql/Implementations/PostgreSql/PostgreSqlTableHelper.cs b/FAnsiSql/Implementations/PostgreSql/PostgreSqlTableHelper.cs
index a03efe7b..2a3201ec 100644
--- a/FAnsiSql/Implementations/PostgreSql/PostgreSqlTableHelper.cs
+++ b/FAnsiSql/Implementations/PostgreSql/PostgreSqlTableHelper.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Configuration.Internal;
using System.Data;
using System.Data.Common;
using System.Globalization;
diff --git a/Tests/FAnsiTests/Aggregation/CalendarWithPivotAggregationTests.cs b/Tests/FAnsiTests/Aggregation/CalendarWithPivotAggregationTests.cs
index 742b85a9..1f973593 100644
--- a/Tests/FAnsiTests/Aggregation/CalendarWithPivotAggregationTests.cs
+++ b/Tests/FAnsiTests/Aggregation/CalendarWithPivotAggregationTests.cs
@@ -58,17 +58,17 @@ public void Test_Calendar_WithPivot(DatabaseType type, bool easy)
//pivot columns should ordered by sum of pivot values (T has the highest followed by E...)
- /*joinDt T E&, %a' mp;E F G
- 2001 3 1 0 1
- 2002 2 1 2 0
- 2003 2 0 0 0
- 2004 0 0 0 0
- 2005 0 1 0 0
- 2006 0 0 0 0
- 2007 0 0 0 0
- 2008 0 0 0 0
- 2009 0 0 0 0
- 2010 0 0 0 0
+ /*joinDt T E&, %a' mp;E F G
+ 2001 3 1 0 1
+ 2002 2 1 2 0
+ 2003 2 0 0 0
+ 2004 0 0 0 0
+ 2005 0 1 0 0
+ 2006 0 0 0 0
+ 2007 0 0 0 0
+ 2008 0 0 0 0
+ 2009 0 0 0 0
+ 2010 0 0 0 0
*/
Assert.That(dt.Rows, Has.Count.EqualTo(10)); //there are 10 years between 2001 and 2010 even though not all years are represented in the data
diff --git a/Tests/FAnsiTests/Aggregation/PivotAggregationTests.cs b/Tests/FAnsiTests/Aggregation/PivotAggregationTests.cs
index 873a16da..a88e1fcd 100644
--- a/Tests/FAnsiTests/Aggregation/PivotAggregationTests.cs
+++ b/Tests/FAnsiTests/Aggregation/PivotAggregationTests.cs
@@ -34,11 +34,11 @@ public void Test_PivotOnlyCount(DatabaseType type)
con.Open();
//Expected Test Results:
/*
- Cat 2001-01-01 00:00:00.0000000 2002-01-01 00:00:00.0000000 2002-02-01 00:00:00.0000000 2002-03-02 00:00:00.0000000 2003-01-01 00:00:00.0000000 2003-04-02 00:00:00.0000000 2005-01-01 00:00:00.0000000 2001-01-02 00:00:00.0000000
- E&, %a' mp;E 1 1 0 0 0 0 1 0
- F 0 2 0 0 0 0 0 0
- G 1 0 0 0 0 0 0 0
- T 2 0 1 1 1 1 0 1
+ Cat 2001-01-01 00:00:00.0000000 2002-01-01 00:00:00.0000000 2002-02-01 00:00:00.0000000 2002-03-02 00:00:00.0000000 2003-01-01 00:00:00.0000000 2003-04-02 00:00:00.0000000 2005-01-01 00:00:00.0000000 2001-01-02 00:00:00.0000000
+ E&, %a' mp;E 1 1 0 0 0 0 1 0
+ F 0 2 0 0 0 0 0 0
+ G 1 0 0 0 0 0 0 0
+ T 2 0 1 1 1 1 0 1
*/
var cmd = svr.GetCommand(sql, con);
diff --git a/Tests/FAnsiTests/CrossPlatformTests.cs b/Tests/FAnsiTests/CrossPlatformTests.cs
index 56dbbd4a..65e592d1 100644
--- a/Tests/FAnsiTests/CrossPlatformTests.cs
+++ b/Tests/FAnsiTests/CrossPlatformTests.cs
@@ -15,31 +15,31 @@
namespace FAnsiTests;
-public sealed class CrossPlatformTests:DatabaseTests
+public sealed class CrossPlatformTests : DatabaseTests
{
- [TestCaseSource(typeof(All),nameof(All.DatabaseTypes))]
+ [TestCaseSource(typeof(All), nameof(All.DatabaseTypes))]
public void TestTableCreation_NullTableName(DatabaseType type)
{
var db = GetTestDatabase(type);
- Assert.Throws(() => db.CreateTable("",new DataTable()));
+ Assert.Throws(() => db.CreateTable("", new DataTable()));
}
- [TestCase(DatabaseType.MicrosoftSQLServer,"01/01/2007 00:00:00")]
- [TestCase(DatabaseType.MySql,"1/1/2007 00:00:00")]
- [TestCase(DatabaseType.MySql,"01/01/2007 00:00:00")]
- [TestCase(DatabaseType.Oracle,"01/01/2007 00:00:00")]
- [TestCase(DatabaseType.MicrosoftSQLServer,"2007-01-01 00:00:00")]
- [TestCase(DatabaseType.MySql,"2007-01-01 00:00:00")]
- [TestCase(DatabaseType.Oracle,"2007-01-01 00:00:00")]
- [TestCase(DatabaseType.PostgreSql,"01/01/2007 00:00:00")]
- [TestCase(DatabaseType.PostgreSql,"2007-01-01 00:00:00")]
- public void DateColumnTests_NoTime(DatabaseType type,object input)
+ [TestCase(DatabaseType.MicrosoftSQLServer, "01/01/2007 00:00:00")]
+ [TestCase(DatabaseType.MySql, "1/1/2007 00:00:00")]
+ [TestCase(DatabaseType.MySql, "01/01/2007 00:00:00")]
+ [TestCase(DatabaseType.Oracle, "01/01/2007 00:00:00")]
+ [TestCase(DatabaseType.MicrosoftSQLServer, "2007-01-01 00:00:00")]
+ [TestCase(DatabaseType.MySql, "2007-01-01 00:00:00")]
+ [TestCase(DatabaseType.Oracle, "2007-01-01 00:00:00")]
+ [TestCase(DatabaseType.PostgreSql, "01/01/2007 00:00:00")]
+ [TestCase(DatabaseType.PostgreSql, "2007-01-01 00:00:00")]
+ public void DateColumnTests_NoTime(DatabaseType type, object input)
{
var db = GetTestDatabase(type);
- var tbl = db.CreateTable("MyTable",[new DatabaseColumnRequest("MyDate",new DatabaseTypeRequest(typeof(DateTime)))]);
+ var tbl = db.CreateTable("MyTable", [new DatabaseColumnRequest("MyDate", new DatabaseTypeRequest(typeof(DateTime)))]);
- tbl.Insert(new Dictionary { { "MyDate",input } });
+ tbl.Insert(new Dictionary { { "MyDate", input } });
using (var blk = tbl.BeginBulkInsert())
{
@@ -51,31 +51,31 @@ public void DateColumnTests_NoTime(DatabaseType type,object input)
}
var result = tbl.GetDataTable();
- var expectedDate = new DateTime(2007,1,1);
+ var expectedDate = new DateTime(2007, 1, 1);
Assert.Multiple(() =>
{
- Assert.That(result.Rows[0][0],Is.EqualTo(expectedDate));
- Assert.That(result.Rows[1][0],Is.EqualTo(expectedDate));
+ Assert.That(result.Rows[0][0], Is.EqualTo(expectedDate));
+ Assert.That(result.Rows[1][0], Is.EqualTo(expectedDate));
});
}
- [TestCase(DatabaseType.MicrosoftSQLServer,"2/28/1993 5:36:27 AM","en-US")]
- [TestCase(DatabaseType.MySql,"2/28/1993 5:36:27 AM","en-US")]
- [TestCase(DatabaseType.Oracle,"2/28/1993 5:36:27 AM","en-US")]
- [TestCase(DatabaseType.MicrosoftSQLServer,"28/2/1993 5:36:27 AM","en-GB")]
- [TestCase(DatabaseType.MySql,"28/2/1993 5:36:27 AM","en-GB")]
- [TestCase(DatabaseType.Oracle,"28/2/1993 5:36:27 AM","en-GB")]
- [TestCase(DatabaseType.PostgreSql,"2/28/1993 5:36:27 AM","en-US")]
- [TestCase(DatabaseType.PostgreSql,"28/2/1993 5:36:27 AM","en-GB")]
- public void DateColumnTests_UkUsFormat_Explicit(DatabaseType type,object input,string culture)
+ [TestCase(DatabaseType.MicrosoftSQLServer, "2/28/1993 5:36:27 AM", "en-US")]
+ [TestCase(DatabaseType.MySql, "2/28/1993 5:36:27 AM", "en-US")]
+ [TestCase(DatabaseType.Oracle, "2/28/1993 5:36:27 AM", "en-US")]
+ [TestCase(DatabaseType.MicrosoftSQLServer, "28/2/1993 5:36:27 AM", "en-GB")]
+ [TestCase(DatabaseType.MySql, "28/2/1993 5:36:27 AM", "en-GB")]
+ [TestCase(DatabaseType.Oracle, "28/2/1993 5:36:27 AM", "en-GB")]
+ [TestCase(DatabaseType.PostgreSql, "2/28/1993 5:36:27 AM", "en-US")]
+ [TestCase(DatabaseType.PostgreSql, "28/2/1993 5:36:27 AM", "en-GB")]
+ public void DateColumnTests_UkUsFormat_Explicit(DatabaseType type, object input, string culture)
{
var db = GetTestDatabase(type);
- var tbl = db.CreateTable("MyTable",[new DatabaseColumnRequest("MyDate",new DatabaseTypeRequest(typeof(DateTime)))]);
+ var tbl = db.CreateTable("MyTable", [new DatabaseColumnRequest("MyDate", new DatabaseTypeRequest(typeof(DateTime)))]);
var cultureInfo = new CultureInfo(culture);
//basic insert
- tbl.Insert(new Dictionary { { "MyDate",input } },cultureInfo);
+ tbl.Insert(new Dictionary { { "MyDate", input } }, cultureInfo);
//then bulk insert, both need to work
using (var blk = tbl.BeginBulkInsert(cultureInfo))
@@ -88,11 +88,11 @@ public void DateColumnTests_UkUsFormat_Explicit(DatabaseType type,object input,s
}
var result = tbl.GetDataTable();
- var expectedDate = new DateTime(1993,2,28,5,36,27);
+ var expectedDate = new DateTime(1993, 2, 28, 5, 36, 27);
Assert.Multiple(() =>
{
- Assert.That(result.Rows[0][0],Is.EqualTo(expectedDate));
- Assert.That(result.Rows[1][0],Is.EqualTo(expectedDate));
+ Assert.That(result.Rows[0][0], Is.EqualTo(expectedDate));
+ Assert.That(result.Rows[1][0], Is.EqualTo(expectedDate));
});
}
@@ -104,14 +104,14 @@ public void DateColumnTests_UkUsFormat_Explicit(DatabaseType type,object input,s
///
///
///
- [TestCase(DatabaseType.MicrosoftSQLServer,"2/28/1993 5:36:27 AM","en-US")]
- [TestCase(DatabaseType.MySql,"2/28/1993 5:36:27 AM","en-US")]
- [TestCase(DatabaseType.Oracle,"2/28/1993 5:36:27 AM","en-US")]
- [TestCase(DatabaseType.PostgreSql,"2/28/1993 5:36:27 AM","en-US")]
- public void DateColumnTests_PrimaryKeyColumn(DatabaseType type,object input,string culture)
+ [TestCase(DatabaseType.MicrosoftSQLServer, "2/28/1993 5:36:27 AM", "en-US")]
+ [TestCase(DatabaseType.MySql, "2/28/1993 5:36:27 AM", "en-US")]
+ [TestCase(DatabaseType.Oracle, "2/28/1993 5:36:27 AM", "en-US")]
+ [TestCase(DatabaseType.PostgreSql, "2/28/1993 5:36:27 AM", "en-US")]
+ public void DateColumnTests_PrimaryKeyColumn(DatabaseType type, object input, string culture)
{
var db = GetTestDatabase(type);
- var tbl = db.CreateTable("MyTable",[
+ var tbl = db.CreateTable("MyTable", [
new DatabaseColumnRequest("MyDate",new DatabaseTypeRequest(typeof(DateTime)))
{IsPrimaryKey = true }
]);
@@ -127,30 +127,30 @@ public void DateColumnTests_PrimaryKeyColumn(DatabaseType type,object input,stri
dt.PrimaryKey = [dt.Columns[0]];
blk.Upload(dt);
- Assert.That(dt.PrimaryKey,Has.Length.EqualTo(1));
- Assert.That(dt.PrimaryKey[0].ColumnName,Is.EqualTo("MyDate"));
+ Assert.That(dt.PrimaryKey, Has.Length.EqualTo(1));
+ Assert.That(dt.PrimaryKey[0].ColumnName, Is.EqualTo("MyDate"));
}
var result = tbl.GetDataTable();
- var expectedDate = new DateTime(1993,2,28,5,36,27);
- Assert.That(result.Rows[0][0],Is.EqualTo(expectedDate));
+ var expectedDate = new DateTime(1993, 2, 28, 5, 36, 27);
+ Assert.That(result.Rows[0][0], Is.EqualTo(expectedDate));
}
- [TestCase(DatabaseType.MicrosoftSQLServer,"00:00:00")]
- [TestCase(DatabaseType.MySql,"00:00:00")]
- [TestCase(DatabaseType.Oracle,"00:00:00")]
- [TestCase(DatabaseType.MicrosoftSQLServer,"00:00")]
- [TestCase(DatabaseType.MySql,"00:00")]
- [TestCase(DatabaseType.Oracle,"00:00")]
- [TestCase(DatabaseType.PostgreSql,"00:00:00")]
- [TestCase(DatabaseType.PostgreSql,"00:00")]
- public void DateColumnTests_TimeOnly_Midnight(DatabaseType type,object input)
+ [TestCase(DatabaseType.MicrosoftSQLServer, "00:00:00")]
+ [TestCase(DatabaseType.MySql, "00:00:00")]
+ [TestCase(DatabaseType.Oracle, "00:00:00")]
+ [TestCase(DatabaseType.MicrosoftSQLServer, "00:00")]
+ [TestCase(DatabaseType.MySql, "00:00")]
+ [TestCase(DatabaseType.Oracle, "00:00")]
+ [TestCase(DatabaseType.PostgreSql, "00:00:00")]
+ [TestCase(DatabaseType.PostgreSql, "00:00")]
+ public void DateColumnTests_TimeOnly_Midnight(DatabaseType type, object input)
{
var db = GetTestDatabase(type);
- var tbl = db.CreateTable("MyTable",[new DatabaseColumnRequest("MyTime",new DatabaseTypeRequest(typeof(TimeSpan)))]);
+ var tbl = db.CreateTable("MyTable", [new DatabaseColumnRequest("MyTime", new DatabaseTypeRequest(typeof(TimeSpan)))]);
- tbl.Insert(new Dictionary { { "MyTime",input } });
+ tbl.Insert(new Dictionary { { "MyTime", input } });
using (var blk = tbl.BeginBulkInsert())
{
@@ -162,19 +162,19 @@ public void DateColumnTests_TimeOnly_Midnight(DatabaseType type,object input)
}
var result = tbl.GetDataTable();
- var expectedTime = new TimeSpan(0,0,0,0);
+ var expectedTime = new TimeSpan(0, 0, 0, 0);
var resultTimeSpans =
//Oracle is a bit special it only stores whole dates then has server side settings about how much to return (like a format string)
type == DatabaseType.Oracle
- ? new[] { (DateTime)result.Rows[0][0],(DateTime)result.Rows[1][0] }.Select(static dt => dt.TimeOfDay)
+ ? new[] { (DateTime)result.Rows[0][0], (DateTime)result.Rows[1][0] }.Select(static dt => dt.TimeOfDay)
.Cast