sql.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. /**
  2. * Parse SQL CREATE TABLE. Simple initial version for community to improve.
  3. */
  4. Draw.loadPlugin(function(ui) {
  5. function TableModel() {
  6. this.Name = null;
  7. this.Properties = []
  8. }
  9. function PropertyModel() {
  10. this.Name = null;
  11. this.Value = null;
  12. this.TableName = null;
  13. this.ForeignKey = [];
  14. this.IsPrimaryKey = false;
  15. this.IsForeignKey = false;
  16. }
  17. function ForeignKeyModel() {
  18. this.PrimaryKeyName = null;
  19. this.ReferencesPropertyName = null
  20. this.PrimaryKeyTableName = null;
  21. this.ReferencesTableName = null;
  22. this.IsDestination = false;
  23. }
  24. function PrimaryKeyModel() {
  25. this.PrimaryKeyName = null;
  26. this.PrimaryKeyTableName = null;
  27. }
  28. //SQL Types
  29. var SQLServer = 'sqlserver';
  30. //SQL Modes
  31. var MODE_SQLSERVER = null;
  32. //Table Info
  33. var foreignKeyList = [];
  34. var primaryKeyList = [];
  35. var tableList = [];
  36. var cells = [];
  37. var tableCell = null;
  38. var rowCell = null;
  39. var dx = 0;
  40. var exportedTables = 0;
  41. //Create Base div
  42. var div = document.createElement('div');
  43. div.style.userSelect = 'none';
  44. div.style.overflow = 'hidden';
  45. div.style.padding = '10px';
  46. div.style.height = '100%';
  47. var graph = ui.editor.graph;
  48. var sqlInput = document.createElement('textarea');
  49. sqlInput.style.height = '200px';
  50. sqlInput.style.width = '100%';
  51. sqlInput.value = 'CREATE TABLE Persons\n(\nPersonID int,\nLastName varchar(255),\n' +
  52. 'FirstName varchar(255),\nAddress varchar(255),\nCity varchar(255)\n);';
  53. mxUtils.br(div);
  54. div.appendChild(sqlInput);
  55. var graph = ui.editor.graph;
  56. // Extends Extras menu
  57. mxResources.parse('fromSql=From SQL');
  58. var wnd = new mxWindow(mxResources.get('fromSql'), div, document.body.offsetWidth - 480, 140,
  59. 320, 300, true, true);
  60. wnd.destroyOnClose = false;
  61. wnd.setMaximizable(false);
  62. wnd.setResizable(false);
  63. wnd.setClosable(true);
  64. function AddRow(propertyModel, tableName) {
  65. var cellName = propertyModel.Name;
  66. if (propertyModel.IsForeignKey && propertyModel.ForeignKey !== undefined && propertyModel.ForeignKey !== null) {
  67. propertyModel.ForeignKey.forEach(function(foreignKeyModel) {
  68. //We do not want the foreign key to be duplicated in our table to the same property
  69. if (tableName !== foreignKeyModel.PrimaryKeyTableName || (tableName === foreignKeyModel.PrimaryKeyTableName && propertyModel.Name !== foreignKeyModel.PrimaryKeyName)) {
  70. cellName += ' | ' + foreignKeyModel.PrimaryKeyTableName + '(' + foreignKeyModel.PrimaryKeyName + ')';
  71. }
  72. })
  73. }
  74. rowCell = new mxCell(cellName, new mxGeometry(0, 0, 90, 26),
  75. 'shape=partialRectangle;top=0;left=0;right=0;bottom=0;align=left;verticalAlign=top;spacingTop=-2;fillColor=none;spacingLeft=64;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;dropTarget=0;');
  76. rowCell.vertex = true;
  77. var columnType = propertyModel.IsPrimaryKey && propertyModel.IsForeignKey ? 'PK | FK' : propertyModel.IsPrimaryKey ? 'PK' : propertyModel.IsForeignKey ? 'FK' : '';
  78. var left = sb.cloneCell(rowCell, columnType);
  79. left.connectable = false;
  80. left.style = 'shape=partialRectangle;top=0;left=0;bottom=0;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=180;points=[];portConstraint=eastwest;part=1;'
  81. left.geometry.width = 54;
  82. left.geometry.height = 26;
  83. rowCell.insert(left);
  84. var size = ui.editor.graph.getPreferredSizeForCell(rowCell);
  85. if (size !== null && tableCell.geometry.width < size.width + 10) {
  86. tableCell.geometry.width = size.width + 10;
  87. }
  88. tableCell.insert(rowCell);
  89. tableCell.geometry.height += 26;
  90. rowCell = rowCell;
  91. };
  92. function ParseMySQLForeignKey(name, currentTableModel) {
  93. var referencesIndex = name.toLowerCase().indexOf("references");
  94. var foreignKeySQL = name.substring(0, referencesIndex);
  95. var referencesSQL = name.substring(referencesIndex, name.length);
  96. //Remove references syntax
  97. referencesSQL = referencesSQL.replace("REFERENCES ", '');
  98. //Get Table and Property Index
  99. var referencedTableIndex = referencesSQL.indexOf("(");
  100. var referencedPropertyIndex = referencesSQL.indexOf(")");
  101. //Get Referenced Table
  102. var referencedTableName = referencesSQL.substring(0, referencedTableIndex);
  103. //Get Referenced Key
  104. var referencedPropertyName = referencesSQL.substring(referencedTableIndex + 1, referencedPropertyIndex);
  105. //Get ForeignKey
  106. var foreignKey = foreignKeySQL.replace("FOREIGN KEY (", '').replace(")", '').replace(" ", '');
  107. //Create ForeignKey
  108. var foreignKeyOriginModel = CreateForeignKey(foreignKey, currentTableModel.Name, referencedPropertyName, referencedTableName, true);
  109. //Add ForeignKey Origin
  110. foreignKeyList.push(foreignKeyOriginModel);
  111. //Create ForeignKey
  112. var foreignKeyDestinationModel = CreateForeignKey(referencedPropertyName, referencedTableName, foreignKey, currentTableModel.Name, false);
  113. //Add ForeignKey Destination
  114. foreignKeyList.push(foreignKeyDestinationModel);
  115. };
  116. function ParseSQLServerForeignKey(name, currentTableModel) {
  117. var referencesIndex = name.toLowerCase().indexOf("references");
  118. if (name.toLowerCase().indexOf("foreign key(") !== -1) {
  119. var foreignKeySQL = name.substring(name.toLowerCase().indexOf("foreign key("), referencesIndex).replace("FOREIGN KEY(", '').replace(')', '');
  120. } else {
  121. var foreignKeySQL = name.substring(name.toLowerCase().indexOf("foreign key ("), referencesIndex).replace("FOREIGN KEY (", '').replace(')', '');
  122. }
  123. var referencesSQL = name.substring(referencesIndex, name.length);
  124. var alterTableName = name.substring(0, name.indexOf("WITH")).replace('ALTER TABLE ', '');
  125. if (referencesIndex !== -1 && alterTableName !== '' && foreignKeySQL !== '' && referencesSQL !== '') {
  126. //Remove references syntax
  127. referencesSQL = referencesSQL.replace("REFERENCES ", '');
  128. //Get Table and Property Index
  129. var referencedTableIndex = referencesSQL.indexOf("(");
  130. var referencedPropertyIndex = referencesSQL.indexOf(")");
  131. //Get Referenced Table
  132. var referencedTableName = referencesSQL.substring(0, referencedTableIndex);
  133. //Parse Name
  134. referencedTableName = ParseSQLServerName(referencedTableName);
  135. //Get Referenced Key
  136. var referencedPropertyName = referencesSQL.substring(referencedTableIndex + 1, referencedPropertyIndex);
  137. //Parse Name
  138. referencedPropertyName = ParseSQLServerName(referencedPropertyName);
  139. //Get ForeignKey
  140. var foreignKey = foreignKeySQL.replace("FOREIGN KEY (", '').replace(")", '');
  141. //Parse Name
  142. foreignKey = ParseSQLServerName(foreignKey);
  143. //Parse Name
  144. alterTableName = ParseSQLServerName(alterTableName);
  145. //Create ForeignKey
  146. var foreignKeyOriginModel = CreateForeignKey(foreignKey, alterTableName, referencedPropertyName, referencedTableName, true);
  147. //Add ForeignKey Origin
  148. foreignKeyList.push(foreignKeyOriginModel);
  149. //Create ForeignKey
  150. var foreignKeyDestinationModel = CreateForeignKey(referencedPropertyName, referencedTableName, foreignKey, alterTableName, false);
  151. //Add ForeignKey Destination
  152. foreignKeyList.push(foreignKeyDestinationModel);
  153. }
  154. };
  155. function ProcessPrimaryKey() {
  156. primaryKeyList.forEach(function(primaryModel) {
  157. tableList.forEach(function(tableModel) {
  158. if (tableModel.Name === primaryModel.PrimaryKeyTableName) {
  159. tableModel.Properties.forEach(function(propertyModel) {
  160. if (propertyModel.Name === primaryModel.PrimaryKeyName) {
  161. propertyModel.IsPrimaryKey = true;
  162. }
  163. });
  164. }
  165. });
  166. });
  167. }
  168. function AssignForeignKey(foreignKeyModel) {
  169. tableList.forEach(function(tableModel) {
  170. if (tableModel.Name === foreignKeyModel.ReferencesTableName) {
  171. tableModel.Properties.forEach(function(propertyModel) {
  172. if (propertyModel.Name === foreignKeyModel.ReferencesPropertyName) {
  173. propertyModel.IsForeignKey = true;
  174. propertyModel.ForeignKey.push(foreignKeyModel);
  175. }
  176. });
  177. }
  178. if (tableModel.Name === foreignKeyModel.PrimaryKeyTableName) {
  179. tableModel.Properties.forEach(function(propertyModel) {
  180. if (propertyModel.Name === foreignKeyModel.PrimaryKeyName) {
  181. propertyModel.IsForeignKey = true;
  182. propertyModel.ForeignKey.push(foreignKeyModel);
  183. }
  184. });
  185. }
  186. });
  187. }
  188. function ProcessForeignKey() {
  189. foreignKeyList.forEach(function(foreignKeyModel) {
  190. //Assign ForeignKey
  191. AssignForeignKey(foreignKeyModel);
  192. });
  193. }
  194. function CreateForeignKey(primaryKeyName, primaryKeyTableName, referencesPropertyName, referencesTableName, isDestination) {
  195. var foreignKey = new ForeignKeyModel;
  196. foreignKey.PrimaryKeyTableName = primaryKeyTableName;
  197. foreignKey.PrimaryKeyName = primaryKeyName;
  198. foreignKey.ReferencesPropertyName = referencesPropertyName;
  199. foreignKey.ReferencesTableName = referencesTableName;
  200. foreignKey.IsDestination = (isDestination !== undefined && isDestination !== null) ? isDestination : false;
  201. return foreignKey;
  202. };
  203. function CreatePrimaryKey(primaryKeyName, primaryKeyTableName) {
  204. var primaryKey = new PrimaryKeyModel;
  205. primaryKey.PrimaryKeyTableName = primaryKeyTableName;
  206. primaryKey.PrimaryKeyName = primaryKeyName;
  207. return primaryKey;
  208. };
  209. function CreateProperty(name, tableName, foreignKey, isPrimaryKey) {
  210. var property = new PropertyModel;
  211. var isForeignKey = foreignKey !== undefined && foreignKey !== null;
  212. property.Name = name;
  213. property.TableName = tableName;
  214. property.ForeignKey = isForeignKey ? foreignKey : [];
  215. property.IsForeignKey = isForeignKey;
  216. property.IsPrimaryKey = isPrimaryKey;
  217. return property;
  218. };
  219. function CreateTable(name) {
  220. var table = new TableModel;
  221. table.Name = name;
  222. //Count exported tables
  223. exportedTables++;
  224. return table;
  225. };
  226. function ParseSQLServerName(name, property) {
  227. name = name.replace('[dbo].[', '');
  228. name = name.replace('](', '');
  229. name = name.replace('].[', '.');
  230. name = name.replace('[', '');
  231. if (property == undefined || property == null) {
  232. name = name.replace(' [', '');
  233. name = name.replace('] ', '');
  234. } else {
  235. if (name.indexOf(']') !== -1) {
  236. name = name.substring(0, name.indexOf(']'));
  237. }
  238. }
  239. if (name.lastIndexOf(']') === (name.length - 1)) {
  240. name = name.substring(0, name.length - 1);
  241. }
  242. if (name.lastIndexOf(')') === (name.length - 1)) {
  243. name = name.substring(0, name.length - 1);
  244. }
  245. if (name.lastIndexOf('(') === (name.length - 1)) {
  246. name = name.substring(0, name.length - 1);
  247. }
  248. name = name.replace(' ', '');
  249. return name;
  250. };
  251. function ParseTableName(name) {
  252. if (name.charAt(name.length - 1) === '(') {
  253. if (!MODE_SQLSERVER) {
  254. name = name.substring(0, name.lastIndexOf(' '));
  255. } else {
  256. name = ParseSQLServerName(name);
  257. }
  258. }
  259. return name;
  260. };
  261. function parseSql(text, type) {
  262. var lines = text.split('\n');
  263. dx = 0;
  264. MODE_SQLSERVER = type !== undefined && type !== null && type == SQLServer;
  265. tableCell = null;
  266. cells = [];
  267. exportedTables = 0;
  268. tableList = [];
  269. foreignKeyList = [];
  270. var currentTableModel = null;
  271. //Parse SQL to objects
  272. for (var i = 0; i < lines.length; i++) {
  273. rowCell = null;
  274. var tmp = mxUtils.trim(lines[i]);
  275. var propertyRow = tmp.substring(0, 12).toLowerCase();
  276. //Parse Table
  277. if (propertyRow === 'create table') {
  278. //Parse row
  279. var name = mxUtils.trim(tmp.substring(12));
  280. //Parse Table Name
  281. name = ParseTableName(name);
  282. if (currentTableModel !== null) {
  283. //Add table to the list
  284. tableList.push(currentTableModel);
  285. }
  286. //Create Table
  287. currentTableModel = CreateTable(name);
  288. }
  289. // Parse Properties
  290. else if (tmp !== '(' && currentTableModel != null && propertyRow !== 'alter table ') {
  291. //Parse the row
  292. var name = tmp.substring(0, (tmp.charAt(tmp.length - 1) === ',') ? tmp.length - 1 : tmp.length);
  293. //Attempt to get the Key Type
  294. var propertyType = name.substring(0, 11).toLowerCase();
  295. //Add special constraints
  296. if (MODE_SQLSERVER) {
  297. if (tmp.indexOf("CONSTRAINT") !== -1 && tmp.indexOf("PRIMARY KEY") !== -1) {
  298. propertyType = "constrain primary key";
  299. }
  300. if (tmp.indexOf("CONSTRAINT") !== -1 && tmp.indexOf("FOREIGN KEY") !== -1) {
  301. propertyType = "constrain foreign key";
  302. }
  303. }
  304. //Verify if this is a property that doesn't have a relationship (One minute of silence for the property)
  305. var normalProperty = propertyType !== 'primary key' && propertyType !== 'foreign key' && propertyType !== 'constrain primary key' && propertyType !== 'constrain foreign key';
  306. //Parse properties that don't have relationships
  307. if (normalProperty) {
  308. if (name === '' || name === "" || name === ");") {
  309. continue;
  310. }
  311. if (MODE_SQLSERVER) {
  312. if (name.indexOf(" ASC") !== -1 ||
  313. name.indexOf(" DESC") !== -1 ||
  314. name.indexOf(" EXEC") !== -1 ||
  315. name.indexOf(" WITH") !== -1 ||
  316. name.indexOf(" ON") !== -1 ||
  317. name.indexOf(" ALTER") !== -1 ||
  318. name.indexOf("/*") !== -1 ||
  319. name.indexOf(" CONSTRAIN") !== -1 ||
  320. name.indexOf(" SET") !== -1 ||
  321. name.indexOf(" NONCLUSTERED") !== -1 ||
  322. name.indexOf(" GO") !== -1 ||
  323. name.indexOf(" REFERENCES") !== -1) {
  324. continue;
  325. }
  326. //Get delimiter of column name
  327. var firstSpaceIndex = name.indexOf(' ');
  328. //Get full name
  329. name = name.substring(0, firstSpaceIndex);
  330. name = ParseSQLServerName(name, true);
  331. } else {
  332. //Get delimiter of column name
  333. var firstSpaceIndex = name.indexOf(' ');
  334. //Get full name
  335. name = name.substring(0, firstSpaceIndex);
  336. }
  337. //Create Property
  338. var propertyModel = CreateProperty(name, currentTableModel.Name, null, false, false);
  339. //Add Property to table
  340. currentTableModel.Properties.push(propertyModel);
  341. }
  342. //Parse Primary Key
  343. if (propertyType === 'primary key' || propertyType === 'constrain primary key') {
  344. if (!MODE_SQLSERVER) {
  345. var primaryKey = name.replace('PRIMARY KEY (', '').replace(')', '');
  346. //Create Primary Key
  347. var primaryKeyModel = CreatePrimaryKey(primaryKey, currentTableModel.Name);
  348. //Add Primary Key to List
  349. primaryKeyList.push(primaryKeyModel);
  350. } else {
  351. var start = i + 2;
  352. var end = 0;
  353. if (name.indexOf('PRIMARY KEY') !== -1 && name.indexOf('CLUSTERED') === -1) {
  354. var primaryKey = name.replace('PRIMARY KEY (', '').replace(')', '');
  355. //Create Primary Key
  356. var primaryKeyModel = CreatePrimaryKey(primaryKey, currentTableModel.Name);
  357. //Add Primary Key to List
  358. primaryKeyList.push(primaryKeyModel);
  359. } else {
  360. while (end === 0) {
  361. var primaryKeyRow = mxUtils.trim(lines[start]);
  362. if (primaryKeyRow.indexOf(')') !== -1) {
  363. end = 1;
  364. break;
  365. }
  366. start++;
  367. primaryKeyRow = primaryKeyRow.replace("ASC", '');
  368. //Parse name
  369. primaryKeyRow = ParseSQLServerName(primaryKeyRow, true);
  370. //Create Primary Key
  371. var primaryKeyModel = CreatePrimaryKey(primaryKeyRow, currentTableModel.Name);
  372. //Add Primary Key to List
  373. primaryKeyList.push(primaryKeyModel);
  374. }
  375. }
  376. }
  377. }
  378. //Parse Foreign Key
  379. if (propertyType === 'foreign key' || propertyType === 'constrain foreign key') {
  380. if (!MODE_SQLSERVER) {
  381. ParseMySQLForeignKey(name, currentTableModel);
  382. } else {
  383. var completeRow = name;
  384. if (name.indexOf('REFERENCES') === -1) {
  385. var referencesRow = mxUtils.trim(lines[i + 1]);
  386. completeRow = 'ALTER TABLE [dbo].[' + currentTableModel.Name + '] WITH CHECK ADD' + ' ' + name + ' ' + referencesRow;
  387. }
  388. ParseSQLServerForeignKey(completeRow, currentTableModel);
  389. }
  390. }
  391. } else if (propertyRow === 'alter table ') {
  392. if (MODE_SQLSERVER) {
  393. //Parse the row
  394. var alterTableRow = tmp.substring(0, (tmp.charAt(tmp.length - 1) === ',') ? tmp.length - 1 : tmp.length);
  395. var referencesRow = mxUtils.trim(lines[i + 1]);
  396. var completeRow = alterTableRow + ' ' + referencesRow;
  397. ParseSQLServerForeignKey(completeRow, currentTableModel);
  398. }
  399. }
  400. }
  401. //Add last table
  402. if (currentTableModel !== null) {
  403. //Add table to the list
  404. tableList.push(currentTableModel);
  405. }
  406. //Process Primary Keys
  407. ProcessPrimaryKey();
  408. //Process Foreign Keys
  409. ProcessForeignKey();
  410. //Create Table in UI
  411. CreateTableUI();
  412. };
  413. function CreateTableUI() {
  414. tableList.forEach(function(tableModel) {
  415. //Define table size width
  416. var maxNameLenght = 100 + tableModel.Name.length;
  417. //Create Table
  418. tableCell = new mxCell(tableModel.Name, new mxGeometry(dx, 0, maxNameLenght, 26),
  419. 'swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=26;fillColor=default;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;marginBottom=0;swimlaneFillColor=default;align=center;');
  420. tableCell.vertex = true;
  421. //Resize row
  422. var size = ui.editor.graph.getPreferredSizeForCell(rowCell);
  423. if (size !== null) {
  424. tableCell.geometry.width = size.width + maxNameLenght;
  425. }
  426. //Add Table to cells
  427. cells.push(tableCell);
  428. //Add properties
  429. tableModel.Properties.forEach(function(propertyModel) {
  430. //Add row
  431. AddRow(propertyModel, tableModel.Name);
  432. });
  433. //Close table
  434. dx += tableCell.geometry.width + 40;
  435. tableCell = null;
  436. });
  437. if (cells.length > 0) {
  438. var graph = ui.editor.graph;
  439. var view = graph.view;
  440. var bds = graph.getGraphBounds();
  441. // Computes unscaled, untranslated graph bounds
  442. var x = Math.ceil(Math.max(0, bds.x / view.scale - view.translate.x) + 4 * graph.gridSize);
  443. var y = Math.ceil(Math.max(0, (bds.y + bds.height) / view.scale - view.translate.y) + 4 * graph.gridSize);
  444. graph.setSelectionCells(graph.importCells(cells, x, y));
  445. graph.scrollCellToVisible(graph.getSelectionCell());
  446. }
  447. wnd.setVisible(false);
  448. };
  449. mxUtils.br(div);
  450. var resetBtn = mxUtils.button(mxResources.get('reset'), function()
  451. {
  452. sqlInput.value = '';
  453. });
  454. resetBtn.style.marginTop = '8px';
  455. resetBtn.style.marginRight = '4px';
  456. resetBtn.style.padding = '4px';
  457. div.appendChild(resetBtn);
  458. var btn = mxUtils.button('Insert MySQL', function()
  459. {
  460. try
  461. {
  462. parseSql(sqlInput.value);
  463. }
  464. catch (e)
  465. {
  466. ui.handleError(e);
  467. }
  468. });
  469. btn.style.marginTop = '8px';
  470. btn.style.padding = '4px';
  471. div.appendChild(btn);
  472. var btn = mxUtils.button('Insert SQL Server', function()
  473. {
  474. try
  475. {
  476. parseSql(sqlInput.value, 'sqlserver');
  477. }
  478. catch (e)
  479. {
  480. ui.handleError(e);
  481. }
  482. });
  483. btn.style.marginTop = '8px';
  484. btn.style.padding = '4px';
  485. div.appendChild(btn);
  486. // Adds action
  487. ui.actions.addAction('fromSql', function() {
  488. wnd.setVisible(!wnd.isVisible());
  489. if (wnd.isVisible()) {
  490. sqlInput.focus();
  491. }
  492. });
  493. var theMenu = ui.menus.get('insert');
  494. var oldMenu = theMenu.funct;
  495. theMenu.funct = function(menu, parent) {
  496. oldMenu.apply(this, arguments);
  497. ui.menus.addMenuItems(menu, ['fromSql'], parent);
  498. };
  499. });