Skip to content

Commit

Permalink
Drop SqlColumnType and replace its uses with SqlColumnTypeDefinition
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Parpart <[email protected]>
  • Loading branch information
christianparpart committed Jan 20, 2025
1 parent bf57764 commit 288639e
Show file tree
Hide file tree
Showing 14 changed files with 172 additions and 182 deletions.
2 changes: 2 additions & 0 deletions src/Lightweight/QueryFormatter/OracleFormatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ class OracleSqlQueryFormatter final: public SQLiteQueryFormatter
},
[](Time const&) -> std::string { return "TIMESTAMP"; },
[](Timestamp const&) -> std::string { return "TIMESTAMP"; },
[](Tinyint const&) -> std::string { return "TINYINT"; },
[](VarBinary const& type) -> std::string { return std::format("VARBINARY({})", type.size); },
[](Varchar const& type) -> std::string { return std::format("VARCHAR({})", type.size); },
},
type);
Expand Down
3 changes: 3 additions & 0 deletions src/Lightweight/QueryFormatter/PostgreSqlFormatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class PostgreSqlFormatter final: public SQLiteQueryFormatter
[](Text const&) -> std::string { return "TEXT"; },
[](Time const&) -> std::string { return "TIME"; },
[](Timestamp const&) -> std::string { return "TIMESTAMP"; },
// NB: PostgreSQL doesn't have a TINYINT type, but it does have a SMALLINT type.
[](Tinyint const&) -> std::string { return "SMALLINT"; },
[](VarBinary const& type) -> std::string { return std::format("BYTEA({})", type.size); },
[](Varchar const& type) -> std::string { return std::format("VARCHAR({})", type.size); },
},
type);
Expand Down
2 changes: 2 additions & 0 deletions src/Lightweight/QueryFormatter/SQLiteFormatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ class SQLiteQueryFormatter: public SqlQueryFormatter
[](Text const&) -> std::string { return "TEXT"; },
[](Time const&) -> std::string { return "TIME"; },
[](Timestamp const&) -> std::string { return "TIMESTAMP"; },
[](Tinyint const&) -> std::string { return "TINYINT"; },
[](VarBinary const& type) -> std::string { return std::format("VARBINARY({})", type.size); },
[](Varchar const& type) -> std::string { return std::format("VARCHAR({})", type.size); },
},
type);
Expand Down
2 changes: 2 additions & 0 deletions src/Lightweight/QueryFormatter/SqlServerFormatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ class SqlServerQueryFormatter final: public SQLiteQueryFormatter
[](Text const&) -> std::string { return "VARCHAR(MAX)"; },
[](Time const&) -> std::string { return "TIME"; },
[](Timestamp const&) -> std::string { return "TIMESTAMP"; },
[](Tinyint const&) -> std::string { return "TINYINT"; },
[](VarBinary const& type) -> std::string { return std::format("VARBINARY({})", type.size); },
[](Varchar const& type) -> std::string { return std::format("VARCHAR({})", type.size); },
},
type);
Expand Down
24 changes: 14 additions & 10 deletions src/Lightweight/SqlColumnTypeDefinitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,25 @@ namespace SqlColumnTypeDefinitions
{

// clang-format off
struct Bigint {};
struct Binary { std::size_t size = 255; };
struct Bool {};
struct Char { std::size_t size = 1; };
struct Date {};
struct DateTime {};
struct Decimal { std::size_t precision {}; std::size_t scale {}; };
struct Guid {};
struct Integer {};
struct NChar { std::size_t size = 1; };
struct Varchar { std::size_t size = 255; };
struct NVarchar { std::size_t size = 255; };
struct Text { std::size_t size {}; };
struct Smallint {};
struct Integer {};
struct Bigint {};
struct Real {};
struct Decimal { std::size_t precision {}; std::size_t scale {}; };
struct DateTime {};
struct Timestamp {};
struct Date {};
struct Smallint {};
struct Text { std::size_t size {}; };
struct Time {};
struct Guid {};
struct Timestamp {};
struct Tinyint {};
struct VarBinary { std::size_t size = 255; };
struct Varchar { std::size_t size = 255; };
// clang-format on

} // namespace SqlColumnTypeDefinitions
Expand All @@ -41,8 +43,10 @@ using SqlColumnTypeDefinition = std::variant<SqlColumnTypeDefinitions::Bigint,
SqlColumnTypeDefinitions::NChar,
SqlColumnTypeDefinitions::NVarchar,
SqlColumnTypeDefinitions::Real,
SqlColumnTypeDefinitions::Tinyint,
SqlColumnTypeDefinitions::Smallint,
SqlColumnTypeDefinitions::Text,
SqlColumnTypeDefinitions::Time,
SqlColumnTypeDefinitions::Timestamp,
SqlColumnTypeDefinitions::VarBinary,
SqlColumnTypeDefinitions::Varchar>;
2 changes: 1 addition & 1 deletion src/Lightweight/SqlQuery/MigrationPlan.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#pragma once

#include "../Api.hpp"
#include "../DataBinder/SqlFixedString.hpp"
#include "../SqlDataBinder.hpp"
#include "../SqlColumnTypeDefinitions.hpp"
#include "../Utils.hpp"

Expand Down
79 changes: 41 additions & 38 deletions src/Lightweight/SqlSchema.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: Apache-2.0

#include "SqlConnection.hpp"
#include "SqlError.hpp"
#include "SqlSchema.hpp"
#include "SqlStatement.hpp"

#include <algorithm>
#include <cassert>

#include <sql.h>
#include <sqlext.h>
Expand All @@ -26,47 +28,46 @@ bool operator<(KeyPair const& a, KeyPair const& b)

namespace
{
SqlColumnType FromNativeDataType(int value)
SqlColumnTypeDefinition FromNativeDataType(int value, size_t size, size_t precision)
{
// Maps ODBC data types to SqlColumnTypeDefinition
// See: https://learn.microsoft.com/en-us/sql/odbc/reference/appendixes/sql-data-types?view=sql-server-ver16
using namespace SqlColumnTypeDefinitions;
// clang-format off
switch (value)
{
case SQL_UNKNOWN_TYPE:
return SqlColumnType::UNKNOWN;
case SQL_CHAR:
case SQL_WCHAR:
return SqlColumnType::CHAR;
case SQL_VARCHAR:
case SQL_WVARCHAR:
return SqlColumnType::STRING;
case SQL_LONGVARCHAR:
case SQL_WLONGVARCHAR:
return SqlColumnType::TEXT;
case SQL_BIT:
return SqlColumnType::BOOLEAN;
case SQL_TINYINT:
return SqlColumnType::INTEGER;
case SQL_SMALLINT:
return SqlColumnType::INTEGER;
case SQL_INTEGER:
return SqlColumnType::INTEGER;
case SQL_BIGINT:
return SqlColumnType::INTEGER;
case SQL_REAL:
return SqlColumnType::REAL;
case SQL_FLOAT:
return SqlColumnType::REAL;
case SQL_DOUBLE:
return SqlColumnType::REAL;
case SQL_TYPE_DATE:
return SqlColumnType::DATE;
case SQL_TYPE_TIME:
return SqlColumnType::TIME;
case SQL_TYPE_TIMESTAMP:
return SqlColumnType::DATETIME;
default:
std::println("Unknown SQL type {}", value);
return SqlColumnType::UNKNOWN;
case SQL_BIGINT: return Bigint {};
case SQL_BINARY: return Binary { size };
case SQL_BIT: return Bool {};
case SQL_CHAR: return Char { size };
case SQL_DATE: return Date {};
case SQL_DECIMAL: assert(size <= precision); return Decimal { .precision = precision, .scale = size };
case SQL_DOUBLE: return Real {};
case SQL_FLOAT: return Real {};
case SQL_GUID: return Guid {};
case SQL_INTEGER: return Integer {};
case SQL_LONGVARBINARY: return VarBinary { size };
case SQL_LONGVARCHAR: return Varchar { size };
case SQL_NUMERIC: assert(size <= precision); return Decimal { .precision = precision, .scale = size };
case SQL_REAL: return Real {};
case SQL_SMALLINT: return Smallint {};
case SQL_TIME: return Time {};
case SQL_TIMESTAMP: return DateTime {};
case SQL_TINYINT: return Tinyint {};
case SQL_TYPE_DATE: return Date {};
case SQL_TYPE_TIME: return Time {};
case SQL_TYPE_TIMESTAMP: return DateTime {};
case SQL_VARBINARY: return Binary { size };
case SQL_VARCHAR: return Varchar { size };
case SQL_WCHAR: return NChar { size };
case SQL_WLONGVARCHAR: return NVarchar { size };
case SQL_WVARCHAR: return NVarchar { size };
// case SQL_UNKNOWN_TYPE:
default:
SqlLogger::GetLogger().OnError(SqlError::UNSUPPORTED_TYPE);
throw std::runtime_error(std::format("Unsupported data type: {}", value));
}
// clang-format on
}

std::vector<std::string> AllTables(std::string_view database, std::string_view schema)
Expand Down Expand Up @@ -241,7 +242,7 @@ void ReadAllTables(std::string_view database, std::string_view schema, EventHand
while (columnStmt.FetchRow())
{
column.name = columnStmt.GetColumn<std::string>(4);
column.type = FromNativeDataType(columnStmt.GetColumn<int>(5));
auto const type = columnStmt.GetColumn<int>(5);
column.dialectDependantTypeString = columnStmt.GetColumn<std::string>(6);
column.size = columnStmt.GetColumn<int>(7);
// 8 - bufferLength
Expand All @@ -251,6 +252,8 @@ void ReadAllTables(std::string_view database, std::string_view schema, EventHand
// 12 - remarks
column.defaultValue = columnStmt.GetColumn<std::string>(13);

column.type = FromNativeDataType(type, column.size, column.decimalDigits);

// accumulated properties
column.isPrimaryKey = std::ranges::contains(primaryKeys, column.name);
// column.isForeignKey = ...;
Expand Down
19 changes: 18 additions & 1 deletion src/Lightweight/SqlSchema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#endif

#include "Api.hpp"
#include "SqlQuery/MigrationPlan.hpp"
#include "SqlTraits.hpp"

#include <format>
Expand Down Expand Up @@ -84,10 +85,11 @@ struct ForeignKeyConstraint
FullyQualifiedTableColumnSequence primaryKey;
};

/// Holds the definition of a column in a SQL table as read from the database schema.
struct Column
{
std::string name = {};
SqlColumnType type = SqlColumnType::UNKNOWN;
SqlColumnTypeDefinition type = {};
std::string dialectDependantTypeString = {};
bool isNullable = true;
bool isUnique = false;
Expand All @@ -100,6 +102,7 @@ struct Column
std::string defaultValue = {};
};

/// Callback interface for handling events while reading a database schema.
class EventHandler
{
public:
Expand All @@ -118,20 +121,34 @@ class EventHandler
virtual void OnTableEnd() = 0;
};

/// Reads all tables in the given database and schema and calls the event handler for each table.
LIGHTWEIGHT_API void ReadAllTables(std::string_view database, std::string_view schema, EventHandler& eventHandler);

/// Holds the definition of a table in a SQL database as read from the database schema.
struct Table
{
// FullyQualifiedTableName name;

/// The name of the table.
std::string name;

/// The columns of the table.
std::vector<Column> columns {};

/// The foreign keys of the table.
std::vector<ForeignKeyConstraint> foreignKeys {};

/// The foreign keys of other tables that reference this table.
std::vector<ForeignKeyConstraint> externalForeignKeys {};

/// The primary keys of the table.
std::vector<std::string> primaryKeys {};
};

/// A list of tables.
using TableList = std::vector<Table>;

/// Retrieves all tables in the given @p database and @p schema.
LIGHTWEIGHT_API TableList ReadAllTables(std::string_view database, std::string_view schema = {});

/// Retrieves all tables in the given database and schema that have a foreign key to the given table.
Expand Down
64 changes: 0 additions & 64 deletions src/Lightweight/SqlTraits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,70 +21,6 @@ enum class SqlServerType : uint8_t
MYSQL,
};

enum class SqlColumnType : uint8_t
{
UNKNOWN,
CHAR,
STRING,
TEXT,
BOOLEAN,
SMALLINT,
INTEGER,
BIGINT,
NUMERIC,
REAL,
BLOB,
DATE,
TIME,
DATETIME,
GUID,
};

namespace detail
{

constexpr std::string_view DefaultColumnTypeName(SqlColumnType value) noexcept
{
switch (value)
{
case SqlColumnType::CHAR:
return "CHAR";
case SqlColumnType::STRING:
return "VARCHAR";
case SqlColumnType::TEXT:
return "TEXT";
case SqlColumnType::BOOLEAN:
return "BOOL";
case SqlColumnType::SMALLINT:
return "SMALLINT";
case SqlColumnType::INTEGER:
return "INTEGER";
case SqlColumnType::BIGINT:
return "BIGINT";
case SqlColumnType::NUMERIC:
return "NUMERIC";
case SqlColumnType::REAL:
return "REAL";
case SqlColumnType::BLOB:
return "BLOB";
case SqlColumnType::DATE:
return "DATE";
case SqlColumnType::TIME:
return "TIME";
case SqlColumnType::DATETIME:
// With SQL Server or Oracle, we could use DATETIME2(7) and have nano-second precision (with 100ns
// resolution) The standard DATETIME and ODBC SQL_TIMESTAMP have only millisecond precision.
return "DATETIME";
case SqlColumnType::GUID:
return "BINARY(16)";
case SqlColumnType::UNKNOWN:
break;
}
return "UNKNOWN";
}

} // namespace detail

struct SqlTraits
{
std::string_view PrimaryKeyAutoIncrement; // Maybe rename this to `PrimaryKeyIdentityColumnType`?
Expand Down
Loading

0 comments on commit 288639e

Please sign in to comment.