Skip to content
Permalink
Browse files

Add support for 'show database for user' query, and show databases ow…

…ned by a user in the web client
  • Loading branch information...
pixelspark committed Dec 5, 2017
1 parent 328629a commit 418fbe31da90fb867e04bc97f2f6b321f8248318
@@ -100,7 +100,14 @@ Currently unimplemented; returns connection settings. The columns are named 'nam

#### SHOW DATABASES

Returns a list of databases. This statement can be executed outside of database context.
Returns a list of databases and their owner public key hashes. This statement can be executed outside
of database context (as well as inside, it does not make a difference).

Optionally, you can specifiy a public key hash for which the owned databases should be returned:

````sql
SHOW DATABASES FOR X'1ac71735e59106b72e0a9d2e4795b5f29077c02ed61a4af46e6e311f88b63e7b';
````

#### SHOW GRANTS

Large diffs are not rendered by default.

Oops, something went wrong.

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -27,6 +27,9 @@
</template>
</dl>

<h2>Owned databases</h2>
<catena-query v-if="agent !== null" :sql="ownedSQL" :agent="agent" :head="head" :database="database" no-data="This user does not currently own any databases."></catena-query>

<h2>Grants</h2>
<dl>
<dt>Show grants in database:</dt>
@@ -38,7 +41,7 @@
</dd>
</dl>

<catena-query v-if="agent !== null && database != '' " :sql="grantsSQL" :agent="agent" :head="head" :database="database"></catena-query>
<catena-query v-if="agent !== null && database != '' " :sql="grantsSQL" :agent="agent" :head="head" :database="database" no-data="This user was not granted any privileges for this database."></catena-query>
<catena-expander title="Grant privileges" icon="plus" v-if="database != '' ">
<catena-granter :agent="agent" :user="identity" :database="database"></catena-granter>
</catena-expander>
@@ -131,6 +134,10 @@ module.exports = {
return "SHOW GRANTS FOR X'"+this.identity.publicHashHex+"';";
},
ownedSQL: function() {
return "SHOW DATABASES FOR X'"+this.identity.publicHashHex+"';";
},
combinedSignedMessage: function() {
return JSON.stringify([this.messageToSign, this.messageSignature]);
}
@@ -31,7 +31,7 @@
</thead>

<tbody>
<tr v-if="!result.rows || result.rows.length == 0" ><td>(No data)</td></tr>
<tr v-if="!result.rows || result.rows.length == 0" ><td>{{noData}}</td></tr>

<tr v-for="(row, idx) in result.rows" :key="idx">
<td v-for="(cell, idx) in row" :key="idx">
@@ -55,7 +55,8 @@ module.exports = {
sql: String,
database: String,
agent: Agent,
head: {type: String, default: null}
head: {type: String, default: null},
noData: {type: String, default: "(No data)"}
},
data: function() {
@@ -601,8 +601,8 @@ class SQLExecutive {
case .tables:
return try self.tables(in: self.context.database, context: self.context)

case .databases:
let data = try self.context.metadata.databases.list()
case .databases(let sg):
let data = try self.context.metadata.databases.list(for: sg.forUser)
let rows = data.map({ (key, value) -> [Value] in
return [.text(key.name), .blob(value.data)]
})
@@ -783,7 +783,7 @@ extension SQLStatement {
switch t {
case .tables: return SQLExecutive.showTablesColumns.map { SQLColumn(name: $0) }
case .all: return SQLExecutive.showAllColumns.map { SQLColumn(name: $0) }
case .databases: return SQLExecutive.showDatabasesColumns.map { SQLColumn(name: $0) }
case .databases(_): return SQLExecutive.showDatabasesColumns.map { SQLColumn(name: $0) }
case .grants(_): return SQLExecutive.showGrantsColumns.map { SQLColumn(name: $0) }
}

@@ -431,11 +431,17 @@ public class SQLDatabasesTable {
}

/** Returns a list of databases with their owners */
public func list() throws -> [SQLDatabase: PublicKey] {
public func list(for user: Data? = nil) throws -> [SQLDatabase: PublicKey] {
var filter: SQLExpression? = nil
if let u = user {
filter = .binary(.column(self.ownerColumn), .equals, .literalBlob(u))
}

let selectStatement = SQLStatement.select(SQLSelect(
these: [.column(self.nameColumn), .column(self.ownerColumn)],
from: self.table,
joins: [],
where: filter,
distinct: false,
orders: []
))
@@ -196,9 +196,13 @@ public struct SQLShowGrants {
var forTable: SQLTable? = nil
}

public struct SQLShowDatabases {
var forUser: Data? = nil
}

public enum SQLShow {
case tables
case databases
case databases(SQLShowDatabases)
case all
case grants(SQLShowGrants)
}
@@ -440,7 +444,13 @@ public enum SQLStatement {
switch s {
case .tables: return "SHOW TABLES\(end)"
case .all: return "SHOW ALL\(end)"
case .databases: return "SHOW DATABASES\(end)"
case .databases(let g):
var forUser = ""
if let u = g.forUser {
forUser = " FOR \(dialect.literalBlob(u))"
}
return "SHOW DATABASES\(forUser)\(end)"

case .grants(let g):
var sql = "SHOW GRANTS"
if let u = g.forUser {
@@ -1243,21 +1253,34 @@ internal class SQLParser {
}, separator: Parser.matchLiteral(","))
)

g["lit-user"] = ^"lit-blob"

g["show-statement"] = Parser.matchLiteralInsensitive("SHOW ") ~~ (
(Parser.matchLiteralInsensitive("TABLES") => { [unowned self] in
self.stack.append(.statement(.show(.tables)))
})
| (Parser.matchLiteralInsensitive("ALL") => { [unowned self] in
self.stack.append(.statement(.show(.all)))
})
| (Parser.matchLiteralInsensitive("DATABASES") => { [unowned self] in
self.stack.append(.statement(.show(.databases)))
})
| (
(Parser.matchLiteralInsensitive("DATABASES") => { [unowned self] in
self.stack.append(.statement(.show(.databases(SQLShowDatabases()))))
})
~~ ((Parser.matchLiteralInsensitive("FOR ")) ~~ ^"lit-user" => {
guard case .expression(let t) = self.stack.popLast()! else { fatalError() }
guard case .literalBlob(let data) = t else { fatalError() }
guard case .statement(let st) = self.stack.popLast()! else { fatalError() }
guard case .show(let showType) = st else { fatalError() }
guard case .databases(var sg) = showType else { fatalError() }
sg.forUser = data
self.stack.append(.statement(.show(.databases(sg))))
})/~
)
| (
(Parser.matchLiteralInsensitive("GRANTS") => { [unowned self] in
self.stack.append(.statement(.show(.grants(SQLShowGrants()))))
})
~~ ((Parser.matchLiteralInsensitive("FOR ")) ~~ ^"lit-blob" => {
~~ ((Parser.matchLiteralInsensitive("FOR ")) ~~ ^"lit-user" => {
guard case .expression(let t) = self.stack.popLast()! else { fatalError() }
guard case .literalBlob(let data) = t else { fatalError() }
guard case .statement(let st) = self.stack.popLast()! else { fatalError() }

0 comments on commit 418fbe3

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.