phpmyadmin / phpmyadmin/phpmyadmin

Uncaught TypeError: can't access property "split", string is undefined

Open
#17,342 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

affects/5.2 affects/6.0 Bug confirmed/5.2 confirmed/6.0 help wanted parser waiting on upstream
Dominant language
PHP
Stars
7.9k
Forks
3.6k
Avg merge
4d 18h
Merged PRs (30d)
36

Description

Describe the bug

When a very large query is formatted from SQL tab, and index.php?route=/database/sql/format can't keep up with formatting, it responds with an invalid JSON object, that throws this JavaScript error. The invalid JSON object has a PHP fatal error.
Fatal error: Maximum execution time of 30 seconds exceeded in /usr/share/phpMyAdmin/vendor/phpmyadmin/sql-parser/src/Lexer.php on line 781. Line 781 for me, is 780 from here:

https://github.com/phpmyadmin/sql-parser/blob/0deffe547532d804cf09d41ab422ffe72d73b36b/src/Lexer.php#L780

So, basically there are two bugs.

To Reproduce

Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error
Expected behavior

A clear and concise description of what you expected to happen.

Screenshots

If applicable, add screenshots to help explain your problem.

Server configuration
  • Operating system: CentOS 8
  • Web server: nginx/1.14.1
  • Database version: MySQL 5.7.37
  • PHP version: 8.1.2
  • phpMyAdmin version: 5.3.0-dev+20220204.d8b5811b82
Client configuration
  • Browser: Firefox 98
  • Operating system: Windows 10
Additional context
{
    "pma_version": "5.3.0-dev+20220204.d8b5811b82",
    "browser_name": "FIREFOX",
    "browser_version": "98.0",
    "user_os": "Win",
    "server_software": "nginx/1.14.1",
    "user_agent_string": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0",
    "locale": "en",
    "configuration_storage": "enabled",
    "php_version": "8.1.2",
    "script_name": "index.php",
    "exception_type": "js",
    "exception": {
        "mode": "stack",
        "name": "TypeError",
        "message": "can't access property \"split\", string is undefined",
        "stack": [
            {
                "func": "splitLinesAuto<",
                "line": "681",
                "column": "27",
                "context": [
                    "        result.push(line);",
                    "        pos = nl + 1;",
                    "      }",
                    "    }",
                    "    return result",
                    "  } : function (string) { return string.split(/\\r\\n?|\\n/); };",
                    "",
                    "  var hasSelection = window.getSelection ? function (te) {",
                    "    try { return te.selectionStart != te.selectionEnd }",
                    "    catch(e) { return false }",
                    "  } : function (te) {"
                ],
                "uri": "js/vendor/codemirror/lib/codemirror.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/codemirror/lib/codemirror.js"
            },
            {
                "func": "splitLines",
                "line": "6504",
                "column": "14",
                "context": [
                    "    getMode: function() {return this.mode},",
                    "    getEditor: function() {return this.cm},",
                    "",
                    "    splitLines: function(str) {",
                    "      if (this.lineSep) { return str.split(this.lineSep) }",
                    "      return splitLinesAuto(str)",
                    "    },",
                    "    lineSeparator: function() { return this.lineSep || \"\\n\" },",
                    "",
                    "    setDirection: docMethodOp(function (dir) {",
                    "      if (dir != \"rtl\") { dir = \"ltr\"; }"
                ],
                "uri": "js/vendor/codemirror/lib/codemirror.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/codemirror/lib/codemirror.js"
            },
            {
                "func": "Doc.prototype<.setValue<",
                "line": "6157",
                "column": "36",
                "context": [
                    "      return lines.join(lineSep || this.lineSeparator())",
                    "    },",
                    "    setValue: docMethodOp(function(code) {",
                    "      var top = Pos(this.first, 0), last = this.first + this.size - 1;",
                    "      makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.l//...",
                    "                        text: this.splitLines(code), origin: \"setValue\", fu//...",
                    "      if (this.cm) { scrollToCoords(this.cm, 0, 0); }",
                    "      setSelection(this, simpleSelection(top), sel_dontScroll);",
                    "    }),",
                    "    replaceRange: function(code, from, to, origin) {",
                    "      from = clipPos(this, from);"
                ],
                "uri": "js/vendor/codemirror/lib/codemirror.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/codemirror/lib/codemirror.js"
            },
            {
                "func": "docMethodOp/<",
                "line": "3971",
                "column": "22",
                "context": [
                    "  function docMethodOp(f) {",
                    "    return function() {",
                    "      var cm = this.cm;",
                    "      if (!cm || cm.curOp) { return f.apply(this, arguments) }",
                    "      startOperation(cm);",
                    "      try { return f.apply(this, arguments) }",
                    "      finally { endOperation(cm); }",
                    "    }",
                    "  }",
                    "",
                    "  // HIGHLIGHT WORKER"
                ],
                "uri": "js/vendor/codemirror/lib/codemirror.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/codemirror/lib/codemirror.js"
            },
            {
                "func": "CodeMirror.prototype[prop]",
                "line": "9802",
                "column": "40",
                "context": [
                    "",
                    "  // Set up methods on CodeMirror's prototype to redirect to the editor's d//...",
                    "  var dontDelegate = \"iter insert remove copy getEditor constructor\".split(\" \");",
                    "  for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) //...",
                    "    { CodeMirror.prototype[prop] = (function(method) {",
                    "      return function() {return method.apply(this.doc, arguments)}",
                    "    })(Doc.prototype[prop]); } }",
                    "",
                    "  eventMixin(Doc);",
                    "  CodeMirror.inputStyles = {\"textarea\": TextareaInput, \"contenteditable\": C//...",
                    ""
                ],
                "uri": "js/vendor/codemirror/lib/codemirror.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/codemirror/lib/codemirror.js"
            },
            {
                "func": "success",
                "line": "1248",
                "column": "30",
                "context": [
                    "        type: 'POST',",
                    "        url: 'index.php?route=/database/sql/format',",
                    "        data: params,",
                    "        success: function (data) {",
                    "          if (data.success) {",
                    "            codeMirrorEditor.setValue(data.sql);",
                    "          }",
                    "",
                    "          $('#querymessage').html('');",
                    "        }",
                    "      });"
                ],
                "uri": "js/dist/functions.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/dist/functions.js"
            },
            {
                "func": "c",
                "line": "2",
                "column": "28327",
                "context": [
                    "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.o//...",
                    "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof modul//...",
                    ""
                ],
                "uri": "js/vendor/jquery/jquery.min.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/jquery/jquery.min.js"
            },
            {
                "func": "fireWith",
                "line": "2",
                "column": "29072",
                "context": [
                    "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.o//...",
                    "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof modul//...",
                    ""
                ],
                "uri": "js/vendor/jquery/jquery.min.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/jquery/jquery.min.js"
            },
            {
                "func": "l",
                "line": "2",
                "column": "79901",
                "context": [
                    "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.o//...",
                    "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof modul//...",
                    ""
                ],
                "uri": "js/vendor/jquery/jquery.min.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/jquery/jquery.min.js"
            },
            {
                "func": "send/o/<",
                "line": "2",
                "column": "82355",
                "context": [
                    "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.o//...",
                    "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof modul//...",
                    ""
                ],
                "uri": "js/vendor/jquery/jquery.min.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/jquery/jquery.min.js"
            },
            {
                "func": "EventHandlerNonNull*send",
                "line": "2",
                "column": "82541",
                "context": [
                    "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.o//...",
                    "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof modul//...",
                    ""
                ],
                "uri": "js/vendor/jquery/jquery.min.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/jquery/jquery.min.js"
            },
            {
                "func": "ajax",
                "line": "2",
                "column": "78291",
                "context": [
                    "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.o//...",
                    "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof modul//...",
                    ""
                ],
                "uri": "js/vendor/jquery/jquery.min.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/jquery/jquery.min.js"
            },
            {
                "func": "jQuery.ajax",
                "line": "305",
                "column": "22",
                "context": [
                    "",
                    "var oldAjax = jQuery.ajax,",
                    "\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;",
                    "",
                    "jQuery.ajax = function( ) {",
                    "\tvar jQXHR = oldAjax.apply( this, arguments );",
                    "",
                    "\t// Be sure we got a jQXHR (e.g., not sync)",
                    "\tif ( jQXHR.promise ) {",
                    "\t\tmigrateWarnFunc( jQXHR, \"success\", jQXHR.done,",
                    "\t\t\t\"jQXHR.success is deprecated and removed\" );"
                ],
                "uri": "js/vendor/jquery/jquery-migrate.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/jquery/jquery-migrate.js"
            },
            {
                "func": "Functions.insertQuery",
                "line": "1242",
                "column": "9",
                "context": [
                    "      var params = {",
                    "        'ajax_request': true,",
                    "        'sql': codeMirrorEditor.getValue(),",
                    "        'server': CommonParams.get('server')",
                    "      };",
                    "      $.ajax({",
                    "        type: 'POST',",
                    "        url: 'index.php?route=/database/sql/format',",
                    "        data: params,",
                    "        success: function (data) {",
                    "          if (data.success) {"
                ],
                "uri": "js/dist/functions.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/dist/functions.js"
            },
            {
                "func": "?",
                "line": "1575",
                "column": "15",
                "context": [
                    "    var $divEditor = $('div#inline_editor_outer');",
                    "    $divEditor.siblings('code.sql').show();",
                    "    $divEditor.remove();",
                    "  });",
                    "  $(document).on('click', 'input.sqlbutton', function (evt) {",
                    "    Functions.insertQuery(evt.target.id);",
                    "    Functions.handleSimulateQueryButton();",
                    "    return false;",
                    "  });",
                    "  $(document).on('change', '#parameterized', Functions.updateQueryParameters);",
                    "  var $inputUsername = $('#input_username');"
                ],
                "uri": "js/dist/functions.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/dist/functions.js"
            },
            {
                "func": "newFunc",
                "line": "259",
                "column": "23",
                "context": [
                    "   */",
                    "  wrapFunction: function (func) {",
                    "    if (!func.wrapped) {",
                    "      var newFunc = function () {",
                    "        try {",
                    "          return func.apply(this, arguments);",
                    "        } catch (x) {",
                    "          TraceKit.report(x);",
                    "        }",
                    "      };",
                    ""
                ],
                "uri": "js/dist/error_report.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/dist/error_report.js"
            },
            {
                "func": "dispatch",
                "line": "2",
                "column": "43064",
                "context": [
                    "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.o//...",
                    "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof modul//...",
                    ""
                ],
                "uri": "js/vendor/jquery/jquery.min.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/jquery/jquery.min.js"
            },
            {
                "func": "add/v.handle",
                "line": "2",
                "column": "41048",
                "context": [
                    "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.o//...",
                    "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof modul//...",
                    ""
                ],
                "uri": "js/vendor/jquery/jquery.min.js?v=5.3.0-dev%2B20220204.d8b5811b82",
                "scriptname": "js/vendor/jquery/jquery.min.js"
            }
        ],
        "uri": "index.php?route=%2Ftable%2Fsql"
    }
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the SQL formatting request at index.php?route=/database/sql/format and its success callback in js/dist/functions.js. Then inspect the referenced parser location in vendor/phpmyadmin/sql-parser/src/Lexer.php and the CodeMirror setValue stack in js/vendor/codemirror/lib/codemirror.js. Done means large-query formatting failures produce a valid response and do not trigger the reported JavaScript error.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, mysql, php
Domain
backend, databases, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.