Autocomplete table/column names in SQL editors
- In DB and Table level SQL editors, console - Updated CodeMirror addon `sql-hint.js` to newer version Signed-off-by: Nisarg Jhaveri <nisarg.jhaveri@research.iiit.ac.in>
This commit is contained in:
parent
bd25766b7b
commit
6cc3ea6eae
22
db_sql_autocomplete.php
Normal file
22
db_sql_autocomplete.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/* vim: set expandtab sw=4 ts=4 sts=4: */
|
||||
/**
|
||||
* Table/Column autocomplete in SQL editors
|
||||
*
|
||||
* @package PhpMyAdmin
|
||||
*/
|
||||
|
||||
require_once 'libraries/common.inc.php';
|
||||
|
||||
$db = isset($_POST['db']) ? $_POST['db'] : $GLOBALS['db'];
|
||||
$sql_autocomplete = array();
|
||||
|
||||
if ($db) {
|
||||
$tableNames = $GLOBALS['dbi']->getTables($db);
|
||||
foreach ($tableNames as $tableName) {
|
||||
$sql_autocomplete[$tableName] = $GLOBALS['dbi']->getColumnNames($db, $tableName);
|
||||
}
|
||||
}
|
||||
|
||||
$response = PMA_Response::getInstance();
|
||||
$response->addJSON("tables", json_encode($sql_autocomplete));
|
||||
72
js/codemirror/addon/hint/sql-hint.js
vendored
72
js/codemirror/addon/hint/sql-hint.js
vendored
@ -12,6 +12,7 @@
|
||||
"use strict";
|
||||
|
||||
var tables;
|
||||
var defaultTable;
|
||||
var keywords;
|
||||
var CONS = {
|
||||
QUERY_DIV: ";",
|
||||
@ -43,18 +44,55 @@
|
||||
}
|
||||
}
|
||||
|
||||
function columnCompletion(result, editor) {
|
||||
function nameCompletion(result, editor) {
|
||||
var cur = editor.getCursor();
|
||||
var token = editor.getTokenAt(cur);
|
||||
var useBacktick = (token.string.charAt(0) == "`");
|
||||
var string = token.string.substr(1);
|
||||
var prevCur = Pos(cur.line, token.start);
|
||||
var table = editor.getTokenAt(prevCur).string;
|
||||
if (!tables.hasOwnProperty(table))
|
||||
table = findTableByAlias(table, editor);
|
||||
var columns = tables[table];
|
||||
if (!columns) return;
|
||||
var prevToken = editor.getTokenAt(Pos(cur.line, token.start));
|
||||
if (token.string.charAt(0) == "." || prevToken.string == "."){
|
||||
//Suggest colunm names
|
||||
if (prevToken.string == ".") {
|
||||
var prevToken = editor.getTokenAt(Pos(cur.line, token.start - 1));
|
||||
}
|
||||
var table = prevToken.string;
|
||||
//Check if backtick is used in table name. If yes, use it for columns too.
|
||||
var useBacktickTable = false;
|
||||
if (table.match(/`/g)) {
|
||||
useBacktickTable = true;
|
||||
table = table.replace(/`/g, "");
|
||||
}
|
||||
//Check if table is available. If not, find table by Alias
|
||||
if (!tables.hasOwnProperty(table))
|
||||
table = findTableByAlias(table, editor);
|
||||
var columns = tables[table];
|
||||
if (!columns) return;
|
||||
|
||||
addMatches(result, string, columns, function(w) {return "." + w;});
|
||||
if (useBacktick) {
|
||||
addMatches(result, string, columns, function(w) {return "`" + w + "`";});
|
||||
}
|
||||
else if(useBacktickTable) {
|
||||
addMatches(result, string, columns, function(w) {return ".`" + w + "`";});
|
||||
}
|
||||
else {
|
||||
addMatches(result, string, columns, function(w) {return "." + w;});
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Suggest table names or colums in defaultTable
|
||||
while (token.start && string.charAt(0) == ".") {
|
||||
token = editor.getTokenAt(Pos(cur.line, token.start - 1));
|
||||
string = token.string + string;
|
||||
}
|
||||
if (useBacktick) {
|
||||
addMatches(result, string, tables, function(w) {return "`" + w + "`";});
|
||||
addMatches(result, string, defaultTable, function(w) {return "`" + w + "`";});
|
||||
}
|
||||
else {
|
||||
addMatches(result, string, tables, function(w) {return w;});
|
||||
addMatches(result, string, defaultTable, function(w) {return w;});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function eachWord(lineText, f) {
|
||||
@ -128,11 +166,14 @@
|
||||
|
||||
CodeMirror.registerHelper("hint", "sql", function(editor, options) {
|
||||
tables = (options && options.tables) || {};
|
||||
var defaultTableName = options && options.defaultTable;
|
||||
defaultTable = (defaultTableName && tables[defaultTableName] || []);
|
||||
keywords = keywords || getKeywords(editor);
|
||||
|
||||
var cur = editor.getCursor();
|
||||
var result = [];
|
||||
var token = editor.getTokenAt(cur), start, end, search;
|
||||
if (token.string.match(/^[.\w@]\w*$/)) {
|
||||
if (token.string.match(/^[.`\w@]\w*$/)) {
|
||||
search = token.string;
|
||||
start = token.start;
|
||||
end = token.end;
|
||||
@ -140,18 +181,11 @@
|
||||
start = end = cur.ch;
|
||||
search = "";
|
||||
}
|
||||
if (search.charAt(0) == ".") {
|
||||
columnCompletion(result, editor);
|
||||
if (!result.length) {
|
||||
while (start && search.charAt(0) == ".") {
|
||||
token = editor.getTokenAt(Pos(cur.line, token.start - 1));
|
||||
start = token.start;
|
||||
search = token.string + search;
|
||||
}
|
||||
addMatches(result, search, tables, function(w) {return w;});
|
||||
}
|
||||
if (search.charAt(0) == "." || search.charAt(0) == "`") {
|
||||
nameCompletion(result, editor);
|
||||
} else {
|
||||
addMatches(result, search, tables, function(w) {return w;});
|
||||
addMatches(result, search, defaultTable, function(w) {return w;});
|
||||
addMatches(result, search, keywords, function(w) {return w.toUpperCase();});
|
||||
}
|
||||
|
||||
|
||||
@ -34,6 +34,16 @@ var codemirror_editor = false;
|
||||
*/
|
||||
var codemirror_inline_editor = false;
|
||||
|
||||
/**
|
||||
* @var sql_autocomplete object containing list of columns in each table
|
||||
*/
|
||||
var sql_autocomplete = false;
|
||||
|
||||
/**
|
||||
* @var sql_autocomplete_default_table string containing default table to autocomplete columns
|
||||
*/
|
||||
var sql_autocomplete_default_table = '';
|
||||
|
||||
/**
|
||||
* @var chart_activeTimeouts object active timeouts that refresh the charts. When disabling a realtime chart, this can be used to stop the continuous ajax requests
|
||||
*/
|
||||
@ -1673,13 +1683,44 @@ AJAX.registerOnload('functions.js', function () {
|
||||
* "inputRead" event handler for CodeMirror SQL query editors for autocompletion
|
||||
*/
|
||||
function codemirrorAutocompleteOnInputRead(instance) {
|
||||
if (!instance.options.hintOptions.tables || !sql_autocomplete){
|
||||
if (!sql_autocomplete) {
|
||||
// Reset after teardown
|
||||
instance.options.hintOptions.tables = false;
|
||||
instance.options.hintOptions.defaultTable = '';
|
||||
|
||||
var href = 'db_sql_autocomplete.php';
|
||||
var params = {
|
||||
'ajax_request': true,
|
||||
'token': PMA_commonParams.get('token'),
|
||||
'db': PMA_commonParams.get('db')
|
||||
};
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: href,
|
||||
data: params,
|
||||
success: function (data) {
|
||||
if (data.success) {
|
||||
sql_autocomplete = $.parseJSON(data.tables);
|
||||
sql_autocomplete_default_table = PMA_commonParams.get('table');
|
||||
instance.options.hintOptions.tables = sql_autocomplete;
|
||||
instance.options.hintOptions.defaultTable = sql_autocomplete_default_table;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
instance.options.hintOptions.tables = sql_autocomplete;
|
||||
instance.options.hintOptions.defaultTable = sql_autocomplete_default_table;
|
||||
}
|
||||
}
|
||||
if (instance.state.completionActive) {
|
||||
return;
|
||||
}
|
||||
var cur = instance.getCursor();
|
||||
var token = instance.getTokenAt(cur);
|
||||
var string = '';
|
||||
if (token.string.match(/^[.\w@]\w*$/)) {
|
||||
if (token.string.match(/^[.`\w@]\w*$/)) {
|
||||
string = token.string;
|
||||
}
|
||||
if (string.length > 0) {
|
||||
@ -1687,6 +1728,14 @@ function codemirrorAutocompleteOnInputRead(instance) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove autocomplete information before tearing down a page
|
||||
*/
|
||||
AJAX.registerTeardown('functions.js', function () {
|
||||
sql_autocomplete = false;
|
||||
sql_autocomplete_default_table = '';
|
||||
});
|
||||
|
||||
/**
|
||||
* Binds the CodeMirror to the text area used to inline edit a query.
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user