sqlite3-cc.nut 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. #!/home/mingo/bin/squilu
  2. /*
  3. * Copyright (C) 2013 by Domingo Alvarez Duarte <[email protected]>
  4. *
  5. * Licensed under GPLv3, see http://www.gnu.org/licenses/gpl.html.
  6. */
  7. dofile("sqlite-utils.nut");
  8. function _tr(str) {return str;}
  9. class Fl_Multiline_Output extends Fl_Output {
  10. constructor(px, py, pw, ph, pl=null){
  11. base.constructor(px, py, pw, ph, pl);
  12. type(4);
  13. }
  14. }
  15. enum Fl_Data_Table_Events {e_none, e_event, e_select, e_insert, e_update, e_delete};
  16. class Fl_Data_Table extends Flv_Data_Table {
  17. _cols_info = null;
  18. _data = null;
  19. _call_this = null;
  20. _forPrint = null;
  21. constructor(px, py, pw, ph, pl=null){
  22. base.constructor(px, py, pw, ph, pl);
  23. _cols_info = [];
  24. _data = [];
  25. _forPrint = false;
  26. has_scrollbar(FLVS_BOTH);
  27. }
  28. function for_print(bval){_forPrint = bval; }
  29. function resize(ax, ay, aw, ah){
  30. base.resize(ax, ay, aw, ah);
  31. calc_cols();
  32. }
  33. function clear_data_rows(){
  34. col(0);
  35. cols(0);
  36. row(0);
  37. rows(0);
  38. _data.clear();
  39. }
  40. function recalc_data(){
  41. col(0);
  42. row(0);
  43. rows(0);
  44. rows(_data.size());
  45. redraw();
  46. }
  47. function set_data(data_array){
  48. _data = data_array;
  49. recalc_data();
  50. }
  51. function set_new_data(data_array){
  52. clear_data_rows();
  53. _data = data_array;
  54. local mycols = _data[0];
  55. _data.remove(0);
  56. set_cols(mycols);
  57. recalc_data();
  58. }
  59. function get_data_value(arow, acol){ return _data[arow][acol];}
  60. function get_value(arow, acol){
  61. if(acol < 0)
  62. {
  63. if(arow < 0) return "#";
  64. return format("%d", arrow+1);
  65. }
  66. if(arow < 0) return _cols_info[acol].header;
  67. local ci = _cols_info[acol];
  68. local value = _data[arow][acol];
  69. switch(ci.format)
  70. {
  71. case 'M': return math.number_format(value.size() ? value.tofloat() : 0, 2);
  72. break;
  73. case 'P': return math.number_format(value.size() ? value.tofloat() : 0, 3);
  74. break;
  75. case 'N': return math.number_format(value.size() ? value.tofloat() : 0, -6);
  76. break;
  77. case 'Z': //Empty when zero
  78. case 'D': //Zero monetary //ZM':
  79. {
  80. if(value == "0" || value == "") return "";
  81. else
  82. {
  83. if(ci.format == 'Z') return math.number_format(value.tofloat(), -6);
  84. else return math.number_format(value.tofloat(), 2);
  85. }
  86. }
  87. break;
  88. case 'B': return (value == "1" ? "@-3+" : "");
  89. break;
  90. case 'S': return value.tostring();
  91. break;
  92. case '@': return value.replace("@", "@@"); //escape any @ {
  93. break;
  94. }
  95. return value;
  96. }
  97. function get_style(style, Row, Col){
  98. base.get_style(style, Row, Col);
  99. if(Row >= 0 && Col >= 0)
  100. {
  101. local rs = row_style().get(Row);
  102. local cs = col_style().get(Col);
  103. local have_bg = 0;
  104. if(cs.background_defined()) have_bg = cs.background();
  105. else if(rs.background_defined()) have_bg = rs.background();
  106. if((Row % 2) == 0)
  107. {
  108. if(have_bg)
  109. //s:background(fltk.fl_color_average(207, have_bg, 0.5))
  110. style.background(have_bg);
  111. else
  112. style.background(207);
  113. }
  114. else
  115. {
  116. if(have_bg)
  117. //s:background(have_bg)
  118. style.background(fl_color_average(FL_WHITE, have_bg, 0.5));
  119. else
  120. style.background(FL_WHITE);
  121. }
  122. }
  123. else if(_forPrint)
  124. {
  125. style.frame(FL_NO_BOX);
  126. }
  127. }
  128. function handle(event){
  129. switch(event){
  130. case FL_RELEASE:{
  131. local done = false;
  132. local clicks = Fl.event_clicks();
  133. if(clicks > 0){
  134. row_selected(Fl_Data_Table_Events.e_update);
  135. done = true;
  136. }
  137. else row_changed();
  138. if(done){
  139. Fl.event_clicks(0);
  140. return 1;
  141. }
  142. }
  143. break;
  144. case FL_KEYBOARD:
  145. local key = Fl.event_key();
  146. switch(key){
  147. case FL_KP_Plus:
  148. if(Fl.event_ctrl()) break;
  149. case FL_Insert:
  150. row_selected(Fl_Data_Table_Events.e_insert);
  151. break;
  152. //case FL_KP_Minus:
  153. // if(Fl::event_ctrl()) break;
  154. case FL_Delete:
  155. row_selected(Fl_Data_Table_Events.e_delete);
  156. break;
  157. case FL_KP_Enter:
  158. case FL_Enter:
  159. case FL_Key_Space:
  160. if(!Fl.event_ctrl()){
  161. row_selected(Fl_Data_Table_Events.e_update);
  162. }
  163. break;
  164. }
  165. break;
  166. }
  167. local rc = base.handle(event);
  168. return rc;
  169. }
  170. function row_selected(ev){ if(_call_this) _call_this.row_selected(this, ev);}
  171. function row_changed(){ if(_call_this) _call_this.row_changed(this);}
  172. function set_cols(mycols, size_absolute=false){
  173. _cols_info.clear();
  174. for(local i=0, max_cols=mycols.size(); i < max_cols; ++i){
  175. local col_info = {};
  176. parse_field_header(mycols[i], col_info);
  177. _cols_info.push(col_info);
  178. }
  179. cols(_cols_info.size());
  180. calc_cols(size_absolute);
  181. }
  182. function parse_field_header(str, col_info){
  183. local ci = str.split('|');
  184. local ci_size = ci.size();
  185. local curr_ci = 0;
  186. col_info.colname <- (ci_size > curr_ci++) ? ci[curr_ci-1] : "?";
  187. col_info.header <- (ci_size > curr_ci++) ? ci[curr_ci-1] : "?";
  188. col_info.width <- (ci_size > curr_ci++) ? ci[curr_ci-1].tofloat() : 10;
  189. col_info.align <- (ci_size > curr_ci++) ? ci[curr_ci-1][0] : 'L';
  190. col_info.format <- (ci_size > curr_ci++) ? ci[curr_ci-1][0] : '\0';
  191. col_info.color <- (ci_size > curr_ci++) ? ci[curr_ci-1].tointeger() : 0;
  192. col_info.bgcolor <- (ci_size > curr_ci++) ? ci[curr_ci-1].tointeger() : 0;
  193. if(ci_size == 1) {
  194. col_info.colname = str;
  195. col_info.header = str;
  196. }
  197. }
  198. function calc_cols(size_absolute=false){
  199. calc_cols_width(size_absolute);
  200. for(local k=0, len = cols(); k < len; ++k)
  201. {
  202. local v = _cols_info[k];
  203. //v.header = _tr(v.header.c_str());
  204. local col_align;
  205. switch(v.align)
  206. {
  207. case 'C':
  208. col_align = FL_ALIGN_CENTER;
  209. break;
  210. case 'R':
  211. col_align = FL_ALIGN_RIGHT;
  212. break;
  213. default:
  214. col_align = FL_ALIGN_LEFT;
  215. }
  216. local cs = col_style().get(k);
  217. cs.align(col_align);
  218. if(v.color) cs.foreground(v.color);
  219. if(v.bgcolor) cs.background(v.bgcolor);
  220. }
  221. }
  222. function calc_cols_width(size_absolute=false){
  223. if(size_absolute){
  224. for(local k=0, len = cols(); k < len; ++k)
  225. {
  226. local cs = col_style().get(k);
  227. cs.width(_cols_info[k].width);
  228. }
  229. return;
  230. }
  231. local grid_width, total_widths, char_width;
  232. grid_width = w();
  233. if(has_scrollbar()) grid_width -= scrollbar_width();
  234. //char_width = self:labelsize() --fltk.fl_width('w')
  235. //it seems that if not set the text font on fluid
  236. //we get segfault here
  237. fl_font(textfont(), textsize());
  238. local gs = global_style();
  239. gs.height(fl_height()+fl_descent());
  240. char_width = fl_width("w");
  241. draw_offset(char_width/3);
  242. //print(grid_width, char_width)
  243. total_widths = 0;
  244. for(local k=0, len = cols(); k < len; ++k)
  245. {
  246. local v = _cols_info[k].width;
  247. if(v > 0) total_widths += ((v * char_width) + 1);
  248. }
  249. for(local k=0, len = cols(); k < len; ++k)
  250. {
  251. local v = _cols_info[k];
  252. local col_width = v.width;
  253. if( col_width < 0) col_width = grid_width - total_widths;
  254. else col_width *= char_width;
  255. local cs = col_style().get(k);
  256. cs.width(col_width);
  257. }
  258. }
  259. function get_selection(ar_out, withIds=false){
  260. }
  261. function clear_selection(){
  262. }
  263. function get_col_name(idx){
  264. return _cols_info.len() ? _cols_info[idx].colname : idx.tostring();
  265. }
  266. function get_row(arow=null){
  267. if(arow == null) arow = row();
  268. return _data.len() ? _data[arow] : null;
  269. }
  270. function get_row_id(arow=null){
  271. if(arow == null) arow = row();
  272. return _data.len() ? _data[arow][0].tointeger() : 0;
  273. }
  274. function get_row_field_by_name(field_name, arow=null){
  275. if(arow == null) arow = row();
  276. foreach(idx, ci in _cols_info)
  277. {
  278. if(ci.colname == field_name)
  279. {
  280. return _data.len() ? _data[arow][idx] : null;
  281. }
  282. }
  283. return null;
  284. }
  285. function select_row_by_id(the_id){
  286. for(local i=0, len=_data.len(); i < len; ++i)
  287. {
  288. if(_data[i][0] == the_id)
  289. {
  290. row(i);
  291. return i;
  292. }
  293. }
  294. return -1;
  295. }
  296. function delete_row_id(arow=null)
  297. {
  298. if(arow == null) arow = row();
  299. _data.remove(arow);
  300. recalc_data();
  301. }
  302. }
  303. dofile("sqlite3-cc-gui.nut", false, false);
  304. local function multiply3(ctx,a,b,c){
  305. //print(ctx.user_data());
  306. ctx.result_double(a*b*c);
  307. }
  308. local function sqlite3_progress_handler(window)
  309. {
  310. //print("sqlite3_progress_handler");
  311. Fl.check();
  312. return window.ref()._stop_processing_query ? 1 : 0;
  313. }
  314. class Sqlite3CC extends Sqlite3cc_Window {
  315. // Declaration of class members
  316. db_file_name = null;
  317. _the_schema_version = null;
  318. _my_tables_data = null;
  319. label_title = null;
  320. db = null;
  321. attached_databases = null;
  322. squilu_edit_window = null;
  323. _busy_working = null;
  324. _stop_processing_query = null;
  325. //_history_db_name = null;
  326. //_history_db = null;
  327. _hide_system_tables = false;
  328. constructor(){
  329. base.constructor();
  330. menuBar.callback(menuBar_cb);
  331. btnExecute.callback(btnExecute_cb);
  332. btnCreateQuery.callback(btnCreateQuery_cb);
  333. tabView.callback(tabView_cb);
  334. grid_tables._call_this = this.weakref();
  335. grid_data._call_this = this.weakref();
  336. grid_fields._call_this = this.weakref();
  337. gridIndexes._call_this = this.weakref();
  338. gridTriggers._call_this = this.weakref();
  339. local last_db_file_name = Fl.preferences_get("last_db_file_name", "");
  340. openDB(last_db_file_name);
  341. iTablesFilter.callback(doDataSearch_cb);
  342. chkSytemTables.callback(showHideSystemTables_cb);
  343. }
  344. function setBusyWorking(turnOn)
  345. {
  346. if(turnOn && _busy_working)
  347. {
  348. _stop_processing_query = true;
  349. return false;
  350. }
  351. _busy_working = turnOn;
  352. _stop_processing_query = false;
  353. return true;
  354. }
  355. function doDataSearch_cb(sender : Fl_Widget, udata : any)
  356. {
  357. this = sender->window();
  358. local filtered_data = doFilterMyData(iTablesFilter->value(), grid_tables->_data);
  359. grid_tables->set_data(filtered_data);
  360. }
  361. function filterSystemTables()
  362. {
  363. local the_data = _my_tables_data;
  364. local filtered_data = [];
  365. foreach(rec in the_data)
  366. {
  367. local tbl_name = rec[1];
  368. if(_hide_system_tables && tbl_name.len() && tbl_name.startswith("__")) continue;
  369. filtered_data.push(rec);
  370. }
  371. return filtered_data
  372. }
  373. function showHideSystemTables()
  374. {
  375. _hide_system_tables = chkSytemTables->value();
  376. local filtered_data = filterSystemTables();
  377. grid_tables->set_data(filtered_data);
  378. }
  379. function showHideSystemTables_cb(sender : Fl_Widget, udata : any)
  380. {
  381. this = sender->window();
  382. showHideSystemTables();
  383. }
  384. function doFilterMyData(value, prev_filtered_data)
  385. {
  386. local the_data = prev_filtered_data;
  387. local value_len = value.len();
  388. //print(__LINE__, _my_tables_data.len(), the_data.len(), value.len(), value);
  389. if(value_len == 0) return _hide_system_tables ? filterSystemTables() : _my_tables_data;
  390. if(value_len == 1 || the_data.len() == 0)
  391. {
  392. //we start from scratch
  393. return _hide_system_tables ? filterSystemTables() : _my_tables_data;
  394. }
  395. local filtered_data = [];
  396. foreach(rec in the_data)
  397. {
  398. if(_hide_system_tables)
  399. {
  400. local tbl_name = rec[1];
  401. if(tbl_name.len() && tbl_name.startswith("__")) continue;
  402. }
  403. foreach(field in rec)
  404. {
  405. if(field)
  406. {
  407. local fs = field.tostring();
  408. if(fs.len() && fs.indexOf(value) >= 0)
  409. {
  410. filtered_data.push(rec);
  411. break;
  412. }
  413. }
  414. }
  415. }
  416. return filtered_data;
  417. }
  418. function getGridTableAttachedDB()
  419. {
  420. return (grid_tables.cols() > 3) ? (grid_tables.get_value(grid_tables.row(), 3) + ".") : "";
  421. }
  422. function checkSchemaVersion()
  423. {
  424. if(_the_schema_version != SQLiteUtils.getSchemaVersion(db, getGridTableAttachedDB()))
  425. {
  426. local tables_idx = grid_tables->row();
  427. get_tables(false);
  428. local v = iTablesFilter->value();
  429. if(v.len())
  430. {
  431. doDataSearch_cb(iTablesFilter, null);
  432. }
  433. else showHideSystemTables();
  434. grid_tables->row(tables_idx < grid_tables->rows() ? tables_idx : grid_tables->rows()-1);
  435. }
  436. }
  437. function showExecutionTime(start_time)
  438. {
  439. local end_time = os.clock();
  440. output_messages->value("Execution time = " + (end_time - start_time) + " seconds");
  441. tabsLog->value(groupMessages);
  442. }
  443. function row_changed(sender)
  444. {
  445. if(sender == grid_tables){
  446. local tbl = grid_tables.get_value(grid_tables.row(), 1);
  447. refreshTabView(tbl, getGridTableAttachedDB());
  448. }
  449. }
  450. function showRecord(the_grid)
  451. {
  452. local row = the_grid.get_row();
  453. local record = blob(0, 8000);
  454. foreach(idx, val in row)
  455. record.write((idx ? "\n" : ""), "----", idx, ":",
  456. grid_data.get_col_name(idx),"\n", val);
  457. edit_record.value(record.tostring());
  458. tabView->value(groupRecord);
  459. }
  460. function row_selected(sender, ev){
  461. if(sender == grid_tables){
  462. if(ev == Fl_Data_Table_Events.e_update){
  463. local tbl = grid_tables.get_value(grid_tables.row(), 1);
  464. local sql = format("select * from %s\"%s\"", getGridTableAttachedDB(), tbl);
  465. local limit = iMaxRows.value();
  466. if(limit && limit.len()) sql += " limit " + limit;
  467. local start_time = os.clock();
  468. get_records_by_sql(grid_data, sql, true);
  469. showExecutionTime(start_time);
  470. tabView->value(groupData);
  471. }
  472. }
  473. else if(
  474. (sender == grid_fields) ||
  475. (sender == grid_data) ||
  476. (sender == gridIndexes) ||
  477. (sender == gridTriggers)
  478. ){
  479. if(ev == Fl_Data_Table_Events.e_update){
  480. showRecord(sender);
  481. }
  482. }
  483. }
  484. function btnExecute_cb(sender, udata){
  485. this = sender->window();
  486. if(!setBusyWorking(true)) return;
  487. local sql;
  488. if(edit_queries->buffer()->selected()) sql = edit_queries->buffer()->selection_text();
  489. else sql = edit_queries->value();
  490. local action = option_query.text();
  491. if( (sql && sql.len()) || (action == "sql update metadata")) {
  492. local start_time;
  493. local foreign_keys_saved = null;
  494. local cursor_wait = fl_cursor_wait();
  495. switch(action)
  496. {
  497. case "references":
  498. local references = SQLiteUtils.getReferencesOnDBSchema(db, sql, getGridTableAttachedDB());
  499. edit_references->value(references);
  500. tabView->value(groupReferences);
  501. break;
  502. case "search all tables":
  503. local references = SQLiteUtils.searchOnAllTables(db, sql, iMaxRows->value().tointeger(), getGridTableAttachedDB());
  504. edit_references->value(references);
  505. tabView->value(groupReferences);
  506. break;
  507. case "schema update":
  508. case "schema update norefs":
  509. foreign_keys_saved = db.exec_get_one(format("PRAGMA %sforeign_keys", getGridTableAttachedDB()));
  510. case "insert":
  511. case "update":
  512. case "delete":
  513. case "create index":
  514. case "create trigger":
  515. case "sqlite_master update":
  516. case "drop table":
  517. try
  518. {
  519. start_time = os.clock();
  520. sql = edit_queries->value();
  521. db.exec_dml(sql);
  522. showExecutionTime(start_time);
  523. switch(action)
  524. {
  525. case "sqlite_master update":
  526. _the_schema_version = 0;
  527. case "create index":
  528. case "create trigger":
  529. case "schema update":
  530. case "schema update norefs":
  531. case "drop table":
  532. checkSchemaVersion();
  533. break;
  534. }
  535. }
  536. catch(e)
  537. {
  538. if(!db.IsAutoCommitOn() || action.startswith("schema update")) db.exec_dml("ROLLBACK;");
  539. if(foreign_keys_saved != null) db.exec_dml(format("PRAGMA %sforeign_keys=" + foreign_keys_saved, getGridTableAttachedDB()));
  540. fl_alert(e);
  541. }
  542. break;
  543. case "dump table":
  544. break;
  545. case "sql update metadata":
  546. start_time = os.clock();
  547. SQLiteUtils.doUpdateMetadata(db);
  548. showExecutionTime(start_time);
  549. checkSchemaVersion();
  550. break;
  551. case "sql macros base":
  552. local sql_pp = new SqlPreprocessor();
  553. local new_sql = sql_pp.getPreprocessorQuery(db, sql, "base");
  554. if(new_sql) edit_queries->value(new_sql);
  555. break;
  556. case "sql macros sql":
  557. local sql_pp = new SqlPreprocessor();
  558. local new_sql = sql_pp.getPreprocessorQuery(db, sql, "sql");
  559. if(new_sql) edit_queries->value(new_sql);
  560. break;
  561. case "sql macros insert":
  562. local sql_pp = new SqlPreprocessor();
  563. sql_pp.insertPreprocessorQuery(db, sql);
  564. break;
  565. case "sql macros update":
  566. local sql_pp = new SqlPreprocessor();
  567. sql_pp.updatePreprocessorQuery(db, sql);
  568. break;
  569. case "sql macros":
  570. local sql_pp = new SqlPreprocessor();
  571. local new_sql = sql_pp.getPreprocessorQuery(db, sql);
  572. if(new_sql)
  573. {
  574. sql = sql_pp.preprocessSqlQueryParams(new_sql, {});
  575. edit_queries->value(sql);
  576. }
  577. else break;
  578. default:
  579. try
  580. {
  581. start_time = os.clock();
  582. get_records_by_sql(grid_data, sql, true, false);
  583. showExecutionTime(start_time);
  584. tabView->value(groupData);
  585. checkSchemaVersion();
  586. }
  587. catch(e)
  588. {
  589. if(!db.IsAutoCommitOn()) db.exec_dml("ROLLBACK;");
  590. fl_alert(e);
  591. }
  592. }
  593. }
  594. setBusyWorking(false);
  595. }
  596. function btnCreateQuery_cb(sender, udata){
  597. this = sender->window();
  598. if(db){
  599. local tbl = grid_tables.get_value(grid_tables.row(), 1);
  600. local sql = SQLiteUtils.createQuery(db, tbl, option_query.text(), iMaxRows.value().tointeger(), getGridTableAttachedDB());
  601. if(sql) edit_queries->value(sql);
  602. }
  603. }
  604. function refreshTabView(tbl, attached_db)
  605. {
  606. local tab = tabView->value();
  607. local sql = false;
  608. local the_grid = false;
  609. if(tab == viewFields)
  610. {
  611. sql = SQLiteUtils.getTableInfoSqlFor(tbl, attached_db);
  612. the_grid = grid_fields;
  613. }
  614. if(tab == viewIndexes)
  615. {
  616. sql = SQLiteUtils.getIndexesSqlFor(tbl, attached_db);
  617. the_grid = gridIndexes;
  618. }
  619. else if(tab == viewTriggers)
  620. {
  621. sql = SQLiteUtils.getTriggersSqlFor(tbl, attached_db);
  622. the_grid = gridTriggers;
  623. }
  624. else if(tab == groupSchema)
  625. {
  626. local str = SQLiteUtils.getSchemaFor(db, tbl, attached_db);
  627. edit_schema->value(str);
  628. }
  629. if(sql && the_grid)
  630. {
  631. get_records_by_sql(the_grid, sql, true);
  632. }
  633. }
  634. function tabView_cb(sender, udata){
  635. this = sender->window();
  636. //print(tab->label());
  637. local tbl = grid_tables.get_value(grid_tables.row(), 1);
  638. if(tbl)
  639. {
  640. refreshTabView(tbl, getGridTableAttachedDB());
  641. }
  642. }
  643. function set_label_dbf(dbf){
  644. db_file_name = dbf;
  645. label_title = "SqliteCC";
  646. if (dbf) label_title += " - " + dbf;
  647. label(label_title);
  648. }
  649. function queryAsArrayOfArrays(sql)
  650. {
  651. local result = [];
  652. local qry = db.exec_query(sql);
  653. local col_count = qry.col_count();
  654. local header = [];
  655. for(local i=0; i < col_count; ++i){
  656. header.append(qry.col_name(i));
  657. }
  658. result.append(header);
  659. while(qry.next_row()){
  660. result.append(qry.row_as_array());
  661. }
  662. qry.close();
  663. return result;
  664. }
  665. function get_records_by_sql(grid, sql , named=false, withBusyWorking=true){
  666. if(withBusyWorking && !setBusyWorking(true)) return;
  667. local cursor_wait = fl_cursor_wait();
  668. local stmt = db.prepare(sql);
  669. local rec_list = stmt.asArrayOfArrays(SQLite3Stmt.WITH_COL_NAMES |
  670. SQLite3Stmt.AS_STRING_ALWAYS | SQLite3Stmt.NULL_AS_EMPTY_STR);
  671. grid.set_new_data(rec_list);
  672. if(withBusyWorking) setBusyWorking(false);
  673. }
  674. function get_tables(withBusyWorking=true){
  675. local with_attached = table_len(attached_databases) > 0;
  676. local sql_template = "SELECT rowid AS 'rowid|ID|0', name AS 'name|Name|-1', type as 'type|Type|4'";
  677. if(with_attached) sql_template += ", '%s' AS 'db|DB|4'";
  678. sql_template += " FROM %s.sqlite_master WHERE (type='table' OR type='view')";
  679. local main_prefix = "main";
  680. local sql = format(sql_template, main_prefix, main_prefix);
  681. foreach(k,v in attached_databases)
  682. {
  683. sql += "\nUNION ALL\n" + format(sql_template, k, k);
  684. }
  685. sql += "\nORDER BY " + (with_attached ? "4,2" : "2");
  686. get_records_by_sql(grid_tables, sql, true, withBusyWorking);
  687. _the_schema_version = SQLiteUtils.getSchemaVersion(db, getGridTableAttachedDB());
  688. _my_tables_data = grid_tables->_data;
  689. }
  690. function openDB(the_db_file_name)
  691. {
  692. if (the_db_file_name) {
  693. //print(dbf);
  694. if (db) db.close();
  695. attached_databases = {};
  696. set_label_dbf(the_db_file_name);
  697. // SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_SUBLATIN_NA_LIKE
  698. db = SQLite3(the_db_file_name);
  699. db.progress_handler(1000, sqlite3_progress_handler, this.weakref());
  700. //db.exec_dml("PRAGMA mmap_size=268435456;");
  701. //db.trace(function(udata, sql){print(udata, ":", sql);}, "SQL");
  702. //db.create_function("multiply3",3, multiply3); //SQLITE_DETERMINISTIC
  703. get_tables();
  704. Fl.preferences_set("last_db_file_name", the_db_file_name);
  705. //_history_db_name = Fl.preferences_getUserdataPath() + "/sqlite3_cc_history.db";
  706. //_history_db = SQLite3(_history_db_name);
  707. }
  708. }
  709. function menuBar_cb(sender, udata){
  710. this = sender->window();
  711. //fl_alert(format("%d = %s", sender.value(), sender.text()));
  712. //print(sender, udata, sender.value(), menu_file_exit);
  713. local choice = sender.value();
  714. local path = db_file_name ? db_file_name.gsub("/[^/]+$", "") : null;
  715. if(choice == menu_file_new) {
  716. local dbf = fl_file_chooser(_tr("Select a database"), "*.db", path);
  717. openDB(dbf);
  718. }
  719. else if(choice == menu_file_open) {
  720. local dbf = fl_file_chooser(_tr("Select a database"), "*.db", path);
  721. openDB(dbf);
  722. }
  723. else if(choice == menu_file_reopen) {
  724. if(db) openDB(db_file_name);
  725. }
  726. else if(choice == menu_file_attach) {
  727. local dbf = fl_file_chooser(_tr("Select a database"), "*.db", path);
  728. if (dbf){
  729. //print(dbf)
  730. local dbname = fl_input(_tr("Attach database with name ?"), "adb");
  731. if (dbname && !table_get(attached_databases, dbname, false)){
  732. attached_databases[dbname] <- true;
  733. local sql = format("ATTACH DATABASE '%s' as %s;", dbf, dbname);
  734. db.exec_dml(sql);
  735. get_tables();
  736. }
  737. }
  738. }
  739. else if(choice == menu_file_close) {
  740. if (db){
  741. db.close();
  742. db = null;
  743. set_label_dbf(null);
  744. grid_tables.clear_data_rows();
  745. attached_databases = {};
  746. }
  747. }
  748. else if(choice == menu_file_open_csv) {
  749. local csvf = fl_file_chooser(_tr("Select a CSV file"), "*.csv", path);
  750. local sep = fl_input("CSV Separator", ",");
  751. local hasHeaders = fl_ask("The CSV first line is header ?");
  752. if(sep)
  753. {
  754. local cursor_wait = fl_cursor_wait();
  755. local max_rows = iMaxRows.value().tointeger();
  756. local fd = file(csvf, "r");
  757. local line;
  758. local rec_list = [];
  759. local isFirstLine = true;
  760. while( (line = fd.read_line()) )
  761. {
  762. local record = line.split_csv(sep[0]);
  763. if(isFirstLine)
  764. {
  765. if(!hasHeaders)
  766. {
  767. local col_count = record.len();
  768. local header = array(col_count);
  769. for(local i=0; i < col_count; ++i) header[i] = "col" + i;
  770. rec_list.append(header);
  771. }
  772. isFirstLine = false;
  773. }
  774. rec_list.append(record);
  775. }
  776. fd.close();
  777. grid_data.set_new_data(rec_list);
  778. tabView->value(groupData);
  779. }
  780. }
  781. else if(choice == menu_file_execute) {
  782. }
  783. else if(choice == menu_file_exit) os.exit();
  784. else if(choice == menu_help_about) {
  785. }
  786. else if(choice == menu_squilu_edit) {
  787. if(!squilu_edit_window){
  788. squilu_edit_window = new SquiLuEditWindow();
  789. }
  790. squilu_edit_window.show();
  791. }
  792. }
  793. }
  794. fl_preferences(Fl.FL_PREFERENCES_USER, "dadbiz", "sqlite3-cc");
  795. Fl.scheme("gtk+");
  796. Fl.visual(FL_RGB);
  797. //allow arrow keys navigation
  798. Fl.option(Fl.OPTION_ARROW_FOCUS, true);
  799. local win = new Sqlite3CC();
  800. //local win = new SalesTaxRatesEditWindow();
  801. win->resizable(win);
  802. win->show_main();
  803. Fl.run();
  804. Fl.preferences_flush();