1/*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17syntax = "proto3";
18
19package androidx.sqlite.inspection;
20
21option java_package = "androidx.sqlite.inspection";
22option java_outer_classname = "SqliteInspectorProtocol";
23
24// --- Commands ---
25
26// Generic Command object grouping all Inspector Command types. Expected in
27// Inspector's onReceiveCommand.
28message Command {
29  // Wrapped specialised Command.
30  oneof OneOf {
31    TrackDatabasesCommand track_databases = 1;
32    GetSchemaCommand get_schema = 2;
33    QueryCommand query = 3;
34    KeepDatabasesOpenCommand keep_databases_open = 4;
35    AcquireDatabaseLockCommand acquire_database_lock = 5;
36    ReleaseDatabaseLockCommand release_database_lock = 6;
37  }
38}
39
40// Request for the Inspector to track database connections (existing and new)
41// and notify of those via DatabaseOpenedEvent objects.
42message TrackDatabasesCommand {}
43
44// Request for the Inspector to return schema information for a given database.
45message GetSchemaCommand {
46  // Id uniquely identifying a connection to the database.
47  int32 database_id = 1;
48}
49
50// Request for the Inspector to execute a query and return its results.
51// TODO: add support for parameterised queries
52message QueryCommand {
53  // Id uniquely identifying a connection to the database.
54  int32 database_id = 1;
55  // Query to execute.
56  string query = 2;
57  // The query may include ?s, which will be replaced by values from
58  // query_parameters, in the order that they appear in the query. Values will
59  // be bound as Strings.
60  repeated QueryParameterValue query_parameter_values = 3;
61  // Approximate response size limit in bytes.
62  // Best effort:
63  // - can deviate from the value up to 40% due to encoding overheads
64  // - in some cases can deviate by an extra ~2MB (max size of one row in Android SQLite)
65  // When unset, or set to <= `0`, it is considered unbounded.
66  int64 response_size_limit_hint = 4;
67}
68
69// Value of a parameter in QueryCommand. Currently only string and null values
70// are supported.
71message QueryParameterValue {
72  oneof OneOf {
73    string string_value = 1;
74  }
75}
76
77// Request to prevent databases from being closed by the app
78// (allowing for a larger time-window for inspection)
79message KeepDatabasesOpenCommand {
80  // True to enable the functionality; false to disable
81  bool set_enabled = 1;
82}
83
84// Request to lock a database to prevent modifications on it
85// (allowing for e.g. creating a consistent snapshot)
86message AcquireDatabaseLockCommand {
87  // Database to secure a lock on
88  int32 database_id = 1;
89}
90
91// Request to release a previously acquired database lock (see AcquireDatabaseLockCommand)
92message ReleaseDatabaseLockCommand {
93  // Id of the lock to release (see AcquireDatabaseLockResponse)
94  int32 lock_id = 1;
95}
96
97// --- Responses ---
98
99// Generic Response object grouping all Inspector Response types to Command
100// objects.
101message Response {
102  // Wrapped specialised Response.
103  oneof OneOf {
104    TrackDatabasesResponse track_databases = 1;
105    GetSchemaResponse get_schema = 2;
106    QueryResponse query = 3;
107    KeepDatabasesOpenResponse keep_databases_open = 4;
108    AcquireDatabaseLockResponse acquire_database_lock = 5;
109    ReleaseDatabaseLockResponse release_database_lock = 6;
110    ErrorOccurredResponse error_occurred = 400;
111  }
112}
113
114// Object expected as a response to TrackDatabasesCommand.
115message TrackDatabasesResponse {}
116
117// Object expected as a response to GetSchemaCommand.
118message GetSchemaResponse {
119  repeated Table tables = 1;
120}
121
122// Schema information for a table or a view.
123message Table {
124  string name = 1;
125  // True for a view; false for a regular table.
126  bool is_view = 2;
127  repeated Column columns = 3;
128}
129
130// Schema information for a table column.
131message Column {
132  string name = 1;
133  // Column type affinity.
134  string type = 2;
135  // PRIMARY KEY constraint: zero for columns that are not part of the primary
136  // key, or the index of the column in the primary key for columns that are
137  // part of the primary key.
138  int32 primary_key = 3;
139  // NOT NULL constraint.
140  bool is_not_null = 4;
141  // UNIQUE constraint on its own (i.e. not as a part of
142  // compound-unique-constraint-index).
143  bool is_unique = 5;
144}
145
146// Object expected as a response to QueryCommand.
147message QueryResponse {
148  repeated Row rows = 1;
149  // Names of columns in the result set
150  repeated string column_names = 2;
151}
152
153// Query result row.
154message Row {
155  repeated CellValue values = 1;
156}
157
158// Query result cell.
159message CellValue {
160  // Resulting cell value depending on type affinity rules.
161  oneof OneOf {
162    double double_value = 1;
163    int64 long_value = 2;
164    string string_value = 3;
165    bytes blob_value = 4;
166  }
167}
168
169message KeepDatabasesOpenResponse {}
170
171// Object expected as a response to AcquireDatabaseLockCommand.
172message AcquireDatabaseLockResponse {
173  // Id of the lock (allowing for releasing the lock later using ReleaseDatabaseLockRequest)
174  int32 lock_id = 1;
175}
176
177// Object expected as a response to ReleaseDatabaseLockCommand.
178message ReleaseDatabaseLockResponse {}
179
180// General Error message.
181// TODO: decide on a more fine-grained approach
182message ErrorOccurredResponse {
183  ErrorContent content = 1;
184}
185
186message ErrorContent {
187  // Main error message.
188  string message = 1;
189  // Optional stack trace.
190  string stack_trace = 2;
191  // Recoverability information
192  ErrorRecoverability recoverability = 3;
193  // Error code
194  enum ErrorCode {
195    NOT_SET = 0;
196    ERROR_UNKNOWN = 10;
197    ERROR_UNRECOGNISED_COMMAND = 20;
198    ERROR_DATABASE_VERSION_TOO_OLD = 30;
199    ERROR_ISSUE_WITH_PROCESSING_QUERY = 40;
200    ERROR_NO_OPEN_DATABASE_WITH_REQUESTED_ID = 50;
201    ERROR_ISSUE_WITH_PROCESSING_NEW_DATABASE_CONNECTION = 60;
202    ERROR_DB_CLOSED_DURING_OPERATION = 70;
203    ERROR_ISSUE_WITH_LOCKING_DATABASE = 80;
204  }
205  ErrorCode error_code = 4;
206}
207
208// Recoverability of an error:
209// - is_recoverable = true -> an error is recoverable (e.g. query syntax error)
210// - is_recoverable = false -> an error is not recoverable (e.g. corrupt internal inspector state)
211// - unset -> not enough information to determine recoverability (e.g. an issue that may or may not
212//   prevent a user from continuing the session - and is left for the user to decide how to act on)
213message ErrorRecoverability {
214  oneof OneOf {
215    bool is_recoverable = 1;
216  }
217}
218
219// --- Events ---
220
221// Generic Event object grouping all Inspector Event types. Expected in
222// Connection's sendEvent method.
223message Event {
224  // Wrapped specialised Event.
225  oneof OneOf {
226    DatabaseOpenedEvent database_opened = 1;
227    DatabaseClosedEvent database_closed = 2;
228    DatabasePossiblyChangedEvent database_possibly_changed = 3;
229    ErrorOccurredEvent error_occurred = 400;
230  }
231}
232
233// Notification of a database connection established (new) / discovered
234// (existing).
235message DatabaseOpenedEvent {
236  // Id uniquely identifying a connection to a database. Required to perform
237  // requests on the database.
238  int32 database_id = 1;
239  // Path to db file or ":memory" if it is in-memory database.
240  // Note: there is no guarantee that it is necessarily unique between databases.
241  string path = 2;
242}
243
244// Notification of a database connection closed (database no longer query-able)
245// TODO: consider consolidating with DatabaseOpenedEvent
246message DatabaseClosedEvent {
247  // Id uniquely identifying a connection to a database. Required to perform
248  // requests on the database.
249  int32 database_id = 1;
250  // Path to db file or ":memory" if it is in-memory database.
251  // Note: there is no guarantee that it is necessarily unique between databases.
252  string path = 2;
253}
254
255// An event sent when an operation that could potentially change the contents of a database has
256// been detected. The event might be used in triggering a refresh of currently displayed query
257// results to keep the results current.
258message DatabasePossiblyChangedEvent {
259    // TODO: add database id
260}
261
262// General Error message.
263// TODO: decide on a more fine-grained approach
264message ErrorOccurredEvent {
265  ErrorContent content = 1;
266}
267