목적 : 로딩한 XML 기반으로 현재 DB와 비교하여 업데이트 된 부분을 반영
우선 추가적으로 콘솔로그를 색상을 넣어 찍게 만들어보자(디버깅용)
// 자세한 내용은 코드내부 참조
#pragma once
enum class Color
{
BLACK,
WHITE,
RED,
GREEN,
BLUE,
YELLOW,
};
class ConsoleLog
{
enum { BUFFER_SIZE = 4096 };
public:
ConsoleLog();
~ConsoleLog();
public:
void WriteStdOut(Color color, const WCHAR* str, ...);
void WriteStdErr(Color color, const WCHAR* str, ...);
protected:
void SetColor(bool stdOut, Color color);
private:
HANDLE _stdOut;
HANDLE _stdErr;
};
#pragma once
#include "Types.h"
NAMESPACE_BEGIN(DBModel)
USING_SHARED_PTR(Column);
USING_SHARED_PTR(Index);
USING_SHARED_PTR(Table);
USING_SHARED_PTR(Procedure);
/*-------------
DataType
--------------*/
// 데이터 타입을 정의
enum class DataType
{
None = 0,
TinyInt = 48,
SmallInt = 52,
Int = 56,
Real = 59,
DateTime = 61,
Float = 62,
Bit = 104,
Numeric = 108,
BigInt = 127,
VarBinary = 165,
Varchar = 167,
Binary = 173,
NVarChar = 231,
};
/*-------------
Column
--------------*/
class Column
{
public:
String CreateText();
public:
// 열에 들어갈 만한 정보를 미리 정의
String _name;
int32 _columnId = 0; // DB
DataType _type = DataType::None;
String _typeText;
int32 _maxLength = 0;
bool _nullable = false;
bool _identity = false;
int64 _seedValue = 0;
int64 _incrementValue = 0;
String _default;
String _defaultConstraintName; // DB
};
/*-----------
Index
------------*/
enum class IndexType
{
Clustered = 1,
NonClustered = 2
};
class Index
{
public:
String GetUniqueName();
String CreateName(const String& tableName);
String GetTypeText();
String GetKeyText();
String CreateColumnsText();
bool DependsOn(const String& columnName);
public:
String _name; // DB
int32 _indexId = 0; // DB
IndexType _type = IndexType::NonClustered;
bool _primaryKey = false;
bool _uniqueConstraint = false;
Vector<ColumnRef> _columns;
};
/*-----------
Table
------------*/
class Table
{
public:
ColumnRef FindColumn(const String& columnName);
public:
int32 _objectId = 0; // DB
String _name;
Vector<ColumnRef> _columns;
Vector<IndexRef> _indexes;
};
/*----------------
Procedures
-----------------*/
struct Param
{
String _name;
String _type;
};
class Procedure
{
public:
String GenerateCreateQuery();
String GenerateAlterQuery();
String GenerateParamString();
public:
String _name;
String _fullBody; // DB
String _body; // XML
Vector<Param> _parameters; // XML
};
/*-------------
Helpers
--------------*/
class Helpers
{
public:
static String Format(const WCHAR* format, ...);
static String DataType2String(DataType type);
static String RemoveWhiteSpace(const String& str);
static DataType String2DataType(const WCHAR* str, OUT int32& maxLen);
};
NAMESPACE_END
#pragma once
#include "DBConnection.h"
#include "DBModel.h"
/*--------------------
DBSynchronizer
---------------------*/
class DBSynchronizer
{
enum
{
PROCEDURE_MAX_LEN = 10000
};
enum UpdateStep : uint8
{
DropIndex,
AlterColumn,
AddColumn,
CreateTable,
DefaultConstraint,
CreateIndex,
DropColumn,
DropTable,
StoredProcecure,
Max
};
enum ColumnFlag : uint8
{
Type = 1 << 0,
Nullable = 1 << 1,
Identity = 1 << 2,
Default = 1 << 3,
Length = 1 << 4,
};
public:
DBSynchronizer(DBConnection& conn) : _dbConn(conn) { }
~DBSynchronizer();
bool Synchronize(const WCHAR* path);
private:
void ParseXmlDB(const WCHAR* path);
bool GatherDBTables();
bool GatherDBIndexes();
bool GatherDBStoredProcedures();
void CompareDBModel();
void CompareTables(DBModel::TableRef dbTable, DBModel::TableRef xmlTable);
void CompareColumns(DBModel::TableRef dbTable, DBModel::ColumnRef dbColumn, DBModel::ColumnRef xmlColumn);
void CompareStoredProcedures();
void ExecuteUpdateQueries();
private:
DBConnection& _dbConn;
Vector<DBModel::TableRef> _xmlTables;
Vector<DBModel::ProcedureRef> _xmlProcedures;
Set<String> _xmlRemovedTables;
Vector<DBModel::TableRef> _dbTables;
Vector<DBModel::ProcedureRef> _dbProcedures;
private:
Set<String> _dependentIndexes;
Vector<String> _updateQueries[UpdateStep::Max];
};
실제 사용은 이렇게
int main()
{
ASSERT_CRASH(GDBConnectionPool->Connect(1, L"Driver={SQL Server Native Client 11.0};Server=(localdb)\\MSSQLLocalDB;Database=ServerDb;Trusted_Connection=Yes;"));
DBConnection* dbConn = GDBConnectionPool->Pop();
DBSynchronizer dbSync(*dbConn);
dbSync.Synchronize(L"GameDB.xml");
// ...