Check SQL schema for reserved words and find suitable replacement

388 views Asked by At

Wasted many hours troubleshooting my DB which included maxValue as a column name. I've since discovered it was a reserved word.

I've used type and timestamp with both MySQL and MariaDB without issues, but I've learned my lesson, and will never do so again (MySQL shows both as being reserved, yet MariaDB only shows timestamp and even says its still okay to use).

  1. Is there some sort of online tool which will check the schema using the SQL dump or create SQL for reserved words?
  2. Is there any resource or strategy showing typical replacement words. I suppose I can make them plural but doing so goes against my personnel standard.
1

There are 1 answers

1
user1032531 On

For what it is worth, here is a tool...

Note that mysql.help_keyword is not being supported with MariaDB 10.2.7, and I had to hardcode the reserved words.

<?php
error_reporting(E_ALL);
ini_set('display_startup_errors', 1);
ini_set('display_errors', 1);
openlog('API', LOG_NDELAY, LOG_LOCAL2);

if ($_SERVER['REQUEST_METHOD'] == 'POST' && !empty($_POST['database'])) {

    $db=parse_ini_file(__DIR__.'/../config.ini',true)['mysql'];
    $pdo=new PDO("mysql:host={$db['host']};dbname={$db['dbname']};charset={$db['charset']}",$db['username'],$db['password'],array(PDO::ATTR_EMULATE_PREPARES=>false,PDO::MYSQL_ATTR_USE_BUFFERED_QUERY=>true,PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_OBJ));

    $error=['tableHelper'=>[],'columnHelper'=>[],'tableMdbReserved'=>[],'columnMdbReserved'=>[],'tableMdbException'=>[],'columnMdbException'=>[]];
    $stmt=$pdo->query('SELECT name FROM mysql.help_keyword');
    $reserved=$stmt->fetchAll(PDO::FETCH_COLUMN);
    $mdbReserved=['ACCESSIBLE','ADD','ALL','ALTER','ANALYZE','AND','AS','ASC','ASENSITIVE','BEFORE','BETWEEN','BIGINT','BINARY','BLOB','BOTH','BY','CALL','CASCADE','CASE','CHANGE','CHAR','CHARACTER','CHECK','COLLATE','COLUMN','CONDITION','CONSTRAINT','CONTINUE','CONVERT','CREATE','CROSS','CURRENT_DATE','CURRENT_TIME','CURRENT_TIMESTAMP','CURRENT_USER','CURSOR','DATABASE','DATABASES','DAY_HOUR','DAY_MICROSECOND','DAY_MINUTE','DAY_SECOND','DEC','DECIMAL','DECLARE','DEFAULT','DELAYED','DELETE','DESC','DESCRIBE','DETERMINISTIC','DISTINCT','DISTINCTROW','DIV','DOUBLE','DROP','DUAL','EACH','ELSE','ELSEIF','ENCLOSED','ESCAPED','EXISTS','EXIT','EXPLAIN','FALSE','FETCH','FLOAT','FLOAT4','FLOAT8','FOR','FORCE','FOREIGN','FROM','FULLTEXT','GENERAL','GRANT','GROUP','HAVING','HIGH_PRIORITY','HOUR_MICROSECOND','HOUR_MINUTE','HOUR_SECOND','IF','IGNORE','IGNORE_SERVER_IDS','IN','INDEX','INFILE','INNER','INOUT','INSENSITIVE','INSERT','INT','INT1','INT2','INT3','INT4','INT8','INTEGER','INTERVAL','INTO','IS','ITERATE','JOIN','KEY','KEYS','KILL','LEADING','LEAVE','LEFT','LIKE','LIMIT','LINEAR','LINES','LOAD','LOCALTIME','LOCALTIMESTAMP','LOCK','LONG','LONGBLOB','LONGTEXT','LOOP','LOW_PRIORITY','MASTER_HEARTBEAT_PERIOD','MASTER_SSL_VERIFY_SERVER_CERT','MATCH','MAXVALUE','MEDIUMBLOB','MEDIUMINT','MEDIUMTEXT','MIDDLEINT','MINUTE_MICROSECOND','MINUTE_SECOND','MOD','MODIFIES','NATURAL','NOT','NO_WRITE_TO_BINLOG','NULL','NUMERIC','ON','OPTIMIZE','OPTION','OPTIONALLY','OR','ORDER','OUT','OUTER','OUTFILE','PARTITION','PRECISION','PRIMARY','PROCEDURE','PURGE','RANGE','READ','READS','READ_WRITE','REAL','RECURSIVE','REFERENCES','REGEXP','RELEASE','RENAME','REPEAT','REPLACE','REQUIRE','RESIGNAL','RESTRICT','RETURN','REVOKE','RIGHT','RLIKE','ROWS','SCHEMA','SCHEMAS','SECOND_MICROSECOND','SELECT','SENSITIVE','SEPARATOR','SET','SHOW','SIGNAL','SLOW','SMALLINT','SPATIAL','SPECIFIC','SQL','SQLEXCEPTION','SQLSTATE','SQLWARNING','SQL_BIG_RESULT','SQL_CALC_FOUND_ROWS','SQL_SMALL_RESULT','SSL','STARTING','STRAIGHT_JOIN','TABLE','TERMINATED','THEN','TINYBLOB','TINYINT','TINYTEXT','TO','TRAILING','TRIGGER','TRUE','UNDO','UNION','UNIQUE','UNLOCK','UNSIGNED','UPDATE','USAGE','USE','USING','UTC_DATE','UTC_TIME','UTC_TIMESTAMP','VALUES','VARBINARY','VARCHAR','VARCHARACTER','VARYING','WHEN','WHERE','WHILE','WITH','WRITE','XOR','YEAR_MONTH','ZEROFILL'];
    $mdbExceptions=['ACTION','BIT','DATE','ENUM','NO','TEXT','TIME','TIMESTAMP'];

    $stmt=$pdo->prepare('SELECT UPPER(TABLE_NAME) tn, UPPER(COLUMN_NAME) cn from information_schema.columns WHERE table_schema = ?');
    $stmt->execute([$_POST['database']]);
    while($rs=$stmt->fetch()) {
        if(in_array($rs->tn,$reserved)) {
            $error['tableHelper'][]=$rs->tn;
        }
        if(in_array($rs->cn,$reserved) && !in_array($rs->cn,$error['columnHelper'])) {
            $error['columnHelper'][]=$rs->cn;
        }
        if(in_array($rs->tn,$mdbReserved)) {
            $error['tableMdbReserved'][]=$rs->tn;
        }
        if(in_array($rs->cn,$mdbReserved) && !in_array($rs->cn,$error['columnMdbReserved'])) {
            $error['columnMdbReserved'][]=$rs->cn;
        }
        if(in_array($rs->tn,$mdbExceptions)) {
            $error['tableMdbException'][]=$rs->tn;
        }
        if(in_array($rs->cn,$mdbExceptions) && !in_array($rs->cn,$error['columnMdbException'])) {
            $error['columnMdbException'][]=$rs->cn;
        }
    }
    echo('<pre>'.print_r($error,1).'</pre>');
}
else {
    echo <<<EOT
<form method="post">
  Database Name: <input type="text" name="database"><br>
  <input type="submit">
</form>
EOT;
}

Output:

Array
(
    [tableHelper] => Array
        (
        )

    [columnHelper] => Array
        (
            [0] => TYPE
            [1] => NAME
            [2] => TIMESTAMP
            [3] => OFFSET
            [4] => VALUE
            [5] => STATUS
            [6] => PORT
        )

    [tableMdbReserved] => Array
        (
        )

    [columnMdbReserved] => Array
        (
            [0] => MAXVALUE
        )

    [tableMdbException] => Array
        (
        )

    [columnMdbException] => Array
        (
            [0] => TIMESTAMP
        )

)