/src/web_root/pgmanage/app/resources/worker-query-detection.js

https://github.com/pgManage/pgManage · JavaScript · 744 lines · 616 code · 52 blank · 76 comment · 77 complexity · 08be1848dd6fb913ce273454d913a157 MD5 · raw file

  1. //global postMessage
  2. function rowAndColumnToIndex(strText, intRow, intColumn) {
  3. 'use strict';
  4. var arrLines;
  5. var intIndex;
  6. var i;
  7. var len;
  8. arrLines = strText.split('\n');
  9. intIndex = 0;
  10. // count previous full lines
  11. i = 0;
  12. len = intRow;
  13. while (i < len) {
  14. if (arrLines[i] !== null && arrLines[i] !== undefined) {
  15. intIndex += arrLines[i].length + 1;
  16. }
  17. i += 1;
  18. }
  19. // add previous characters
  20. intIndex += intColumn;
  21. return intIndex;
  22. }
  23. function indexToRowAndColumn(strText, intIndex) {
  24. 'use strict';
  25. var i;
  26. var len;
  27. var intRows;
  28. var intColumns;
  29. i = 0;
  30. len = intIndex;
  31. intRows = 0;
  32. intColumns = 0;
  33. while (i < len) {
  34. intColumns += 1;
  35. if (strText[i] === '\n') {
  36. intRows += 1;
  37. intColumns = 0;
  38. }
  39. i += 1;
  40. }
  41. return {'row': intRows, 'column': intColumns};
  42. }
  43. function positionFindRange(
  44. strScript,
  45. intSearchFromPos,
  46. arrQueryStartKeywords,
  47. arrDangerousQueryStartKeywords,
  48. arrExtraSearchKeywords
  49. ) {
  50. "use strict";
  51. var intNeedle;
  52. var prevChar;
  53. var currChar;
  54. var intWordPoint;
  55. var strChar;
  56. var str2Char;
  57. var strWord;
  58. var bolAlpha;
  59. var bolEnder;
  60. var intQueryStart;
  61. var intQueryEnd;
  62. var intQuoteStatus;
  63. var strTag;
  64. var intQuoteNeedle;
  65. var bolExtraSearch;
  66. var bolWord;
  67. var strFirstWord;
  68. var bolDeduced;
  69. var bolFoundStart;
  70. var arrExtraSearchWords;
  71. var intStartingWordsToFind;
  72. var intParenLevel; // what the current parenthesis level is for the current query
  73. var intParenLevelAtCursor; // what parenthesis level the cursor is at for the current query
  74. var scriptLen = strScript.length;
  75. var i;
  76. var len;
  77. var bolIgnore = false;
  78. var intDollarQuotes = 0;
  79. var arrDollarQuotes = [];
  80. var incompleteQoute = '';
  81. var overRideBolExtraSearch = false;
  82. var currLookaheadChar;
  83. var prevLookaheadChar;
  84. var intLookahead = 0;
  85. var bolCheckedLine = false;
  86. var bolDoubleDash = false;
  87. // behaviours:
  88. // if the cursor is on a starting word for a query, that query is selected
  89. // if the cursor is inside a query, that query is selected
  90. // if the cursor is inside a query that's within a comment, that query is selected
  91. // if the cursor is inside a query that's within a string, that query is selected
  92. // the overview of how this is going to work:
  93. // we are going to iterate through the SQL text starting at the cursor position.
  94. // we are going to call the variable we use to keep track of our position "the needle".
  95. // we are going to move the needle forward until we run into a non alphabet character.
  96. // we are going to move the needle backward until we run into a character that's not in the alphabet.
  97. // we are going to look at the word in between the two points we found.
  98. // if the word is not in the list of query starting words
  99. // carry on to the next previous word
  100. // if the word is in the list of query starting words
  101. // save the starting position
  102. // move forward with query split to find the end of the query
  103. intNeedle = intSearchFromPos;
  104. strChar = strScript[intNeedle];
  105. if (strChar === '"') {
  106. intNeedle += 1;
  107. intSearchFromPos += 1;
  108. strChar = strScript[intNeedle];
  109. }
  110. //if (!strScript[intNeedle + 1]) {
  111. // strChar = '\n';
  112. //}
  113. // if the current char is in the alphabet
  114. if ((/[a-z]/gi).test(strChar)) {
  115. // move the needle forward until we run into a non alphabet character
  116. while (intNeedle < scriptLen) {
  117. strChar = strScript[intNeedle];
  118. bolAlpha = (/[a-z]/gi).test(strChar);
  119. if (!bolAlpha) {
  120. intWordPoint = (intNeedle - 1);
  121. break;
  122. }
  123. if (intNeedle === (scriptLen - 1)) {
  124. intWordPoint = intNeedle;
  125. break;
  126. }
  127. intNeedle += 1;
  128. }
  129. }
  130. //console.log(intNeedle, strChar);
  131. // move the needle backward until we run into a character that's not in the alphabet
  132. while (intNeedle >= 0) {
  133. currChar = strScript[intNeedle];
  134. if (intNeedle > 0) {
  135. prevChar = strScript[intNeedle - 1];
  136. } else {
  137. prevChar = strScript[intNeedle];
  138. }
  139. // if (currChar === '\n' || currChar === '\r' && bolCheckedLine) {
  140. // bolCheckedLine = false;
  141. // bolIgnore = false;
  142. // intLookahead = 0;
  143. // }
  144. if (currChar === '\n') {
  145. intLookahead = 1;
  146. currLookaheadChar = strScript[intNeedle - intLookahead];
  147. while (currLookaheadChar && currLookaheadChar !== '\n' && currLookaheadChar !== '\r') {
  148. intLookahead += 1;
  149. currLookaheadChar = strScript[intNeedle - intLookahead];
  150. //console.log(currLookaheadChar === '-' && strScript[intNeedle - (intLookahead - 1)] === '-', currLookaheadChar, 1);
  151. if (currLookaheadChar === '-' && strScript[intNeedle - (intLookahead - 1)] === '-') {
  152. bolIgnore = true;
  153. bolDoubleDash = true;
  154. break;
  155. }
  156. }
  157. }
  158. //console.log(bolIgnore, currChar, 2)
  159. if (bolIgnore === false) {
  160. // if (bolCheckedLine === false) {
  161. // while (1 < 2) {
  162. // intLookahead += 1;
  163. // currLookaheadChar = strScript[intNeedle + intLookahead];
  164. // //console.log(currLookaheadChar);
  165. // if (currLookaheadChar === '\n' || currLookaheadChar === '\r' || !currLookaheadChar) {
  166. // //console.log('found it');
  167. // bolCheckedLine = true;
  168. // break;
  169. // } else if (currLookaheadChar === '-') {
  170. // //console.log('here, here', " :" + strScript[intNeedle - 5] + strScript[intNeedle - 4] + strScript[intNeedle - 3] + strScript[intNeedle - 2] + prevChar + currChar + ": ");
  171. // bolIgnore = true;
  172. // bolDoubleDash = true;
  173. // }
  174. // }
  175. // }
  176. if (currChar === '/' && prevChar === '*') {
  177. bolIgnore = true;
  178. } else if (currChar === '*' && prevChar === '/') {
  179. bolIgnore = true;
  180. } else if (currChar === '"') {
  181. bolIgnore = true;
  182. } else if (currChar === "'") {
  183. bolIgnore = true;
  184. } else if (currChar === ')') {
  185. bolIgnore = true;
  186. } else if (currChar === '$') {
  187. bolIgnore = false;
  188. i = 1;
  189. len = strScript.length;
  190. while (i < len) {
  191. if (strScript[intNeedle - i] !== '$') {
  192. incompleteQoute += strScript[intNeedle - i];
  193. bolIgnore = true;
  194. } else {
  195. if (arrDollarQuotes.indexOf(incompleteQoute) === -1) {
  196. arrDollarQuotes.push(incompleteQoute);
  197. bolIgnore = true;
  198. } else {
  199. if (arrDollarQuotes.indexOf(incompleteQoute) !== -1) {
  200. arrDollarQuotes.splice(arrDollarQuotes.indexOf(incompleteQoute), 1);
  201. bolIgnore = false;
  202. }
  203. }
  204. incompleteQoute = '';
  205. intNeedle -= i;
  206. i = strScript.length;
  207. }
  208. i += 1;
  209. }
  210. }
  211. } else {
  212. if (currChar === '*' && prevChar === '/') {
  213. bolIgnore = false;
  214. } else if (currChar === '-' && prevChar === '-') {
  215. bolIgnore = false;
  216. bolDoubleDash = false;
  217. } else if (currChar === '"') {
  218. bolIgnore = false;
  219. } else if (currChar === "'") {
  220. bolIgnore = false;
  221. } else if (currChar === '(') {
  222. bolIgnore = false;
  223. } else if (currChar === '$') {
  224. bolIgnore = false;
  225. i = 1;
  226. len = strScript.length;
  227. while (i < len) {
  228. if (strScript[intNeedle - i] !== '$') {
  229. incompleteQoute += strScript[intNeedle - i];
  230. bolIgnore = true;
  231. } else {
  232. if (arrDollarQuotes.indexOf(incompleteQoute) === -1) {
  233. arrDollarQuotes.push(incompleteQoute);
  234. bolIgnore = true;
  235. } else {
  236. if (arrDollarQuotes.indexOf(incompleteQoute) !== -1) {
  237. arrDollarQuotes.splice(arrDollarQuotes.indexOf(incompleteQoute), 1);
  238. bolIgnore = false;
  239. }
  240. }
  241. incompleteQoute = '';
  242. intNeedle -= i;
  243. i = strScript.length;
  244. }
  245. i += 1;
  246. }
  247. }
  248. }
  249. strChar = strScript[intNeedle];
  250. bolAlpha = (/[a-z]/gi).test(strChar);
  251. bolEnder = (/[\s\(\)\'\"\.]/gi).test(strChar);
  252. //$SELECT$SELECT$SELECT$
  253. if (!bolIgnore || bolEnder || overRideBolExtraSearch) {
  254. // if we have an intWordPoint and we run into a whitespace character (or the beginning of the script):
  255. if (typeof intWordPoint === 'number' || intNeedle === 0) {
  256. if (bolEnder) {
  257. //console.log(strWord);
  258. strWord = strScript.substring(intNeedle + 1, intWordPoint + 1);
  259. intQueryStart = (intNeedle + 1);
  260. } else if (intNeedle === 0) {
  261. strWord = '';
  262. if (typeof intWordPoint === 'number') {
  263. strWord = strScript.substring(0, intWordPoint + 1);
  264. }
  265. intQueryStart = 0;
  266. }
  267. if (bolEnder || intNeedle === 0) {
  268. bolWord = false;
  269. // if word is only alpha: test word
  270. if ((/^[a-z]*$/gi).test(strWord)) {
  271. bolWord = true;
  272. strWord = strWord.toUpperCase();
  273. }
  274. // if we found a word
  275. // and it's a dangerous starting word
  276. // and we haven't started an extra search
  277. if (
  278. bolWord &&
  279. arrDangerousQueryStartKeywords.indexOf(strWord) !== -1 &&
  280. !bolExtraSearch
  281. ) {
  282. // set the number of words to find to 8, add the current word and set bolExtraSearch to true
  283. if (overRideBolExtraSearch) {
  284. bolExtraSearch = false;
  285. } else {
  286. intStartingWordsToFind = 8;
  287. arrExtraSearchWords = [];
  288. bolExtraSearch = true;
  289. }
  290. }
  291. // if we found a word
  292. // and it's a starting word or an extra search keyword
  293. // and we've started an extra search
  294. if (
  295. bolWord &&
  296. (
  297. arrQueryStartKeywords.indexOf(strWord) !== -1 ||
  298. arrExtraSearchKeywords.indexOf(strWord) !== -1
  299. ) &&
  300. bolExtraSearch
  301. ) {
  302. // add starting word to extra word array and decrease the number of words to find
  303. arrExtraSearchWords.push({
  304. 'word': strWord,
  305. 'index': (
  306. intNeedle === 0
  307. ? 0
  308. : intNeedle + 1
  309. )
  310. });
  311. intStartingWordsToFind -= 1;
  312. }
  313. // if we've started an extra search
  314. // and (
  315. // we've found our last extra word
  316. // or we've scanned to the beginning of the document
  317. // )
  318. if (
  319. bolExtraSearch && (
  320. intStartingWordsToFind === 0 ||
  321. intNeedle === 0
  322. )
  323. ) {
  324. // deduce the real starting word
  325. // if we run into a TO or FROM, query starts at first found word
  326. // if we run into a GRANT or REVOKE, query starts there
  327. //// if we run into a WITH immediatly before SELECT,INSERT,UPDATE,DELETE, query starts there
  328. // else, query starts at first found word
  329. i = 0;
  330. len = arrExtraSearchWords.length;
  331. while (i < len) {
  332. if (
  333. arrExtraSearchWords[i].word === 'TO' ||
  334. arrExtraSearchWords[i].word === 'FROM'
  335. ) {
  336. bolDeduced = true;
  337. intQueryStart = arrExtraSearchWords[0].index;
  338. strFirstWord = arrExtraSearchWords[0].word;
  339. break;
  340. } else if (
  341. arrExtraSearchWords[i].word === 'GRANT' ||
  342. arrExtraSearchWords[i].word === 'REVOKE'
  343. ) {
  344. bolDeduced = true;
  345. intQueryStart = arrExtraSearchWords[i].index;
  346. strFirstWord = arrExtraSearchWords[i].word;
  347. break;
  348. } else if (
  349. arrExtraSearchWords[i].word === 'UPDATE' &&
  350. arrExtraSearchWords[0].word === 'SET'
  351. ) {
  352. bolDeduced = true;
  353. intQueryStart = arrExtraSearchWords[i].index;
  354. strFirstWord = arrExtraSearchWords[i].word;
  355. break;
  356. }
  357. i += 1;
  358. }
  359. if (!bolDeduced) {
  360. intQueryStart = arrExtraSearchWords[0].index;
  361. strFirstWord = arrExtraSearchWords[0].word;
  362. }
  363. bolFoundStart = true;
  364. break;
  365. }
  366. // if we haven't started an extra search
  367. // and we've found a word
  368. // and we've found a query starting word
  369. if (!bolExtraSearch && bolWord && arrQueryStartKeywords.indexOf(strWord) !== -1) {
  370. // we've found the query start
  371. bolFoundStart = true;
  372. strFirstWord = strWord;
  373. break;
  374. }
  375. //// if word is only alpha: test word
  376. //if ((/^[a-z]*$/gi).test(strWord)) {
  377. // strWord = strWord.toUpperCase();
  378. // if (arrQueryStartKeywords.indexOf(strWord) !== -1) {
  379. // break;
  380. // }
  381. //}
  382. intWordPoint = null;
  383. }
  384. intQueryStart = null;
  385. // if we dont have an intWordPoint and we run into an alpha character: set intWordPoint
  386. } else if (typeof intWordPoint !== 'number' && bolAlpha) {
  387. intWordPoint = intNeedle;
  388. }
  389. }
  390. intNeedle -= 1;
  391. if (bolIgnore && intNeedle === 1) {
  392. overRideBolExtraSearch = true;
  393. }
  394. }
  395. /*
  396. // sometimes a query doesn't have a semicolon like it's supposed to, here we define
  397. // what query starting keywords mark the end of other queries
  398. var arrAllQueryEndKeywords = [
  399. 'ABORT', 'ALTER', 'ANALYZE', 'CHECKPOINT', 'CLOSE', 'CLUSTER', 'COMMENT',
  400. 'COMMIT', 'COPY', 'CREATE', 'DEALLOCATE', 'DELETE', 'DISCARD', 'DO', 'DROP',
  401. 'EXECUTE', 'EXPLAIN', 'FETCH', 'GRANT', 'IMPORT', 'INSERT', 'LISTEN',
  402. 'LOAD', 'LOCK', 'MOVE', 'NOTIFY', 'PREPARE', 'REASSIGN', 'REFRESH', 'REINDEX',
  403. 'RELEASE', 'RESET', 'REVOKE', 'ROLLBACK', 'SAVEPOINT', 'SECURITY',
  404. 'SET', 'SHOW', 'START', 'TRUNCATE', 'UNLISTEN', 'UPDATE', 'VACUUM', 'VALUES',
  405. 'WITH' //, 'BEGIN', 'DECLARE', 'END'
  406. ];
  407. var jsnQueryEndKeywords = {
  408. "insert": [
  409. 'SELECT'
  410. ],
  411. "grant": [
  412. 'EXECUTE', 'SELECT', 'TRUNCATE', 'INSERT', 'UPDATE', 'DELETE'
  413. ],
  414. "revoke": [
  415. 'EXECUTE', 'SELECT', 'TRUNCATE', 'INSERT', 'UPDATE', 'DELETE'
  416. ],
  417. "explain": [
  418. 'ANALYZE', 'SELECT'
  419. ],
  420. "create": [
  421. 'ANALYZE', 'SELECT', 'WITH', 'EXECUTE', 'INSERT', 'UPDATE', 'DELETE',
  422. 'COMMIT', 'TRUNCATE', 'SECURITY'
  423. ],
  424. "alter": [
  425. 'ALTER', 'SET', 'RESET', 'DROP', 'WITH', 'GRANT', 'REVOKE', 'SELECT',
  426. 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'EXECUTE', 'SECURITY'
  427. ],
  428. "else": []
  429. };
  430. */
  431. // quote status (intQuoteStatus) values
  432. // 0 => no quotes
  433. // 2 => dollar tag
  434. // 3 => single quote
  435. // 4 => double quote
  436. // 5 => multiline comment
  437. // 6 => line comment
  438. // 7 => create function quote
  439. // special mention:
  440. // intParenLevel is the number of parenthesis we are deep
  441. // if we found the query start: move forward with query split to find the end of the query
  442. if (bolFoundStart) {
  443. intParenLevel = 0;
  444. intQuoteStatus = 0;
  445. intNeedle = intQueryStart;
  446. while (intNeedle < scriptLen) {
  447. strChar = strScript[intNeedle];
  448. str2Char = strChar + (strScript[intNeedle + 1] || '');
  449. //console.log(str2Char);
  450. // FOUND MULTILINE COMMENT:
  451. if (intQuoteStatus === 0 && str2Char === "/*") {
  452. intQuoteStatus = 5;
  453. // ENDING MULTILINE COMMENT
  454. } else if (intQuoteStatus === 5 && str2Char === "*/") {
  455. intQuoteStatus = 0;
  456. // FOUND DASH COMMENT:
  457. } else if (intQuoteStatus === 0 && str2Char === "--") {
  458. intQuoteStatus = 6;
  459. // ENDING DASH COMMENT
  460. } else if (intQuoteStatus === 6 && (strChar === "\n" || strChar === "\r")) {
  461. intQuoteStatus = 0;
  462. // FOUND SLASH: we don't skip slashed chars within dollar tags, double quotes and comments.
  463. } else if (strChar === "\\" && intQuoteStatus !== 4 && intQuoteStatus !== 2 && intQuoteStatus !== 5 && intQuoteStatus !== 6) {
  464. // skip next character
  465. intNeedle += 1;
  466. // FOUND SINGLE QUOTE:
  467. } else if (intQuoteStatus === 0 && strChar === "'") {
  468. intQuoteStatus = 3;
  469. // ENDING SINGLE QUOTE
  470. } else if (intQuoteStatus === 3 && strChar === "'") {
  471. intQuoteStatus = 0;
  472. // FOUND DOUBLE QUOTE:
  473. } else if (intQuoteStatus === 0 && strChar === "\"") {
  474. intQuoteStatus = 4;
  475. // ENDING DOUBLE QUOTE
  476. } else if (intQuoteStatus === 4 && strChar === "\"") {
  477. intQuoteStatus = 0;
  478. // FOUND OPEN PARENTHESIS:
  479. } else if (intQuoteStatus === 0 && strChar === "(") {
  480. intParenLevel = intParenLevel + 1;
  481. // FOUND CLOSE PARENTHESIS
  482. } else if (intQuoteStatus === 0 && strChar === ")") {
  483. intParenLevel = intParenLevel - 1;
  484. // FOUND DOLLAR TAG START:
  485. } else if (intQuoteStatus === 0 && strChar === "$") {
  486. // lookahead to get tag name
  487. intQuoteNeedle = intNeedle + 1;
  488. while (intQuoteNeedle < scriptLen && strScript[intQuoteNeedle].match(/^[a-z0-9_]$/gi)) {
  489. intQuoteNeedle += 1;
  490. }
  491. if (strScript[intQuoteNeedle] === "$") {
  492. strTag = strScript.substring(intNeedle + 1, intQuoteNeedle);
  493. intNeedle = (intQuoteNeedle + 1);
  494. intQuoteStatus = 2;
  495. }
  496. // END DOLLAR TAG
  497. } else if (intQuoteStatus === 2 && strScript.substr(intNeedle, strTag.length) === strTag) {
  498. intQuoteStatus = 0;
  499. // move pointer to end of end dollar tag
  500. intNeedle += strTag.length;
  501. }
  502. // FOUND AN UNQUOTED SEMICOLON:
  503. if (intParenLevel === 0 && intQuoteStatus === 0 && strChar === ';') {
  504. intQueryEnd = intNeedle;
  505. break;
  506. // FOUND THE SCRIPT END:
  507. } else if (intNeedle === (scriptLen - 1)) {
  508. intQueryEnd = intNeedle;
  509. break;
  510. // FOUND EXTRA PAREN:
  511. } else if (intParenLevel < 0) {
  512. intQueryEnd = intNeedle;
  513. break;
  514. }
  515. // if we've hit the current mouse position: save the parenthesis level
  516. if (intNeedle === intSearchFromPos) {
  517. intParenLevelAtCursor = intParenLevel;
  518. }
  519. intNeedle += 1;
  520. }
  521. }
  522. // V--- chops off the last character
  523. //// move the needle back one character so that we don't include the character that ended the query detection
  524. //intQueryEnd -= 1;
  525. // V--- prevents you from adding lines after the query and still detecting the query
  526. //// move the needle backwards to trim off extra whitespace (if needed)
  527. //if (strScript[intQueryEnd - 1] && (/^[\s]$/g).test(strScript[intQueryEnd - 1])) {
  528. // intNeedle = (intQueryEnd - 1);
  529. // while (intNeedle > intQueryStart) {
  530. // if (strScript[intNeedle] && !(/^[\s]$/g).test(strScript[intNeedle])) {
  531. // intQueryEnd = (intNeedle + 1);
  532. // break;
  533. // }
  534. // intNeedle -= 1;
  535. // }
  536. //}
  537. // return the query start/end, first word end and parenthesis level at the cursor
  538. return {
  539. 'intQueryStart': intQueryStart,
  540. 'intFirstWordEnd': intQueryStart + (strFirstWord || '').length,
  541. 'intQueryEnd': intQueryEnd,
  542. 'intParenLevelAtCursor': intParenLevelAtCursor || 0
  543. };
  544. }
  545. function selectionFindRange(strScript, intCursorPos) {
  546. "use strict";
  547. var jsnQuery;
  548. var intSearchPos = intCursorPos;
  549. var jsnQueryStart;
  550. var jsnQueryEnd;
  551. var i;
  552. var arrQueryStartKeywords;
  553. var arrDangerousQueryStartKeywords;
  554. var arrExtraSearchKeywords;
  555. var newCurrentQueryRange;
  556. // ######################
  557. // known issues
  558. // in a query that looks like this: "EXPLAIN ANALYZE ..." the ANALYZE is found
  559. // first. to fix this we need to alter the extra search code to handle
  560. // different patterns of extra search (currently it's handling only
  561. // GRANT/REVOKE queries)
  562. // (same thing for ROLLBACK TO SAVEPOINT and SAVEPOINT)
  563. // (same thing for (SELECT, INSERT, UPDATE, DELETE) and WITH)
  564. // (same thing for (SELECT, INSERT, UPDATE, DELETE) and CREATE TRIGGER)
  565. // (same thing for (INSERT, UPDATE, DELETE) and CREATE RULE)
  566. // ######################
  567. arrQueryStartKeywords = [
  568. 'ABORT', 'ALTER', 'ANALYZE', 'CHECKPOINT', 'CLOSE', 'CLUSTER', 'COMMENT',
  569. 'COMMIT', 'COPY', 'CREATE', 'DEALLOCATE', 'DELETE', 'DISCARD', 'DO', 'DROP',
  570. 'EXECUTE', 'EXPLAIN', 'FETCH', 'GRANT', 'IMPORT', 'INSERT', 'LISTEN',
  571. 'LOAD', 'LOCK', 'MOVE', 'NOTIFY', 'PREPARE', 'REASSIGN', 'REFRESH', 'REINDEX',
  572. 'RELEASE', 'RESET', 'REVOKE', 'ROLLBACK', 'SAVEPOINT', 'SECURITY', 'SELECT',
  573. 'SET', 'SHOW', 'START', 'TRUNCATE', 'UNLISTEN', 'UPDATE', 'VACUUM', 'VALUES',
  574. // For snippets
  575. 'RESTART', 'UPSERT'
  576. //'BEGIN', 'DECLARE', 'END'
  577. ];
  578. arrDangerousQueryStartKeywords = [
  579. 'EXECUTE', 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'SET'
  580. ];
  581. arrExtraSearchKeywords = [
  582. 'TO', 'FROM', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE'
  583. ];
  584. jsnQuery = positionFindRange(
  585. strScript,
  586. intSearchPos,
  587. arrQueryStartKeywords,
  588. arrDangerousQueryStartKeywords,
  589. arrExtraSearchKeywords
  590. );
  591. // this solves #108
  592. if (intCursorPos === strScript.length) {
  593. intCursorPos -= 1;
  594. }
  595. //console.log(jsnQuery);
  596. // if the cursor is not in the selection: search higher
  597. if (intCursorPos > jsnQuery.intQueryEnd) {
  598. // there are only some queries that can wrap around other queries. that's
  599. // why this list of start keywords is shorter than the full list
  600. arrQueryStartKeywords = [
  601. 'COMMENT', 'COPY', 'CREATE', 'DELETE', 'DO', 'EXPLAIN', 'INSERT', 'NOTIFY',
  602. 'PREPARE', 'SELECT', 'UPDATE', 'VALUES'
  603. ];
  604. i = 0;
  605. while (i < 8000 && intSearchPos > 0 && intCursorPos > jsnQuery.intQueryEnd) {
  606. //console.log('intSearchPos: ', intSearchPos);
  607. intSearchPos = jsnQuery.intQueryStart - 1;
  608. jsnQuery = positionFindRange(strScript, intSearchPos, arrQueryStartKeywords, arrDangerousQueryStartKeywords, arrExtraSearchKeywords);
  609. if (jsnQuery.intQueryStart === undefined) {
  610. break;
  611. }
  612. i += 1;
  613. }
  614. }
  615. if (intCursorPos > jsnQuery.intQueryEnd || jsnQuery.intQueryEnd === undefined) {
  616. jsnQuery = {
  617. 'intQueryStart': undefined,
  618. 'intQueryEnd': undefined,
  619. 'intParenLevelAtCursor': undefined
  620. };
  621. }
  622. // clear selection range storage
  623. newCurrentQueryRange = null;
  624. // if we found a query
  625. if (jsnQuery.intQueryStart !== jsnQuery.intQueryEnd) {
  626. // resolve query positions to jsn
  627. jsnQueryStart = indexToRowAndColumn(strScript, jsnQuery.intQueryStart);
  628. jsnQueryEnd = indexToRowAndColumn(strScript, jsnQuery.intQueryEnd);
  629. // set current range in the editor
  630. newCurrentQueryRange = {
  631. 'start': jsnQueryStart,
  632. 'end': jsnQueryEnd,
  633. 'startIndex': jsnQuery.intQueryStart,
  634. 'endIndex': jsnQuery.intQueryEnd,
  635. 'text': strScript.substring(jsnQuery.intQueryStart, jsnQuery.intQueryEnd),
  636. 'intParenLevel': jsnQuery.intParenLevelAtCursor,
  637. 'intFirstWordEnd': jsnQuery.intFirstWordEnd
  638. };
  639. }
  640. return newCurrentQueryRange;
  641. }
  642. var onmessage = function (event) {
  643. "use strict";
  644. var jsnParameters = event.data;
  645. var newCurrentQueryRange;
  646. if (
  647. jsnParameters.strScript !== null &&
  648. jsnParameters.strScript !== undefined &&
  649. jsnParameters.intCursorPos !== null &&
  650. jsnParameters.intCursorPos !== undefined &&
  651. jsnParameters.intTabNumber !== null &&
  652. jsnParameters.intTabNumber !== undefined
  653. ) {
  654. newCurrentQueryRange = selectionFindRange(
  655. jsnParameters.strScript,
  656. jsnParameters.intCursorPos
  657. );
  658. postMessage({
  659. "strScript": jsnParameters.strScript,
  660. "tabNumber": jsnParameters.intTabNumber,
  661. "currentQueryRange": newCurrentQueryRange
  662. });
  663. }
  664. };