execute.mako 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. ## Licensed to Cloudera, Inc. under one
  2. ## or more contributor license agreements. See the NOTICE file
  3. ## distributed with this work for additional information
  4. ## regarding copyright ownership. Cloudera, Inc. licenses this file
  5. ## to you under the Apache License, Version 2.0 (the
  6. ## "License"); you may not use this file except in compliance
  7. ## with the License. You may obtain a copy of the License at
  8. ##
  9. ## http://www.apache.org/licenses/LICENSE-2.0
  10. ##
  11. ## Unless required by applicable law or agreed to in writing, software
  12. ## distributed under the License is distributed on an "AS IS" BASIS,
  13. ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ## See the License for the specific language governing permissions and
  15. ## limitations under the License.
  16. <%!
  17. from desktop.lib.django_util import extract_field_data
  18. from desktop.views import commonheader, commonfooter
  19. from django.utils.translation import ugettext as _
  20. %>
  21. <%namespace name="comps" file="beeswax_components.mako" />
  22. <%namespace name="layout" file="layout.mako" />
  23. <%def name="query()">
  24. % if error_message:
  25. <div class="alert alert-error">
  26. <p><strong>${_('Your query has the following error(s):')}</strong></p>
  27. <p class="queryErrorMessage">${error_message}</p>
  28. % if log:
  29. <small>${_('click the')} <b>${_('Error Log')}</b> ${_('tab below for details')}</small>
  30. % endif
  31. </div>
  32. % endif
  33. <textarea class="hide" tabindex="1" name="${form.query["query"].html_name}" id="queryField">${extract_field_data(form.query["query"]) or ''}</textarea>
  34. <div id="validationResults">
  35. % if len(form.query["query"].errors):
  36. ${ unicode(form.query["query"].errors) | n,unicode }
  37. % endif
  38. </div>
  39. <div class="actions">
  40. <button type="button" id="executeQuery" class="btn btn-primary" tabindex="2">${_('Execute')}</button>
  41. % if app_name == 'impala':
  42. <button type="button" id="downloadQuery" class="btn">${_('Download')}</button>
  43. % endif
  44. % if design and not design.is_auto and design.name:
  45. <button type="button" id="saveQuery" class="btn">${_('Save')}</button>
  46. % endif
  47. <button type="button" id="saveQueryAs" class="btn">${_('Save as...')}</button>
  48. % if app_name != 'impala':
  49. <button type="button" id="explainQuery" class="btn">${_('Explain')}</button>
  50. % endif
  51. &nbsp; ${_('or create a')} &nbsp;<a type="button" class="btn" href="${ url(app_name + ':execute_query') }">${_('New query')}</a>
  52. </div>
  53. </%def>
  54. ${ commonheader(_('Query'), app_name, user, '100px') | n,unicode }
  55. ${layout.menubar(section='query')}
  56. <div class="container-fluid">
  57. <div class="row-fluid">
  58. <div class="span3">
  59. <div class="well sidebar-nav">
  60. <form id="advancedSettingsForm" action="${action}" method="POST" class="form form-horizontal noPadding">
  61. <ul class="nav nav-list">
  62. <li class="nav-header">${_('database')}</li>
  63. <li>
  64. ${ form.query['database'] | n,unicode }
  65. </li>
  66. <li class="nav-header">${_('settings')}</li>
  67. <li>
  68. % for i, f in enumerate(form.settings.forms):
  69. <div class="param">
  70. <div class="remove">
  71. ${comps.field(f['_deleted'], tag="button", button_text="x", notitle=True, attrs=dict(
  72. type="submit",
  73. title=_("Delete this setting"),
  74. klass="btn btn-mini settingsDelete"
  75. ), value=True)}
  76. </div>
  77. <div class="control-group">
  78. ${comps.label(f['key'])}
  79. ${comps.field(f['key'], attrs=dict(placeholder=app_name == 'impala' and "ABORT_ON_ERROR" or "mapred.reduce.tasks",
  80. klass="settingsField span8",
  81. autocomplete="off"
  82. ))}
  83. </div>
  84. <div class="control-group">
  85. ${comps.label(f['value'])}
  86. ${comps.field(f['value'], attrs=dict(
  87. placeholder="1",
  88. klass="span8"
  89. ))}
  90. </div>
  91. </div>
  92. ${comps.field(f['_exists'], hidden=True)}
  93. % endfor
  94. <div class="control-group">
  95. <a class="btn btn-small" data-form-prefix="settings">${_('Add')}</a>
  96. </div>
  97. </li>
  98. <li class="nav-header
  99. % if app_name == 'impala':
  100. hide
  101. % endif
  102. ">
  103. ${_('File Resources')}
  104. </li>
  105. <li
  106. % if app_name == 'impala':
  107. class="hide"
  108. % endif
  109. >
  110. % for i, f in enumerate(form.file_resources.forms):
  111. <div class="param">
  112. <div class="remove">
  113. ${comps.field(f['_deleted'], tag="button", button_text="x", notitle=True, attrs=dict(
  114. type="submit",
  115. title=_("Delete this setting"),
  116. klass="btn btn-mini file_resourcesDelete"
  117. ), value=True)}
  118. </div>
  119. <div class="control-group">
  120. ${comps.label(f['type'])}
  121. ${comps.field(f['type'], render_default=True, attrs=dict(
  122. klass="span8"
  123. ))}
  124. </div>
  125. <div class="control-group">
  126. ${comps.label(f['path'])}
  127. ${comps.field(f['path'], attrs=dict(
  128. placeholder="/user/foo/udf.jar",
  129. klass="input-small file_resourcesField span8",
  130. data_filters=f['path'].html_name
  131. ))}
  132. </div>
  133. </div>
  134. ${comps.field(f['_exists'], hidden=True)}
  135. % endfor
  136. <div class="control-group">
  137. <a class="btn btn-small" data-form-prefix="file_resources">${_('Add')}</a>
  138. </div>
  139. </li>
  140. <li class="nav-header
  141. % if app_name == 'impala':
  142. hide
  143. % endif
  144. ">
  145. ${_('User-defined Functions')}
  146. </li>
  147. <li
  148. % if app_name == 'impala':
  149. class="hide"
  150. % endif
  151. >
  152. % for i, f in enumerate(form.functions.forms):
  153. <div class="param">
  154. <div class="remove">
  155. ${comps.field(f['_deleted'], tag="button", button_text="x", notitle=True, attrs=dict(
  156. type="submit",
  157. title=_("Delete this setting"),
  158. klass="btn btn-mini file_resourcesDelete"
  159. ), value=True)}
  160. </div>
  161. <div class="control-group">
  162. ${comps.label(f['name'])}
  163. ${comps.field(f['name'], attrs=dict(
  164. placeholder=_("myFunction"),
  165. klass="span8 functionsField"
  166. ))}
  167. </div>
  168. <div class="control-group">
  169. ${comps.label(f['class_name'])}
  170. ${comps.field(f['class_name'], attrs=dict(
  171. placeholder="com.acme.example",
  172. klass="span8"
  173. ))}
  174. </div>
  175. </div>
  176. ${comps.field(f['_exists'], hidden=True)}
  177. % endfor
  178. <div class="control-group">
  179. <a class="btn btn-small" data-form-prefix="functions">${_('Add')}</a>
  180. </div>
  181. </li>
  182. <li class="nav-header">${_('Parameterization')}</li>
  183. <li>
  184. <label class="checkbox" rel="tooltip" data-original-title="${_("If checked (the default), you can include parameters like $parameter_name in your query, and users will be prompted for a value when the query is run.")}">
  185. <input type="checkbox" id="id_${form.query["is_parameterized"].html_name | n}" name="${form.query["is_parameterized"].html_name | n}" ${extract_field_data(form.query["is_parameterized"]) and "CHECKED" or ""}/>
  186. ${_("Enable Parameterization")}
  187. </label>
  188. </li>
  189. <li class="nav-header
  190. % if app_name == 'impala':
  191. hide
  192. % endif
  193. ">${_('Email Notification')}</li>
  194. <li
  195. % if app_name == 'impala':
  196. class="hide"
  197. % endif
  198. >
  199. <label class="checkbox" rel="tooltip" data-original-title="${_("If checked, you will receive an email notification when the query completes.")}">
  200. <input type="checkbox" id="id_${form.query["email_notify"].html_name | n}" name="${form.query["email_notify"].html_name | n}" ${extract_field_data(form.query["email_notify"]) and "CHECKED" or ""}/>
  201. ${_("Email me on completion")}
  202. </label>
  203. </li>
  204. % if app_name == 'impala':
  205. <li class="nav-header">
  206. ${_('Metastore Catalog')}
  207. </li>
  208. <li>
  209. <div class="control-group">
  210. <button id="refresh-btn" class="btn btn-small" data-loading-text="Refreshing..." rel="tooltip" data-placement="right" data-original-title="${ _('Update the list of tables seen by Impala. It can take a few seconds...') }">
  211. ${ _('Refresh') }
  212. </button>
  213. </div>
  214. </li>
  215. % endif
  216. <li class="nav-header"></li>
  217. <li>
  218. <div class="control-group">
  219. <i class="icon-question-sign" id="help"></i>
  220. <div id="help-content" class="hide">
  221. <ul style="text-align: left;">
  222. <li>${ _('Press Shift + Space to autocomplete') }</li>
  223. <li>${ _("You can execute queries with multiple SQL statements delimited by a semicolon ';'") }</li>
  224. <li>${ _('You can highlight and run a fragment of a query') }</li>
  225. </ul>
  226. </div>
  227. </div>
  228. </li>
  229. </ul>
  230. <input type="hidden" name="${form.query["query"].html_name | n}" class="query" value="" />
  231. </form>
  232. </div>
  233. </div>
  234. <div id="querySide" class="span9">
  235. % if on_success_url:
  236. <input type="hidden" name="on_success_url" value="${on_success_url}"/>
  237. % endif
  238. <div style="margin-bottom: 30px">
  239. <h1>
  240. ${ _('Query Editor') }
  241. % if can_edit_name:
  242. :
  243. <a href="#" id="query-name" data-type="text" data-pk="${ design.id }"
  244. data-name="name"
  245. data-url="${ url(app_name + ':save_design_properties') }"
  246. data-original-title="${ _('Query name') }"
  247. data-value="${ design.name }"
  248. data-placement="left">
  249. </a>
  250. %endif
  251. </h1>
  252. % if can_edit_name:
  253. <p>
  254. <a href="#" id="query-description" data-type="textarea" data-pk="${ design.id }"
  255. data-name="description"
  256. data-url="${ url(app_name + ':save_design_properties') }"
  257. data-original-title="${ _('Query description') }"
  258. data-value="${ design.desc }"
  259. data-placement="bottom">
  260. </a>
  261. </p>
  262. % endif
  263. </div>
  264. % if error_messages or log:
  265. <ul class="nav nav-tabs">
  266. <li class="active">
  267. <a href="#queryPane" data-toggle="tab">${_('Query')}</a>
  268. </li>
  269. % if error_message or log:
  270. <li>
  271. <a href="#errorPane" data-toggle="tab">
  272. % if log:
  273. ${_('Error Log')}
  274. % else:
  275. &nbsp;
  276. % endif
  277. </a>
  278. </li>
  279. % endif
  280. </ul>
  281. <div class="tab-content">
  282. <div class="active tab-pane" id="queryPane">
  283. ${query()}
  284. </div>
  285. % if error_message or log:
  286. <div class="tab-pane" id="errorPane">
  287. % if log:
  288. <pre>${ log }</pre>
  289. % endif
  290. </div>
  291. % endif
  292. </div>
  293. % else:
  294. <div class="tab-content">
  295. <div id="queryPane">
  296. ${query()}
  297. </div>
  298. </div>
  299. % endif
  300. <br/>
  301. </div>
  302. </div>
  303. </div>
  304. <div id="chooseFile" class="modal hide fade">
  305. <div class="modal-header">
  306. <a href="#" class="close" data-dismiss="modal">&times;</a>
  307. <h3>${_('Choose a file')}</h3>
  308. </div>
  309. <div class="modal-body">
  310. <div id="filechooser">
  311. </div>
  312. </div>
  313. <div class="modal-footer">
  314. </div>
  315. </div>
  316. <div id="saveAs" class="modal hide fade">
  317. <div class="modal-header">
  318. <a href="#" class="close" data-dismiss="modal">&times;</a>
  319. <h3>${_('Choose a name')}</h3>
  320. </div>
  321. <div class="modal-body">
  322. <form class="form-horizontal">
  323. <div class="control-group">
  324. <label class="control-label">${_('Name')}</label>
  325. <div class="controls">
  326. ${comps.field(form.saveform['name'], klass="input-xlarge")}
  327. </div>
  328. </div>
  329. <div class="control-group">
  330. <label class="control-label">${_('Description')}</label>
  331. <div class="controls">
  332. ${comps.field(form.saveform['desc'], klass="input-xlarge")}
  333. </div>
  334. </div>
  335. </form>
  336. </div>
  337. <div class="modal-footer">
  338. <button class="btn" data-dismiss="modal">${_('Cancel')}</button>
  339. <button id="saveAsNameBtn" class="btn btn-primary">${_('Save')}</button>
  340. </div>
  341. </div>
  342. <script src="/static/ext/js/codemirror-3.11.js"></script>
  343. <link rel="stylesheet" href="/static/ext/css/codemirror.css">
  344. <script src="/static/js/Source/jHue/codemirror-hql.js"></script>
  345. <script src="/static/js/Source/jHue/codemirror-hql-hint.js"></script>
  346. <script src="/static/ext/js/codemirror-show-hint.js"></script>
  347. <link rel="stylesheet" href="/static/ext/css/codemirror-show-hint.css">
  348. <link href="/static/ext/css/bootstrap-editable.css" rel="stylesheet">
  349. <script src="/static/ext/js/bootstrap-editable.min.js"></script>
  350. <style>
  351. h1 {
  352. margin-bottom: 5px;
  353. }
  354. #filechooser {
  355. min-height: 100px;
  356. overflow-y: scroll;
  357. }
  358. .control-group label {
  359. float: left;
  360. padding-top: 5px;
  361. text-align: left;
  362. width: 40px;
  363. }
  364. .nav-list {
  365. padding: 0;
  366. }
  367. .param {
  368. background: #FDFDFD;
  369. padding: 8px 8px 1px 8px;
  370. border-radius: 4px;
  371. -webkit-border-radius: 4px;
  372. -moz-border-radius: 4px;
  373. margin-bottom: 5px;
  374. border: 1px solid #EEE;
  375. }
  376. .remove {
  377. float: right;
  378. }
  379. .file_resourcesField {
  380. border-radius: 3px 0 0 3px;
  381. border-right: 0;
  382. }
  383. .fileChooserBtn {
  384. border-radius: 0 3px 3px 0;
  385. }
  386. .CodeMirror {
  387. border: 1px solid #eee;
  388. margin-bottom: 20px;
  389. }
  390. .editorError {
  391. color: #B94A48;
  392. background-color: #F2DEDE;
  393. padding: 4px;
  394. font-size: 11px;
  395. }
  396. </style>
  397. <script src="/static/ext/js/jquery/plugins/jquery.cookie.js"></script>
  398. <script src="/static/ext/js/jquery/plugins/jquery-fieldselection.js" type="text/javascript"></script>
  399. <script type="text/javascript" charset="utf-8">
  400. $(document).ready(function(){
  401. var queryPlaceholder = "${_('Example: SELECT * FROM tablename')}";
  402. var successfunction = function(response, newValue) {
  403. if (response.status != 0) {
  404. $.jHueNotify.error("${ _('Problem: ') }" + response.data);
  405. };
  406. }
  407. $("#query-name").editable({
  408. 'validate': function(value) {
  409. if($.trim(value) == '') {
  410. return "${ _('This field is required') }";
  411. }
  412. },
  413. 'success': successfunction
  414. });
  415. $("#query-description").editable({
  416. 'success': successfunction
  417. });
  418. $("*[rel=tooltip]").tooltip({
  419. placement: 'bottom'
  420. });
  421. $("a[data-form-prefix]").each(function () {
  422. var _prefix = $(this).attr("data-form-prefix");
  423. var _nextID = 0;
  424. if ($("." + _prefix + "Field").length) {
  425. _nextID = ($("." + _prefix + "Field").last().attr("name").substr(_prefix.length + 1).split("-")[0] * 1) + 1;
  426. }
  427. $("<input>").attr("type", "hidden").attr("name", _prefix + "-next_form_id").attr("value", _nextID).appendTo($("#advancedSettingsForm"));
  428. $("." + _prefix + "Delete").click(function (e) {
  429. e.preventDefault();
  430. $("input[name=" + _prefix + "-add]").attr("value", "");
  431. $("<input>").attr("type", "hidden").attr("name", $(this).attr("name")).attr("value", "True").appendTo($("#advancedSettingsForm"));
  432. checkAndSubmit();
  433. });
  434. });
  435. $("a[data-form-prefix]").click(function () {
  436. var _prefix = $(this).attr("data-form-prefix");
  437. $("<input>").attr("type", "hidden").attr("name", _prefix + "-add").attr("value", "True").appendTo($("#advancedSettingsForm"));
  438. checkAndSubmit();
  439. });
  440. $(".file_resourcesField").each(function () {
  441. var self = $(this);
  442. self.after(getFileBrowseButton(self));
  443. });
  444. function getFileBrowseButton(inputElement) {
  445. return $("<button>").addClass("btn").addClass("fileChooserBtn").text("..").click(function (e) {
  446. e.preventDefault();
  447. $("#filechooser").jHueFileChooser({
  448. initialPath: inputElement.val(),
  449. onFileChoose: function (filePath) {
  450. inputElement.val(filePath);
  451. $("#chooseFile").modal("hide");
  452. },
  453. createFolder: false
  454. });
  455. $("#chooseFile").modal("show");
  456. })
  457. }
  458. $("#id_query-database").change(function () {
  459. $.cookie("hueBeeswaxLastDatabase", $(this).val(), {expires: 90});
  460. });
  461. ## If no particular query is loaded
  462. % if design is None or design.id is None:
  463. if ($.cookie("hueBeeswaxLastDatabase") != null) {
  464. $("#id_query-database").val($.cookie("hueBeeswaxLastDatabase"));
  465. }
  466. % endif
  467. var executeQuery = function () {
  468. $("<input>").attr("type", "hidden").attr("name", "button-submit").attr("value", "Execute").appendTo($("#advancedSettingsForm"));
  469. checkAndSubmit();
  470. }
  471. $("#executeQuery").click(executeQuery);
  472. $("#executeQuery").tooltip({
  473. title: '${_("Press \"tab\", then \"enter\".")}'
  474. });
  475. $("#executeQuery").keyup(function (event) {
  476. if (event.keyCode == 13) {
  477. executeQuery();
  478. }
  479. });
  480. % if app_name == 'impala':
  481. $("#downloadQuery").click(function () {
  482. $("<input>").attr("type", "hidden").attr("name", "button-submit").attr("value", "Execute").appendTo($("#advancedSettingsForm"));
  483. $("<input>").attr("type", "hidden").attr("name", "download").attr("value", "true").appendTo($("#advancedSettingsForm"));
  484. checkAndSubmit();
  485. });
  486. % endif
  487. $("#saveQuery").click(function () {
  488. $("<input>").attr("type", "hidden").attr("name", "saveform-name")
  489. .attr("value", "${extract_field_data(form.saveform["name"])}").appendTo($("#advancedSettingsForm"));
  490. $("<input>").attr("type", "hidden").attr("name", "saveform-desc")
  491. .attr("value", "${extract_field_data(form.saveform["desc"])}").appendTo($("#advancedSettingsForm"));
  492. $("<input>").attr("type", "hidden").attr("name", "saveform-save").attr("value", "Save").appendTo($("#advancedSettingsForm"));
  493. checkAndSubmit();
  494. });
  495. $("#saveQueryAs").click(function () {
  496. $("<input>").attr("type", "hidden").attr("name", "saveform-saveas").attr("value", "Save As...").appendTo($("#advancedSettingsForm"));
  497. $("#saveAs").modal("show");
  498. });
  499. $("#saveAsNameBtn").click(function () {
  500. $("<input>").attr("type", "hidden").attr("name", "saveform-name")
  501. .attr("value", $("input[name=saveform-name]").val()).appendTo($("#advancedSettingsForm"));
  502. $("<input>").attr("type", "hidden").attr("name", "saveform-desc")
  503. .attr("value", $("input[name=saveform-desc]").val()).appendTo($("#advancedSettingsForm"));
  504. checkAndSubmit();
  505. });
  506. $("#explainQuery").click(function () {
  507. $("<input>").attr("type", "hidden").attr("name", "button-explain").attr("value", "Explain").appendTo($("#advancedSettingsForm"));
  508. checkAndSubmit();
  509. });
  510. initQueryField();
  511. var resizeTimeout = -1;
  512. var winWidth = $(window).width();
  513. var winHeight = $(window).height();
  514. $(window).on("resize", function () {
  515. window.clearTimeout(resizeTimeout);
  516. resizeTimeout = window.setTimeout(function () {
  517. // prevents endless loop in IE8
  518. if (winWidth != $(window).width() || winHeight != $(window).height()) {
  519. codeMirror.setSize("95%", $(window).height() - 270 - $("#queryPane .alert-error").outerHeight() - $(".nav-tabs").outerHeight());
  520. winWidth = $(window).width();
  521. winHeight = $(window).height();
  522. }
  523. }, 200);
  524. });
  525. function initQueryField() {
  526. if ($("#queryField").val() == "") {
  527. $("#queryField").val(queryPlaceholder);
  528. }
  529. }
  530. var dbTree = ${ autocomplete | n,unicode };
  531. function getTableAliases() {
  532. var _aliases = {};
  533. var _val = codeMirror.getValue();
  534. var _from = _val.toUpperCase().indexOf("FROM");
  535. if (_from > -1) {
  536. var _match = _val.toUpperCase().substring(_from).match(/ON|WHERE|GROUP|SORT/);
  537. var _to = _val.length;
  538. if (_match) {
  539. _to = _match.index;
  540. }
  541. var _found = _val.substr(_from, _to).replace(/(\r\n|\n|\r)/gm, "").replace(/from/gi, "").replace(/join/gi, ",").split(",");
  542. for (var i = 0; i < _found.length; i++) {
  543. var _tablealias = $.trim(_found[i]).split(" ");
  544. if (_tablealias.length > 1) {
  545. _aliases[_tablealias[1]] = _tablealias[0];
  546. }
  547. }
  548. }
  549. return _aliases;
  550. }
  551. function getTableFields(tableName, withDot) {
  552. if (tableName.indexOf("(") > -1) {
  553. tableName = tableName.substr(tableName.indexOf("(") + 1);
  554. }
  555. var _branch = dbTree[$("#id_query-database").val()];
  556. if (_branch != null && _branch.tables) {
  557. for (var i = 0; i < _branch.tables.length; i++) {
  558. var _aliases = getTableAliases();
  559. if (_aliases[tableName]) {
  560. tableName = _aliases[tableName];
  561. }
  562. if (_branch.tables[i].name == tableName) {
  563. var _cols = _branch.tables[i].cols.slice(0);
  564. if (withDot) {
  565. for (var idx = 0; idx < _cols.length; idx++) {
  566. _cols[idx] = "." + _cols[idx];
  567. }
  568. }
  569. return _cols.join(" ");
  570. }
  571. }
  572. }
  573. return "";
  574. }
  575. function tableHasAlias(tableName) {
  576. var _aliases = getTableAliases();
  577. for (var alias in _aliases) {
  578. if (_aliases[alias] == tableName) {
  579. return true;
  580. }
  581. }
  582. return false;
  583. }
  584. function getTables() {
  585. var _branch = dbTree[$("#id_query-database").val()];
  586. if (_branch != null && _branch.tables) {
  587. var _names = "";
  588. for (var i = 0; i < _branch.tables.length; i++) {
  589. if (i > 0) {
  590. _names += " ";
  591. }
  592. _names += _branch.tables[i].name;
  593. }
  594. return _names;
  595. }
  596. return "";
  597. }
  598. var queryEditor = $("#queryField")[0];
  599. CodeMirror.commands.autocomplete = function (cm) {
  600. CodeMirror.catalogTables = getTables();
  601. var _before = codeMirror.getRange({line: 0, ch: 0}, {line: codeMirror.getCursor().line, ch: codeMirror.getCursor().ch}).replace(/(\r\n|\n|\r)/gm, " ");
  602. CodeMirror.possibleTable = false;
  603. if (_before.toUpperCase().indexOf(" FROM ") > -1 && _before.toUpperCase().indexOf(" ON ") == -1 && _before.toUpperCase().indexOf(" WHERE ") == -1) {
  604. CodeMirror.possibleTable = true;
  605. }
  606. CodeMirror.possibleSoloField = false;
  607. if (_before.toUpperCase().indexOf("SELECT ") > -1 && _before.toUpperCase().indexOf(" FROM ") && !CodeMirror.fromDot) {
  608. CodeMirror.possibleSoloField = true;
  609. try {
  610. var _possibleTables = $.trim(codeMirror.getValue().substr(codeMirror.getValue().toUpperCase().indexOf("FROM") + 4)).split(" ");
  611. var _foundTable = "";
  612. for (var i = 0; i < _possibleTables.length; i++) {
  613. if ($.trim(_possibleTables[i]) != "" && _foundTable == "") {
  614. _foundTable = _possibleTables[i];
  615. }
  616. }
  617. if (_foundTable != "") {
  618. if (tableHasAlias(_foundTable)) {
  619. CodeMirror.possibleSoloField = false;
  620. }
  621. else {
  622. CodeMirror.catalogFields = getTableFields(_foundTable, false);
  623. }
  624. }
  625. }
  626. catch (e) {
  627. }
  628. }
  629. CodeMirror.showHint(cm, CodeMirror.hiveQLHint);
  630. }
  631. CodeMirror.fromDot = false;
  632. var codeMirror = CodeMirror(function (elt) {
  633. queryEditor.parentNode.replaceChild(elt, queryEditor);
  634. }, {
  635. value: queryEditor.value,
  636. readOnly: false,
  637. lineNumbers: true,
  638. mode: "text/x-hiveql",
  639. extraKeys: {
  640. "Shift-Space": function () {
  641. CodeMirror.fromDot = false;
  642. codeMirror.execCommand("autocomplete");
  643. },
  644. Tab: function (cm) {
  645. $("#executeQuery").focus();
  646. }
  647. },
  648. onKeyEvent: function (e, s) {
  649. if (s.type == "keyup") {
  650. if (s.keyCode == 190) {
  651. window.setTimeout(function () {
  652. var _line = codeMirror.getLine(codeMirror.getCursor().line);
  653. var _partial = _line.substring(0, codeMirror.getCursor().ch);
  654. var _table = _partial.substring(_partial.lastIndexOf(" ") + 1, _partial.length - 1);
  655. CodeMirror.catalogFields = getTableFields(_table, true);
  656. CodeMirror.fromDot = true;
  657. codeMirror.execCommand("autocomplete");
  658. }, 100); // timeout for IE8
  659. }
  660. }
  661. }
  662. });
  663. var selectedLine = -1;
  664. var errorWidget = null;
  665. if ($(".queryErrorMessage").length > 0) {
  666. var err = $(".queryErrorMessage").text().toLowerCase();
  667. var firstPos = err.indexOf("line");
  668. selectedLine = $.trim(err.substring(err.indexOf(" ", firstPos), err.indexOf(":", firstPos))) * 1;
  669. errorWidget = codeMirror.addLineWidget(selectedLine - 1, $("<div>").addClass("editorError").html("<i class='icon-exclamation-sign'></i> " + err)[0], {coverGutter: true, noHScroll: true})
  670. }
  671. codeMirror.setSize("95%", $(window).height() - 270 - $("#queryPane .alert-error").outerHeight() - $(".nav-tabs").outerHeight());
  672. codeMirror.on("focus", function () {
  673. if (codeMirror.getValue() == queryPlaceholder) {
  674. codeMirror.setValue("");
  675. }
  676. if (errorWidget) {
  677. errorWidget.clear();
  678. }
  679. $("#validationResults").empty();
  680. });
  681. codeMirror.on("change", function () {
  682. $(".query").val(codeMirror.getValue());
  683. });
  684. function getHighlightedQuery() {
  685. var selection = codeMirror.getSelection();
  686. if (selection != "") {
  687. return selection;
  688. }
  689. return null;
  690. }
  691. function checkAndSubmit() {
  692. var query = getHighlightedQuery() || codeMirror.getValue();
  693. $(".query").val(query);
  694. $("#advancedSettingsForm").submit();
  695. }
  696. % if app_name == 'impala':
  697. $("#refresh-btn").click(function() {
  698. var _this = this;
  699. $(_this).button('loading');
  700. $.post('/impala/refresh_catalog',
  701. function(response) {
  702. if (response['status'] != 0) {
  703. $.jHueNotify.error("${ _('Problem: ') }" + response['data']);
  704. } else {
  705. $.jHueNotify.info("${ _('Refresh successful!') }")
  706. }
  707. }
  708. ).fail(function(e) { $.jHueNotify.error("${ _('Problem: ') }" + e) })
  709. .always(function() { $(_this).button('reset') });
  710. return false;
  711. });
  712. % endif
  713. });
  714. $.getJSON("${ url(app_name + ':configuration') }", function(data) {
  715. $(".settingsField").typeahead({
  716. source: $.map(data.config_values, function(value, key) {
  717. return value.key;
  718. })
  719. });
  720. });
  721. $("#help").popover({
  722. 'title': "${_('Did you know?')}",
  723. 'content': $("#help-content").html(),
  724. 'trigger': 'hover',
  725. 'html': true
  726. });
  727. </script>
  728. ${ commonfooter(messages) | n,unicode }