├── README.rst └── sqliteboy.py /README.rst: -------------------------------------------------------------------------------- 1 | 2 | :: 3 | 4 | SQLiteBoy 5 | Simple web-based management tool for SQLite database 6 | (with form, report, website, and many other features) 7 | (c) Noprianto 8 | 2012-2019 9 | License: GPL 10 | Version: 1.83 11 | 12 | SQLiteBoy is an independent product, developed separately from the 13 | SQLite core library, which is maintained by SQLite.org. 14 | Neither noprianto.com nor SQLite.org take any responsibility for the 15 | work of the other. 16 | 17 | 18 | 19 | 20 | .. contents:: 21 | 22 | 23 | 24 | What Is SQLiteBoy 25 | ======================================================================== 26 | 27 | - Easy to use, python and web.py based, simple web-based management tool 28 | for SQLite database with user-defined functions and many extended features 29 | (Free/open source) 30 | 31 | - User-defined functions: number to words (multi language), number format, 32 | table lookup, hash, base64, random, additional date/time, additional 33 | string, regular expression, utility 34 | 35 | - If Extended feature is enabled: 36 | 37 | Multi user, simple (yet flexible) form (data entry) and reporting can 38 | be created by admin (simple JSON syntax), and can be run by 39 | admin/user (configurable). Very simple subform is also supported. 40 | 41 | Form field supports predefined values (options) from SQL Query or 42 | Python list. Also, default value can be result of function call, 43 | static value or SQL Query. Constraint is also supported, to check before 44 | save, to prevent saving invalid value (it's possible to call 45 | function before comparison). Onsave event is also supported, to 46 | execute SQL Query (and use the result) just before the data is saved. 47 | 48 | Reporting wizard also supports form field predefined values, default 49 | value and constraint (checking before reporting query is executed). 50 | Supported report format: PDF, HTML, HTML (printer friendly) and CSV. 51 | 52 | Form and Report support python handler, which will be automatically called, if 53 | provided. Python handler eases the integration with external system 54 | (for example: ERP system). Python handler also could be useful in, 55 | for example, complex database operation, reading from/writing to 56 | external devices, etc. 57 | 58 | User accounts, Notes, Files (with file sharing support), Page (home page), 59 | calculator, configurable hosts allowed, database backup, system configuration, 60 | Scripts, profile (with user-defined profile support) 61 | and others are available as extended features 62 | 63 | SQLiteBoy script (simple JSON syntax, single file) can be used to automate 64 | the creation of tables (including addition of columns, for existing table), 65 | forms, reports or user-defined profiles 66 | 67 | It is also possible to use SQLiteBoy to serve a website with custom URLs. 68 | URL can be handled by a python function, redirect, Files, template, or HTML. 69 | POST method is also supported and can be handled by python function. 70 | 71 | 72 | Links 73 | ======================================================================== 74 | 75 | - screenshot, probably not up-to-date: 76 | https://github.com/nopri/sqliteboy/wiki 77 | 78 | - Free Book: Form dan Report sederhana dengan SQLiteBoy 79 | (Bahasa Indonesia, available as PDF/ODT, 250+ pages, revision 2): 80 | https://github.com/nopri/publication/raw/master/form-dan-report-sederhana-dengan-sqliteboy.pdf 81 | 82 | - Tutorial: simple medical record: 83 | https://github.com/nopri/sqliteboy/wiki/Tutorial-simple-medical-record 84 | 85 | - Tutorial: install sqliteboy on ACRyan Playon!HD Mini2 ACRPV73800: 86 | https://github.com/nopri/sqliteboy/wiki/Tutorial-install-sqliteboy-on-ACRyan-Playon!HD-Mini2-ACRPV73800 87 | 88 | - Tutorial: Using sqliteboy udf in python handler: 89 | https://github.com/nopri/sqliteboy/wiki/Tutorial-using-sqliteboy-udf-in-python-handler 90 | 91 | - Tutorial: Create a new partner in OpenERP: 92 | https://github.com/nopri/sqliteboy/wiki/Tutorial-create-a-new-partner-in-openerp 93 | 94 | - Tutorial: Search partners in OpenERP: 95 | https://github.com/nopri/sqliteboy/wiki/Tutorial-search-partners-in-openerp 96 | 97 | - Tutorial: Hyperlink and Javascript in label: 98 | https://github.com/nopri/sqliteboy/wiki/Tutorial-hyperlink-and-javascript-in-label 99 | 100 | - More: https://github.com/nopri/sqliteboy/wiki/_pages 101 | 102 | 103 | Development Notes 104 | ======================================================================== 105 | 106 | - Standalone version is no longer provided, but codes for this 107 | are still in the source code 108 | 109 | - Version 1.51 was released as a bug fix (reported in issue #1). In this 110 | commit, many lines (both in this file and the source code) had been 111 | added/deleted (due to text reformatting). Please, let me know if 112 | something was accidentally added or deleted. 113 | 114 | - As of v1.64, index URL was changed to /index because / is used for 115 | public home page (new in v1.64, please read WEBSITE AND CUSTOM URL REFERENCE) 116 | 117 | 118 | Features 119 | ======================================================================== 120 | 121 | - Works with single SQLite database per instance 122 | 123 | - Single python file 124 | 125 | - Configurable port (default 11738 because it looks like sqliteboy). 126 | As of v1.75, it is possible to run SQLiteBoy as WSGI application, 127 | please read HOW TO RUN. 128 | 129 | - SSL Support 130 | 131 | - Basic/Extended Feature 132 | 133 | - Basic: Database management + User-defined function 134 | 135 | - Extended: Form, Report, User/Login, etc 136 | 137 | - Completely optional 138 | 139 | - Can be enabled in menu 140 | 141 | - If enabled, one table:: 142 | 143 | _sqliteboy_ 144 | 145 | will be created. You can delete this table 146 | and extended feature will be disabled 147 | 148 | - Form Support (Extended feature, new in v0.12) 149 | 150 | - Simple data entry 151 | 152 | - Simple syntax (JSON) 153 | 154 | - Please read FORM CODE REFERENCE section (below) 155 | 156 | - Readonly field 157 | 158 | - Required field 159 | 160 | - Predefined values (field options) from SQL Query 161 | or Python list 162 | 163 | - Default value: function call or static value or SQL Query 164 | 165 | - Constraint: check before save, 166 | prevent saving invalid value 167 | (possible to call function before comparison) 168 | 169 | - Simple security setting 170 | 171 | - As of v0.21, onsave event is also supported, to execute SQL Query 172 | (and use the result) just before the data is saved. The SQL Query 173 | can be very complex and involves nested function calls. 174 | 175 | - As of v0.26, very simple subform is also supported. Subform can be 176 | used in one to many relationship. However, field in subform is 177 | limited, compared to form. 178 | 179 | - As of v0.27, custom result message (based on SQL query result), 180 | is also supported. 181 | 182 | - As of v0.27, optional, additional SQL query statement(s) can be 183 | provided, and each of them will be executed in order, if you need 184 | to perform additional task(s), after the form data is saved (for 185 | example, write to another table). Previously, one might use report 186 | if need to write to several tables. Last insert rowid value is 187 | provided. 188 | 189 | - As of v0.75, insert into table can be disabled by setting insert key 190 | to zero/negative value. This is useful if you need to update/delete data in 191 | table(s), using additional SQL query statement(s). By default, 192 | form/subform save will insert new row(s) into table(s). 193 | 194 | - As of v0.98, form supports python handler, which will be automatically 195 | called, if provided. Python handler eases the integration with external 196 | system (for example: ERP system). Please read PYTHON HANDLER REFERENCE 197 | section. 198 | 199 | - As of v1.33, optional, (run before) additional SQL query statement(s) 200 | can be provided. 201 | 202 | - As of v1.72, links can be added to form 203 | 204 | - As of v1.73, form supports extended result message. This extends 205 | custom result message introduced in v0.27. Using extended result, 206 | it is possible to perform operations on form fields, and use the result. 207 | Like custom result message, it is based on SQL query result. 208 | But unlike custom result message, the result is not limited to integer 209 | (can be string or another types; probably returned from function call). 210 | 211 | - Report Support (Extended feature, new in v0.16) 212 | 213 | - Simple reporting (and data entry) 214 | 215 | - Simple syntax (JSON) 216 | 217 | - Please read REPORT CODE REFERENCE section (below) 218 | 219 | - Readonly field 220 | 221 | - Predefined values (field options) from SQL Query 222 | or Python list 223 | 224 | - Default value: function call or static value or SQL Query 225 | 226 | - Constraint: check before query, 227 | (possible to call function before comparison) 228 | 229 | - Flexible SQL query 230 | (and relation to wizard/user input) 231 | (free form query, You can use join, etc) 232 | 233 | - Custom header order 234 | 235 | - Simple security setting 236 | 237 | - As of v0.18, report also can be used as form/data entry, using 238 | insert SQL query. Custom result message (based on SQL query result), 239 | is also supported. 240 | 241 | - As of v0.60, headers and footers are supported. If not defined, a 242 | default one will be created. Plain text, SQL Query, and Image are 243 | supported. 244 | 245 | - As of v0.85, printer friendly version of report result is supported 246 | in default output format (HTML) 247 | 248 | - As of v1.00, report supports python handler, which will be automatically 249 | called, if provided. Python handler eases the integration with external 250 | system (for example: ERP system). Please read PYTHON HANDLER REFERENCE 251 | section. 252 | 253 | - As of v1.17, CSV output is supported 254 | 255 | - As of v1.28, PDF output (paper size, margins, image) is supported 256 | 257 | - As of v1.36, text align is supported (HTML and PDF only) 258 | 259 | - As of v1.72, links can be added to report 260 | 261 | - Files (Extended feature, new in v0.47) 262 | 263 | - System configuration: maximum number of files per user (admin: unlimited) 264 | 265 | - System configuration: maximum file size (admin: unlimited) 266 | 267 | - Multiple file upload (content type, filename, etc are saved) 268 | 269 | - Action: view 270 | 271 | - Action: download (disposition attachment) 272 | 273 | - Simple file sharing support 274 | 275 | - Human readable file size 276 | 277 | - URL: /fs 278 | 279 | - HTTP 404 Error: file not found or not shared 280 | 281 | - Page (Extended feature, new in v0.48) 282 | 283 | - Static page per user (home page) 284 | 285 | - URL: /page/ 286 | 287 | - Please read PAGE CODE REFERENCE section (below) 288 | 289 | - Scripts (Extended feature, new in v0.71) 290 | 291 | - Simple script, to automate the creation of tables 292 | (including addition of columns, for existing table), 293 | forms, reports or user-defined profiles 294 | 295 | - Solution can be deployed in form of script, that can be uploaded 296 | and run by admin 297 | 298 | - Simple syntax (JSON) in single file 299 | 300 | - Please read SCRIPT CODE REFERENCE section (below) 301 | 302 | - Profile (Extended feature, new in v0.91) 303 | 304 | - User profile 305 | 306 | - style 307 | 308 | - User-defined profile is also supported. Using this feature, 309 | custom field(s) in user profile can be added. This is useful, 310 | for example, in multi-company environment. 311 | 312 | - system configuration 313 | 314 | - Simple syntax (JSON) 315 | 316 | - Predefined values (field options) from SQL Query or Python list 317 | (as in form or report, is also supported) 318 | 319 | - Please read USER-DEFINED PROFILE REFERENCE section (below) 320 | 321 | - Website (Extended feature, new in v1.64) 322 | 323 | - Custom URLs 324 | 325 | - URL can be handled by a python function, redirect, Files, template, or HTML 326 | 327 | - As of v1.67, POST method handler is supported, using python function 328 | 329 | - As of v1.68, custom not found URL is supported 330 | 331 | - Please read WEBSITE AND CUSTOM URL REFERENCE 332 | 333 | - Browse table 334 | 335 | - Sort (asc/desc) 336 | 337 | - Download for BLOB type (if not NULL) 338 | 339 | - Multiple selection 340 | 341 | - Delete selected 342 | 343 | - Edit selected 344 | 345 | - Maintain last selected row(s) 346 | 347 | - Limit rows 348 | 349 | - Pagination 350 | 351 | - Insert into table 352 | 353 | - Default value hint 354 | 355 | - Work with default value(s) 356 | 357 | - Upload for BLOB type 358 | 359 | - Edit/Update table 360 | 361 | - Default value hint 362 | 363 | - Work with default value(s) 364 | 365 | - Download for BLOB type (if not NULL) 366 | 367 | - Upload for BLOB type 368 | 369 | - Column 370 | 371 | - Add column (with type and default value) 372 | 373 | - Multiple column addition 374 | 375 | - Rename table 376 | 377 | - Empty table 378 | 379 | - Drop table 380 | 381 | - CSV export/import 382 | 383 | - Schema (view schema, create new table) 384 | 385 | - Copy table 386 | 387 | - Create table 388 | 389 | - Support type, primary key, default value 390 | 391 | - Single or multiple primary key 392 | 393 | - Support for integer primary key autoincrement 394 | 395 | - Default value can be non-constant 396 | (for example: current_time, current_timestamp) 397 | 398 | - Query 399 | 400 | - Free form SQL Query 401 | 402 | - Automatically view query output (as integer or table) 403 | 404 | - Export query result to CSV (if applicable) 405 | 406 | - User-defined variable is also supported (max per user: 3). 407 | Please use the following functions: sqliteboy_var_set, 408 | sqliteboy_var_get, sqliteboy_var_del. 409 | 410 | - Vacuum 411 | 412 | - User account (Extended feature) 413 | 414 | - Type: admin (full access), 415 | standard (limited or configurable form/report access) 416 | 417 | - Change password 418 | 419 | - User management 420 | 421 | - Notes (Extended feature, new in v0.41) 422 | 423 | - Simple notes 424 | 425 | - Content as SQL Query (admin), calculator, source code 426 | 427 | - Please read Interpreter below 428 | 429 | - Calculator (Extended feature, new in v0.50) 430 | 431 | - Simple calculator 432 | 433 | - Valid characters: 0123456789.-+*/() 434 | 435 | - Maximum length: 36 436 | 437 | - Interpreter (Extended feature, new in v1.81) 438 | 439 | - Please read MONKEY PROGRAMMING LANGUAGE 440 | 441 | - User-defined function 442 | 443 | - Prefix:: 444 | 445 | sqliteboy_ 446 | 447 | - Can be used in Query or Form or Report 448 | 449 | - Please read USER-DEFINED FUNCTION below 450 | 451 | - Will be added regularly (or by your request) 452 | 453 | - Easy to translate 454 | 455 | - Configurable hosts allowed (default: local) (Extended feature) 456 | 457 | - Database backup (admin) (Extended feature) 458 | 459 | - System configuration (admin) (Extended feature, new in v0.43) 460 | 461 | - Shortcut (form, report) (Extended feature, new in v0.84) 462 | 463 | - Logs (Extended feature, new in v1.61) 464 | 465 | - Human readable database size (GB, MB, KB, B) 466 | 467 | - Load time 468 | 469 | - Custom Template 470 | 471 | - Minimum use of Javascript in default/builtin template 472 | (only for confirmation dialog and toggle select all) 473 | 474 | - Table name limitation: 475 | cannot handle table with whitespace in name 476 | 477 | 478 | Requirements 479 | ======================================================================== 480 | 481 | - python 482 | 483 | - web.py (http://webpy.org) 484 | 485 | - SQLite module (included as sqlite3, in python 2.5+) 486 | 487 | - JSON module (included as json, in python 2.6+) 488 | 489 | - Optional: ReportLab (PDF output) 490 | 491 | - Optional: pyOpenSSL (SSL support) 492 | 493 | 494 | Standalone Version 495 | ======================================================================== 496 | Note: Standalone version is no longer provided 497 | 498 | 499 | Login 500 | ======================================================================== 501 | 502 | - Default admin user and password: admin 503 | 504 | - As of v1.63, additional/custom links at login page are supported. Links 505 | may be placed at multiple page sections (please read LINK CODE REFERENCE 506 | and TITLE REFERENCE). 507 | 508 | - As of v1.66, it is possible to define redirect URL after logged in, 509 | using to= parameter. However, only valid URL is allowed, according 510 | to WEBSITE AND CUSTOM URL REFERENCE. 511 | 512 | - As of v1.69, logout uses redirect URL set in login 513 | 514 | 515 | SSL Support 516 | ======================================================================== 517 | To enable SSL support, please put the following files into current 518 | working directory: 519 | 520 | - sqliteboy.cert (SSL certificate) 521 | - sqliteboy.key (SSL private key) 522 | 523 | If you need to create a self-signed test certificate, 524 | OpenSSL can be used:: 525 | 526 | openssl req -new -x509 -newkey rsa:1024 -keyout sqliteboy.key -out sqliteboy.cert -days 365 -nodes 527 | 528 | 529 | How To Run 530 | ======================================================================== 531 | Command:: 532 | 533 | python sqliteboy.py [port] 534 | 535 | (if you are using source code) 536 | 537 | or 538 | 539 | python sqliteboy.py [port] > LOGFILE 2>&1 & 540 | 541 | (if you are using source code, sh compatible shell (with job control), 542 | and want to run in the background. If applicable, You could use 543 | /dev/null as LOGFILE if you don't care about the logs.) 544 | 545 | then, using web browser, visit localhost:11738, or localhost:PORT, if 546 | PORT is specified 547 | 548 | Please use https if SSL support is enabled 549 | 550 | (Please also read SERVER COMMAND REFERENCE) 551 | 552 | As of v1.62, it is possible to run multiple SQLiteBoy instances 553 | (single host, different ports / databases), as the HTTP cookie name is 554 | set based on database path. 555 | 556 | As of v1.75, it is possible to run as WSGI application: 557 | 558 | - Please make sure that an SQLite database named data.db exists in 559 | current working directory (or, it can be an empty file) 560 | - If 'application' is expected:: 561 | 562 | from sqliteboy import wsgi_application as application 563 | 564 | As of v1.76, disk-based session is supported. If a readable/writable directory 565 | named sqliteboy-session is found in current working directory, disk-based 566 | session will be used. Otherwise, default memory-based session will be used. 567 | 568 | 569 | Custom Template 570 | ======================================================================== 571 | 572 | - sqliteboy.html, if found in current working directory 573 | 574 | - For template example: T_BASE variable 575 | 576 | - Please do not put '$def with (data, content)' line in template 577 | 578 | 579 | Website and Custom URL Reference 580 | ======================================================================== 581 | 582 | - To manage a website, please visit /admin/website (as admin), or visit 583 | info -> website 584 | 585 | - Custom URLs, as long as the URLs are not used by SQLiteBoy (reserved). 586 | List of reserved URLs is shown in website management screen. 587 | 588 | - URL can be handled by a python function, redirect, Files, template, or HTML 589 | 590 | - Each URL is specified by: 591 | 592 | - id: must be alphabetic only (maximum length: 36), converted to 593 | lowercase on save. This id is used in python handler. 594 | 595 | - url: must be alphanumeric/underscore/dot/slash/dash (maximum length: 128), 596 | converted to lowercase on save. This is the URL. Please read the 597 | additional rules below. 598 | 599 | - content: content, interpreted. 600 | 601 | - Additional URL rules: 602 | 603 | - Please use / for home page. Without this URL, / will be redirected 604 | to /index (and then /login if the user is not logged in) 605 | 606 | - Please start url with / (but do not end it with /) 607 | 608 | - Only valid values are saved (id and url are checked on save) 609 | 610 | - Content interpretation: 611 | 612 | - If there is a python function named web_ (in sqliteboy_user.py, 613 | please also read PYTHON HANDLER REFERENCE): 614 | 615 | - It will be called and the return value is used as dynamic contents 616 | (with custom HTTP headers) 617 | 618 | - If there is an exception, redirection to /index will be performed. 619 | Please make sure that the python function is valid. 620 | 621 | - If python handler for that URL is NOT available: 622 | 623 | - If the content looks like a number: 624 | 625 | - If the number is a valid file id: 626 | 627 | - Contents of the file will be returned (along with saved headers) 628 | 629 | - To set Content-Disposition as attachment, please set download parameter 630 | (for example: ?download=download or ?download=true) 631 | 632 | - Default Content-Disposition is inline 633 | 634 | - Valid file id: 635 | 636 | - Exists in Files 637 | 638 | - If user is logged in: 639 | 640 | - File sharing status is checked. If a file is not shared 641 | (and logged in user is not the owner), it is considered 642 | invalid. This applies for all users, including admin users. 643 | 644 | - If the number is NOT a valid file id: 645 | 646 | - Content will be returned 647 | 648 | - If it is NOT a number: 649 | 650 | - If the content starts with http:// or https://, redirection is 651 | performed 652 | 653 | - Otherwise, the content is interpreted as HTML with template 654 | 655 | - HTML template interpretation: 656 | 657 | - If there is an exception (or content is HTML), content will be returned as is 658 | 659 | - If this meant to be a template, please start the content with 660 | :: 661 | 662 | $def with (id, url, content, param) 663 | 664 | - The following globals are available to template: 665 | 666 | - Note: most user-defined functions are also available. 667 | Please read USER-DEFINED FUNCTION. 668 | Unavailable functions are marked with: 669 | not available in HTML template interpretation. 670 | 671 | - size: a function, requires no argument, returns database size as string 672 | 673 | - user: a function, requires no argument, returns logged in user name 674 | as string (or an empty string) 675 | 676 | - table_browse: a function, to browse a table 677 | (excluding _sqliteboy_, sqlite_sequence, sqlite_master) 678 | :: 679 | 680 | table_browse(table, what='*', where=None, order=None, group=None, limit=None, offset=None) 681 | 682 | - begin: a function, to begin an HTML document 683 | :: 684 | 685 | begin(title='', style='', lang='en', charset='utf-8') 686 | 687 | - end: a function, to end an HTML document 688 | 689 | - redirect: a function, to redirect to a URL 690 | :: 691 | 692 | redirect(url, title='', after=0, lang='en') 693 | 694 | - redirect_check: a function, to redirect to a URL, 695 | if a condition is false. Otherwise, begin an HTML document. 696 | :: 697 | 698 | redirect_check(check, url, title_redirect='', after=0, 699 | lang='en', title='', style='', charset='utf-8') 700 | 701 | - redirect_user: a function, to redirect to a URL, 702 | if user is not logged in. Otherwise, begin an HTML document. 703 | :: 704 | 705 | redirect_user(url, title_redirect='', after=0, 706 | lang='en', title='', style='', charset='utf-8') 707 | 708 | - Please read web.py template for more information 709 | 710 | - Example (begin, end): 711 | :: 712 | 713 | $def with (id, url, content, param) 714 | $ a = begin(title='Hello') 715 | $ b = end() 716 | $:a 717 | Hello 718 | $:b 719 | 720 | - Example (custom URL:/test, /test?hello=world): 721 | :: 722 | 723 | $def with (id, url, content, param) 724 | 725 | 726 | 727 | 728 | 729 | $ u = user() 730 | $if u: 731 | Hello, $u 732 |
733 | $ data = table_browse('A', order='name') 734 | $if data: 735 | $for d in data: 736 | $d['name'] 737 |
738 | URL: $url 739 |
740 | Hello: $param.get('hello', '') 741 | 742 | 743 | 744 | - Python handler: 745 | 746 | - Required arguments: 747 | 748 | - user: current user (str) 749 | 750 | - db: database connection object (web.py database object) 751 | 752 | - url_id: url id (str) 753 | 754 | - url: url (str) 755 | 756 | - content: content (str) 757 | 758 | - param: parameter (web.input()) 759 | 760 | - data: additional data (helper functions, UDFs, templates, modules, etc) (dict) 761 | 762 | - Function *must* return a list of two members: 763 | 764 | - headers, empty list OR list of [HTTP header name, HTTP header value] 765 | 766 | - content (str) 767 | 768 | - Example (url id: test, url: /test, url: test?hello=world): 769 | :: 770 | 771 | def web_test(user, db, url_id, url, content, param, data): 772 | headers = [ 773 | ['Content-Type', 'text/plain'], 774 | ] 775 | content = 'hello %s' %(param.get('hello', '')) 776 | return [headers, content] 777 | 778 | - POST method: 779 | 780 | - Can only be handled by a python function named post_ (in sqliteboy_user.py, 781 | please also read PYTHON HANDLER REFERENCE) 782 | 783 | - If there is an exception, or handler is not available, an empty string 784 | is returned 785 | 786 | - Example (url id: form, url: /form): 787 | :: 788 | 789 | 790 | 791 | 792 | 793 | 794 |
795 | Hello 796 | 797 |
798 | 799 | 800 | 801 | - POST method handler: 802 | :: 803 | 804 | def post_form(user, db, url_id, url, content, param, data): 805 | headers = [ 806 | ['Content-Type', 'text/plain'], 807 | ] 808 | content = 'POST: hello %s' %(param.get('name', '')) 809 | return [headers, content] 810 | 811 | - Custom not found URL: 812 | 813 | - Can be set at System configuration 814 | 815 | - Only applicable when not logged in 816 | 817 | - Please set to existing custom URL 818 | 819 | - Note: it is probably a good idea to consider/use a reverse proxy 820 | 821 | 822 | User-defined Function 823 | ======================================================================== 824 | 825 | Note: please use SQLite built-in functions whenever and wherever possible. 826 | 827 | - sqliteboy_strs(s) 828 | 829 | - sqliteboy_as_integer(s) 830 | 831 | - sqliteboy_as_float(s) 832 | 833 | - sqliteboy_len(s) 834 | 835 | - sqliteboy_md5(s) 836 | 837 | - sqliteboy_sha1(s) 838 | 839 | - sqliteboy_sha224(s) 840 | 841 | - sqliteboy_sha256(s) 842 | 843 | - sqliteboy_sha384(s) 844 | 845 | - sqliteboy_sha512(s) 846 | 847 | - sqliteboy_b64encode(s) 848 | 849 | - sqliteboy_b64decode(s) 850 | 851 | - sqliteboy_randrange(a, b) 852 | 853 | - sqliteboy_randstr(s, a, b) 854 | :: 855 | 856 | random string 857 | argument : 858 | s (set characters) 859 | a (min length, > 0) 860 | b (max length, > 0, >=a) 861 | 862 | example : 863 | sqliteboy_randstr('abcdef123456', 3, 8) 864 | -> 'e2e6' 865 | 866 | tips : 867 | - fix length: a = b 868 | - use sqliteboy_randstr2() or sqliteboy_randstr3() for predefined 869 | set characters 870 | - use sqliteboy_randstr_simple() for simple random string 871 | 872 | - sqliteboy_randstr2(a, b) 873 | :: 874 | 875 | random string (predefined set characters, letters + digits + punctuation) 876 | argument : 877 | a (min length, > 0) 878 | b (max length, > 0, >=a) 879 | 880 | example : 881 | sqliteboy_randstr2(3, 8) 882 | -> '"Z\@Z' 883 | 884 | - sqliteboy_randstr3(a, b) 885 | :: 886 | 887 | random string (predefined set characters, letters + digits) 888 | argument : 889 | a (min length, > 0) 890 | b (max length, > 0, >=a) 891 | 892 | example : 893 | sqliteboy_randstr3(3, 8) 894 | -> 'nItJ8' 895 | 896 | - sqliteboy_randstr_simple() 897 | :: 898 | 899 | random string (simple) 900 | example : 901 | sqliteboy_randstr_simple() 902 | -> 'VUmDAQeJCpww9IjmiexrWRuRT6ZgpacKVdOA' 903 | 904 | - sqliteboy_is_datetime_format(s, fmt) 905 | :: 906 | 907 | is date time according to format 908 | argument : 909 | s (input string) 910 | fmt (date time format string) 911 | 912 | example : 913 | sqliteboy_is_datetime_format('2014', '%Y') 914 | -> 1 915 | 916 | sqliteboy_is_datetime_format('2014-01-01', '%Y-%m-%d') 917 | -> 1 918 | 919 | sqliteboy_is_datetime_format('2014-01-01', '%Y-%m-%d %H:%M:%S') 920 | -> 0 921 | 922 | sqliteboy_is_datetime_format('2014-01-01 01:02:03', '%Y-%m-%d %H:%M:%S') 923 | -> 1 924 | 925 | tips : 926 | - use sqliteboy_is_datetime(), sqliteboy_is_date() or sqliteboy_is_time() 927 | for predefined date time format 928 | 929 | - sqliteboy_is_datetime(s) 930 | 931 | - sqliteboy_is_date(s) 932 | 933 | - sqliteboy_is_time(s) 934 | 935 | - sqliteboy_time() 936 | 937 | - sqliteboy_time2(s) 938 | :: 939 | 940 | get time from string (YYYY-MM-DD HH:MM:SS) 941 | argument : 942 | s (date/time string) 943 | 944 | example : 945 | sqliteboy_time2('2012-03-28 19:20:21') 946 | -> 1332937221.0 947 | 948 | - sqliteboy_time2_date(s) 949 | :: 950 | 951 | sqliteboy_time2() using YYYY-MM-DD format 952 | 953 | - sqliteboy_time2_format(s, fmt) 954 | :: 955 | 956 | sqliteboy_time2() using custom format 957 | 958 | - sqliteboy_time3(f) 959 | :: 960 | 961 | get string (YYYY-MM-DD HH:MM:SS) from time (local time) 962 | argument : 963 | f (time) 964 | 965 | example : 966 | sqliteboy_time3(1) 967 | -> 1970-01-01 07:00:01 968 | -> timezone is UTC+7 969 | 970 | - sqliteboy_time3a() 971 | :: 972 | 973 | alias for sqliteboy_time3(sqliteboy_time()) 974 | 975 | - sqliteboy_time4(f) 976 | :: 977 | 978 | get string (YYYY-MM-DD HH:MM:SS) from time (UTC) 979 | argument : 980 | f (time) 981 | 982 | example : 983 | sqliteboy_time4(1) 984 | -> 1970-01-01 00:00:01 985 | 986 | - sqliteboy_time4a() 987 | :: 988 | 989 | alias for sqliteboy_time4(sqliteboy_time()) 990 | 991 | - sqliteboy_time5(s1, s2, mode) 992 | :: 993 | 994 | calculate the difference between two dates in seconds, minutes, hours, days, or years 995 | (1 year = 365.2425 days) 996 | argument : 997 | s1 (YYYY-MM-DD HH:MM:SS) 998 | s2 (YYYY-MM-DD HH:MM:SS) 999 | mode (1=seconds, 2=minutes, 3=hours, 4=days, 5=years) 1000 | 1001 | example : 1002 | sqliteboy_time5('2010-11-12 13:14:15', '2011-12-13 14:15:16', 1) 1003 | -> 34218061.0 1004 | 1005 | sqliteboy_time5('2010-11-12 13:14:15', '2011-12-13 14:15:16', 2) 1006 | -> 570301.016667 1007 | 1008 | sqliteboy_time5('2010-11-12 13:14:15', '2011-12-13 14:15:16', 3) 1009 | -> 9505.01694444 1010 | 1011 | sqliteboy_time5('2010-11-12 13:14:15', '2011-12-13 14:15:16', 4) 1012 | -> 396.042372685 1013 | 1014 | sqliteboy_time5('2010-11-12 13:14:15', '2011-12-13 14:15:16', 5) 1015 | -> 1.08432718724 1016 | 1017 | tips : 1018 | empty/invalid s1 or s2: current date/time (localtime) 1019 | use sqliteboy_number_format() to format the result 1020 | 1021 | - sqliteboy_time6(f, year, month, day, mode) 1022 | :: 1023 | 1024 | format the difference between two dates in 1025 | y (years) m (months) d (days) format 1026 | argument : 1027 | f (number, in year, use sqliteboy_time5 function (mode=5) ) 1028 | year (year string) 1029 | month (month string) 1030 | day (day string) 1031 | mode (1=30.44 days/month, 1=30 days/month, 2=31 days/month) 1032 | 1033 | example : 1034 | sqliteboy_time6(sqliteboy_time5('2010-11-12 01:02:03', '2011-12-13 11:12:13', 5), ' years ', ' months ', ' days ', 0) 1035 | -> 1 years 1 months 1 days 1036 | 1037 | sqliteboy_time6(sqliteboy_time5('2010-11-12 01:02:03', '2011-10-11 11:12:13', 5), ' years ', ' months ', ' days ', 0) 1038 | -> 0 years 10 months 29 days 1039 | 1040 | sqliteboy_time6(sqliteboy_time5('2013-01-01 10:20:30', '2013-01-02 10:20:30', 5), ' years ', ' months ', ' days ', 0) 1041 | -> 0 years 0 months 1 days 1042 | 1043 | sqliteboy_time6(sqliteboy_time5('2013-01-02 10:20:30', '2013-01-01 10:20:30', 5), ' years ', ' months ', ' days ', 0) 1044 | -> 0 years 0 months -1 days 1045 | 1046 | sqliteboy_time6(1000, ' years ', ' months ', ' days ', 0) 1047 | -> 1000 years 0 months 0 days 1048 | 1049 | sqliteboy_time6(1.5, ' years ', ' months ', ' days ', 0) 1050 | -> 1 years 6 months 0 days 1051 | 1052 | sqliteboy_time6(1.24, ' years ', ' months ', ' days ', 0) 1053 | -> 1 years 2 months 27 days 1054 | 1055 | sqliteboy_time6(1.24, ' years ', ' months ', ' days ', 1) 1056 | -> 1 years 2 months 26 days 1057 | 1058 | sqliteboy_time6(1.24, ' years, ', ' months, ', ' days', 0) 1059 | -> 1 years, 2 months, 27 days 1060 | 1061 | sqliteboy_time6(1.24, ' tahun ', ' bulan ', ' hari ', 0) 1062 | -> 1 tahun 2 bulan 27 hari 1063 | 1064 | - sqliteboy_is_leap(n) 1065 | :: 1066 | 1067 | is leap year 1068 | argument : 1069 | n (year) 1070 | 1071 | return value: 1072 | 1 (leap year) or 0 (not leap year) 1073 | 1074 | - sqliteboy_datetime_format(fmt) 1075 | :: 1076 | 1077 | format date time 1078 | argument : 1079 | fmt (format string) 1080 | 1081 | - sqliteboy_datetime_format_local(fmt) 1082 | :: 1083 | 1084 | format date time (local) 1085 | argument : 1086 | fmt (format string) 1087 | 1088 | - sqliteboy_date() 1089 | :: 1090 | 1091 | get current date in YYYY-MM-DD format 1092 | 1093 | - sqliteboy_date_local() 1094 | :: 1095 | 1096 | get current date (local) in YYYY-MM-DD format 1097 | 1098 | - sqliteboy_date_delta_format(s, fmt, n) 1099 | :: 1100 | 1101 | get date delta (days) from date string, using custom format 1102 | argument : 1103 | s (date string) 1104 | fmt (format string) 1105 | n (days) 1106 | 1107 | - sqliteboy_date_local_delta_format(s, fmt, n) 1108 | :: 1109 | 1110 | get date delta (days) from date string, using custom format 1111 | (local time) 1112 | argument : 1113 | s (date string) 1114 | fmt (format string) 1115 | n (days) 1116 | 1117 | - sqliteboy_date_delta(s, n) 1118 | :: 1119 | 1120 | get date delta (days) from date string (YYYY-MM-DD) 1121 | argument : 1122 | s (date string) 1123 | n (days) 1124 | 1125 | - sqliteboy_date_local_delta(s, n) 1126 | :: 1127 | 1128 | get date delta (days) from date string (YYYY-MM-DD) 1129 | (local time) 1130 | argument : 1131 | s (date string) 1132 | n (days) 1133 | 1134 | - sqliteboy_today_local_delta(n) 1135 | :: 1136 | 1137 | get date delta (days) from current date (YYYY-MM-DD) 1138 | (local time) 1139 | argument : 1140 | n (days) 1141 | 1142 | - sqliteboy_today_local_delta_hour(n) 1143 | :: 1144 | 1145 | get date delta (days) from current date/time (YYYY-MM-DD) 1146 | (local time) 1147 | argument : 1148 | n (hours) 1149 | 1150 | - sqliteboy_lower(s) 1151 | 1152 | - sqliteboy_upper(s) 1153 | 1154 | - sqliteboy_swapcase(s) 1155 | 1156 | - sqliteboy_capitalize(s, what) 1157 | :: 1158 | 1159 | capitalize string 1160 | argument : 1161 | s (input string) 1162 | what (0=first word, 1=all) 1163 | 1164 | example : 1165 | sqliteboy_capitalize('hello world', 0) 1166 | -> 'Hello world' 1167 | 1168 | sqliteboy_capitalize('hello world', 1) 1169 | -> 'Hello World' 1170 | 1171 | - sqliteboy_justify(s, justify, length, padding) 1172 | :: 1173 | 1174 | left, right, center justify string 1175 | argument : 1176 | s (input string) 1177 | justify (0=left, 1=right, 2=center) 1178 | length (length) 1179 | padding (single padding character) 1180 | 1181 | example : 1182 | sqliteboy_justify('hello', 0, 10, 'x') 1183 | -> 'helloxxxxx' 1184 | 1185 | sqliteboy_justify('hello', 1, 10, 'x') 1186 | -> 'xxxxxhello' 1187 | 1188 | sqliteboy_justify('hello', 2, 10, 'x') 1189 | -> 'xxhelloxxx' 1190 | 1191 | sqliteboy_justify(12345, 1, 10, 0) 1192 | -> '0000012345' 1193 | 1194 | - sqliteboy_find(s, sub, position, case) 1195 | :: 1196 | 1197 | find index in s where substring sub is found 1198 | argument : 1199 | s (input string) 1200 | sub (substring) 1201 | position (0=lowest index, 1=highest index) 1202 | case (0=ignore case, 1=case sensitive) 1203 | 1204 | return value: 1205 | -1 (not found) or > -1 (found, starts from 0) 1206 | 1207 | example : 1208 | sqliteboy_find('hello sqliteboy', 'e', 0, 0) 1209 | -> 1 1210 | 1211 | sqliteboy_find('hello sqliteboy', 'e', 1, 0) 1212 | -> 11 1213 | 1214 | sqliteboy_find('hello sqlitEboy', 'e', 1, 0) 1215 | -> 11 1216 | 1217 | sqliteboy_find('hello sqlitEboy', 'e', 1, 1) 1218 | -> 1 1219 | 1220 | - sqliteboy_reverse(s) 1221 | :: 1222 | 1223 | reverse string 1224 | argument : 1225 | s (input string) 1226 | 1227 | example : 1228 | sqliteboy_reverse('hello world') 1229 | -> 'dlrow olleh' 1230 | 1231 | sqliteboy_reverse(12345) 1232 | -> '54321' 1233 | 1234 | - sqliteboy_repeat(s, n) 1235 | :: 1236 | 1237 | repeat s (n times) 1238 | argument : 1239 | s (input string) 1240 | n (n times) 1241 | 1242 | example : 1243 | sqliteboy_repeat('sqliteboy ', 5) 1244 | -> 'sqliteboy sqliteboy sqliteboy sqliteboy sqliteboy' 1245 | 1246 | sqliteboy_repeat(1, 20) 1247 | -> '11111111111111111111' 1248 | 1249 | sqliteboy_repeat('=', 10) 1250 | -> '==========' 1251 | 1252 | - sqliteboy_count(s, sub, case) 1253 | :: 1254 | 1255 | count substring sub in s 1256 | argument : 1257 | s (input string) 1258 | sub (substring) 1259 | case (0=ignore case, 1=case sensitive) 1260 | 1261 | return value: 1262 | 0 (not found) or > 0 (found) 1263 | 1264 | example : 1265 | sqliteboy_count('hello sqliteboy', 'e', 0) 1266 | -> 2 1267 | 1268 | sqliteboy_count('hello hello hello', 'Hello', 0) 1269 | -> 3 1270 | 1271 | sqliteboy_count('hello hello hello', 'Hello', 1) 1272 | -> 0 1273 | 1274 | - sqliteboy_is_valid_email(s) 1275 | :: 1276 | 1277 | return value : 1278 | 1 (valid) or 0 (invalid) 1279 | 1280 | - sqliteboy_match(s1, s2) 1281 | :: 1282 | 1283 | regular expression match 1284 | argument : 1285 | s1 (pattern string) 1286 | s2 (test string) 1287 | 1288 | return value: 1289 | 1 (match) or 0 (not match) 1290 | 1291 | - sqliteboy_is_number(n) 1292 | :: 1293 | 1294 | argument : 1295 | n (number or string to test) 1296 | 1297 | return value: 1298 | 1 (number) or 0 (not number) 1299 | 1300 | - sqliteboy_is_float(n) 1301 | :: 1302 | 1303 | return value: 1304 | 1 (float) or 0 (not float) 1305 | 1306 | - sqliteboy_is_integer(n) 1307 | :: 1308 | 1309 | return value: 1310 | 1 (integer) or 0 (not integer) 1311 | 1312 | - sqliteboy_normalize_separator(s, separator, remove_space, unique) 1313 | :: 1314 | 1315 | argument : 1316 | separator (separator string) 1317 | remove_space (remove space in s, 1 or 0) 1318 | unique (1 or 0) 1319 | 1320 | example : 1321 | sqliteboy_normalize_separator 1322 | (',,,,,1,1,, 2, 3, 4,,,,', ',', 1, 1) 1323 | -> '1,2,3,4' 1324 | 1325 | - sqliteboy_split0(s, separator, index) 1326 | :: 1327 | 1328 | split string s using separator as the delimiter string and 1329 | return index (in list) 1330 | argument : 1331 | s (input string) 1332 | separator (separator string) 1333 | index (index) 1334 | 1335 | return value: 1336 | index (in list) or '' 1337 | 1338 | example : 1339 | sqliteboy_split0('s.q.l.i.t.e.b.o.y', '.', 1) 1340 | -> 'q' 1341 | 1342 | sqliteboy_split0('s.q.l.i.t.e.b.o.y', '', 1) 1343 | -> '' 1344 | 1345 | sqliteboy_split0('s.q.l.i.t.e.b.o.y', '.', -3) 1346 | -> 'b' 1347 | 1348 | sqliteboy_split0('h e l l o', '', 1) 1349 | -> 'e' 1350 | 1351 | tips : 1352 | empty separator: use whitespace 1353 | 1354 | - sqliteboy_chunk(s, n, separator, justify, padding) 1355 | :: 1356 | 1357 | split string into evenly sized chunks 1358 | argument : 1359 | s (string) 1360 | n (length/size) 1361 | separator (separator string) 1362 | justify (0=left, 1=right) 1363 | padding (single padding character) 1364 | 1365 | example : 1366 | select sqliteboy_chunk('123456789', 3, '-', 1, 'x') 1367 | -> '123-456-789' 1368 | 1369 | select sqliteboy_chunk('123456789', 2, '-', 0, 'x') 1370 | -> '12-34-56-78-9x' 1371 | 1372 | select sqliteboy_chunk('123456789', 2, '-', 1, 'x') 1373 | -> 'x1-23-45-67-89' 1374 | 1375 | select sqliteboy_chunk('123456789', 4, ',', 1, '*') 1376 | -> '***1,2345,6789' 1377 | 1378 | - sqliteboy_number_format(n, decimals, decimal_point, thousands_separator) 1379 | :: 1380 | 1381 | format a number (or number as string) with grouped thousands and decimals 1382 | (works with number in scientific notation (e)) 1383 | argument : 1384 | n (number or number as string), use string for very big number 1385 | decimals (number of decimal points) 1386 | decimal_point (separator for the decimal point) 1387 | thousands_separator (thousands separator) 1388 | 1389 | example : 1390 | sqliteboy_number_format(12345, 3, '.', ',') 1391 | -> '12,345' 1392 | 1393 | sqliteboy_number_format(12345, 3, ',', '.') 1394 | -> '12.345' 1395 | 1396 | sqliteboy_number_format(12345.1234, 3, ',', '.') 1397 | -> '12.345,123' 1398 | 1399 | sqliteboy_number_format(12345.1234, 0, ',', '.') 1400 | -> '12.345' 1401 | 1402 | sqliteboy_number_format(12345.1234, 10, ',', '.') 1403 | -> '12.345,1234000000' 1404 | 1405 | sqliteboy_number_format(12345.1234, 2, ',', ' ') 1406 | -> '12 345,12' 1407 | 1408 | sqliteboy_number_format('-12345678912345678912345678912345678912.123', 10, ',', '.') 1409 | -> '-12.345.678.912.345.678.912.345.678.912.345.678.912,1230000000' 1410 | 1411 | - sqliteboy_number_to_words(s, language) 1412 | :: 1413 | 1414 | number to words 1415 | Please read NUMBER TO WORDS REFERENCE section (below) 1416 | 1417 | argument : 1418 | s (number as string) 1419 | language (language code) 1420 | 1421 | return value: 1422 | number to words or '' (error/unsupported) 1423 | 1424 | example : 1425 | language : 'id' 1426 | 1427 | sqliteboy_number_to_words('-0', 'id') 1428 | -> 'nol' 1429 | 1430 | sqliteboy_number_to_words('11', 'id') 1431 | -> 'sebelas' 1432 | 1433 | sqliteboy_number_to_words('1000', 'id') 1434 | -> 'seribu' 1435 | 1436 | sqliteboy_number_to_words('1000000', 'id') 1437 | -> 'satu juta' 1438 | 1439 | sqliteboy_number_to_words('-123456789123456789123456789.123456789', 'id') 1440 | -> 'min seratus dua puluh tiga triliun empat ratus lima puluh enam milyar tujuh ratus delapan puluh sembilan juta seratus dua puluh tiga ribu empat ratus lima puluh enam triliun tujuh ratus delapan puluh sembilan milyar seratus dua puluh tiga juta empat ratus lima puluh enam ribu tujuh ratus delapan puluh sembilan koma satu dua tiga empat lima enam tujuh delapan sembilan' 1441 | 1442 | language : 'en1' 1443 | 1444 | sqliteboy_number_to_words('-0', 'en1') 1445 | -> 'zero' 1446 | 1447 | sqliteboy_number_to_words('11', 'en1') 1448 | -> 'eleven' 1449 | 1450 | sqliteboy_number_to_words('1000', 'en1') 1451 | -> 'one thousand' 1452 | 1453 | sqliteboy_number_to_words('1000000', 'en1') 1454 | -> 'one million' 1455 | 1456 | sqliteboy_number_to_words('-123456789123456789123456789.123456789', 'en1') 1457 | -> 'minus one hundred twenty-three trillion four hundred fifty-six billion seven hundred eighty-nine million one hundred twenty-three thousand four hundred fifty-six trillion seven hundred eighty-nine billion one hundred twenty-three million four hundred fifty-six thousand seven hundred eighty-nine point one two three four five six seven eight nine' 1458 | 1459 | - sqliteboy_lookup1(table, field, field1, value1, function, distinct) 1460 | :: 1461 | 1462 | (not available in HTML template interpretation) 1463 | 1464 | SELECT () FROM WHERE = 1465 | and 1466 | return function result 1467 | argument : 1468 | table (table name) 1469 | field (field name) 1470 | field1 (where field) 1471 | value1 (where field value) 1472 | function (avg, count, group_concat, max, min, sum, total) 1473 | distinct (0=non distinct, 1=distinct) 1474 | 1475 | return value: 1476 | function result (as str) or '' (error) 1477 | 1478 | example : 1479 | data in 'lookup' table: 1480 | | a | b | 1481 | --------- 1482 | |a | 0 | 1483 | |a | 1 | 1484 | |a1 | 2 | 1485 | |a2 | 3 | 1486 | 1487 | sqliteboy_lookup1('lookup', 'b', 'a', 'a', 'avg', 0) 1488 | -> '0.5' 1489 | 1490 | sqliteboy_lookup1('lookup', 'a', 'a', 'a', 'count', 0) 1491 | -> '2' 1492 | 1493 | sqliteboy_lookup1('lookup', 'a', 'a', 'a', 'count', 1) 1494 | -> '1' 1495 | 1496 | sqliteboy_lookup1('lookup', 'a', 'a', 'a', 'group_concat', 0) 1497 | -> 'a,a' 1498 | 1499 | sqliteboy_lookup1('lookup', 'b', 'a', 'a', 'max', 0) 1500 | -> '1' 1501 | 1502 | sqliteboy_lookup1('lookup', 'b', 'a', 'a', 'min', 0) 1503 | -> '0' 1504 | 1505 | sqliteboy_lookup1('lookup', 'b', 'a', 'a', 'sum', 0) 1506 | -> '1' 1507 | 1508 | sqliteboy_lookup1('lookup', 'b', 'a', 'a2', 'total', 0) 1509 | -> '3.0' 1510 | 1511 | - sqliteboy_lookup2(table, field, field1, value1, order, default) 1512 | :: 1513 | 1514 | (not available in HTML template interpretation) 1515 | 1516 | lookup into table 1517 | SELECT FROM
WHERE = ORDER BY rowid asc 1518 | or 1519 | SELECT FROM
WHERE = ORDER BY rowid desc 1520 | and 1521 | return first row 1522 | argument : 1523 | table (table name) 1524 | field (field name) 1525 | field1 (where field) 1526 | value1 (where field value) 1527 | order (0=asc, 1=desc) 1528 | default (default return value) 1529 | 1530 | example : 1531 | data in 'lookup' table: 1532 | | a | b | c | 1533 | ------------- 1534 | |a1 |b1 |c1 | 1535 | |a2 |b2 |c2 | 1536 | 1537 | sqliteboy_lookup2('lookup', 'c', 'a', 'a1', 0, ':(') 1538 | -> 'c1' 1539 | 1540 | sqliteboy_lookup2('lookup', 'c_notfound', 'a', 'a1', 0, ':(') 1541 | -> ':(' 1542 | 1543 | sqliteboy_lookup2('lookup', 'b', 'a', 'a1', 0, ':(') 1544 | -> 'b1' 1545 | 1546 | sqliteboy_lookup2(12345, 'b', 'a', 'a1', 0, ':(') 1547 | -> ':(' 1548 | 1549 | - sqliteboy_lookup3(table, field, field1, value1, field2, value2, order, default) 1550 | :: 1551 | 1552 | (not available in HTML template interpretation) 1553 | 1554 | lookup into table 1555 | SELECT FROM
WHERE = and = ORDER BY rowid asc 1556 | or 1557 | SELECT FROM
WHERE = and = ORDER BY rowid desc 1558 | and 1559 | return first row 1560 | argument : 1561 | table (table name) 1562 | field (field name) 1563 | field1 (where field1) 1564 | value1 (where field1 value) 1565 | field2 (where field2) 1566 | value2 (where field2 value) 1567 | order (0=asc, 1=desc) 1568 | default (default return value) 1569 | 1570 | example : 1571 | data in 'lookup' table: 1572 | | a | b | c | 1573 | ------------- 1574 | |a1 |b1 |c1 | 1575 | |a2 |b2 |c2 | 1576 | 1577 | sqliteboy_lookup3('lookup', 'c', 'a', 'a1', 'b', 'b1', 0, ':(') 1578 | -> 'c1' 1579 | 1580 | sqliteboy_lookup3('lookup', 'c', 'a', 'a1', 'b', 'b2', 0, ':(') 1581 | -> ':(' 1582 | 1583 | sqliteboy_lookup3(12345, 'c', 'a', 'a1', 'b', 'b1', 0, ':(') 1584 | -> ':(' 1585 | 1586 | - sqliteboy_split1(s, separator, table, column, convert) 1587 | :: 1588 | 1589 | (not available in HTML template interpretation) 1590 | 1591 | split string s using separator as the delimiter string and 1592 | insert into table (column) for each member in list 1593 | argument : 1594 | s (input string) 1595 | separator (separator string) 1596 | table (table to insert) 1597 | column (column in table) 1598 | convert(0=no conversion, 1=convert to column type if applicable (or to string) ) 1599 | 1600 | return value: 1601 | number of row(s) inserted into table, or 0 1602 | 1603 | example : 1604 | sqliteboy_split1('h.e.l.l.o.w.o.r.l.d', '.', 'test_split', 'c', 1) 1605 | -> 10 1606 | 1607 | sqliteboy_split1('hello', '', 'test_split', 'c', 0) 1608 | -> 1 1609 | 1610 | tips : 1611 | empty separator: use whitespace 1612 | 1613 | - sqliteboy_list_datetime1(s, n, interval, table, column, local) 1614 | :: 1615 | 1616 | (not available in HTML template interpretation) 1617 | 1618 | generate list of datetime starting with s (inclusive), 1619 | as much as n, with interval, 1620 | and insert into table (column) for each member in list 1621 | argument : 1622 | s (YYYY-MM-DD HH:MM:SS) 1623 | n (as much as, must be > 0) 1624 | interval (interval in seconds, must not zero) 1625 | table (table to insert) 1626 | column (column in table) 1627 | local (0=UTC, 1=local) 1628 | 1629 | return value: 1630 | number of row(s) inserted into table, or 0 1631 | 1632 | example : 1633 | (local timezone is UTC+7) 1634 | 1635 | sqliteboy_list_datetime1('', 5, 60*60*24, 'test_date', 'a', 1) 1636 | -> 5 1637 | (data in table) 1638 | 2013-06-03 23:13:27 1639 | 2013-06-04 23:13:27 1640 | 2013-06-05 23:13:27 1641 | 2013-06-06 23:13:27 1642 | 2013-06-07 23:13:27 1643 | 1644 | sqliteboy_list_datetime1('', 5, 60*60*24, 'test_date', 'a', 0) 1645 | -> 5 1646 | (data in table) 1647 | 2013-06-03 16:14:09 1648 | 2013-06-04 16:14:09 1649 | 2013-06-05 16:14:09 1650 | 2013-06-06 16:14:09 1651 | 2013-06-07 16:14:09 1652 | 1653 | sqliteboy_list_datetime1('', 5, -60*60*24, 'test_date', 'a', 1) 1654 | -> 5 1655 | (data in table) 1656 | 2013-06-03 23:14:55 1657 | 2013-06-02 23:14:55 1658 | 2013-06-01 23:14:55 1659 | 2013-05-31 23:14:55 1660 | 2013-05-30 23:14:55 1661 | 1662 | sqliteboy_list_datetime1('2013-01-01 00:00:00', 5, 60*60, 'test_date', 'a', 1) 1663 | -> 5 1664 | (data in table) 1665 | 2013-01-01 00:00:00 1666 | 2013-01-01 01:00:00 1667 | 2013-01-01 02:00:00 1668 | 2013-01-01 03:00:00 1669 | 2013-01-01 04:00:00 1670 | 1671 | tips : 1672 | empty s: current date/time (localtime) 1673 | 1674 | - sqliteboy_if(s, a, b) 1675 | :: 1676 | 1677 | (not available in HTML template interpretation) 1678 | 1679 | if s, return a, else return b 1680 | argument : 1681 | s (SQL query, must return column alias named 'if') 1682 | a (return this, if 'if' column considered true) 1683 | b (return this, if 'if' column considered false) 1684 | 1685 | return value: 1686 | a or b, or '' (error) 1687 | 1688 | example : 1689 | sqliteboy_if('select 1 as if' , 'True', 'False') 1690 | -> 'True' 1691 | 1692 | sqliteboy_if('select -1 as if' , 'True', 'False') 1693 | -> 'True' 1694 | 1695 | sqliteboy_if('select 0 as if' , 'True', 'False') 1696 | -> 'False' 1697 | 1698 | sqliteboy_if('select -1 as if' , 1, -1) 1699 | -> 1 1700 | 1701 | sqliteboy_if('select "" as if' , 'True', 'False') 1702 | -> 'False' 1703 | 1704 | sqliteboy_if('select "sqliteboy" as if' , 'True', 'False') 1705 | -> 'True' 1706 | 1707 | sqliteboy_if('select 1' , 'True', 'False') 1708 | -> '' 1709 | 1710 | tips : 1711 | for SQLite built-in command, please use CASE expression 1712 | 1713 | - sqliteboy_http_remote_addr() 1714 | :: 1715 | 1716 | return value : 1717 | http remote address 1718 | 1719 | - sqliteboy_http_remote_addr_ext() 1720 | :: 1721 | 1722 | return value : 1723 | http remote address (read HTTP_X_FORWARDED_FOR) 1724 | 1725 | - sqliteboy_http_user_agent() 1726 | :: 1727 | 1728 | return value : 1729 | http user agent (for example: web browser) 1730 | 1731 | - sqliteboy_app_title() 1732 | :: 1733 | 1734 | return value: 1735 | application title 1736 | 1737 | example : 1738 | sqliteboy_app_title() 1739 | -> 'sqliteboy 1.10' 1740 | 1741 | - sqliteboy_var_set(name, value) 1742 | :: 1743 | 1744 | (not available in HTML template interpretation) 1745 | 1746 | user-defined variable: set 1747 | (max per user apply) 1748 | argument : 1749 | name (variable name, underscore and alphanumeric only, not case-sensitive) 1750 | value (value) 1751 | 1752 | return value: 1753 | 1 (ok) or 0 1754 | 1755 | example : 1756 | sqliteboy_var_set('a', 1000) 1757 | -> 1 1758 | 1759 | sqliteboy_var_set('b', 'hello') 1760 | -> 1 1761 | 1762 | tips : 1763 | to free some space, please use sqliteboy_var_del function below, 1764 | setting to empty string or 0 does not delete the variable 1765 | 1766 | - sqliteboy_var_get(name) 1767 | :: 1768 | 1769 | (not available in HTML template interpretation) 1770 | 1771 | user-defined variable: get 1772 | argument : 1773 | name (variable name, underscore and alphanumeric only, not case-sensitive) 1774 | 1775 | return value: 1776 | value of variable or '' 1777 | 1778 | example : 1779 | sqliteboy_var_get('a') 1780 | -> 1000 1781 | 1782 | sqliteboy_var_get('b') 1783 | -> hello 1784 | 1785 | - sqliteboy_var_del(name) 1786 | :: 1787 | 1788 | (not available in HTML template interpretation) 1789 | 1790 | user-defined variable: delete 1791 | argument : 1792 | name (variable name, underscore and alphanumeric only, not case-sensitive) 1793 | 1794 | return value: 1795 | 1 (ok) or 0 1796 | 1797 | example : 1798 | sqliteboy_var_del('a') 1799 | -> 1 1800 | 1801 | sqliteboy_var_del('b') 1802 | -> 1 1803 | 1804 | - sqliteboy_strip_html(s) 1805 | :: 1806 | 1807 | strip html 1808 | argument : 1809 | s (input string) 1810 | 1811 | example : 1812 | sqliteboy_strip_html('hello') 1813 | -> 'hello' 1814 | 1815 | - sqliteboy_x_user() 1816 | :: 1817 | 1818 | (not available in HTML template interpretation) 1819 | 1820 | return value : 1821 | user name (if extended feature is enabled, or '') 1822 | 1823 | - sqliteboy_x_profile_all(u, field, system) 1824 | :: 1825 | 1826 | (not available in HTML template interpretation) 1827 | 1828 | read user profile (both system and user-defined) 1829 | 1830 | argument : 1831 | u (user) 1832 | field (custom field) 1833 | system (0=user-defined, 1=system) 1834 | 1835 | return value: 1836 | field value (if extended feature is enabled and field is set, 1837 | or '') 1838 | 1839 | - sqliteboy_x_profile(u, field) 1840 | :: 1841 | 1842 | (not available in HTML template interpretation) 1843 | 1844 | read custom field in user-defined profile for user u 1845 | Please read USER-DEFINED PROFILE REFERENCE section (below) 1846 | 1847 | argument : 1848 | u (user) 1849 | field (custom field) 1850 | 1851 | return value: 1852 | field value (if extended feature is enabled and field is set, 1853 | or '') 1854 | 1855 | - sqliteboy_x_profile_system(u, field) 1856 | :: 1857 | 1858 | (not available in HTML template interpretation) 1859 | 1860 | read system profile for user u 1861 | Please read SYSTEM PROFILE REFERENCE section (below) 1862 | 1863 | argument : 1864 | u (user) 1865 | field (field) 1866 | 1867 | return value: 1868 | field value (if extended feature is enabled and field is set, 1869 | or '') 1870 | 1871 | - sqliteboy_x_my(field) 1872 | :: 1873 | 1874 | (not available in HTML template interpretation) 1875 | 1876 | alias for sqliteboy_x_profile(sqliteboy_x_user(), field) 1877 | 1878 | - sqliteboy_x_my_system(field) 1879 | :: 1880 | 1881 | (not available in HTML template interpretation) 1882 | 1883 | alias for sqliteboy_x_profile_system(sqliteboy_x_user(), field) 1884 | 1885 | 1886 | Form Code Reference 1887 | ======================================================================== 1888 | 1889 | - Must be valid JSON syntax (json.org) 1890 | 1891 | - String (including keys below) must be double-quoted 1892 | (between " and ") 1893 | 1894 | - No trailling comma in dict or list 1895 | 1896 | - Python dict (keys are case-sensitive) 1897 | 1898 | - Only single table is supported. If you need to write to another 1899 | table after form data is saved, you can use additional SQL query 1900 | statement(s) (see below). 1901 | 1902 | - Onsave event can be used to execute SQL Query (and use the result) 1903 | just before the data is saved. The SQL Query can be very complex and 1904 | involves nested function calls. 1905 | 1906 | - Very simple subform is also supported. Subform can be used in one to 1907 | many relationship. However, fields in subform is limited, compared to 1908 | form (only reference and default are supported; all is required; 1909 | none is readonly; column(s) can be selected). When saving data, 1910 | transaction is used. 1911 | 1912 | - Custom result message (based on SQL query result), is also supported. 1913 | 1914 | - Extended result message is supported, as an alternative to custom result 1915 | message. Using extended result, it is possible to perform operations on 1916 | form fields, and use the result. Like custom result message, it is based 1917 | on SQL query result. But unlike custom result message, the result is 1918 | not limited to integer (can be string or another types; probably returned 1919 | from function call). 1920 | 1921 | - Optional, additional SQL query statement(s) can be provided, and each 1922 | of them will be executed in order, if you need to perform additional 1923 | task(s), after the form data is saved (for example, write to another 1924 | table). Previously, one might use report if need to write to several 1925 | tables. Last insert rowid value is provided. 1926 | 1927 | - Insert into table can be disabled by setting insert key to zero/negative 1928 | value. This is useful if you need to update/delete data in table(s), using 1929 | additional SQL query statement(s). By default, form/subform save will 1930 | insert new row(s) into table(s). Please note that setting insert key 1931 | to zero/negative value will also set last insert rowid/query result 1932 | to same value as insert value. 1933 | 1934 | - Please also read PYTHON HANDLER REFERENCE section 1935 | 1936 | - Keys: 1937 | 1938 | +---------------+-------------------------+---------------+-------------+--------------------------+ 1939 | | Key | Description | Type | Status | Example | 1940 | +===============+=========================+===============+=============+==========================+ 1941 | | data | form data | list of dict | required | see: Keys (data) | 1942 | +---------------+-------------------------+---------------+-------------+--------------------------+ 1943 | | security | form security | dict | required | see: Keys (security) | 1944 | +---------------+-------------------------+---------------+-------------+--------------------------+ 1945 | | title | form title | str | optional | "My Form" | 1946 | +---------------+-------------------------+---------------+-------------+--------------------------+ 1947 | | info | form information | str | optional | "Form Information" | 1948 | | | | | | | 1949 | | | (html is allowed) | | | | 1950 | +---------------+-------------------------+---------------+-------------+--------------------------+ 1951 | | sub | subform | list | optional | | 1952 | | | | | | | 1953 | | | - must be list of five | | | - ["table2", "a", [5,3], | 1954 | | | members: related | | | [["b", "Column B", | 1955 | | | table (str); related | | | [ ["0", "NO"], | 1956 | | | column in that table | | | ["1", "YES"] ], "1"], | 1957 | | | (str); list of [rows | | | ["c", "Column C", | 1958 | | | (int), required rows | | | "select a, b from | 1959 | | | (int)]; list of | | | table1", ""]], | 1960 | | | list (column) [column | | | "My Subform"] | 1961 | | | (str), label (str), | | | | 1962 | | | reference, default]; | | | | 1963 | | | subform information | | | | 1964 | | | (str) | | | | 1965 | | | | | | | 1966 | | | - see Keys (data) below | | | | 1967 | | | for reference/default | | | | 1968 | | | | | | | 1969 | | | - return value of | | | | 1970 | | | last_insert_rowid() | | | | 1971 | | | will be written to | | | | 1972 | | | related column (each | | | | 1973 | | | row). Use ROWID column| | | | 1974 | | | in master table to get| | | | 1975 | | | the relation. | | | | 1976 | | | | | | | 1977 | | | | | | | 1978 | +---------------+-------------------------+---------------+-------------+--------------------------+ 1979 | | message | custom result message | list | optional | | 1980 | | | | | | | 1981 | | | | | | - [ | 1982 | | | - not applicable to | | | "unknown result", | 1983 | | | subform | | | "zero result", | 1984 | | | | | | "success: $result" | 1985 | | | - must be list of three | | | ] | 1986 | | | members (str) | | | | 1987 | | | | | | | 1988 | | | ["message res < 0", | | | | 1989 | | | "message res = 0", | | | | 1990 | | | "message res > 0"] | | | | 1991 | | | | | | | 1992 | | | - $result (in message) | | | | 1993 | | | will be replaced by | | | | 1994 | | | actual SQL Query | | | | 1995 | | | result | | | | 1996 | | | | | | | 1997 | | | - $ will be | | | | 1998 | | | replaced by user input| | | | 1999 | | | value for that column | | | | 2000 | | | | | | | 2001 | | | - $last_insert_rowid | | | | 2002 | | | will be replaced by | | | | 2003 | | | last_insert_rowid() | | | | 2004 | | | function call result | | | | 2005 | | | (after insert to main | | | | 2006 | | | table) | | | | 2007 | | | | | | | 2008 | | | - $python_handler | | | | 2009 | | | will be replaced by | | | | 2010 | | | return value of python| | | | 2011 | | | handler (if provided, | | | | 2012 | | | default: -1) | | | | 2013 | | | | | | | 2014 | | | | | | | 2015 | | | (html is allowed) | | | | 2016 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2017 | | result | extended result message | list | optional | | 2018 | | | | | | | 2019 | | | | | | [ | 2020 | | | - not applicable to | | | "$a + $b = $result", | 2021 | | | subform | | | "select $a+$b as result"| 2022 | | | | | | ] | 2023 | | | - must be list of two | | | | 2024 | | | members (str) | | | (Example 3) | 2025 | | | | | | | 2026 | | | ["template", | | | | 2027 | | | "sql query"] | | | | 2028 | | | | | | | 2029 | | | - $result (in template) | | | | 2030 | | | will be replaced by | | | | 2031 | | | actual SQL Query | | | | 2032 | | | result | | | | 2033 | | | | | | | 2034 | | | - $ will be | | | | 2035 | | | replaced by user input| | | | 2036 | | | value for that column | | | | 2037 | | | | | | | 2038 | | | - $last_insert_rowid | | | | 2039 | | | will be replaced by | | | | 2040 | | | last_insert_rowid() | | | | 2041 | | | function call result | | | | 2042 | | | (after insert to main | | | | 2043 | | | table) | | | | 2044 | | | | | | | 2045 | | | - $python_handler | | | | 2046 | | | will be replaced by | | | | 2047 | | | return value of python| | | | 2048 | | | handler (if provided, | | | | 2049 | | | default: -1) | | | | 2050 | | | | | | | 2051 | | | | | | | 2052 | | | (html is allowed) | | | | 2053 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2054 | | sql0 | additional sql query | list | optional | | 2055 | | | statement(s) | | | | 2056 | | | | | | | 2057 | | | (run before) | | | | 2058 | | | | | | | 2059 | | | (please see sql2) | | | | 2060 | | | | | | | 2061 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2062 | | sql2 | additional sql query | list | optional | | 2063 | | | statement(s) | | | | 2064 | | | | | | | 2065 | | | (run after) | | | | 2066 | | | | | | - ["insert into table3( | 2067 | | | - must be list of str | | | a, b, c, d, e) values( | 2068 | | | | | | $a, $b, $c, $d, $e)", | 2069 | | | - $ will be | | | "insert into table4(x) | 2070 | | | replaced by user input| | | values( | 2071 | | | value for that column | | | $last_insert_rowid)"] | 2072 | | | | | | | 2073 | | | - $last_insert_rowid | | | | 2074 | | | will be replaced by | | | | 2075 | | | last_insert_rowid() | | | | 2076 | | | function call result | | | | 2077 | | | (after insert to main | | | | 2078 | | | table) | | | | 2079 | | | (sql2 only) | | | | 2080 | | | | | | | 2081 | | | - quoting is | | | | 2082 | | | automatically done | | | | 2083 | | | | | | | 2084 | | | - each statement is | | | | 2085 | | | executed in | | | | 2086 | | | transaction | | | | 2087 | | | | | | | 2088 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2089 | | insert | prevent insert new | int | optional | | 2090 | | | row(s) into table(s) | | | | 2091 | | | on form/subform save, | | | | 2092 | | | if zero/negative value | | | | 2093 | | | is given | | | | 2094 | | | | | | | 2095 | | | (noted above) | | | | 2096 | | | | | | | 2097 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2098 | | confirm | confirmation message | str | optional | | 2099 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2100 | | focus | autofocus column | str | optional | | 2101 | | | | | | | 2102 | | | (please see "column" | | | | 2103 | | | key in data) | | | | 2104 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2105 | | link | links | list of list | optional | [["http://sqliteboy.com",| 2106 | | | | of two members| | "sqliteboy"]] | 2107 | | | | | | | 2108 | | | | [target,label]| | | 2109 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2110 | 2111 | - Keys (data): 2112 | 2113 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2114 | | Key | Description | Type | Status | Example | 2115 | +===============+=========================+===============+=============+==========================+ 2116 | | table | table name; | str | required | "table1" | 2117 | | | only single table is | | | | 2118 | | | supported, and first | | | | 2119 | | | table found will be | | | | 2120 | | | used, other table(s) | | | | 2121 | | | will be ignored | | | | 2122 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2123 | | column | column | str | required | "col1" | 2124 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2125 | | label | label | str | optional | "column 1" | 2126 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2127 | | required | is required; | int | optional | 1 | 2128 | | | (0 = not required, | | | | 2129 | | | 1 = required) | | | | 2130 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2131 | | readonly | is readonly; | int | optional | 0 | 2132 | | | (0 = not readonly, | | | | 2133 | | | 1 = readonly) | | | | 2134 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2135 | | reference | predefined value(s) | str, list or | optional | | 2136 | | | | int | | | 2137 | | | - str: SQL query; | | | - "select col1 as a, | 2138 | | | returns 2 columns: | | | col2 as b from table1" | 2139 | | | a and b; HTML select | | | | 2140 | | | | | | | 2141 | | | - list: static value(s);| | | - [ ["0", "NO"], | 2142 | | | contains list(s), | | | ["1", "YES"] ] | 2143 | | | which contains | | | | 2144 | | | two members; | | | | 2145 | | | HTML select | | | | 2146 | | | | | | | 2147 | | | - int: flag | | | - 2 | 2148 | | | (2: HTML input | | | | 2149 | | | password) | | | | 2150 | | | | | | | 2151 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2152 | | default | default value | str, list or | optional | | 2153 | | | | int | | | 2154 | | | - str, int: use as is | | | | 2155 | | | | | | | 2156 | | | - list: SQL function | | | - ["sqliteboy_md5", | 2157 | | | call; at least one | | | "hello"] | 2158 | | | member; first member | | | | 2159 | | | must be str (function | | | - ["sqlite_version"] | 2160 | | | name); return value | | | | 2161 | | | will be used as | | | | 2162 | | | default; | | | | 2163 | | | | | | | 2164 | | | format: | | | | 2165 | | | [function_name, arg1, | | | | 2166 | | | ...] | | | | 2167 | | | | | | | 2168 | | | do not put () in | | | | 2169 | | | function_name | | | | 2170 | | | | | | | 2171 | | | - list (SQL query): | | | | 2172 | | | must be list of two | | | | 2173 | | | str members; first | | | | 2174 | | | member: empty string; | | | | 2175 | | | second member: SQL | | | | 2176 | | | query (must return | | | | 2177 | | | one column: a) | | | | 2178 | | | | | | | 2179 | | | | | | | 2180 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2181 | | constraint | check before save | list | optional | | 2182 | | | | | | | 2183 | | | - must be list of four | | | - ["", 0, "> 10", | 2184 | | | members | | | "must be larger than | 2185 | | | | | | 10"]; | 2186 | | | ["function_name", | | | check if column value | 2187 | | | as_str, | | | is > 10 | 2188 | | | "condition", | | | | 2189 | | | "error_message"] | | | - ["sqliteboy_len", 1, | 2190 | | | | | | "> 10", ""]; | 2191 | | | function_name | | | check if sqliteboy_len | 2192 | | | might be empty; | | | (column value) is > 10 | 2193 | | | as_str must be 1 | | | | 2194 | | | (treat function call | | | | 2195 | | | argument as string) | | | | 2196 | | | or 0; | | | | 2197 | | | condition must not | | | | 2198 | | | empty; | | | | 2199 | | | condition must | | | | 2200 | | | contain boolean | | | | 2201 | | | comparison; | | | | 2202 | | | error_message might | | | | 2203 | | | be empty; | | | | 2204 | | | | | | | 2205 | | | - if function_name is | | | | 2206 | | | not empty, | | | | 2207 | | | function_name will be | | | | 2208 | | | called with column | | | | 2209 | | | value as an argument; | | | | 2210 | | | function result will | | | | 2211 | | | be compared with | | | | 2212 | | | condition | | | | 2213 | | | | | | | 2214 | | | - if function_name is | | | | 2215 | | | empty, | | | | 2216 | | | column value will | | | | 2217 | | | be compared with | | | | 2218 | | | condition | | | | 2219 | | | | | | | 2220 | | | - if comparison result | | | | 2221 | | | is 0 (false), | | | | 2222 | | | form saving will be | | | | 2223 | | | cancelled; | | | | 2224 | | | if error_message is | | | | 2225 | | | specified, | | | | 2226 | | | error_message will be | | | | 2227 | | | displayed; | | | | 2228 | | | else, | | | | 2229 | | | generic error message | | | | 2230 | | | with column name, | | | | 2231 | | | function_name (if any)| | | | 2232 | | | and condition | | | | 2233 | | | will be displayed | | | | 2234 | | | | | | | 2235 | | | | | | | 2236 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2237 | | onsave | execute sql query just | str | optional | | 2238 | | | before the data is saved| | | | 2239 | | | | | | - "select $value || | 2240 | | | - sql query can be very | | | ' : ' || | 2241 | | | complex and involves | | | sqliteboy_upper( | 2242 | | | nested function calls | | | sqliteboy_md5($value) | 2243 | | | | | | ) as onsave" | 2244 | | | - sql query must return | | | | 2245 | | | one column: onsave | | | - In example above, md5 | 2246 | | | | | | hash of user input | 2247 | | | - quoting is | | | will be calculated | 2248 | | | automatically done | | | using sqliteboy_md5. | 2249 | | | | | | Then the result will | 2250 | | | - $value will replaced | | | be uppercased using | 2251 | | | with user input value | | | sqliteboy_upper. Then | 2252 | | | | | | the result will be | 2253 | | | - the returned value | | | concatenated with | 2254 | | | will be saved to | | | another string (final).| 2255 | | | table (not the | | | | 2256 | | | user input value) | | | - Example (input=hello): | 2257 | | | | | | hello : 5D41402ABC4B2A7| 2258 | | | | | | 6B9719D911017C592 | 2259 | | | | | | | 2260 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2261 | 2262 | - Keys (security): 2263 | 2264 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2265 | | Key | Description | Type | Status | Example | 2266 | +===============+=========================+===============+=============+==========================+ 2267 | | run | can run form; | "" or list | required | | 2268 | | | admin(s): always can run| | | | 2269 | | | form | | | | 2270 | | | | | | | 2271 | | | - "": all users can | | | | 2272 | | | run this form | | | | 2273 | | | | | | | 2274 | | | - list: only users in | | | - [] | 2275 | | | this list can run | | | | 2276 | | | this form | | | - ["user1", "user2"] | 2277 | | | | | | | 2278 | | | | | | | 2279 | | | | | | | 2280 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2281 | 2282 | - note: 2283 | 2284 | - if you are using primary key column in form data, 2285 | '*' character will be added to column label 2286 | 2287 | - tips: use sqliteboy_as_integer function in constraint 2288 | to do integer conversion/comparison 2289 | 2290 | - Example 1: 2291 | :: 2292 | 2293 | { 2294 | "title" : "My Form (Simple)", 2295 | "info" : "Form Information", 2296 | "data" : [ 2297 | { 2298 | "table" : "table1", 2299 | "column" : "a" 2300 | }, 2301 | { 2302 | "table" : "table1", 2303 | "column" : "d" 2304 | }, 2305 | { 2306 | "table" : "table1", 2307 | "column" : "f" 2308 | } 2309 | ], 2310 | "security" : { 2311 | "run" : "" 2312 | } 2313 | } 2314 | 2315 | - Example 2: 2316 | :: 2317 | 2318 | { 2319 | "title" : "My Form 1", 2320 | "info" : "Form Information", 2321 | "sub" : [ 2322 | "table2", 2323 | "a", 2324 | [5,3], 2325 | [ 2326 | ["b", "Column B", [ ["0", "NO"], ["1", "YES"] ], "1"], 2327 | ["c", "Column C", "select a, b from table1", ""] 2328 | ], 2329 | "My Subform" 2330 | ], 2331 | "sql2" : [ 2332 | "insert into table3(a, b, c, d, e) values($a, $b, $c, $d, $e)", 2333 | "insert into table4(x) values($last_insert_rowid)" 2334 | ], 2335 | "data" : [ 2336 | { 2337 | "table" : "table1", 2338 | "column" : "a", 2339 | "label" : "column a", 2340 | "required" : 1, 2341 | "reference" : [ ["0", "NO"], ["1", "YES"] ], 2342 | "default" : "1" 2343 | }, 2344 | { 2345 | "table" : "table1", 2346 | "column" : "b", 2347 | "reference" : "select sqliteboy_randrange(1, 100000000000) as a, 'hello ' || sqliteboy_time() as b from _sqliteboy_" 2348 | }, 2349 | { 2350 | "table" : "table1", 2351 | "column" : "c", 2352 | "default" : ["sqliteboy_md5", "hello"], 2353 | "constraint": ["sqliteboy_len", 1, "= 32", ""], 2354 | "onsave" : "select sqliteboy_upper($value) as onsave" 2355 | }, 2356 | { 2357 | "table" : "table1", 2358 | "column" : "d", 2359 | "label" : "d (incorrect larger than 100)", 2360 | "required" : 1, 2361 | "constraint": ["", 0, "> 100", "must be larger than 100"] 2362 | }, 2363 | { 2364 | "table" : "table1", 2365 | "column" : "e", 2366 | "label" : "e (correct larger than 100)", 2367 | "required" : 1, 2368 | "constraint": ["sqliteboy_as_integer", 1, "> 100", "must be larger than 100"] 2369 | }, 2370 | { 2371 | "table" : "table1", 2372 | "column" : "f" 2373 | } 2374 | ], 2375 | "focus" : "d", 2376 | "link" : [["http://sqliteboy.com","sqliteboy"]], 2377 | "message" : ["unknown result", "zero result", "success: $result"], 2378 | "security" : { 2379 | "run" : "" 2380 | } 2381 | } 2382 | 2383 | - Example 3: 2384 | :: 2385 | 2386 | { 2387 | "title" : "Addition", 2388 | "data" : [ 2389 | { 2390 | "table" : "table1", 2391 | "column" : "a" 2392 | }, 2393 | { 2394 | "table" : "table1", 2395 | "column" : "b" 2396 | } 2397 | ], 2398 | "insert" : 0, 2399 | "result" : ["$a + $b = $result", "select $a+$b as result"], 2400 | "security" : { 2401 | "run" : "" 2402 | } 2403 | } 2404 | 2405 | 2406 | Report Code Reference 2407 | ======================================================================== 2408 | 2409 | - Must be valid JSON syntax (json.org) 2410 | 2411 | - String (including keys below) must be double-quoted 2412 | (between " and ") 2413 | 2414 | - No trailling comma in dict or list 2415 | 2416 | - Python dict (keys are case-sensitive) 2417 | 2418 | - All key (HTML input) in data is required. See Keys (data) below. 2419 | 2420 | - Report also can be used as form/data entry, using insert SQL query. 2421 | Custom result message (based on SQL query result), is also supported. 2422 | Using free form SQL query, data entry can work with multiple table. 2423 | 2424 | - Headers and footers are supported. If not defined, a default one will be 2425 | created. Plain text, SQL Query, and Image are supported. Headers and 2426 | footers are rendered as tables (multiple rows/columns; one table for 2427 | headers, one table for footers). If there is difference in number of 2428 | columns for each row, largest one will be used. 2429 | 2430 | - Default headers: 2431 | 2432 | - First row: first column (report title), second column (report info) 2433 | 2434 | - Next row(s): first column (search key), second column (user input) 2435 | 2436 | - Default footers (SELECT SQL): 2437 | 2438 | - First row: first column (number of rows), second column ("row(s)"/translated) 2439 | 2440 | - Default footers (NON-SELECT SQL): 2441 | 2442 | - First row: first column (message or ""), second column ("") 2443 | 2444 | - Printer friendly version of report result is supported in default 2445 | output format (HTML) 2446 | 2447 | - Keys: 2448 | 2449 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2450 | | Key | Description | Type | Status | Example | 2451 | +===============+=========================+===============+=============+==========================+ 2452 | | data | wizard/search data | list of dict | required | see: Keys (data) | 2453 | | | | | (might be | | 2454 | | | | | empty list) | | 2455 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2456 | | security | reporting security | dict | required | see: Keys (security) | 2457 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2458 | | sql | free form sql query; | str | required | "select a.a as | 2459 | | | please note that any | | | 'column a of table1', | 2460 | | | placeholder must have | | | a.e from table1 | 2461 | | | relation with key in | | | a where a.a = | 2462 | | | data (see Keys (data)) | | | $input_a_a and | 2463 | | | | | | a.e > $a_e" | 2464 | | | | | | | 2465 | | | | | | For that example, | 2466 | | | | | | you must define | 2467 | | | | | | "input_a_a" | 2468 | | | | | | and "a_e" | 2469 | | | | | | key in data | 2470 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2471 | | title | report title | str | optional | "My Report" | 2472 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2473 | | info | report information | str | optional | "Report Information" | 2474 | | | | | | | 2475 | | | (html is allowed) | | | | 2476 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2477 | | header | header order; | list | optional | | 2478 | | | header order for query | | | | 2479 | | | result | | | - [ | 2480 | | | | | | "column a of table1", | 2481 | | | - if not specified, | | | "e" | 2482 | | | header order is | | | ] | 2483 | | | unpredictable, | | | | 2484 | | | because each row of | | | | 2485 | | | query result is | | | | 2486 | | | python dict and | | | | 2487 | | | default header order | | | | 2488 | | | will be read from | | | | 2489 | | | first row | | | | 2490 | | | | | | | 2491 | | | | | | | 2492 | | | | | | | 2493 | | | | | | | 2494 | | | | | | | 2495 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2496 | | align | text align | list | optional | | 2497 | | | | | | | 2498 | | | (please see header; | | | - [1, 2] | 2499 | | | only applicable if | | | | 2500 | | | header is set) | | | | 2501 | | | | | | | 2502 | | | - HTML and PDF only | | | | 2503 | | | | | | | 2504 | | | - must be list of int | | | | 2505 | | | | | | | 2506 | | | - 0: left | | | | 2507 | | | | | | | 2508 | | | - 1: center | | | | 2509 | | | | | | | 2510 | | | - 2: right | | | | 2511 | | | | | | | 2512 | | | - 3: justify | | | | 2513 | | | | | | | 2514 | | | | | | | 2515 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2516 | | message | custom result message; | list | optional | | 2517 | | | only for SQL query that | | | | 2518 | | | returns integer (insert,| | | - [ | 2519 | | | update, etc). Useful for| | | "unknown result", | 2520 | | | data entry function. | | | "zero result", | 2521 | | | | | | "success: $result" | 2522 | | | - must be list of three | | | ] | 2523 | | | members (str) | | | | 2524 | | | | | | | 2525 | | | ["message res < 0", | | | | 2526 | | | "message res = 0", | | | | 2527 | | | "message res > 0"] | | | | 2528 | | | | | | | 2529 | | | - $result (in message) | | | | 2530 | | | will be replaced by | | | | 2531 | | | actual SQL Query | | | | 2532 | | | result | | | | 2533 | | | | | | | 2534 | | | - $ will be | | | | 2535 | | | replaced by user input| | | | 2536 | | | value for that column | | | | 2537 | | | | | | | 2538 | | | | | | | 2539 | | | | | | | 2540 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2541 | | headers | custom headers | list of list | optional | | 2542 | | | | of list | | | 2543 | | | - must be list of list | | | (please see Example 2 | 2544 | | | (rows) of list | | | below) | 2545 | | | (columns) of three | | | | 2546 | | | members (each cell) | | | | 2547 | | | (str, str/int, dict) | | | | 2548 | | | | | | | 2549 | | | - cell: [type, value, | | | | 2550 | | | attr] | | | | 2551 | | | | | | | 2552 | | | - type: "" (plain text),| | | | 2553 | | | "sql" (sql query), | | | | 2554 | | | "files.image" (file | | | | 2555 | | | number in user files) | | | | 2556 | | | | | | | 2557 | | | - value: any valid value| | | | 2558 | | | for type (str is valid| | | | 2559 | | | for types above) | | | | 2560 | | | | | | | 2561 | | | - attr: {} | | | | 2562 | | | | | | | 2563 | | | - for "sql" type, | | | | 2564 | | | $result_row_count will| | | | 2565 | | | be replaced by actual | | | | 2566 | | | row count (or -1), | | | | 2567 | | | $result will | | | | 2568 | | | be replaced by sql | | | | 2569 | | | query result (integer/| | | | 2570 | | | non-select, or -1), | | | | 2571 | | | $result_message will | | | | 2572 | | | be replaced by actual | | | | 2573 | | | message (or "", for | | | | 2574 | | | custom result | | | | 2575 | | | message), and each key| | | | 2576 | | | in data will be | | | | 2577 | | | replaced by user input| | | | 2578 | | | value; quoting is | | | | 2579 | | | automatically done; | | | | 2580 | | | sql query must return | | | | 2581 | | | one column: a | | | | 2582 | | | | | | | 2583 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2584 | | footers | custom footers | list of list | optional | | 2585 | | | | of list | | | 2586 | | | (please see headers) | | | | 2587 | | | | | | | 2588 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2589 | | paper | paper size in point | list | optional | | 2590 | | | (1/72 inch) | | | | 2591 | | | (PDF) | | | | 2592 | | | | | | | 2593 | | | - must be list of two | | | | 2594 | | | int/float members | | | | 2595 | | | (width, height) | | | | 2596 | | | | | | | 2597 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2598 | | margins | margins in point | list | optional | | 2599 | | | (1/72 inch) | | | | 2600 | | | (PDF) | | | | 2601 | | | | | | | 2602 | | | - must be list of four | | | | 2603 | | | int/float members | | | | 2604 | | | (left, right, top, | | | | 2605 | | | bottom) | | | | 2606 | | | | | | | 2607 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2608 | | confirm | confirmation message | str | optional | | 2609 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2610 | | focus | autofocus field | str | optional | | 2611 | | | | | | | 2612 | | | (please see "key" key | | | | 2613 | | | in data) | | | | 2614 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2615 | | link | links | list of list | optional | [["http://sqliteboy.com",| 2616 | | | | of two members| | "sqliteboy"]] | 2617 | | | | | | | 2618 | | | | [target,label]| | | 2619 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2620 | 2621 | - Keys (data): 2622 | 2623 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2624 | | Key | Description | Type | Status | Example | 2625 | +===============+=========================+===============+=============+==========================+ 2626 | | key | HTML input name; | str | required | "input_a_a" | 2627 | | | underscore and | | | | 2628 | | | alphanumeric only | | | | 2629 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2630 | | label | label | str | optional | "column a =" | 2631 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2632 | | readonly | is readonly; | int | optional | 0 | 2633 | | | (0 = not readonly, | | | | 2634 | | | 1 = readonly) | | | | 2635 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2636 | | reference | predefined value(s) | str, list or | optional | | 2637 | | | | int | | | 2638 | | | - str: SQL query; | | | - "select col1 as a, | 2639 | | | returns 2 columns: | | | col2 as b from table1" | 2640 | | | a and b; HTML select | | | | 2641 | | | | | | | 2642 | | | - list: static value(s);| | | - [ ["0", "NO"], | 2643 | | | contains list(s), | | | ["1", "YES"] ] | 2644 | | | which contains | | | | 2645 | | | two members; | | | | 2646 | | | HTML select | | | | 2647 | | | | | | | 2648 | | | - int: flag | | | - 2 | 2649 | | | (2: HTML input | | | | 2650 | | | password) | | | | 2651 | | | | | | | 2652 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2653 | | default | default value | str, list or | optional | | 2654 | | | | int | | | 2655 | | | - str, int: use as is | | | | 2656 | | | | | | | 2657 | | | - list: SQL function | | | - ["sqliteboy_md5", | 2658 | | | call; at least one | | | "hello"] | 2659 | | | member; first member | | | | 2660 | | | must be str (function | | | - ["sqlite_version"] | 2661 | | | name); return value | | | | 2662 | | | will be used as | | | | 2663 | | | default; | | | | 2664 | | | | | | | 2665 | | | format: | | | | 2666 | | | [function_name, arg1, | | | | 2667 | | | ...] | | | | 2668 | | | | | | | 2669 | | | do not put () in | | | | 2670 | | | function_name | | | | 2671 | | | | | | | 2672 | | | - list (SQL query): | | | | 2673 | | | must be list of two | | | | 2674 | | | str members; first | | | | 2675 | | | member: empty string; | | | | 2676 | | | second member: SQL | | | | 2677 | | | query (must return | | | | 2678 | | | one column: a) | | | | 2679 | | | | | | | 2680 | | | | | | | 2681 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2682 | | type | type; | str | optional | | 2683 | | | cast input type as | | | | 2684 | | | given type; | | | | 2685 | | | currently, only | | | | 2686 | | | "integer" is supported | | | | 2687 | | | (default: str) | | | | 2688 | | | | | | | 2689 | | | - if integer is | | | | 2690 | | | specified, | | | | 2691 | | | input will be | | | | 2692 | | | converted to | | | | 2693 | | | integer using | | | | 2694 | | | python's int() | | | | 2695 | | | | | | | 2696 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2697 | | constraint | check before reporting | list | optional | | 2698 | | | | | | | 2699 | | | - must be list of four | | | - ["", 0, "> 10", | 2700 | | | members | | | "must be larger than | 2701 | | | | | | 10"]; | 2702 | | | ["function_name", | | | check if column value | 2703 | | | as_str, | | | is > 10 | 2704 | | | "condition", | | | | 2705 | | | "error_message"] | | | - ["sqliteboy_len", 1, | 2706 | | | | | | "> 10", ""]; | 2707 | | | function_name | | | check if sqliteboy_len | 2708 | | | might be empty; | | | (column value) is > 10 | 2709 | | | as_str must be 1 | | | | 2710 | | | (treat function call | | | | 2711 | | | argument as string) | | | | 2712 | | | or 0; | | | | 2713 | | | condition must not | | | | 2714 | | | empty; | | | | 2715 | | | condition must | | | | 2716 | | | contain boolean | | | | 2717 | | | comparison; | | | | 2718 | | | error_message might | | | | 2719 | | | be empty; | | | | 2720 | | | | | | | 2721 | | | - if function_name is | | | | 2722 | | | not empty, | | | | 2723 | | | function_name will be | | | | 2724 | | | called with column | | | | 2725 | | | value as an argument; | | | | 2726 | | | function result will | | | | 2727 | | | be compared with | | | | 2728 | | | condition | | | | 2729 | | | | | | | 2730 | | | - if function_name is | | | | 2731 | | | empty, | | | | 2732 | | | column value will | | | | 2733 | | | be compared with | | | | 2734 | | | condition | | | | 2735 | | | | | | | 2736 | | | - if comparison result | | | | 2737 | | | is 0 (false), | | | | 2738 | | | reporting will be | | | | 2739 | | | cancelled; | | | | 2740 | | | if error_message is | | | | 2741 | | | specified, | | | | 2742 | | | error_message will be | | | | 2743 | | | displayed; | | | | 2744 | | | else, | | | | 2745 | | | generic error message | | | | 2746 | | | with column name, | | | | 2747 | | | function_name (if any)| | | | 2748 | | | and condition | | | | 2749 | | | will be displayed | | | | 2750 | | | | | | | 2751 | | | | | | | 2752 | | | | | | | 2753 | | | | | | | 2754 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2755 | 2756 | - Keys (security): 2757 | 2758 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2759 | | Key | Description | Type | Status | Example | 2760 | +===============+=========================+===============+=============+==========================+ 2761 | | run | can run report; | "" or list | required | | 2762 | | | admin(s): always can run| | | | 2763 | | | report | | | | 2764 | | | | | | | 2765 | | | - "": all users can | | | | 2766 | | | run this report | | | | 2767 | | | | | | | 2768 | | | - list: only users in | | | - [] | 2769 | | | this list can run | | | | 2770 | | | this report | | | - ["user1", "user2"] | 2771 | | | | | | | 2772 | | | | | | | 2773 | | | | | | | 2774 | +---------------+-------------------------+---------------+-------------+--------------------------+ 2775 | 2776 | - note: 2777 | 2778 | - tips: use sqliteboy_as_integer function in constraint 2779 | to do integer conversion/comparison 2780 | 2781 | - Example 1: 2782 | :: 2783 | 2784 | { 2785 | "title" : "My Report", 2786 | "info" : "Report Information", 2787 | "header": ["column a of table1", "e"], 2788 | "sql" : "select a.a as 'column a of table1', a.e from table1 a where a.a = $input_a_a and a.e > $a_e", 2789 | "data" : [ 2790 | { 2791 | "key" : "input_a_a", 2792 | "label" : "column a equals", 2793 | "reference" : [ ["0", "NO"], ["1", "YES"] ], 2794 | "default" : "1" 2795 | }, 2796 | { 2797 | "key" : "a_e", 2798 | "label" : "e (as integer) >", 2799 | "constraint": ["sqliteboy_as_integer", 1, "> 0", "e must be integer"] 2800 | } 2801 | ], 2802 | "security" : { 2803 | "run" : "" 2804 | } 2805 | } 2806 | 2807 | - Example 2: 2808 | :: 2809 | 2810 | { 2811 | "title" : "My Report", 2812 | "info" : "Report Information", 2813 | "header": ["column a of table1", "e"], 2814 | "sql" : "select a.a as 'column a of table1', a.e from table1 a where a.a = $input_a_a and a.e > $a_e", 2815 | "data" : [ 2816 | { 2817 | "key" : "input_a_a", 2818 | "label" : "column a equals", 2819 | "reference" : [ ["0", "NO"], ["1", "YES"] ], 2820 | "default" : "1" 2821 | }, 2822 | { 2823 | "key" : "a_e", 2824 | "label" : "e (as integer) >", 2825 | "constraint": ["sqliteboy_as_integer", 1, "> 0", "e must be integer"] 2826 | } 2827 | ], 2828 | "focus" : "a_e", 2829 | "link" : [["http://sqliteboy.com","sqliteboy"]], 2830 | "headers" : [ 2831 | [ 2832 | ["files.image", "31", {}], 2833 | ["", "My Report", {}] 2834 | ], 2835 | [ 2836 | ["", "Date/Time", {}], 2837 | ["sql", "select sqliteboy_time3(sqliteboy_time()) as a", {}] 2838 | ], 2839 | [ 2840 | ["", "User", {}], 2841 | ["sql", "select sqliteboy_x_user() as a", {}] 2842 | ], 2843 | [ 2844 | ["", "column a equals", {}], 2845 | ["sql", "select $input_a_a as a", {}] 2846 | ], 2847 | [ 2848 | ["", "e (as integer) >", {}], 2849 | ["sql", "select $a_e as a", {}] 2850 | ], 2851 | [ 2852 | ["", "Rows", {}], 2853 | ["sql", "select $result_row_count as a", {}] 2854 | ] 2855 | ], 2856 | "security" : { 2857 | "run" : "" 2858 | } 2859 | } 2860 | 2861 | 2862 | Page Code Reference 2863 | ======================================================================== 2864 | 2865 | - emphasis 2866 | :: 2867 | 2868 | ~text~ -> text 2869 | 2870 | - strong 2871 | :: 2872 | 2873 | *text* -> text 2874 | 2875 | - underline 2876 | :: 2877 | 2878 | _text_ -> text 2879 | 2880 | - link 2881 | :: 2882 | 2883 | [text|url] -> text 2884 | 2885 | - form 2886 | :: 2887 | 2888 | [form:name] -> link to run form (or empty string if the form is not available) 2889 | [FORM:name] -> link to run form, followed by a line break (or empty string if the form is not available) 2890 | 2891 | - report 2892 | :: 2893 | 2894 | [report:name] -> link to run report (or empty string if the report is not available) 2895 | [REPORT:name] -> link to run report, followed by a line break (or empty string if the report is not available) 2896 | 2897 | - horizontal rule 2898 | :: 2899 | 2900 | [-] ->
2901 | 2902 | - Note: HTML tags will be stripped on page save 2903 | 2904 | - Note: rendered in
 tag
2905 | 
2906 | - Note: as of v1.59, page supports form/report
2907 | 
2908 | 
2909 | Number To Words Reference
2910 | ========================================================================
2911 | - Supported languages:
2912 | 
2913 |   - id            : Bahasa Indonesia
2914 |   - en            : English (trillion billion million thousand scheme)
2915 |   - en1           : English (trillion billion million thousand scheme)
2916 | 
2917 | - More languages will be added
2918 | 
2919 | - Please let me know/correct me if there is something wrong in the
2920 |   implementation
2921 | 
2922 | - Currently, highest supported large number name is trillion (short scale)
2923 |   or 10**12 or 1,000,000,000,000. And, number supported is ranged
2924 |   from: -999,999,999,999,999,999,999,999,999.99...
2925 |   (minus 999.999 999 999 999 999 999 999 999 trillion trillion plus digits after decimal point)
2926 |   to:    999,999,999,999,999,999,999,999,999.99...
2927 |   (      999.999 999 999 999 999 999 999 999 trillion trillion plus digits after decimal point)
2928 | 
2929 |   (This is, however, might be different for each language)
2930 | 
2931 | - Digits after the decimal point is limited only by python float
2932 |   (that is, very very long long number), so this is valid and supported number:
2933 |   999999999999999999999999999.999999999999999999999999999999999999999999999999999999
2934 | 
2935 | 
2936 | Script Code Reference
2937 | ========================================================================
2938 | 
2939 | - Script can be used to automate the creation of tables
2940 |   (including addition of columns, for existing table),
2941 |   forms, reports or user-defined profiles
2942 | 
2943 | - Solution can be deployed in form of script, that can be uploaded
2944 |   and run by admin
2945 | 
2946 | - Notes on tables:
2947 | 
2948 |   - Multiple tables support
2949 | 
2950 |   - For each table, script developer must define valid columns
2951 | 
2952 |   - For each column, script developer must define valid name, type and
2953 |     flag
2954 | 
2955 |   - Valid column type: integer, real, char, varchar, text, blob, null
2956 | 
2957 |   - Valid column flag: 0, 1 (primary key), 2 (only for integer:
2958 |     primary key autoincrement)
2959 | 
2960 |   - Multiple primary key support (column flag 1 for multiple columns; do
2961 |     not use both flag 1 and 2 in same table)
2962 | 
2963 |   - Currently, default value is not supported
2964 | 
2965 |   - For existing table, addition of columns is supported
2966 | 
2967 |     - Developer could define columns and only non-existing ones will be added
2968 | 
2969 |     - Existing columns, if defined, will be compared. Error, if there is
2970 |       mismatch between new column type and existing column type.
2971 | 
2972 | - Notes on forms, reports:
2973 | 
2974 |   - Multiple forms, reports support
2975 | 
2976 |   - Error, if there is existing form or report
2977 | 
2978 |   - Please read FORM CODE REFERENCE section (forms) or
2979 |     REPORT CODE REFERENCE section (reports)
2980 | 
2981 | - Only valid value(s) will be read
2982 | 
2983 | - Script cannot be run if there is an error
2984 | 
2985 | - If there is exception while the script is running, any newly created
2986 |   table (if empty) will be explicitly deleted. However, newly added
2987 |   columns could not be deleted (easily).
2988 | 
2989 | - Script is designed to be run only once
2990 | 
2991 | - Must be valid JSON syntax (json.org)
2992 | 
2993 | - Must be put in single file
2994 | 
2995 | - String (including keys below) must be double-quoted
2996 |   (between " and ")
2997 | 
2998 | - No trailling comma in dict or list
2999 | 
3000 | - Python dict (keys are case-sensitive)
3001 | 
3002 | - Keys:
3003 | 
3004 | +---------------+-------------------------+---------------+-------------+--------------------------+
3005 | | Key           | Description             | Type          | Status      | Example                  |
3006 | +===============+=========================+===============+=============+==========================+
3007 | | name          | script name             | str           | required    | "my script 1"            |
3008 | +---------------+-------------------------+---------------+-------------+--------------------------+
3009 | | tables        | tables definition       | list of list  | required    | (please see Examples     |
3010 | |               |                         |               |             | below)                   |
3011 | |               | - must be list of list  |               |             |                          |
3012 | |               |   (table) or []         |               |             |                          |
3013 | |               |                         |               |             |                          |
3014 | |               | - for each table:       |               |             |                          |
3015 | |               |   ["tablename",         |               |             |                          |
3016 | |               |   [column], ...]        |               |             |                          |
3017 | |               |                         |               |             |                          |
3018 | |               | - for each [column]:    |               |             |                          |
3019 | |               |   ["name", "type", flag]|               |             |                          |
3020 | |               |   (please read notes    |               |             |                          |
3021 | |               |   above)                |               |             |                          |
3022 | |               |                         |               |             |                          |
3023 | +---------------+-------------------------+---------------+-------------+--------------------------+
3024 | | forms         | forms definition        | list of list  | required    | (please see Examples     |
3025 | |               |                         |               |             | below)                   |
3026 | |               | - must be list of list  |               |             |                          |
3027 | |               |   (form) or []          |               |             |                          |
3028 | |               |                         |               |             |                          |
3029 | |               | - for each form:        |               |             |                          |
3030 | |               |   ["formname",          |               |             |                          |
3031 | |               |   {formcode}]           |               |             |                          |
3032 | |               |                         |               |             |                          |
3033 | |               | - formcode: valid form  |               |             |                          |
3034 | |               |   code (dict)           |               |             |                          |
3035 | |               |                         |               |             |                          |
3036 | +---------------+-------------------------+---------------+-------------+--------------------------+
3037 | | reports       | reports definition      | list of list  | required    | (please see Examples     |
3038 | |               |                         |               |             | below)                   |
3039 | |               | - must be list of list  |               |             |                          |
3040 | |               |   (report) or []        |               |             |                          |
3041 | |               |                         |               |             |                          |
3042 | |               | - for each report:      |               |             |                          |
3043 | |               |   ["reportname",        |               |             |                          |
3044 | |               |   {reportcode}]         |               |             |                          |
3045 | |               |                         |               |             |                          |
3046 | |               | - reportcode: valid     |               |             |                          |
3047 | |               |   report code (dict)    |               |             |                          |
3048 | |               |                         |               |             |                          |
3049 | +---------------+-------------------------+---------------+-------------+--------------------------+
3050 | | profiles      | user-defined profiles   | list          | optional    | (please see Examples     |
3051 | |               |                         |               |             | below)                   |
3052 | |               |                         |               |             |                          |
3053 | +---------------+-------------------------+---------------+-------------+--------------------------+
3054 | | info          | script information      | str           | optional    | "Script Information"     |
3055 | +---------------+-------------------------+---------------+-------------+--------------------------+
3056 | | author        | author information      | str           | optional    | "(c) Author "     |
3057 | +---------------+-------------------------+---------------+-------------+--------------------------+
3058 | | license       | license information     | str           | optional    | "license"                |
3059 | +---------------+-------------------------+---------------+-------------+--------------------------+
3060 | 
3061 | - Example 1:
3062 | ::
3063 | 
3064 |     {
3065 |         "name": "my script",
3066 |         "info": "Script Information",
3067 |         "author": "(c) Author ",
3068 |         "license": "GPL",
3069 |         "tables": [
3070 |                         [
3071 |                             "new_table",
3072 |                             ["a", "integer", 1],
3073 |                             ["b", "integer", 1],
3074 |                             ["c", "integer", 1],
3075 |                             ["d", "text", 0]
3076 |                         ]
3077 |                     ],
3078 |         "forms": [
3079 |                     ],
3080 |         "reports": [
3081 |                     ]
3082 |     }
3083 | 
3084 | - Example 2:
3085 | ::
3086 | 
3087 |     {
3088 |         "name": "my script 1",
3089 |         "info": "Script Information",
3090 |         "author": "(c) Author ",
3091 |         "license": "GPL",
3092 |         "tables": [
3093 |                         [
3094 |                             "new_table_1",
3095 |                             ["a", "integer", 1],
3096 |                             ["b", "integer", 1],
3097 |                             ["c", "integer", 1],
3098 |                             ["d", "text", 0]
3099 |                         ],
3100 |                         [
3101 |                             "new_table_2",
3102 |                             ["a", "integer", 2],
3103 |                             ["b", "integer", 0],
3104 |                             ["c", "integer", 0],
3105 |                             ["d", "text", 0]
3106 |                         ]
3107 |                     ],
3108 |         "forms": [
3109 |                         [
3110 |                             "new_form_1",
3111 |                             {
3112 |                               "title" : "New Form 1",
3113 |                               "info"  : "Form Information",
3114 |                               "data"  : [
3115 |                                           {
3116 |                                             "table"     : "new_table_1",
3117 |                                             "column"    : "a"
3118 |                                           },
3119 |                                           {
3120 |                                             "table"     : "new_table_1",
3121 |                                             "column"    : "b"
3122 |                                           }
3123 |                                         ],
3124 |                               "security" : {
3125 |                                              "run" : ""
3126 |                                            }
3127 |                             }
3128 |                         ],
3129 |                         [
3130 |                             "new_form_2",
3131 |                             {
3132 |                               "title" : "New Form 2",
3133 |                               "info"  : "Form Information",
3134 |                               "data"  : [
3135 |                                           {
3136 |                                             "table"     : "new_table_2",
3137 |                                             "column"    : "c"
3138 |                                           },
3139 |                                           {
3140 |                                             "table"     : "new_table_2",
3141 |                                             "column"    : "d"
3142 |                                           }
3143 |                                         ],
3144 |                               "security" : {
3145 |                                              "run" : ""
3146 |                                            }
3147 |                             }
3148 |                         ]
3149 |                     ],
3150 |         "reports": [
3151 |                         [
3152 |                             "new_report_1",
3153 |                             {
3154 |                               "title" : "New Report 1",
3155 |                               "info"  : "Report Information",
3156 |                               "header": ["a", "b"],
3157 |                               "sql"   : "select a,b from new_table_1 a where a > $input_a or b > $input_b",
3158 |                               "data"  : [
3159 |                                           {
3160 |                                             "key"       : "input_a",
3161 |                                             "label"     : "column a >",
3162 |                                             "default"   : "0"
3163 |                                           },
3164 |                                           {
3165 |                                             "key"       : "input_b",
3166 |                                             "label"     : "column b >",
3167 |                                             "default"   : "0"
3168 |                                           }
3169 |                                         ],
3170 |                               "security" : {
3171 |                                              "run" : ""
3172 |                                            }
3173 |                             }
3174 |                         ]
3175 |                     ],
3176 |         "profiles": [
3177 |                       [
3178 |                          "company",
3179 |                          "Company",
3180 |                          "select id as a, name as b from company",
3181 |                          0
3182 |                       ],
3183 |                       [
3184 |                          "sqliteboy",
3185 |                          "Happy SQLiteBoy user?",
3186 |                          [ [0,"no :("], [1,"yes :)"] ],
3187 |                          1
3188 |                       ],
3189 |                       [
3190 |                          "signature",
3191 |                          "Signature",
3192 |                          0,
3193 |                          ""
3194 |                       ]
3195 |                     ]
3196 | 
3197 |     }
3198 | 
3199 | 
3200 | System Profile Reference
3201 | ========================================================================
3202 | - style: user interface style (int)
3203 | 
3204 | - first_name: first name (str)
3205 | 
3206 | - last_name: last name (str)
3207 | 
3208 | - email: email (str)
3209 | 
3210 | - website: website (str)
3211 | 
3212 | 
3213 | User-defined Profile Reference
3214 | ========================================================================
3215 | 
3216 | - Custom field(s) in user profile can be added. This is useful,
3217 |   for example, in multi-company environment.
3218 | 
3219 | - System configuration
3220 | 
3221 | - Must be valid JSON syntax (json.org)
3222 | 
3223 | - String must be double-quoted (between " and ")
3224 | 
3225 | - No trailling comma in list
3226 | 
3227 | - Python list
3228 | 
3229 | - Each member in list, must be list of 4 members:
3230 | 
3231 |   - field name (underscore and alphanumeric only)
3232 | 
3233 |   - field label
3234 | 
3235 |   - reference (please refer to reference in FORM CODE REFERENCE
3236 |     or REPORT CODE REFERENCE)
3237 | 
3238 |   - default or initial value
3239 | 
3240 | - Field(s) in user-defined profile will always be saved as str.
3241 |   Conversion might be needed.
3242 | 
3243 | - In Form/Report/Query, user-defined profile can be read using
3244 |   sqliteboy_x_profile or sqliteboy_x_my function
3245 | 
3246 | - Example:
3247 | ::
3248 | 
3249 |     [
3250 |       [
3251 |          "company",
3252 |          "Company",
3253 |          "select id as a, name as b from company",
3254 |          0
3255 |       ],
3256 |       [
3257 |          "sqliteboy",
3258 |          "Happy SQLiteBoy user?",
3259 |          [ [0,"no :("], [1,"yes :)"] ],
3260 |          1
3261 |       ],
3262 |       [
3263 |          "signature",
3264 |          "Signature",
3265 |          0,
3266 |          ""
3267 |       ]
3268 |     ]
3269 | 
3270 | - Example using sqliteboy_x_profile / sqliteboy_x_my function:
3271 | ::
3272 | 
3273 |     select sqliteboy_x_my('company')
3274 | 
3275 |     select sqliteboy_x_profile('admin', 'company')
3276 | 
3277 |     select sqliteboy_as_integer(sqliteboy_x_profile('admin', 'company'))
3278 | 
3279 | 
3280 | Python Handler Reference
3281 | ========================================================================
3282 | 
3283 | - Python handler eases the integration with external system
3284 |   (for example: ERP system). Python handler also could be useful in,
3285 |   for example, complex database operation, reading from/writing to
3286 |   external devices, etc.
3287 | 
3288 | - Availability:
3289 | 
3290 |   - Form
3291 | 
3292 |   - Report
3293 | 
3294 |   - Website
3295 | 
3296 | - All handlers must be put in sqliteboy_user.py, in current working
3297 |   directory.
3298 | 
3299 | - Form:
3300 | 
3301 |   - Only one handler is allowed for each form. If provided, it will
3302 |     be called, automatically.
3303 | 
3304 |   - function name: form_. Please rename this function, if you
3305 |     need to temporarily disable python handler for that form.
3306 | 
3307 |   - function arguments:
3308 | 
3309 |     - user: current user (str)
3310 | 
3311 |     - db: database connection object (web.py database object)
3312 | 
3313 |     - parsed: parsed form data (list)
3314 | 
3315 |     - user_data: list of user input (list)
3316 | 
3317 |     - data: additional data (helper functions, UDFs, templates, modules, etc) (dict)
3318 | 
3319 |   - Function *must* return an integer. To get this value, developer can use
3320 |     $python_handler in custom form message. If there is exception, -1 will
3321 |     be assigned to $python_handler.
3322 | 
3323 |   - Please note that python handler is an additional action, called at
3324 |     the end. It will not replace the default/built-in form handler.
3325 | 
3326 |   - Integration with external system, for example, can be done by reading
3327 |     user input value from SQLiteBoy, and writing to external system
3328 | 
3329 | - Report:
3330 | 
3331 |   - Only one handler is allowed for each report. If provided, it will
3332 |     be called, automatically.
3333 | 
3334 |   - function name: report_. Please rename this function, if you
3335 |     need to temporarily disable python handler for that report.
3336 | 
3337 |   - function arguments:
3338 | 
3339 |     - user: current user (str)
3340 | 
3341 |     - db: database connection object (web.py database object)
3342 | 
3343 |     - parsed: parsed report data (list)
3344 | 
3345 |     - user_data: list of user input (list)
3346 | 
3347 |     - data: additional data (helper functions, UDFs, templates, modules, etc) (dict)
3348 | 
3349 |   - Function may return an integer, list of dict or web.py database query
3350 |     result
3351 | 
3352 |   - Please note that python handler is a replacement to the sql query.
3353 |     Return value of function will be used as report result.
3354 | 
3355 |   - Integration with external system, for example, can be done by reading
3356 |     from external system
3357 | 
3358 | - Website: please read WEBSITE AND CUSTOM URL REFERENCE
3359 | 
3360 | 
3361 | Server Command Reference
3362 | ========================================================================
3363 | 
3364 | - Server command (new in v0.81) can be used to do actions related to 
3365 |   server, database, development, or advanced usage, at the server side. 
3366 |   After running such command, SQLiteBoy server will quit. 
3367 | 
3368 | - Command is passed as third argument when running SQLiteBoy (after port)
3369 | 
3370 | - Command may require additional arguments, which must be concatenated to the command 
3371 |   (separated with a dash, for each argument)
3372 | 
3373 | - Command may also require additional files to be present
3374 | 
3375 | - Available commands:
3376 | 
3377 |   - generate_favicon (generates icon file, requires output file, new in v0.81)::
3378 |   
3379 |         python sqliteboy.py test.db 11738 generate_favicon-sqliteboy.ico
3380 |   
3381 |   - generate_pyinstaller (generates spec file, requires output and icon file, new in v0.82)::
3382 |   
3383 |         python sqliteboy.py test.db 11738 generate_pyinstaller-sqliteboy.spec-sqliteboy.ico
3384 |   
3385 |   - generate_build (generates version, icon, and spec file, new in v0.83)::
3386 |   
3387 |         python sqliteboy.py test.db 11738 generate_build
3388 |   
3389 |   - generate_version (generates version file, requires output file, new in v1.07)::
3390 |   
3391 |         python sqliteboy.py test.db 11738 generate_version-sqliteboy.version
3392 |   
3393 |   - enable_extended (enables extended features, new in v1.60)::
3394 |   
3395 |         python sqliteboy.py test.db 11738 enable_extended
3396 |   
3397 |   - enable_extended_allow_all (enables extended features and allows all hosts, new in v1.60)::
3398 | 
3399 |         python sqliteboy.py test.db 11738 enable_extended_allow_all
3400 | 
3401 |   - reset_admin_password (resets admin password to default password, new in v1.69)::
3402 |   
3403 |         python sqliteboy.py test.db 11738 reset_admin_password
3404 |   
3405 |   - disable_log (temporarily disables log, new in v1.70)::
3406 |   
3407 |         python sqliteboy.py test.db 11738 disable_log
3408 |   
3409 |   - restore_log (restores log, new in v1.70)::
3410 |   
3411 |         python sqliteboy.py test.db 11738 restore_log
3412 |   
3413 | - Note on usage: 
3414 | 
3415 |   - generate_favicon, generate_pyinstaller, generate_build, generate_version 
3416 |     are usually used in building standalone SQLiteBoy version
3417 | 
3418 |   - enable_extended and enable_extended_allow_all are provided in order 
3419 |     to easily enable extended features and allow connection from 
3420 |     all hosts (without using the web-based user interface). 
3421 |     This way, SQLiteBoy can be installed on a remote server, 
3422 |     connected to a database, and managed/accessed from another hosts. 
3423 |     Before v1.60, these steps must be done manually (because only
3424 |     local connection is allowed by default; probably using text-based 
3425 |     web browser on server without GUI). 
3426 | 
3427 |   - These commands are not intended for regular use. In order to run
3428 |     SQLiteBoy, please read HOW TO RUN.
3429 | 
3430 | 
3431 | Link Code Reference
3432 | ========================================================================
3433 | 
3434 | - Must be valid JSON syntax (json.org)
3435 | 
3436 | - String (including keys below) must be double-quoted
3437 |   (between " and ")
3438 | 
3439 | - No trailling comma in dict or list
3440 | 
3441 | - Python dict (keys are case-sensitive)
3442 | 
3443 | - Additional/custom links at login page can be set at System configuration
3444 | 
3445 | - Keys must be non-empty strings, values must be lists (or empty lists), 
3446 |   and targets/labels must be non-empty strings. 
3447 |   Please note that strict checking is performed on link code. If there is
3448 |   an error, no link will be available.
3449 | 
3450 | - Keys:
3451 | 
3452 | +---------------+-------------------------+---------------+----------------------------------------+
3453 | | Key           | Description             | Type          | Example                                |
3454 | +===============+=========================+===============+========================================+
3455 | | login.main    | shown on login page     | list of list  | [["http://sqliteboy.com", "sqliteboy"]]|
3456 | |               | at links section        | of two members|                                        |
3457 | |               |                         |               |                                        |
3458 | |               |                         | [target,label]|                                        |
3459 | +---------------+-------------------------+---------------+----------------------------------------+
3460 | | login.extra   | shown on login page     | list of list  | [["http://sqliteboy.com", "sqliteboy"]]|
3461 | |               | after login form        | of two members|                                        |
3462 | |               |                         |               |                                        |
3463 | |               |                         | [target,label]|                                        |
3464 | +---------------+-------------------------+---------------+----------------------------------------+
3465 | 
3466 | - Example:
3467 | ::
3468 | 
3469 |     {
3470 |       "login.main": [["http://sqliteboy.com", "sqliteboy"]],
3471 |       "login.extra": [["http://sqliteboy.com", "sqliteboy"]]
3472 |     }
3473 | 
3474 | 
3475 | Title Reference
3476 | ========================================================================
3477 | 
3478 | - If extended feature is enabled:
3479 | 
3480 |   - Title bar:
3481 |   
3482 |     - Logged in::
3483 |     
3484 |         [sqliteboy] [] title 
3485 |         or
3486 |         [sqliteboy] []
3487 |     
3488 |     - Not logged in::
3489 |     
3490 |         [sqliteboy] 
3491 |     
3492 |   - Main title:
3493 |   
3494 |     - Logged in: 
3495 |     
3496 |       - If Application title is set::
3497 | 
3498 |             
3499 |             
3500 |             [] [] title 
3501 |             or
3502 |             [] [] 
3503 |        
3504 |       - If Application title is not set::
3505 | 
3506 |             [] [] title 
3507 |             or
3508 |             [] [] 
3509 | 
3510 |     - Not logged in:
3511 | 
3512 |       - If Application title is set::
3513 | 
3514 |             
3515 | 
3516 |       - If Application title is not set::
3517 | 
3518 |             [sqliteboy] 
3519 | 
3520 | - If extended feature is not enabled:
3521 | 
3522 |   - Title bar::
3523 |   
3524 |         [sqliteboy] [] title 
3525 |         or
3526 |         [sqliteboy] []
3527 |   
3528 |   - Main title::
3529 | 
3530 |         [] [] title 
3531 |         or
3532 |         [] [] 
3533 | 
3534 | - Default: 
3535 | 
3536 |   -  is home
3537 | 
3538 |   -  is login
3539 | 
3540 | - As of v1.58, SQLiteBoy version is no longer shown in titles
3541 | 
3542 | 
3543 | Logs
3544 | ========================================================================
3545 | 
3546 | - Logs (new in v1.61) can be set in System configuration
3547 | 
3548 | - Access logs are saved in an SQLite database (table name: sqliteboy_log)
3549 | 
3550 | - Columns:
3551 | 
3552 |   - rowtime: timestamp in local time
3553 |   
3554 |   - a: REMOTE_ADDR
3555 |   
3556 |   - b: HTTP_X_FORWARDED_FOR
3557 |   
3558 |   - c: HTTP_USER_AGENT
3559 |   
3560 |   - d: user name
3561 |   
3562 |   - e: request method
3563 |   
3564 |   - f: path
3565 |   
3566 |   - g: query
3567 | 
3568 | - Note:
3569 | 
3570 |   - Use only absolute path and forward slash / for separator
3571 |   
3572 |   - On system configuration save, verification will be performed. 
3573 |     If verification fails, an empty string will be saved and access logs will be disabled.  
3574 | 
3575 |   - Please make sure that log database file is writable by current user
3576 |   
3577 |   - It is possible to use current database as log database. However, 
3578 |     because logs are written per HTTP request, it might impact the 
3579 |     database.  
3580 | 
3581 | - To view the logs, please use SQLiteBoy 
3582 | 
3583 |   - If the logs are stored in external SQLite database, please run another 
3584 |     SQLiteBoy instance to connect to the log database
3585 | 
3586 |   - If the logs are stored in the current database, please use table browse
3587 |     (admin) or reports
3588 | 
3589 | - To log only specific URLs (and discard everything else), please set in
3590 |   System configuration (new in v1.71). Please start each URL with / and 
3591 |   separate URLs with whitespace.
3592 | 
3593 | 
3594 | Monkey Programming Language
3595 | ========================================================================
3596 | 
3597 | - Monkey programming language interpreter (new in v1.81)
3598 | 
3599 | - Availability:
3600 | 
3601 |   - interpreter (link)
3602 | 
3603 |   - notes
3604 | 
3605 | - Initial environments (as monkey identifiers):
3606 | 
3607 |   - SQLITEBOY_NAME
3608 |   
3609 |   - SQLITEBOY_VERSION_STRING
3610 | 
3611 |   - SQLITEBOY_VERSION_INTEGER
3612 | 
3613 | 
3614 | 
3615 | 


--------------------------------------------------------------------------------