SetInfoTable.cpp (11380B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "SetInfoTable.h" 5 #include "UnitInfoTable.h" 6 #include "ConfigurationSetSerializer.h" 7 #include "ConfigurationSetParser.h" 8 #include <AppInstallerDateTime.h> 9 #include <AppInstallerStrings.h> 10 #include <winget/SQLiteStatementBuilder.h> 11 12 using namespace AppInstaller::SQLite; 13 using namespace AppInstaller::SQLite::Builder; 14 using namespace AppInstaller::Utility; 15 16 namespace winrt::Microsoft::Management::Configuration::implementation::Database::Schema::V0_1 17 { 18 namespace 19 { 20 constexpr std::string_view s_SetInfoTable_Table = "set_info"sv; 21 22 constexpr std::string_view s_SetInfoTable_Column_InstanceIdentifier = "instance_identifier"sv; 23 constexpr std::string_view s_SetInfoTable_Column_Name = "name"sv; 24 constexpr std::string_view s_SetInfoTable_Column_Origin = "origin"sv; 25 constexpr std::string_view s_SetInfoTable_Column_Path = "path"sv; 26 constexpr std::string_view s_SetInfoTable_Column_FirstApply = "first_apply"sv; 27 constexpr std::string_view s_SetInfoTable_Column_SchemaVersion = "schema_version"sv; 28 constexpr std::string_view s_SetInfoTable_Column_Metadata = "metadata"sv; 29 constexpr std::string_view s_SetInfoTable_Column_Parameters = "parameters"sv; 30 constexpr std::string_view s_SetInfoTable_Column_Variables = "variables"sv; 31 32 void BuildBaseSetSelectStatement(StatementBuilder& builder) 33 { 34 builder.Select({ 35 RowIDName, // 0 36 s_SetInfoTable_Column_InstanceIdentifier, // 1 37 s_SetInfoTable_Column_Name, // 2 38 s_SetInfoTable_Column_Origin, // 3 39 s_SetInfoTable_Column_Path, // 4 40 s_SetInfoTable_Column_SchemaVersion, // 5 41 s_SetInfoTable_Column_Metadata, // 6 42 s_SetInfoTable_Column_Parameters, // 7 43 s_SetInfoTable_Column_Variables, // 8 44 }).From(s_SetInfoTable_Table); 45 } 46 47 IConfigurationDatabase::ConfigurationSetPtr GetSetFromStatement(Statement& statement, UnitInfoTable& unitInfoTable) 48 { 49 auto configurationSet = make_self<implementation::ConfigurationSet>(statement.GetColumn<GUID>(1)); 50 51 configurationSet->Name(hstring{ ConvertToUTF16(statement.GetColumn<std::string>(2)) }); 52 configurationSet->Origin(hstring{ ConvertToUTF16(statement.GetColumn<std::string>(3)) }); 53 configurationSet->Path(hstring{ ConvertToUTF16(statement.GetColumn<std::string>(4)) }); 54 55 std::string schemaVersion = statement.GetColumn<std::string>(5); 56 configurationSet->SchemaVersion(hstring{ ConvertToUTF16(schemaVersion) }); 57 58 auto parser = ConfigurationSetParser::CreateForSchemaVersion(schemaVersion); 59 configurationSet->Metadata(parser->ParseValueSet(statement.GetColumn<std::string>(6))); 60 parser->ExtractEnvironmentFromMetadata(configurationSet->Metadata(), configurationSet->EnvironmentInternal()); 61 62 THROW_HR_IF(E_NOTIMPL, !statement.GetColumn<std::string>(7).empty()); 63 configurationSet->Variables(parser->ParseValueSet(statement.GetColumn<std::string>(8))); 64 65 std::vector<Configuration::ConfigurationUnit> winrtUnits; 66 for (const auto& unit : unitInfoTable.GetAllUnitsForSet(statement.GetColumn<rowid_t>(0), schemaVersion)) 67 { 68 winrtUnits.emplace_back(*unit); 69 } 70 configurationSet->Units(std::move(winrtUnits)); 71 72 return configurationSet; 73 } 74 } 75 76 SetInfoTable::SetInfoTable(Connection& connection) : m_connection(connection) {} 77 78 std::string_view SetInfoTable::TableName() 79 { 80 return s_SetInfoTable_Table; 81 } 82 83 std::string_view SetInfoTable::InstanceIdentifierColumn() 84 { 85 return s_SetInfoTable_Column_InstanceIdentifier; 86 } 87 88 void SetInfoTable::Create() 89 { 90 Savepoint savepoint = Savepoint::Create(m_connection, "SetInfoTable_Create_0_1"); 91 92 StatementBuilder tableBuilder; 93 tableBuilder.CreateTable(s_SetInfoTable_Table).Columns({ 94 IntegerPrimaryKey(), 95 ColumnBuilder(s_SetInfoTable_Column_InstanceIdentifier, Type::Blob).Unique().NotNull(), 96 ColumnBuilder(s_SetInfoTable_Column_Name, Type::Text).NotNull(), 97 ColumnBuilder(s_SetInfoTable_Column_Origin, Type::Text).NotNull(), 98 ColumnBuilder(s_SetInfoTable_Column_Path, Type::Text).NotNull(), 99 ColumnBuilder(s_SetInfoTable_Column_FirstApply, Type::Int64).NotNull(), 100 ColumnBuilder(s_SetInfoTable_Column_SchemaVersion, Type::Text).NotNull(), 101 ColumnBuilder(s_SetInfoTable_Column_Metadata, Type::Text).NotNull(), 102 ColumnBuilder(s_SetInfoTable_Column_Parameters, Type::Text).NotNull(), 103 ColumnBuilder(s_SetInfoTable_Column_Variables, Type::Text).NotNull(), 104 }); 105 106 tableBuilder.Execute(m_connection); 107 108 savepoint.Commit(); 109 } 110 111 rowid_t SetInfoTable::Add(const Configuration::ConfigurationSet& configurationSet) 112 { 113 THROW_HR_IF(E_NOTIMPL, configurationSet.Parameters().Size() > 0); 114 115 Savepoint savepoint = Savepoint::Create(m_connection, "SetInfoTable_Add_0_1"); 116 117 hstring schemaVersion = configurationSet.SchemaVersion(); 118 auto serializer = ConfigurationSetSerializer::CreateSerializer(schemaVersion); 119 120 StatementBuilder builder; 121 builder.InsertInto(s_SetInfoTable_Table).Columns({ 122 s_SetInfoTable_Column_InstanceIdentifier, 123 s_SetInfoTable_Column_Name, 124 s_SetInfoTable_Column_Origin, 125 s_SetInfoTable_Column_Path, 126 s_SetInfoTable_Column_FirstApply, 127 s_SetInfoTable_Column_SchemaVersion, 128 s_SetInfoTable_Column_Metadata, 129 s_SetInfoTable_Column_Parameters, 130 s_SetInfoTable_Column_Variables, 131 }).Values( 132 static_cast<GUID>(configurationSet.InstanceIdentifier()), 133 ConvertToUTF8(configurationSet.Name()), 134 ConvertToUTF8(configurationSet.Origin()), 135 ConvertToUTF8(configurationSet.Path()), 136 GetCurrentUnixEpoch(), 137 ConvertToUTF8(schemaVersion), 138 serializer->SerializeMetadataWithEnvironment(configurationSet.Metadata(), configurationSet.Environment()), 139 std::string{}, // Parameters 140 serializer->SerializeValueSet(configurationSet.Variables()) 141 ); 142 143 builder.Execute(m_connection); 144 rowid_t result = m_connection.GetLastInsertRowID(); 145 146 UnitInfoTable unitInfoTable(m_connection); 147 148 auto winrtUnits = configurationSet.Units(); 149 std::vector<Configuration::ConfigurationUnit> units{ winrtUnits.Size() }; 150 winrtUnits.GetMany(0, units); 151 152 for (const auto& unit : units) 153 { 154 unitInfoTable.Add(unit, result, schemaVersion); 155 } 156 157 savepoint.Commit(); 158 return result; 159 } 160 161 void SetInfoTable::Update(rowid_t target, const Configuration::ConfigurationSet& configurationSet) 162 { 163 THROW_HR_IF(E_NOTIMPL, configurationSet.Parameters().Size() > 0); 164 165 Savepoint savepoint = Savepoint::Create(m_connection, "SetInfoTable_Update_0_1"); 166 167 hstring schemaVersion = configurationSet.SchemaVersion(); 168 auto serializer = ConfigurationSetSerializer::CreateSerializer(schemaVersion); 169 170 StatementBuilder builder; 171 builder.Update(s_SetInfoTable_Table).Set(). 172 Column(s_SetInfoTable_Column_Name).Equals(ConvertToUTF8(configurationSet.Name())). 173 Column(s_SetInfoTable_Column_Origin).Equals(ConvertToUTF8(configurationSet.Origin())). 174 Column(s_SetInfoTable_Column_Path).Equals(ConvertToUTF8(configurationSet.Path())). 175 Column(s_SetInfoTable_Column_SchemaVersion).Equals(ConvertToUTF8(schemaVersion)). 176 Column(s_SetInfoTable_Column_Metadata).Equals(serializer->SerializeMetadataWithEnvironment(configurationSet.Metadata(), configurationSet.Environment())). 177 Column(s_SetInfoTable_Column_Variables).Equals(serializer->SerializeValueSet(configurationSet.Variables())). 178 Where(RowIDName).Equals(target); 179 180 builder.Execute(m_connection); 181 182 UnitInfoTable unitInfoTable(m_connection); 183 unitInfoTable.UpdateForSet(target, configurationSet.Units(), schemaVersion); 184 185 savepoint.Commit(); 186 } 187 188 void SetInfoTable::Remove(rowid_t target) 189 { 190 Savepoint savepoint = Savepoint::Create(m_connection, "SetInfoTable_Remove_0_1"); 191 192 StatementBuilder builder; 193 builder.DeleteFrom(s_SetInfoTable_Table).Where(RowIDName).Equals(target); 194 builder.Execute(m_connection); 195 196 UnitInfoTable unitInfoTable(m_connection); 197 unitInfoTable.RemoveForSet(target); 198 199 savepoint.Commit(); 200 } 201 202 std::vector<IConfigurationDatabase::ConfigurationSetPtr> SetInfoTable::GetAllSets() 203 { 204 std::vector<IConfigurationDatabase::ConfigurationSetPtr> result; 205 206 StatementBuilder builder; 207 BuildBaseSetSelectStatement(builder); 208 209 Statement getAllSets = builder.Prepare(m_connection); 210 211 UnitInfoTable unitInfoTable(m_connection); 212 213 while (getAllSets.Step()) 214 { 215 result.emplace_back(GetSetFromStatement(getAllSets, unitInfoTable)); 216 } 217 218 return result; 219 } 220 221 std::optional<rowid_t> SetInfoTable::GetSetRowId(const GUID& instanceIdentifier) 222 { 223 StatementBuilder builder; 224 builder.Select(RowIDName).From(s_SetInfoTable_Table).Where(s_SetInfoTable_Column_InstanceIdentifier).Equals(instanceIdentifier); 225 226 Statement select = builder.Prepare(m_connection); 227 228 if (select.Step()) 229 { 230 return select.GetColumn<rowid_t>(0); 231 } 232 233 return std::nullopt; 234 } 235 236 IConfigurationDatabase::ConfigurationSetPtr SetInfoTable::GetSet(const GUID& instanceIdentifier) 237 { 238 IConfigurationDatabase::ConfigurationSetPtr result; 239 240 StatementBuilder builder; 241 BuildBaseSetSelectStatement(builder); 242 builder.Where(s_SetInfoTable_Column_InstanceIdentifier).Equals(instanceIdentifier); 243 244 Statement getSet = builder.Prepare(m_connection); 245 246 if (getSet.Step()) 247 { 248 UnitInfoTable unitInfoTable(m_connection); 249 result = GetSetFromStatement(getSet, unitInfoTable); 250 } 251 252 return result; 253 } 254 255 std::chrono::system_clock::time_point SetInfoTable::GetSetFirstApply(const GUID& instanceIdentifier) 256 { 257 StatementBuilder builder; 258 builder.Select(s_SetInfoTable_Column_FirstApply).From(s_SetInfoTable_Table).Where(s_SetInfoTable_Column_InstanceIdentifier).Equals(instanceIdentifier); 259 260 Statement statement = builder.Prepare(m_connection); 261 262 return (statement.Step() ? ConvertUnixEpochToSystemClock(statement.GetColumn<int64_t>(0)) : std::chrono::system_clock::time_point{}); 263 } 264 }