4#include "../SqlQueryFormatter.hpp"
5#include "SQLiteFormatter.hpp"
7#include <reflection-cpp/reflection.hpp>
15class SqlServerQueryFormatter final:
public SQLiteQueryFormatter
18 [[nodiscard]]
static std::string FormatFromTable(std::string_view table)
21 if (!table.empty() && (table.front() ==
'[' || table.front() ==
'"'))
22 return std::string(table);
25 return std::format(R
"("{}")", table);
29 [[nodiscard]] StringList DropTable(std::string_view schemaName,
30 std::string_view
const& tableName,
31 bool ifExists =
false,
32 bool cascade =
false)
const override
39 std::string
const schemaFilter = schemaName.empty() ?
"dbo" : std::string(schemaName);
41 result.emplace_back(std::format(
42 R
"(DECLARE @sql NVARCHAR(MAX) = N'';
43SELECT @sql = @sql + 'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id)) + '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id)) + ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + '; '
44FROM sys.foreign_keys fk
45WHERE OBJECT_NAME(fk.referenced_object_id) = '{}' AND OBJECT_SCHEMA_NAME(fk.referenced_object_id) = '{}';
46EXEC sp_executesql @sql;)",
53 result.emplace_back(std::format(
"DROP TABLE IF EXISTS {};", FormatTableName(schemaName, tableName)));
55 result.emplace_back(std::format(
"DROP TABLE {};", FormatTableName(schemaName, tableName)));
60 [[nodiscard]] std::string BinaryLiteral(std::span<uint8_t const> data)
const override
63 result.reserve((data.size() * 2) + 2);
65 for (uint8_t
byte: data)
66 result += std::format(
"{:02X}", byte);
70 [[nodiscard]] std::string QualifiedTableName(std::string_view schema, std::string_view table)
const override
73 return std::format(
"[{}]", table);
74 return std::format(
"[{}].[{}]", schema, table);
77 [[nodiscard]] std::string QueryLastInsertId(std::string_view )
const override
80 return std::format(
"SELECT @@IDENTITY");
83 [[nodiscard]] std::string_view BooleanLiteral(
bool literalValue)
const noexcept override
85 return literalValue ?
"1" :
"0";
88 [[nodiscard]] std::string_view DateFunction() const noexcept
override
93 [[nodiscard]] std::string SelectFirst(
bool distinct,
95 std::string_view fields,
96 std::string_view fromTable,
97 std::string_view fromTableAlias,
98 std::string_view tableJoins,
99 std::string_view whereCondition,
100 std::string_view orderBy,
101 size_t count)
const override
103 std::stringstream sqlQueryString;
104 sqlQueryString <<
"SELECT";
106 sqlQueryString <<
" DISTINCT";
107 sqlQueryString <<
" TOP " << count;
108 sqlQueryString <<
' ' << fields;
109 sqlQueryString <<
" FROM " << FormatFromTable(fromTable);
110 if (!fromTableAlias.empty())
111 sqlQueryString <<
" AS [" << fromTableAlias <<
']';
112 sqlQueryString << tableJoins;
113 sqlQueryString << whereCondition;
114 sqlQueryString << orderBy;
115 return sqlQueryString.str();
118 [[nodiscard]] std::string SelectRange(
bool distinct,
120 std::string_view fields,
121 std::string_view fromTable,
122 std::string_view fromTableAlias,
123 std::string_view tableJoins,
124 std::string_view whereCondition,
125 std::string_view orderBy,
126 std::string_view groupBy,
128 std::size_t limit)
const override
130 assert(!orderBy.empty());
131 std::stringstream sqlQueryString;
132 sqlQueryString <<
"SELECT " << fields;
134 sqlQueryString <<
" DISTINCT";
135 sqlQueryString <<
" FROM " << FormatFromTable(fromTable);
136 if (!fromTableAlias.empty())
137 sqlQueryString <<
" AS [" << fromTableAlias <<
']';
138 sqlQueryString << tableJoins;
139 sqlQueryString << whereCondition;
140 sqlQueryString << groupBy;
141 sqlQueryString << orderBy;
142 sqlQueryString <<
" OFFSET " << offset <<
" ROWS FETCH NEXT " << limit <<
" ROWS ONLY";
143 return sqlQueryString.str();
146 [[nodiscard]] std::string ColumnType(SqlColumnTypeDefinition
const& type)
const override
148 using namespace SqlColumnTypeDefinitions;
149 return std::visit(detail::overloaded {
150 [](Bigint
const&) -> std::string {
return "BIGINT"; },
151 [](Binary
const& type) -> std::string {
152 if (type.size == 0 || type.size > 8000)
153 return "VARBINARY(MAX)";
155 return std::format(
"VARBINARY({})", type.size);
157 [](Bool
const&) -> std::string {
return "BIT"; },
158 [](Char
const& type) -> std::string {
return std::format(
"CHAR({})", type.size); },
159 [](Date
const&) -> std::string {
return "DATE"; },
160 [](DateTime
const&) -> std::string {
return "DATETIME"; },
161 [](Decimal
const& type) -> std::string {
162 return std::format(
"DECIMAL({}, {})", type.precision, type.scale);
164 [](Guid
const&) -> std::string {
return "UNIQUEIDENTIFIER"; },
165 [](Integer
const&) -> std::string {
return "INTEGER"; },
166 [](NChar
const& type) -> std::string {
return std::format(
"NCHAR({})", type.size); },
167 [](NVarchar
const& type) -> std::string {
168 if (type.size == 0 || type.size > SqlOptimalMaxColumnSize)
169 return "NVARCHAR(MAX)";
171 return std::format(
"NVARCHAR({})", type.size);
173 [](Real
const&) -> std::string {
return "REAL"; },
174 [](Smallint
const&) -> std::string {
return "SMALLINT"; },
175 [](Text
const&) -> std::string {
return "VARCHAR(MAX)"; },
176 [](Time
const&) -> std::string {
return "TIME"; },
177 [](Timestamp
const&) -> std::string {
return "TIMESTAMP"; },
178 [](Tinyint
const&) -> std::string {
return "TINYINT"; },
179 [](VarBinary
const& type) -> std::string {
180 if (type.size == 0 || type.size > 8000)
181 return "VARBINARY(MAX)";
183 return std::format(
"VARBINARY({})", type.size);
185 [](Varchar
const& type) -> std::string {
186 if (type.size == 0 || type.size > SqlOptimalMaxColumnSize)
187 return "VARCHAR(MAX)";
189 return std::format(
"VARCHAR({})", type.size);
195 [[nodiscard]] std::string BuildColumnDefinition(SqlColumnDeclaration
const& column)
const override
197 std::stringstream sqlQueryString;
198 sqlQueryString <<
'"' << column.name <<
"\" " << ColumnType(column.type);
201 sqlQueryString <<
" NOT NULL";
203 if (column.primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT)
204 sqlQueryString <<
" IDENTITY(1,1) PRIMARY KEY";
205 else if (column.primaryKey == SqlPrimaryKeyType::NONE && !column.index && column.unique)
206 sqlQueryString <<
" UNIQUE";
208 if (!column.defaultValue.empty())
209 sqlQueryString <<
" DEFAULT " << column.defaultValue;
211 return sqlQueryString.str();
215 [[nodiscard]] StringList CreateTable(std::string_view schema,
216 std::string_view tableName,
217 std::vector<SqlColumnDeclaration>
const& columns,
218 std::vector<SqlCompositeForeignKeyConstraint>
const& foreignKeys,
219 bool ifNotExists =
false)
const override
221 std::stringstream ss;
226 std::string schemaFilter = schema.empty() ?
"dbo" : std::string(schema);
227 ss << std::format(
"IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = '{}' AND schema_id = SCHEMA_ID('{}'))\n",
232 ss << std::format(
"CREATE TABLE {} (", FormatTableName(schema, tableName));
235 for (
auto const& column: columns)
240 ss <<
"\n " << BuildColumnDefinition(column);
243 auto const primaryKeys = [&]() -> std::vector<std::string> {
244 std::vector<std::pair<uint16_t, std::string>> indexedPrimaryKeys;
245 for (
auto const& col: columns)
246 if (col.primaryKey != SqlPrimaryKeyType::NONE)
247 indexedPrimaryKeys.emplace_back(col.primaryKeyIndex, col.name);
248 std::ranges::sort(indexedPrimaryKeys, [](
auto const& a,
auto const& b) {
return a.first < b.first; });
250 std::vector<std::string> primaryKeys;
251 primaryKeys.reserve(indexedPrimaryKeys.size());
252 for (
auto const& [index, name]: indexedPrimaryKeys)
253 primaryKeys.push_back(name);
257 if (!primaryKeys.empty())
267 bool hasIdentity =
false;
268 for (
auto const& col: columns)
269 if (col.primaryKey == SqlPrimaryKeyType::AUTO_INCREMENT)
274 ss <<
",\n PRIMARY KEY (";
276 for (
auto const& pk: primaryKeys)
281 ss <<
'"' << pk <<
'"';
287 if (!foreignKeys.empty())
289 for (
auto const& fk: foreignKeys)
291 ss <<
",\n CONSTRAINT " << std::format(
"\"FK_{}_{}\"", tableName, fk.columns[0])
295 for (
auto const& col: fk.columns)
299 ss <<
'"' << col <<
'"';
302 ss <<
") REFERENCES " << FormatTableName(schema, fk.referencedTableName) <<
" (";
305 for (
auto const& col: fk.referencedColumns)
309 ss <<
'"' << col <<
'"';
317 for (
auto const& column: columns)
319 if (column.foreignKey)
321 ss <<
",\n " << BuildForeignKeyConstraint(tableName, column.name, *column.foreignKey);
328 result.emplace_back(ss.str());
331 for (SqlColumnDeclaration
const& column: columns)
333 if (column.index && column.primaryKey == SqlPrimaryKeyType::NONE)
339 result.emplace_back(std::format(R
"(CREATE UNIQUE INDEX "{}_{}_index" ON "{}" ("{}");)",
345 result.emplace_back(std::format(R
"(CREATE UNIQUE INDEX "{}_{}_index" ON "{}"."{}" ("{}");)",
355 result.emplace_back(std::format(
356 R
"(CREATE INDEX "{}_{}_index" ON "{}" ("{}");)", tableName, column.name, tableName, column.name));
358 result.emplace_back(std::format(R
"(CREATE INDEX "{}_{}_index" ON "{}"."{}" ("{}");)",
372 [[nodiscard]] StringList AlterTable(std::string_view schemaName,
373 std::string_view tableName,
374 std::vector<SqlAlterTableCommand>
const& commands)
const override
376 std::stringstream sqlQueryString;
378 int currentCommand = 0;
379 for (SqlAlterTableCommand
const& command: commands)
381 if (currentCommand > 0)
382 sqlQueryString <<
'\n';
385 using namespace SqlAlterTableCommands;
386 sqlQueryString << std::visit(
388 [schemaName, tableName](RenameTable
const& actualCommand) -> std::string {
389 return std::format(R
"(ALTER TABLE {} RENAME TO "{}";)",
390 FormatTableName(schemaName, tableName),
391 actualCommand.newTableName);
393 [schemaName, tableName, this](AddColumn
const& actualCommand) -> std::string {
394 return std::format(R
"(ALTER TABLE {} ADD "{}" {} {};)",
395 FormatTableName(schemaName, tableName),
396 actualCommand.columnName,
397 ColumnType(actualCommand.columnType),
398 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
400 [schemaName, tableName,
this](AlterColumn
const& actualCommand) -> std::string {
401 return std::format(R
"(ALTER TABLE {} ALTER COLUMN "{}" {} {};)",
402 FormatTableName(schemaName, tableName),
403 actualCommand.columnName,
404 ColumnType(actualCommand.columnType),
405 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
407 [schemaName, tableName](RenameColumn
const& actualCommand) -> std::string {
408 return std::format(R
"(ALTER TABLE {} RENAME COLUMN "{}" TO "{}";)",
409 FormatTableName(schemaName, tableName),
410 actualCommand.oldColumnName,
411 actualCommand.newColumnName);
413 [schemaName, tableName](DropColumn const& actualCommand) -> std::string {
414 return std::format(R
"(ALTER TABLE {} DROP COLUMN "{}";)",
415 FormatTableName(schemaName, tableName),
416 actualCommand.columnName);
418 [schemaName, tableName](AddIndex const& actualCommand) -> std::string {
419 using namespace std::string_view_literals;
420 auto const uniqueStr = actualCommand.unique ?
"UNIQUE "sv :
""sv;
421 if (schemaName.empty())
422 return std::format(R
"(CREATE {2}INDEX "{0}_{1}_index" ON "{0}" ("{1}");)",
424 actualCommand.columnName,
427 return std::format(R
"(CREATE {3}INDEX "{0}_{1}_{2}_index" ON "{0}"."{1}" ("{2}");)",
430 actualCommand.columnName,
433 [schemaName, tableName](DropIndex const& actualCommand) -> std::string {
434 if (schemaName.empty())
435 return std::format(R
"(DROP INDEX "{0}_{1}_index";)", tableName, actualCommand.columnName);
438 R
"(DROP INDEX "{0}_{1}_{2}_index";)", schemaName, tableName, actualCommand.columnName);
440 [schemaName, tableName](AddForeignKey const& actualCommand) -> std::string {
442 R
"(ALTER TABLE {} ADD {};)",
443 FormatTableName(schemaName, tableName),
444 BuildForeignKeyConstraint(tableName, actualCommand.columnName, actualCommand.referencedColumn));
446 [schemaName, tableName](DropForeignKey const& actualCommand) -> std::string {
447 return std::format(R
"(ALTER TABLE {} DROP CONSTRAINT "{}";)",
448 FormatTableName(schemaName, tableName),
449 std::format("FK_{}_{}", tableName, actualCommand.columnName));
451 [schemaName, tableName](AddCompositeForeignKey
const& actualCommand) -> std::string {
452 std::stringstream ss;
453 ss <<
"ALTER TABLE " << FormatTableName(schemaName, tableName) <<
" ADD CONSTRAINT "
454 << std::format(
"\"FK_{}_{}\"", tableName, actualCommand.columns[0]) <<
" FOREIGN KEY (";
457 for (
auto const& col: actualCommand.columns)
461 ss <<
'"' << col <<
'"';
463 ss <<
") REFERENCES " << FormatTableName(schemaName, actualCommand.referencedTableName) <<
" (";
466 for (
auto const& col: actualCommand.referencedColumns)
470 ss <<
'"' << col <<
'"';
475 [schemaName, tableName,
this](AddColumnIfNotExists
const& actualCommand) -> std::string {
478 R
"(IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('{}') AND name = '{}')
479ALTER TABLE {} ADD "{}" {} {};)",
480 FormatTableName(schemaName, tableName),
481 actualCommand.columnName,
482 FormatTableName(schemaName, tableName),
483 actualCommand.columnName,
484 ColumnType(actualCommand.columnType),
485 actualCommand.nullable == SqlNullable::NotNull ? "NOT NULL" :
"NULL");
487 [schemaName, tableName](DropColumnIfExists
const& actualCommand) -> std::string {
490 R
"(IF EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('{}') AND name = '{}')
491ALTER TABLE {} DROP COLUMN "{}";)",
492 FormatTableName(schemaName, tableName),
493 actualCommand.columnName,
494 FormatTableName(schemaName, tableName),
495 actualCommand.columnName);
497 [schemaName, tableName](DropIndexIfExists const& actualCommand) -> std::string {
498 if (schemaName.empty())
500 R
"(IF EXISTS (SELECT * FROM sys.indexes WHERE name = '{0}_{1}_index' AND object_id = OBJECT_ID('{0}'))
501DROP INDEX "{0}_{1}_index" ON "{0}";)",
503 actualCommand.columnName);
506 R
"(IF EXISTS (SELECT * FROM sys.indexes WHERE name = '{0}_{1}_{2}_index')
507DROP INDEX "{0}_{1}_{2}_index" ON "{0}"."{1}";)",
510 actualCommand.columnName);
516 return { sqlQueryString.str() };
519 [[nodiscard]] std::string QueryServerVersion()
const override
521 return "SELECT @@VERSION";