File: statistics_table.cc

package info (click to toggle)
chromium-browser 57.0.2987.98-1~deb8u1
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 2,637,852 kB
  • ctags: 2,544,394
  • sloc: cpp: 12,815,961; ansic: 3,676,222; python: 1,147,112; asm: 526,608; java: 523,212; xml: 286,794; perl: 92,654; sh: 86,408; objc: 73,271; makefile: 27,698; cs: 18,487; yacc: 13,031; tcl: 12,957; pascal: 4,875; ml: 4,716; lex: 3,904; sql: 3,862; ruby: 1,982; lisp: 1,508; php: 1,368; exp: 404; awk: 325; csh: 117; jsp: 39; sed: 37
file content (179 lines) | stat: -rw-r--r-- 5,863 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/password_manager/core/browser/statistics_table.h"

#include <stdint.h>

#include <algorithm>
#include <limits>
#include <set>

#include "base/memory/ptr_util.h"
#include "sql/connection.h"
#include "sql/statement.h"

namespace password_manager {
namespace {

// Convenience enum for interacting with SQL queries that use all the columns.
enum LoginTableColumns {
  COLUMN_ORIGIN_DOMAIN = 0,
  COLUMN_USERNAME,
  COLUMN_DISMISSALS,
  COLUMN_DATE,
};

}  // namespace

InteractionsStats::InteractionsStats() = default;

bool operator==(const InteractionsStats& lhs, const InteractionsStats& rhs) {
  return lhs.origin_domain == rhs.origin_domain &&
         lhs.username_value == rhs.username_value &&
         lhs.dismissal_count == rhs.dismissal_count &&
         lhs.update_time == rhs.update_time;
}

const InteractionsStats* FindStatsByUsername(
    const std::vector<InteractionsStats>& stats,
    const base::string16& username) {
  auto it = std::find_if(stats.begin(), stats.end(),
                         [&username](const InteractionsStats& element) {
                           return username == element.username_value;
                         });
  return it == stats.end() ? nullptr : &*it;
}

StatisticsTable::StatisticsTable() : db_(nullptr) {
}

StatisticsTable::~StatisticsTable() = default;

void StatisticsTable::Init(sql::Connection* db) {
  db_ = db;
}

bool StatisticsTable::CreateTableIfNecessary() {
  if (!db_->DoesTableExist("stats")) {
    const char query[] =
        "CREATE TABLE stats ("
        "origin_domain VARCHAR NOT NULL, "
        "username_value VARCHAR, "
        "dismissal_count INTEGER, "
        "update_time INTEGER NOT NULL, "
        "UNIQUE(origin_domain, username_value))";
    if (!db_->Execute(query))
      return false;
    const char index[] = "CREATE INDEX stats_origin ON stats(origin_domain)";
    if (!db_->Execute(index))
      return false;
  }
  return true;
}

bool StatisticsTable::MigrateToVersion(int version) {
  if (!db_->DoesTableExist("stats"))
    return true;
  if (version == 16)
    return db_->Execute("DROP TABLE stats");
  return true;
}

bool StatisticsTable::AddRow(const InteractionsStats& stats) {
  if (!stats.origin_domain.is_valid())
    return false;
  sql::Statement s(db_->GetCachedStatement(
      SQL_FROM_HERE,
      "INSERT OR REPLACE INTO stats "
      "(origin_domain, username_value, dismissal_count, update_time) "
      "VALUES (?, ?, ?, ?)"));
  s.BindString(COLUMN_ORIGIN_DOMAIN, stats.origin_domain.spec());
  s.BindString16(COLUMN_USERNAME, stats.username_value);
  s.BindInt(COLUMN_DISMISSALS, stats.dismissal_count);
  s.BindInt64(COLUMN_DATE, stats.update_time.ToInternalValue());
  return s.Run();
}

bool StatisticsTable::RemoveRow(const GURL& domain) {
  if (!domain.is_valid())
    return false;
  sql::Statement s(db_->GetCachedStatement(SQL_FROM_HERE,
                                           "DELETE FROM stats WHERE "
                                           "origin_domain = ? "));
  s.BindString(0, domain.spec());
  return s.Run();
}

std::vector<InteractionsStats> StatisticsTable::GetRows(const GURL& domain) {
  if (!domain.is_valid())
    return std::vector<InteractionsStats>();
  const char query[] =
      "SELECT origin_domain, username_value, "
      "dismissal_count, update_time FROM stats WHERE origin_domain == ?";
  sql::Statement s(db_->GetCachedStatement(SQL_FROM_HERE, query));
  s.BindString(0, domain.spec());
  std::vector<InteractionsStats> result;
  while (s.Step()) {
    result.push_back(InteractionsStats());
    result.back().origin_domain = GURL(s.ColumnString(COLUMN_ORIGIN_DOMAIN));
    result.back().username_value = s.ColumnString16(COLUMN_USERNAME);
    result.back().dismissal_count = s.ColumnInt(COLUMN_DISMISSALS);
    result.back().update_time =
        base::Time::FromInternalValue(s.ColumnInt64(COLUMN_DATE));
  }
  return result;
}

bool StatisticsTable::RemoveStatsByOriginAndTime(
    const base::Callback<bool(const GURL&)>& origin_filter,
    base::Time delete_begin,
    base::Time delete_end) {
  if (delete_end.is_null())
    delete_end = base::Time::Max();

  // All origins.
  if (origin_filter.is_null()) {
    sql::Statement delete_statement(db_->GetCachedStatement(
        SQL_FROM_HERE,
        "DELETE FROM stats WHERE update_time >= ? AND update_time < ?"));
    delete_statement.BindInt64(0, delete_begin.ToInternalValue());
    delete_statement.BindInt64(1, delete_end.ToInternalValue());

    return delete_statement.Run();
  }

  // Origin filtering.
  sql::Statement select_statement(
      db_->GetCachedStatement(SQL_FROM_HERE,
                              "SELECT origin_domain FROM stats "
                              "WHERE update_time >= ? AND update_time < ?"));
  select_statement.BindInt64(0, delete_begin.ToInternalValue());
  select_statement.BindInt64(1, delete_end.ToInternalValue());

  std::set<std::string> origins;
  while (select_statement.Step()) {
    if (!origin_filter.Run(GURL(select_statement.ColumnString(0))))
      continue;

    origins.insert(select_statement.ColumnString(0));
  }

  bool success = true;

  for (const std::string& origin : origins) {
    sql::Statement origin_delete_statement(db_->GetCachedStatement(
        SQL_FROM_HERE,
        "DELETE FROM stats "
        "WHERE origin_domain = ? AND update_time >= ? AND update_time < ?"));
    origin_delete_statement.BindString(0, origin);
    origin_delete_statement.BindInt64(1, delete_begin.ToInternalValue());
    origin_delete_statement.BindInt64(2, delete_end.ToInternalValue());
    success = success && origin_delete_statement.Run();
  }

  return success;
}

}  // namespace password_manager