winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

SystemReferenceStringTable.cpp (10377B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "Microsoft/Schema/2_0/SystemReferenceStringTable.h"
      5 #include "Microsoft/Schema/2_0/PackagesTable.h"
      6 #include <winget/SQLiteStatementBuilder.h>
      7 
      8 
      9 namespace AppInstaller::Repository::Microsoft::Schema::V2_0
     10 {
     11     namespace details
     12     {
     13         using PrimaryTable = PackagesTable;
     14 
     15         using namespace std::string_view_literals;
     16         static constexpr std::string_view s_SystemReferenceStringTable_PrimaryName = "package"sv;
     17 
     18         std::string_view SystemReferenceStringTableGetPrimaryColumnName()
     19         {
     20             return s_SystemReferenceStringTable_PrimaryName;
     21         }
     22 
     23         void SystemReferenceStringTableCreate(SQLite::Connection& connection, std::string_view tableName, std::string_view valueName)
     24         {
     25             using namespace SQLite::Builder;
     26 
     27             SQLite::Savepoint savepoint = SQLite::Savepoint::Create(connection, std::string{ tableName } + "_create_v2_0");
     28 
     29             StatementBuilder createTableBuilder;
     30             createTableBuilder.CreateTable(tableName).Columns({
     31                 ColumnBuilder(valueName, Type::Text).NotNull(),
     32                 ColumnBuilder(s_SystemReferenceStringTable_PrimaryName, Type::RowId).NotNull(),
     33                 PrimaryKeyBuilder({ valueName, s_SystemReferenceStringTable_PrimaryName })
     34                 }).WithoutRowID();
     35 
     36             createTableBuilder.Execute(connection);
     37 
     38             savepoint.Commit();
     39         }
     40 
     41         void SystemReferenceStringTableDrop(SQLite::Connection& connection, std::string_view tableName)
     42         {
     43             SQLite::Builder::StatementBuilder dropTableBuilder;
     44             dropTableBuilder.DropTable(tableName);
     45 
     46             dropTableBuilder.Execute(connection);
     47         }
     48 
     49         std::vector<std::string> SystemReferenceStringTableGetValuesByPrimaryId(
     50             const SQLite::Connection& connection,
     51             std::string_view tableName,
     52             std::string_view valueName,
     53             SQLite::rowid_t primaryId)
     54         {
     55             std::vector<std::string> result;
     56 
     57             SQLite::Builder::StatementBuilder builder;
     58             builder.Select(valueName).
     59                 From(tableName).Where(s_SystemReferenceStringTable_PrimaryName).Equals(primaryId);
     60 
     61             SQLite::Statement statement = builder.Prepare(connection);
     62 
     63             while (statement.Step())
     64             {
     65                 result.emplace_back(statement.GetColumn<std::string>(0));
     66             }
     67 
     68             return result;
     69         }
     70 
     71         void SystemReferenceStringTableEnsureExists(
     72             SQLite::Connection& connection,
     73             std::string_view tableName,
     74             std::string_view valueName,
     75             const std::vector<std::string>& values,
     76             SQLite::rowid_t primaryId)
     77         {
     78             SQLite::Savepoint savepoint = SQLite::Savepoint::Create(connection, std::string{ tableName } + "_ensure_v2_0");
     79 
     80             SQLite::Builder::StatementBuilder builder;
     81 
     82             builder.InsertOrIgnore(tableName).
     83                 Columns({ valueName, s_SystemReferenceStringTable_PrimaryName }).Values(SQLite::Builder::Unbound, primaryId);
     84 
     85             SQLite::Statement insertStatement = builder.Prepare(connection);
     86 
     87             for (const std::string& value : values)
     88             {
     89                 // Second, insert into the mapping table
     90                 insertStatement.Reset();
     91                 insertStatement.Bind(1, value);
     92 
     93                 insertStatement.Execute();
     94             }
     95 
     96             savepoint.Commit();
     97         }
     98 
     99         bool SystemReferenceStringTableCheckConsistency(const SQLite::Connection& connection, std::string_view tableName, std::string_view valueName, bool log)
    100         {
    101             using QCol = SQLite::Builder::QualifiedColumn;
    102 
    103             bool result = true;
    104 
    105             {
    106                 // Build a select statement to find rows containing references to primaries with nonexistent rowids
    107                 // Such as:
    108                 // Select data.data, data.primary from data left outer join primary on data.primary = primary.rowid where primary.id is null
    109 
    110                 SQLite::Builder::StatementBuilder builder;
    111                 builder.
    112                     Select({ QCol(tableName, valueName), QCol(tableName, s_SystemReferenceStringTable_PrimaryName) }).
    113                     From(tableName).
    114                     LeftOuterJoin(details::PrimaryTable::TableName()).On(QCol(tableName, s_SystemReferenceStringTable_PrimaryName), QCol(details::PrimaryTable::TableName(), SQLite::RowIDName)).
    115                     Where(QCol(details::PrimaryTable::TableName(), SQLite::RowIDName)).IsNull();
    116 
    117                 SQLite::Statement select = builder.Prepare(connection);
    118 
    119                 while (select.Step())
    120                 {
    121                     result = false;
    122 
    123                     if (!log)
    124                     {
    125                         break;
    126                     }
    127 
    128                     AICLI_LOG(Repo, Info, << "  [INVALID] " << tableName << " [" << select.GetColumn<std::string>(0) <<
    129                         ", " << select.GetColumn<SQLite::rowid_t>(1) << "] refers to invalid " << details::PrimaryTable::TableName());
    130                 }
    131             }
    132 
    133             if (!result && !log)
    134             {
    135                 return result;
    136             }
    137 
    138             // Build a select statement to find values that contain an embedded null character
    139             // Such as:
    140             // Select count(*) from table where instr(value,char(0))>0
    141             SQLite::Builder::StatementBuilder builder;
    142             builder.
    143                 Select({ valueName, s_SystemReferenceStringTable_PrimaryName }).
    144                 From(tableName).
    145                 WhereValueContainsEmbeddedNullCharacter(valueName);
    146 
    147             SQLite::Statement select = builder.Prepare(connection);
    148 
    149             while (select.Step())
    150             {
    151                 result = false;
    152 
    153                 if (!log)
    154                 {
    155                     break;
    156                 }
    157 
    158                 AICLI_LOG(Repo, Info, << "  [INVALID] value in table [" << tableName << "] for primary [" << select.GetColumn<SQLite::rowid_t>(1) << "] contains an embedded null character and starts with [" << select.GetColumn<std::string>(0) << "]");
    159             }
    160 
    161             return result;
    162         }
    163 
    164         bool SystemReferenceStringTableIsEmpty(SQLite::Connection& connection, std::string_view tableName)
    165         {
    166             SQLite::Builder::StatementBuilder countBuilder;
    167             countBuilder.Select(SQLite::Builder::RowCount).From(tableName);
    168 
    169             SQLite::Statement countStatement = countBuilder.Prepare(connection);
    170 
    171             THROW_HR_IF(E_UNEXPECTED, !countStatement.Step());
    172 
    173             return countStatement.GetColumn<int>(0) == 0;
    174         }
    175 
    176         int SystemReferenceStringTableBuildSearchStatement(
    177             SQLite::Builder::StatementBuilder& builder,
    178             std::string_view tableName,
    179             std::string_view valueName,
    180             std::string_view primaryAlias,
    181             std::string_view valueAlias,
    182             bool useLike)
    183         {
    184             using QCol = SQLite::Builder::QualifiedColumn;
    185 
    186             // Build a statement like:
    187             //      SELECT table.package as p, table.value as v from table
    188             //      where table.value = <value>
    189             builder.Select().
    190                 Column(s_SystemReferenceStringTable_PrimaryName).As(primaryAlias).
    191                 Column(valueName).As(valueAlias).
    192                 From(tableName).
    193                 Where(valueName);
    194 
    195             int result = -1;
    196 
    197             if (useLike)
    198             {
    199                 builder.Like(SQLite::Builder::Unbound);
    200                 result = builder.GetLastBindIndex();
    201                 builder.Escape(SQLite::EscapeCharForLike);
    202             }
    203             else
    204             {
    205                 builder.Equals(SQLite::Builder::Unbound);
    206                 result = builder.GetLastBindIndex();
    207             }
    208 
    209             return result;
    210         }
    211 
    212         std::vector<int> SystemReferenceStringTableBuildPairedSearchStatement(
    213             SQLite::Builder::StatementBuilder& builder,
    214             std::string_view tableName,
    215             std::string_view valueName,
    216             std::string_view pairedTableName,
    217             std::string_view pairedValueName,
    218             std::string_view primaryAlias,
    219             std::string_view valueAlias,
    220             bool useLike)
    221         {
    222             using QCol = SQLite::Builder::QualifiedColumn;
    223 
    224             // Build a statement like:
    225             //      SELECT table.package as p, '' as v from table
    226             //      join paired on table.package = paired.package
    227             //      where table.value = <value1> and paired.pairedValue = <value2>
    228             builder.Select().
    229                 Column(QCol(tableName, s_SystemReferenceStringTable_PrimaryName)).As(primaryAlias).
    230                 Value(std::string_view{}).As(valueAlias).
    231                 From(tableName).
    232                 Join(pairedTableName).On(QCol(tableName, s_SystemReferenceStringTable_PrimaryName), QCol(pairedTableName, s_SystemReferenceStringTable_PrimaryName)).
    233                 Where(QCol(tableName, valueName));
    234 
    235             std::vector<int> result;
    236 
    237             if (useLike)
    238             {
    239                 builder.Like(SQLite::Builder::Unbound);
    240                 result.push_back(builder.GetLastBindIndex());
    241                 builder.Escape(SQLite::EscapeCharForLike);
    242             }
    243             else
    244             {
    245                 builder.Equals(SQLite::Builder::Unbound);
    246                 result.push_back(builder.GetLastBindIndex());
    247             }
    248 
    249             builder.And(QCol(pairedTableName, pairedValueName));
    250 
    251             if (useLike)
    252             {
    253                 builder.Like(SQLite::Builder::Unbound);
    254                 result.push_back(builder.GetLastBindIndex());
    255                 builder.Escape(SQLite::EscapeCharForLike);
    256             }
    257             else
    258             {
    259                 builder.Equals(SQLite::Builder::Unbound);
    260                 result.push_back(builder.GetLastBindIndex());
    261             }
    262 
    263             return result;
    264         }
    265     }
    266 }