diff --git a/caravel/__init__.py b/caravel/__init__.py
index bb74091a714a5..d53b8e579ca12 100644
--- a/caravel/__init__.py
+++ b/caravel/__init__.py
@@ -10,12 +10,12 @@
from flask import Flask, redirect
from flask_appbuilder import SQLA, AppBuilder, IndexView
-from sqlalchemy import event, exc
from flask_appbuilder.baseviews import expose
from flask_cache import Cache
from flask_migrate import Migrate
from caravel.source_registry import SourceRegistry
from werkzeug.contrib.fixers import ProxyFix
+from caravel import utils
APP_DIR = os.path.dirname(__file__)
@@ -31,33 +31,7 @@
db = SQLA(app)
-@event.listens_for(db.engine, 'checkout')
-def checkout(dbapi_con, con_record, con_proxy):
- """
- Making sure the connection is live, and preventing against:
- 'MySQL server has gone away'
-
- Copied from:
- http://stackoverflow.com/questions/30630120/mysql-keeps-losing-connection-during-celery-tasks
- """
- try:
- try:
- if hasattr(dbapi_con, 'ping'):
- dbapi_con.ping(False)
- else:
- cursor = dbapi_con.cursor()
- cursor.execute("SELECT 1")
- except TypeError:
- app.logger.debug('MySQL connection died. Restoring...')
- dbapi_con.ping()
- except dbapi_con.OperationalError as e:
- app.logger.warning(e)
- if e.args[0] in (2006, 2013, 2014, 2045, 2055):
- raise exc.DisconnectionError()
- else:
- raise
- return db
-
+utils.pessimistic_connection_handling(db.engine.pool)
cache = Cache(app, config=app.config.get('CACHE_CONFIG'))
@@ -103,6 +77,7 @@ def index(self):
sm = appbuilder.sm
get_session = appbuilder.get_session
+results_backend = app.config.get("RESULTS_BACKEND")
# Registering sources
module_datasource_map = app.config.get("DEFAULT_MODULE_DS_MAP")
diff --git a/caravel/assets/javascripts/SqlLab/actions.js b/caravel/assets/javascripts/SqlLab/actions.js
index b03a30d259623..f805dce41141b 100644
--- a/caravel/assets/javascripts/SqlLab/actions.js
+++ b/caravel/assets/javascripts/SqlLab/actions.js
@@ -1,17 +1,17 @@
+import shortid from 'shortid';
+import { now } from '../modules/dates';
+const $ = require('jquery');
+
export const RESET_STATE = 'RESET_STATE';
export const ADD_QUERY_EDITOR = 'ADD_QUERY_EDITOR';
export const CLONE_QUERY_TO_NEW_TAB = 'CLONE_QUERY_TO_NEW_TAB';
export const REMOVE_QUERY_EDITOR = 'REMOVE_QUERY_EDITOR';
export const MERGE_TABLE = 'MERGE_TABLE';
export const REMOVE_TABLE = 'REMOVE_TABLE';
-export const START_QUERY = 'START_QUERY';
-export const STOP_QUERY = 'STOP_QUERY';
export const END_QUERY = 'END_QUERY';
export const REMOVE_QUERY = 'REMOVE_QUERY';
export const EXPAND_TABLE = 'EXPAND_TABLE';
export const COLLAPSE_TABLE = 'COLLAPSE_TABLE';
-export const QUERY_SUCCESS = 'QUERY_SUCCESS';
-export const QUERY_FAILED = 'QUERY_FAILED';
export const QUERY_EDITOR_SETDB = 'QUERY_EDITOR_SETDB';
export const QUERY_EDITOR_SET_SCHEMA = 'QUERY_EDITOR_SET_SCHEMA';
export const QUERY_EDITOR_SET_TITLE = 'QUERY_EDITOR_SET_TITLE';
@@ -25,11 +25,117 @@ export const ADD_ALERT = 'ADD_ALERT';
export const REMOVE_ALERT = 'REMOVE_ALERT';
export const REFRESH_QUERIES = 'REFRESH_QUERIES';
export const SET_NETWORK_STATUS = 'SET_NETWORK_STATUS';
+export const RUN_QUERY = 'RUN_QUERY';
+export const START_QUERY = 'START_QUERY';
+export const STOP_QUERY = 'STOP_QUERY';
+export const REQUEST_QUERY_RESULTS = 'REQUEST_QUERY_RESULTS';
+export const QUERY_SUCCESS = 'QUERY_SUCCESS';
+export const QUERY_FAILED = 'QUERY_FAILED';
+export const CLEAR_QUERY_RESULTS = 'CLEAR_QUERY_RESULTS';
+export const HIDE_DATA_PREVIEW = 'HIDE_DATA_PREVIEW';
export function resetState() {
return { type: RESET_STATE };
}
+export function startQuery(query) {
+ Object.assign(query, {
+ id: shortid.generate(),
+ progress: 0,
+ startDttm: now(),
+ state: (query.runAsync) ? 'pending' : 'running',
+ });
+ return { type: START_QUERY, query };
+}
+
+export function querySuccess(query, results) {
+ return { type: QUERY_SUCCESS, query, results };
+}
+
+export function queryFailed(query, msg) {
+ return { type: QUERY_FAILED, query, msg };
+}
+
+export function stopQuery(query) {
+ return { type: STOP_QUERY, query };
+}
+
+export function clearQueryResults(query) {
+ return { type: CLEAR_QUERY_RESULTS, query };
+}
+
+export function hideDataPreview() {
+ return { type: HIDE_DATA_PREVIEW };
+}
+
+export function requestQueryResults(query) {
+ return { type: REQUEST_QUERY_RESULTS, query };
+}
+
+export function fetchQueryResults(query) {
+ return function (dispatch) {
+ dispatch(requestQueryResults(query));
+ const sqlJsonUrl = `/caravel/results/${query.resultsKey}/`;
+ $.ajax({
+ type: 'GET',
+ dataType: 'json',
+ url: sqlJsonUrl,
+ success(results) {
+ dispatch(querySuccess(query, results));
+ },
+ error() {
+ dispatch(queryFailed(query, 'Failed at retrieving results from the results backend'));
+ },
+ });
+ };
+}
+
+export function runQuery(query) {
+ return function (dispatch) {
+ dispatch(startQuery(query));
+ const sqlJsonUrl = '/caravel/sql_json/';
+ const sqlJsonRequest = {
+ client_id: query.id,
+ database_id: query.dbId,
+ json: true,
+ runAsync: query.runAsync,
+ schema: query.schema,
+ sql: query.sql,
+ sql_editor_id: query.sqlEditorId,
+ tab: query.tab,
+ tmp_table_name: query.tempTableName,
+ select_as_cta: query.ctas,
+ };
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ url: sqlJsonUrl,
+ data: sqlJsonRequest,
+ success(results) {
+ if (!query.runAsync) {
+ dispatch(querySuccess(query, results));
+ }
+ },
+ error(err, textStatus, errorThrown) {
+ let msg;
+ try {
+ msg = err.responseJSON.error;
+ } catch (e) {
+ if (err.responseText !== undefined) {
+ msg = err.responseText;
+ }
+ }
+ if (textStatus === 'error' && errorThrown === '') {
+ msg = 'Could not connect to server';
+ } else if (msg === null) {
+ msg = `[${textStatus}] ${errorThrown}`;
+ }
+ dispatch(queryFailed(query, msg));
+ },
+ });
+ };
+}
+
export function setDatabases(databases) {
return { type: SET_DATABASES, databases };
}
@@ -102,22 +208,6 @@ export function removeTable(table) {
return { type: REMOVE_TABLE, table };
}
-export function startQuery(query) {
- return { type: START_QUERY, query };
-}
-
-export function stopQuery(query) {
- return { type: STOP_QUERY, query };
-}
-
-export function querySuccess(query, results) {
- return { type: QUERY_SUCCESS, query, results };
-}
-
-export function queryFailed(query, msg) {
- return { type: QUERY_FAILED, query, msg };
-}
-
export function addWorkspaceQuery(query) {
return { type: ADD_WORKSPACE_QUERY, query };
}
diff --git a/caravel/assets/javascripts/SqlLab/common.js b/caravel/assets/javascripts/SqlLab/common.js
index 6d0ab5f5979df..4005c591a727f 100644
--- a/caravel/assets/javascripts/SqlLab/common.js
+++ b/caravel/assets/javascripts/SqlLab/common.js
@@ -1,8 +1,12 @@
export const STATE_BSSTYLE_MAP = {
failed: 'danger',
pending: 'info',
+ fetching: 'info',
running: 'warning',
+ stopped: 'danger',
success: 'success',
};
+export const DATA_PREVIEW_ROW_COUNT = 100;
+
export const STATUS_OPTIONS = ['success', 'failed', 'running'];
diff --git a/caravel/assets/javascripts/SqlLab/components/App.jsx b/caravel/assets/javascripts/SqlLab/components/App.jsx
index 9cf62e4559647..074ef63b98e39 100644
--- a/caravel/assets/javascripts/SqlLab/components/App.jsx
+++ b/caravel/assets/javascripts/SqlLab/components/App.jsx
@@ -5,6 +5,7 @@ import TabbedSqlEditors from './TabbedSqlEditors';
import QueryAutoRefresh from './QueryAutoRefresh';
import QuerySearch from './QuerySearch';
import Alerts from './Alerts';
+import DataPreviewModal from './DataPreviewModal';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
@@ -26,8 +27,9 @@ class App extends React.Component {
this.setState({ hash: window.location.hash });
}
render() {
+ let content;
if (this.state.hash) {
- return (
+ content = (
@@ -37,16 +39,18 @@ class App extends React.Component {
);
}
+ content = (
+
+
+
+
+ );
return (
);
diff --git a/caravel/assets/javascripts/SqlLab/components/DataPreviewModal.jsx b/caravel/assets/javascripts/SqlLab/components/DataPreviewModal.jsx
new file mode 100644
index 0000000000000..989b94148ce9f
--- /dev/null
+++ b/caravel/assets/javascripts/SqlLab/components/DataPreviewModal.jsx
@@ -0,0 +1,58 @@
+import * as Actions from '../actions';
+import React from 'react';
+import { bindActionCreators } from 'redux';
+import { connect } from 'react-redux';
+import { Modal } from 'react-bootstrap';
+
+import ResultSet from './ResultSet';
+
+const propTypes = {
+ queries: React.PropTypes.object,
+ actions: React.PropTypes.object,
+ showDataPreviewModal: React.PropTypes.bool,
+ dataPreviewQueryId: React.PropTypes.string,
+};
+
+class DataPreviewModal extends React.Component {
+ hide() {
+ this.props.actions.hideDataPreview();
+ }
+ render() {
+ if (this.props.showDataPreviewModal && this.props.dataPreviewQueryId) {
+ const query = this.props.queries[this.props.dataPreviewQueryId];
+ return (
+
+
+
+ Data preview for {query.tableName}
+
+
+
+
+
+
+ );
+ }
+ return null;
+ }
+}
+DataPreviewModal.propTypes = propTypes;
+
+function mapStateToProps(state) {
+ return {
+ queries: state.queries,
+ showDataPreviewModal: state.showDataPreviewModal,
+ dataPreviewQueryId: state.dataPreviewQueryId,
+ };
+}
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators(Actions, dispatch),
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(DataPreviewModal);
diff --git a/caravel/assets/javascripts/SqlLab/components/SqlShrink.jsx b/caravel/assets/javascripts/SqlLab/components/HighlightedSql.jsx
similarity index 57%
rename from caravel/assets/javascripts/SqlLab/components/SqlShrink.jsx
rename to caravel/assets/javascripts/SqlLab/components/HighlightedSql.jsx
index c67dfc469df42..c3db7870ad22b 100644
--- a/caravel/assets/javascripts/SqlLab/components/SqlShrink.jsx
+++ b/caravel/assets/javascripts/SqlLab/components/HighlightedSql.jsx
@@ -2,38 +2,43 @@ import React from 'react';
import SyntaxHighlighter from 'react-syntax-highlighter';
import { github } from 'react-syntax-highlighter/dist/styles';
-const SqlShrink = (props) => {
+const HighlightedSql = (props) => {
const sql = props.sql || '';
let lines = sql.split('\n');
if (lines.length >= props.maxLines) {
lines = lines.slice(0, props.maxLines);
lines.push('{...}');
}
- const shrunk = lines.map((line) => {
- if (line.length > props.maxWidth) {
- return line.slice(0, props.maxWidth) + '{...}';
- }
- return line;
- })
- .join('\n');
+ let shownSql = sql;
+ if (props.shrink) {
+ shownSql = lines.map((line) => {
+ if (line.length > props.maxWidth) {
+ return line.slice(0, props.maxWidth) + '{...}';
+ }
+ return line;
+ })
+ .join('\n');
+ }
return (
- {shrunk}
+ {shownSql}
);
};
-SqlShrink.defaultProps = {
+HighlightedSql.defaultProps = {
maxWidth: 60,
maxLines: 6,
+ shrink: false,
};
-SqlShrink.propTypes = {
+HighlightedSql.propTypes = {
sql: React.PropTypes.string,
maxWidth: React.PropTypes.number,
maxLines: React.PropTypes.number,
+ shrink: React.PropTypes.bool,
};
-export default SqlShrink;
+export default HighlightedSql;
diff --git a/caravel/assets/javascripts/SqlLab/components/QueryTable.jsx b/caravel/assets/javascripts/SqlLab/components/QueryTable.jsx
index 3f80058be6db0..5d75a98e236e7 100644
--- a/caravel/assets/javascripts/SqlLab/components/QueryTable.jsx
+++ b/caravel/assets/javascripts/SqlLab/components/QueryTable.jsx
@@ -6,14 +6,30 @@ import * as Actions from '../actions';
import moment from 'moment';
import { Table } from 'reactable';
-import { ProgressBar } from 'react-bootstrap';
+import { Label, ProgressBar } from 'react-bootstrap';
import Link from './Link';
import VisualizeModal from './VisualizeModal';
-import SqlShrink from './SqlShrink';
+import ResultSet from './ResultSet';
+import ModalTrigger from '../../components/ModalTrigger';
+import HighlightedSql from './HighlightedSql';
import { STATE_BSSTYLE_MAP } from '../common';
import { fDuration } from '../../modules/dates';
import { getLink } from '../../../utils/common';
+const propTypes = {
+ columns: React.PropTypes.array,
+ actions: React.PropTypes.object,
+ queries: React.PropTypes.array,
+ onUserClicked: React.PropTypes.func,
+ onDbClicked: React.PropTypes.func,
+};
+const defaultProps = {
+ columns: ['started', 'duration', 'rows'],
+ queries: [],
+ onUserClicked: () => {},
+ onDbClicked: () => {},
+};
+
class QueryTable extends React.Component {
constructor(props) {
@@ -45,6 +61,12 @@ class QueryTable extends React.Component {
openQueryInNewTab(query) {
this.props.actions.cloneQueryToNewTab(query);
}
+ openAsyncResults(query) {
+ this.props.actions.fetchQueryResults(query);
+ }
+ clearQueryResults(query) {
+ this.props.actions.clearQueryResults(query);
+ }
render() {
const data = this.props.queries.map((query) => {
@@ -71,9 +93,30 @@ class QueryTable extends React.Component {
q.started = moment(q.startDttm).format('HH:mm:ss');
const source = (q.ctas) ? q.executedSql : q.sql;
q.sql = (
-
+
);
- q.output = q.tempTable;
+ if (q.resultsKey) {
+ q.output = (
+
+ view results
+
+ )}
+ modalTitle={'Data preview'}
+ beforeOpen={this.openAsyncResults.bind(this, query)}
+ onExit={this.clearQueryResults.bind(this, query)}
+ modalBody={}
+ />
+ );
+ } else {
+ q.output = q.tempTable;
+ }
q.progress = (
+
{},
- onDbClicked: () => {},
-};
+QueryTable.propTypes = propTypes;
+QueryTable.defaultProps = defaultProps;
function mapStateToProps() {
return {};
@@ -174,4 +206,5 @@ function mapDispatchToProps(dispatch) {
actions: bindActionCreators(Actions, dispatch),
};
}
+export { QueryTable };
export default connect(mapStateToProps, mapDispatchToProps)(QueryTable);
diff --git a/caravel/assets/javascripts/SqlLab/components/ResultSet.jsx b/caravel/assets/javascripts/SqlLab/components/ResultSet.jsx
index 566193ff2f634..e8c4375b91a31 100644
--- a/caravel/assets/javascripts/SqlLab/components/ResultSet.jsx
+++ b/caravel/assets/javascripts/SqlLab/components/ResultSet.jsx
@@ -1,8 +1,32 @@
import React from 'react';
-import { Alert, Button, ButtonGroup } from 'react-bootstrap';
+import { Alert, Button, ButtonGroup, ProgressBar } from 'react-bootstrap';
import { Table } from 'reactable';
+import shortid from 'shortid';
+
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import * as Actions from '../actions';
import VisualizeModal from './VisualizeModal';
+import HighlightedSql from './HighlightedSql';
+
+const propTypes = {
+ actions: React.PropTypes.object,
+ csv: React.PropTypes.bool,
+ query: React.PropTypes.object,
+ search: React.PropTypes.bool,
+ searchText: React.PropTypes.string,
+ showSql: React.PropTypes.bool,
+ visualize: React.PropTypes.bool,
+};
+const defaultProps = {
+ search: true,
+ visualize: true,
+ showSql: false,
+ csv: true,
+ searchText: '',
+ actions: {},
+};
class ResultSet extends React.Component {
@@ -13,83 +37,166 @@ class ResultSet extends React.Component {
showModal: false,
};
}
- changeSearch(event) {
- this.setState({ searchText: event.target.value });
- }
- showModal() {
- this.setState({ showModal: true });
- }
- hideModal() {
- this.setState({ showModal: false });
- }
- render() {
- const results = this.props.query.results;
- let controls = ;
- if (this.props.showControls) {
- controls = (
+ getControls() {
+ if (this.props.search || this.props.visualize || this.props.csv) {
+ let csvButton;
+ if (this.props.csv) {
+ csvButton = (
+
+ );
+ }
+ let visualizeButton;
+ if (this.props.visualize) {
+ visualizeButton = (
+
+ );
+ }
+ let searchBox;
+ if (this.props.search) {
+ searchBox = (
+
+ );
+ }
+ return (
);
}
- if (results && results.data && results.data.length > 0) {
+ return ;
+ }
+ popSelectStar() {
+ const qe = {
+ id: shortid.generate(),
+ title: this.props.query.tempTable,
+ autorun: false,
+ dbId: this.props.query.dbId,
+ sql: `SELECT * FROM ${this.props.query.tempTable}`,
+ };
+ this.props.actions.addQueryEditor(qe);
+ }
+ showModal() {
+ this.setState({ showModal: true });
+ }
+ hideModal() {
+ this.setState({ showModal: false });
+ }
+ changeSearch(event) {
+ this.setState({ searchText: event.target.value });
+ }
+ fetchResults(query) {
+ this.props.actions.fetchQueryResults(query);
+ }
+ render() {
+ const query = this.props.query;
+ const results = query.results;
+ let sql;
+ if (this.props.showSql) {
+ sql = ;
+ }
+ if (['running', 'pending', 'fetching'].includes(query.state)) {
+ let progressBar;
+ if (query.progress > 0 && query.state === 'running') {
+ progressBar = (
+ );
+ }
return (
-
- {controls}
-
-
col.name)}
- sortable
- className="table table-condensed table-bordered"
- filterBy={this.state.searchText}
- filterable={results.columns}
- hideFilterInput
- />
-
+
+ {progressBar}
);
+ } else if (query.state === 'failed') {
+ return {query.errorMessage};
+ } else if (query.state === 'success' && query.ctas) {
+ return (
+
+
+ Table [{query.tempTable}] was
+ created
+
+
+
);
+ } else if (query.state === 'success') {
+ if (results && results.data && results.data.length > 0) {
+ return (
+
+
+ {this.getControls.bind(this)()}
+ {sql}
+
+
col.name)}
+ sortable
+ className="table table-condensed table-bordered"
+ filterBy={this.state.searchText}
+ filterable={results.columns.map((c) => c.name)}
+ hideFilterInput
+ />
+
+
+ );
+ } else if (query.resultsKey) {
+ return (
+
+
This query was run asynchronously
+
+
+
+ );
+ }
}
return (The query returned no data);
}
}
-ResultSet.propTypes = {
- query: React.PropTypes.object,
- showControls: React.PropTypes.bool,
- search: React.PropTypes.bool,
- searchText: React.PropTypes.string,
-};
-ResultSet.defaultProps = {
- showControls: true,
- search: true,
- searchText: '',
-};
+ResultSet.propTypes = propTypes;
+ResultSet.defaultProps = defaultProps;
-export default ResultSet;
+function mapStateToProps() {
+ return {};
+}
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators(Actions, dispatch),
+ };
+}
+export default connect(mapStateToProps, mapDispatchToProps)(ResultSet);
diff --git a/caravel/assets/javascripts/SqlLab/components/SouthPane.jsx b/caravel/assets/javascripts/SqlLab/components/SouthPane.jsx
index 9723899d37a41..1941cc93101b0 100644
--- a/caravel/assets/javascripts/SqlLab/components/SouthPane.jsx
+++ b/caravel/assets/javascripts/SqlLab/components/SouthPane.jsx
@@ -1,4 +1,4 @@
-import { Alert, Button, Tab, Tabs } from 'react-bootstrap';
+import { Alert, Tab, Tabs } from 'react-bootstrap';
import QueryHistory from './QueryHistory';
import ResultSet from './ResultSet';
import React from 'react';
@@ -8,66 +8,29 @@ import { bindActionCreators } from 'redux';
import * as Actions from '../actions';
import shortid from 'shortid';
-class SouthPane extends React.Component {
- popSelectStar() {
- const qe = {
- id: shortid.generate(),
- title: this.props.latestQuery.tempTable,
- autorun: false,
- dbId: this.props.latestQuery.dbId,
- sql: `SELECT * FROM ${this.props.latestQuery.tempTable}`,
- };
- this.props.actions.addQueryEditor(qe);
+const SouthPane = function (props) {
+ let results = ;
+ const latestQuery = props.latestQuery;
+ if (latestQuery) {
+ results = ;
+ } else {
+ results = Run a query to display results here;
}
- render() {
- let results = ;
- const latestQuery = this.props.latestQuery;
- if (latestQuery) {
- if (['running', 'pending'].includes(latestQuery.state)) {
- results = (
-
- );
- } else if (latestQuery.state === 'failed') {
- results = {latestQuery.errorMessage};
- } else if (latestQuery.state === 'success' && latestQuery.ctas) {
- results = (
-
-
- Table [{latestQuery.tempTable}] was created
-
-
-
-
-
-
);
- } else if (latestQuery.state === 'success') {
- results = ;
- }
- } else {
- results = Run a query to display results here;
- }
- return (
-
-
-
-
- {results}
-
-
-
-
-
-
-
- );
- }
-}
+ return (
+
+
+
+
+ {results}
+
+
+
+
+
+
+
+ );
+};
SouthPane.propTypes = {
latestQuery: React.PropTypes.object,
diff --git a/caravel/assets/javascripts/SqlLab/components/SqlEditor.jsx b/caravel/assets/javascripts/SqlLab/components/SqlEditor.jsx
index 4f69b9ce253ed..a3abdc36ee5f5 100644
--- a/caravel/assets/javascripts/SqlLab/components/SqlEditor.jsx
+++ b/caravel/assets/javascripts/SqlLab/components/SqlEditor.jsx
@@ -1,5 +1,3 @@
-const $ = require('jquery');
-import { now } from '../../modules/dates';
import React from 'react';
import {
Button,
@@ -53,64 +51,16 @@ class SqlEditor extends React.Component {
this.startQuery(runAsync);
}
startQuery(runAsync = false, ctas = false) {
- const that = this;
const query = {
dbId: this.props.queryEditor.dbId,
- id: shortid.generate(),
- progress: 0,
sql: this.props.queryEditor.sql,
sqlEditorId: this.props.queryEditor.id,
- startDttm: now(),
- state: 'running',
tab: this.props.queryEditor.title,
- };
- if (runAsync) {
- query.state = 'pending';
- }
-
- // Execute the Query
- that.props.actions.startQuery(query);
-
- const sqlJsonUrl = '/caravel/sql_json/';
- const sqlJsonRequest = {
- client_id: query.id,
- database_id: this.props.queryEditor.dbId,
- json: true,
+ tempTableName: this.state.ctas,
runAsync,
- schema: this.props.queryEditor.schema,
- select_as_cta: ctas,
- sql: this.props.queryEditor.sql,
- sql_editor_id: this.props.queryEditor.id,
- tab: this.props.queryEditor.title,
- tmp_table_name: this.state.ctas,
+ ctas,
};
- $.ajax({
- type: 'POST',
- dataType: 'json',
- url: sqlJsonUrl,
- data: sqlJsonRequest,
- success(results) {
- if (!runAsync) {
- that.props.actions.querySuccess(query, results);
- }
- },
- error(err, textStatus, errorThrown) {
- let msg;
- try {
- msg = err.responseJSON.error;
- } catch (e) {
- if (err.responseText !== undefined) {
- msg = err.responseText;
- }
- }
- if (textStatus === 'error' && errorThrown === '') {
- msg = 'Could not connect to server';
- } else if (msg === null) {
- msg = `[${textStatus}] ${errorThrown}`;
- }
- that.props.actions.queryFailed(query, msg);
- },
- });
+ this.props.actions.runQuery(query);
}
stopQuery() {
this.props.actions.stopQuery(this.props.latestQuery);
@@ -180,7 +130,7 @@ class SqlEditor extends React.Component {
{runButtons}
);
- if (this.props.latestQuery && this.props.latestQuery.state === 'running') {
+ if (this.props.latestQuery && ['running', 'pending'].includes(this.props.latestQuery.state)) {
runButtons = (