MySQL: Quote identifiers that include special characters (#61135)

* SQL: toRawSQL required and escape table

* Fix autocomplete for MySQL

* Change the way we escape for builder

* Rework escape ident to be smart instead

* Fix A11y for alias

* Add first e2e test

* Add test for code editor

* Add doc

* Review comments

* Move functions to sqlUtil
This commit is contained in:
Zoltán Bedi
2023-01-31 18:16:28 +01:00
committed by GitHub
parent bba80b6c7a
commit 62c30dea4d
18 changed files with 678 additions and 191 deletions
+21
View File
@@ -0,0 +1,21 @@
{
"results": {
"datasets": {
"status": 200,
"frames": [
{
"schema": {
"refId": "datasets",
"meta": {
"executedQueryString": "SELECT DISTINCT TABLE_SCHEMA from information_schema.TABLES where TABLE_TYPE != 'SYSTEM VIEW' ORDER BY TABLE_SCHEMA"
},
"fields": [
{ "name": "TABLE_SCHEMA", "type": "string", "typeInfo": { "frame": "string", "nullable": true } }
]
},
"data": { "values": [["DataMaker", "mysql", "performance_schema", "sys"]] }
}
]
}
}
}
+27
View File
@@ -0,0 +1,27 @@
{
"results": {
"fields": {
"status": 200,
"frames": [
{
"schema": {
"refId": "fields",
"meta": {
"executedQueryString": "SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'DataMaker' AND table_name = 'RandomIntsWithTimes' ORDER BY column_name"
},
"fields": [
{ "name": "COLUMN_NAME", "type": "string", "typeInfo": { "frame": "string", "nullable": true } },
{ "name": "DATA_TYPE", "type": "string", "typeInfo": { "frame": "string", "nullable": true } }
]
},
"data": {
"values": [
["createdAt", "id", "time", "updatedAt", "bigint"],
["datetime", "int", "datetime", "datetime", "int"]
]
}
}
]
}
}
}
+59
View File
@@ -0,0 +1,59 @@
import { e2e } from '@grafana/e2e';
import datasetResponse from './datasets-response.json';
import fieldsResponse from './fields-response.json';
import tablesResponse from './tables-response.json';
const tableNameWithSpecialCharacter = tablesResponse.results.tables.frames[0].data.values[0][1];
const normalTableName = tablesResponse.results.tables.frames[0].data.values[0][0];
describe('MySQL datasource', () => {
it('code editor autocomplete should handle table name escaping/quoting', () => {
e2e.flows.login('admin', 'admin');
e2e().intercept('POST', '**/api/ds/query', (req) => {
if (req.body.queries[0].refId === 'datasets') {
req.alias = 'datasets';
req.reply({
body: datasetResponse,
});
} else if (req.body.queries[0].refId === 'tables') {
req.alias = 'tables';
req.reply({
body: tablesResponse,
});
} else if (req.body.queries[0].refId === 'fields') {
req.alias = 'fields';
req.reply({
body: fieldsResponse,
});
}
});
e2e.pages.Explore.visit();
e2e.components.DataSourcePicker.container().should('be.visible').type('gdev-mysql{enter}');
e2e().get("label[for^='option-code']").should('be.visible').click();
e2e().get('textarea').type('S{downArrow}{enter}');
e2e().wait('@tables');
e2e().get('.suggest-widget').contains(tableNameWithSpecialCharacter).should('be.visible');
e2e().get('textarea').type('{enter}');
e2e().get('textarea').should('have.value', `SELECT FROM grafana.\`${tableNameWithSpecialCharacter}\``);
const deleteTimes = new Array(tableNameWithSpecialCharacter.length + 2).fill(
'{backspace}',
0,
tableNameWithSpecialCharacter.length + 2
);
e2e().get('textarea').type(deleteTimes.join(''));
e2e().get('textarea').type('{command}i');
e2e().get('.suggest-widget').contains(tableNameWithSpecialCharacter).should('be.visible');
e2e().get('textarea').type('S{downArrow}{enter}');
e2e().get('textarea').should('have.value', `SELECT FROM grafana.${normalTableName}`);
e2e().get('textarea').type('.');
e2e().get('.suggest-widget').contains('No suggestions.').should('be.visible');
});
});
+19
View File
@@ -0,0 +1,19 @@
{
"results": {
"tables": {
"status": 200,
"frames": [
{
"schema": {
"refId": "tables",
"meta": {
"executedQueryString": "SELECT table_name FROM information_schema.tables WHERE table_schema = 'DataMaker' ORDER BY table_name"
},
"fields": [{ "name": "TABLE_NAME", "type": "string", "typeInfo": { "frame": "string", "nullable": true } }]
},
"data": { "values": [["normalTable", "table-name"]] }
}
]
}
}
}