sqlpad
Version:
Web app. Write SQL and visualize the results. Supports Postgres, MySQL, SQL Server, Crate, Vertica and SAP HANA.
174 lines (159 loc) • 4.01 kB
JavaScript
const mysql = require('mysql');
const { formatSchemaQueryResults } = require('../utils');
const id = 'mysql';
const name = 'MySQL';
function getSchemaSql(database) {
const whereSql = database
? `WHERE t.table_schema = '${database}'`
: `WHERE t.table_schema NOT IN (
'mysql',
'performance_schema',
'information_schema'
)`;
return `
SELECT
t.table_schema,
t.table_name,
c.column_name,
c.data_type
FROM
INFORMATION_SCHEMA.TABLES t
JOIN INFORMATION_SCHEMA.COLUMNS c ON t.table_schema = c.table_schema AND t.table_name = c.table_name
${whereSql}
ORDER BY
t.table_schema,
t.table_name,
c.ordinal_position
`;
}
/**
* Run query for connection
* Should return { rows, incomplete }
* @param {string} query
* @param {object} connection
*/
function runQuery(query, connection) {
const myConnection = mysql.createConnection({
multipleStatements: true,
host: connection.host,
port: connection.port ? connection.port : 3306,
user: connection.username,
password: connection.password,
database: connection.database,
insecureAuth: connection.mysqlInsecureAuth,
timezone: 'Z',
supportBigNumbers: true
});
return new Promise((resolve, reject) => {
let incomplete = false;
const rows = [];
myConnection.connect(err => {
if (err) {
return reject(err);
}
let queryError;
let resultsSent = false;
function continueOn() {
if (!resultsSent) {
resultsSent = true;
if (queryError) {
return reject(queryError);
}
return resolve({ rows, incomplete });
}
}
const myQuery = myConnection.query(query);
myQuery
.on('error', function(err) {
// Handle error,
// an 'end' event will be emitted after this as well
// so we'll call the callback there.
queryError = err;
})
.on('result', function(row) {
// If we haven't hit the max yet add row to results
if (rows.length < connection.maxRows) {
return rows.push(row);
}
// Too many rows
incomplete = true;
// Stop the query stream
myConnection.pause();
// Destroy the underlying connection
// Calling end() will wait and eventually time out
myConnection.destroy();
continueOn();
})
.on('end', function() {
// all rows have been received
// This will not fire if we end the connection early
// myConnection.end()
// myConnection.destroy()
myConnection.end(error => {
if (error) {
console.error('Error ending MySQL connection', error);
}
continueOn();
});
});
});
});
}
/**
* Test connectivity of connection
* @param {*} connection
*/
function testConnection(connection) {
const query = "SELECT 'success' AS TestQuery;";
return runQuery(query, connection);
}
/**
* Get schema for connection
* @param {*} connection
*/
function getSchema(connection) {
const schemaSql = getSchemaSql(connection.database);
return runQuery(schemaSql, connection).then(queryResult =>
formatSchemaQueryResults(queryResult)
);
}
const fields = [
{
key: 'host',
formType: 'TEXT',
label: 'Host/Server/IP Address'
},
{
key: 'port',
formType: 'TEXT',
label: 'Port (optional)'
},
{
key: 'database',
formType: 'TEXT',
label: 'Database'
},
{
key: 'username',
formType: 'TEXT',
label: 'Database Username'
},
{
key: 'password',
formType: 'PASSWORD',
label: 'Database Password'
},
{
key: 'mysqlInsecureAuth',
formType: 'CHECKBOX',
label: 'Use old/insecure pre 4.1 Auth System'
}
];
module.exports = {
id,
name,
fields,
getSchema,
runQuery,
testConnection
};