@@ -26,6 +26,7 @@ class SqlFormatter
2626 const TOKEN_TYPE_BLOCK_COMMENT = 9 ;
2727 const TOKEN_TYPE_NUMBER = 10 ;
2828 const TOKEN_TYPE_ERROR = 11 ;
29+ const TOKEN_TYPE_FUNCTION = 12 ;
2930
3031 // Constants for different components of a token
3132 const TOKEN_TYPE = 0 ;
@@ -36,7 +37,7 @@ class SqlFormatter
3637 'ACCESSIBLE ' , 'ACTION ' , 'AGAINST ' , 'AGGREGATE ' , 'ALGORITHM ' , 'ALL ' , 'ALTER ' , 'ANALYSE ' , 'ANALYZE ' , 'AS ' , 'ASC ' ,
3738 'AUTOCOMMIT ' , 'AUTO_INCREMENT ' , 'BACKUP ' , 'BEGIN ' , 'BETWEEN ' , 'BINLOG ' , 'BOTH ' , 'CASCADE ' , 'CASE ' , 'CHANGE ' , 'CHANGED ' , 'CHARACTER SET ' ,
3839 'CHARSET ' , 'CHECK ' , 'CHECKSUM ' , 'COLLATE ' , 'COLLATION ' , 'COLUMN ' , 'COLUMNS ' , 'COMMENT ' , 'COMMIT ' , 'COMMITTED ' , 'COMPRESSED ' , 'CONCURRENT ' ,
39- 'CONSTRAINT ' , 'CONTAINS ' , 'CONVERT ' , 'COUNT ' , ' CREATE ' , 'CROSS ' , 'CURRENT_TIMESTAMP ' , 'DATABASE ' , 'DATABASES ' , 'DAY ' , 'DAY_HOUR ' , 'DAY_MINUTE ' ,
40+ 'CONSTRAINT ' , 'CONTAINS ' , 'CONVERT ' , 'CREATE ' , 'CROSS ' , 'CURRENT_TIMESTAMP ' , 'DATABASE ' , 'DATABASES ' , 'DAY ' , 'DAY_HOUR ' , 'DAY_MINUTE ' ,
4041 'DAY_SECOND ' , 'DEFAULT ' , 'DEFINER ' , 'DELAYED ' , 'DELETE ' , 'DESC ' , 'DESCRIBE ' , 'DETERMINISTIC ' , 'DISTINCT ' , 'DISTINCTROW ' , 'DIV ' ,
4142 'DO ' , 'DUMPFILE ' , 'DUPLICATE ' , 'DYNAMIC ' , 'ELSE ' , 'ENCLOSED ' , 'END ' , 'ENGINE ' , 'ENGINE_TYPE ' , 'ENGINES ' , 'ESCAPE ' , 'ESCAPED ' , 'EVENTS ' , 'EXECUTE ' ,
4243 'EXISTS ' , 'EXPLAIN ' , 'EXTENDED ' , 'FAST ' , 'FIELDS ' , 'FILE ' , 'FIRST ' , 'FIXED ' , 'FLUSH ' , 'FOR ' , 'FORCE ' , 'FOREIGN ' , 'FULL ' , 'FULLTEXT ' ,
@@ -46,7 +47,7 @@ class SqlFormatter
4647 'LINES ' , 'LOAD ' , 'LOCAL ' , 'LOCK ' , 'LOCKS ' , 'LOGS ' , 'LOW_PRIORITY ' , 'MARIA ' , 'MASTER ' , 'MASTER_CONNECT_RETRY ' , 'MASTER_HOST ' , 'MASTER_LOG_FILE ' ,
4748 'MATCH ' ,'MAX_CONNECTIONS_PER_HOUR ' , 'MAX_QUERIES_PER_HOUR ' , 'MAX_ROWS ' , 'MAX_UPDATES_PER_HOUR ' , 'MAX_USER_CONNECTIONS ' ,
4849 'MEDIUM ' , 'MERGE ' , 'MINUTE ' , 'MINUTE_SECOND ' , 'MIN_ROWS ' , 'MODE ' , 'MODIFY ' ,
49- 'MONTH ' , 'MRG_MYISAM ' , 'MYISAM ' , 'NAMES ' , 'NATURAL ' , 'NOT ' , 'NOW() ' , ' NULL ' , 'OFFSET ' , 'ON ' , 'OPEN ' , 'OPTIMIZE ' , 'OPTION ' , 'OPTIONALLY ' ,
50+ 'MONTH ' , 'MRG_MYISAM ' , 'MYISAM ' , 'NAMES ' , 'NATURAL ' , 'NOT ' , 'NULL ' , 'OFFSET ' , 'ON ' , 'OPEN ' , 'OPTIMIZE ' , 'OPTION ' , 'OPTIONALLY ' ,
5051 'ON UPDATE ' , 'ON DELETE ' , 'OUTFILE ' , 'PACK_KEYS ' , 'PAGE ' , 'PARTIAL ' , 'PARTITION ' , 'PARTITIONS ' , 'PASSWORD ' , 'PRIMARY ' , 'PRIVILEGES ' , 'PROCEDURE ' ,
5152 'PROCESS ' , 'PROCESSLIST ' , 'PURGE ' , 'QUICK ' , 'RANGE ' , 'RAID0 ' , 'RAID_CHUNKS ' , 'RAID_CHUNKSIZE ' ,'RAID_TYPE ' , 'READ ' , 'READ_ONLY ' ,
5253 'READ_WRITE ' , 'REFERENCES ' , 'REGEXP ' , 'RELOAD ' , 'RENAME ' , 'REPAIR ' , 'REPEATABLE ' , 'REPLACE ' , 'REPLICATION ' , 'RESET ' , 'RESTORE ' , 'RESTRICT ' ,
@@ -71,6 +72,35 @@ class SqlFormatter
7172 'LEFT OUTER JOIN ' , 'RIGHT OUTER JOIN ' , 'LEFT JOIN ' , 'RIGHT JOIN ' , 'OUTER JOIN ' , 'INNER JOIN ' , 'JOIN ' , 'XOR ' , 'OR ' , 'AND '
7273 );
7374
75+ protected static $ mysql_function = array (
76+ 'ABS ' , 'ACOS ' , 'ADDDATE ' , 'ADDTIME ' , 'AES_DECRYPT ' , 'AES_ENCRYPT ' , 'AREA ' , 'ASBINARY ' , 'ASCII ' , 'ASIN ' , 'ASTEXT ' , 'ATAN ' , 'ATAN2 ' ,
77+ 'AVG ' , 'BDMPOLYFROMTEXT ' , 'BDMPOLYFROMWKB ' , 'BDPOLYFROMTEXT ' , 'BDPOLYFROMWKB ' , 'BENCHMARK ' , 'BIN ' , 'BIT_AND ' , 'BIT_COUNT ' , 'BIT_LENGTH ' ,
78+ 'BIT_OR ' , 'BIT_XOR ' , 'BOUNDARY ' , 'BUFFER ' , 'CAST ' , 'CEIL ' , 'CEILING ' , 'CENTROID ' , 'CHAR ' , 'CHARACTER_LENGTH ' , 'CHARSET ' , 'CHAR_LENGTH ' ,
79+ 'COALESCE ' , 'COERCIBILITY ' , 'COLLATION ' , 'COMPRESS ' , 'CONCAT ' , 'CONCAT_WS ' , 'CONNECTION_ID ' , 'CONTAINS ' , 'CONV ' , 'CONVERT ' , 'CONVERT_TZ ' ,
80+ 'CONVEXHULL ' , 'COS ' , 'COT ' , 'COUNT ' , 'CRC32 ' , 'CROSSES ' , 'CURDATE ' , 'CURRENT_DATE ' , 'CURRENT_TIME ' , 'CURRENT_TIMESTAMP ' , 'CURRENT_USER ' ,
81+ 'CURTIME ' , 'DATABASE ' , 'DATE ' , 'DATEDIFF ' , 'DATE_ADD ' , 'DATE_DIFF ' , 'DATE_FORMAT ' , 'DATE_SUB ' , 'DAY ' , 'DAYNAME ' , 'DAYOFMONTH ' , 'DAYOFWEEK ' ,
82+ 'DAYOFYEAR ' , 'DECODE ' , 'DEFAULT ' , 'DEGREES ' , 'DES_DECRYPT ' , 'DES_ENCRYPT ' , 'DIFFERENCE ' , 'DIMENSION ' , 'DISJOINT ' , 'DISTANCE ' , 'ELT ' , 'ENCODE ' ,
83+ 'ENCRYPT ' , 'ENDPOINT ' , 'ENVELOPE ' , 'EQUALS ' , 'EXP ' , 'EXPORT_SET ' , 'EXTERIORRING ' , 'EXTRACT ' , 'EXTRACTVALUE ' , 'FIELD ' , 'FIND_IN_SET ' , 'FLOOR ' ,
84+ 'FORMAT ' , 'FOUND_ROWS ' , 'FROM_DAYS ' , 'FROM_UNIXTIME ' , 'GEOMCOLLFROMTEXT ' , 'GEOMCOLLFROMWKB ' , 'GEOMETRYCOLLECTION ' , 'GEOMETRYCOLLECTIONFROMTEXT ' ,
85+ 'GEOMETRYCOLLECTIONFROMWKB ' , 'GEOMETRYFROMTEXT ' , 'GEOMETRYFROMWKB ' , 'GEOMETRYN ' , 'GEOMETRYTYPE ' , 'GEOMFROMTEXT ' , 'GEOMFROMWKB ' , 'GET_FORMAT ' ,
86+ 'GET_LOCK ' , 'GLENGTH ' , 'GREATEST ' , 'GROUP_CONCAT ' , 'GROUP_UNIQUE_USERS ' , 'HEX ' , 'HOUR ' , 'IF ' , 'IFNULL ' , 'INET_ATON ' , 'INET_NTOA ' , 'INSERT ' , 'INSTR ' ,
87+ 'INTERIORRINGN ' , 'INTERSECTION ' , 'INTERSECTS ' , 'INTERVAL ' , 'ISCLOSED ' , 'ISEMPTY ' , 'ISNULL ' , 'ISRING ' , 'ISSIMPLE ' , 'IS_FREE_LOCK ' , 'IS_USED_LOCK ' ,
88+ 'LAST_DAY ' , 'LAST_INSERT_ID ' , 'LCASE ' , 'LEAST ' , 'LEFT ' , 'LENGTH ' , 'LINEFROMTEXT ' , 'LINEFROMWKB ' , 'LINESTRING ' , 'LINESTRINGFROMTEXT ' , 'LINESTRINGFROMWKB ' ,
89+ 'LN ' , 'LOAD_FILE ' , 'LOCALTIME ' , 'LOCALTIMESTAMP ' , 'LOCATE ' , 'LOG ' , 'LOG10 ' , 'LOG2 ' , 'LOWER ' , 'LPAD ' , 'LTRIM ' , 'MAKEDATE ' , 'MAKETIME ' , 'MAKE_SET ' ,
90+ 'MASTER_POS_WAIT ' , 'MAX ' , 'MBRCONTAINS ' , 'MBRDISJOINT ' , 'MBREQUAL ' , 'MBRINTERSECTS ' , 'MBROVERLAPS ' , 'MBRTOUCHES ' , 'MBRWITHIN ' , 'MD5 ' , 'MICROSECOND ' ,
91+ 'MID ' , 'MIN ' , 'MINUTE ' , 'MLINEFROMTEXT ' , 'MLINEFROMWKB ' , 'MOD ' , 'MONTH ' , 'MONTHNAME ' , 'MPOINTFROMTEXT ' , 'MPOINTFROMWKB ' , 'MPOLYFROMTEXT ' , 'MPOLYFROMWKB ' ,
92+ 'MULTILINESTRING ' , 'MULTILINESTRINGFROMTEXT ' , 'MULTILINESTRINGFROMWKB ' , 'MULTIPOINT ' , 'MULTIPOINTFROMTEXT ' , 'MULTIPOINTFROMWKB ' , 'MULTIPOLYGON ' ,
93+ 'MULTIPOLYGONFROMTEXT ' , 'MULTIPOLYGONFROMWKB ' , 'NAME_CONST ' , 'NOW ' , 'NULLIF ' , 'NUMGEOMETRIES ' , 'NUMINTERIORRINGS ' , 'NUMPOINTS ' , 'OCT ' , 'OCTET_LENGTH ' ,
94+ 'OLD_PASSWORD ' , 'ORD ' , 'OVERLAPS ' , 'PASSWORD ' , 'PERIOD_ADD ' , 'PERIOD_DIFF ' , 'PI ' , 'POINT ' , 'POINTFROMTEXT ' , 'POINTFROMWKB ' , 'POINTN ' , 'POINTONSURFACE ' ,
95+ 'POLYFROMTEXT ' , 'POLYFROMWKB ' , 'POLYGON ' , 'POLYGONFROMTEXT ' , 'POLYGONFROMWKB ' , 'POSITION ' , 'POW ' , 'POWER ' , 'QUARTER ' , 'QUOTE ' , 'RADIANS ' , 'RAND ' ,
96+ 'RELATED ' , 'RELEASE_LOCK ' , 'REPEAT ' , 'REPLACE ' , 'REVERSE ' , 'RIGHT ' , 'ROUND ' , 'ROW_COUNT ' , 'RPAD ' , 'RTRIM ' , 'SCHEMA ' , 'SECOND ' , 'SEC_TO_TIME ' ,
97+ 'SESSION_USER ' , 'SHA ' , 'SHA1 ' , 'SIGN ' , 'SIN ' , 'SLEEP ' , 'SOUNDEX ' , 'SPACE ' , 'SQRT ' , 'SRID ' , 'STARTPOINT ' , 'STD ' , 'STDDEV ' , 'STDDEV_POP ' , 'STDDEV_SAMP ' ,
98+ 'STRCMP ' , 'STR_TO_DATE ' , 'SUBDATE ' , 'SUBSTR ' , 'SUBSTRING ' , 'SUBSTRING_INDEX ' , 'SUBTIME ' , 'SUM ' , 'SYMDIFFERENCE ' , 'SYSDATE ' , 'SYSTEM_USER ' , 'TAN ' ,
99+ 'TIME ' , 'TIMEDIFF ' , 'TIMESTAMP ' , 'TIMESTAMPADD ' , 'TIMESTAMPDIFF ' , 'TIME_FORMAT ' , 'TIME_TO_SEC ' , 'TOUCHES ' , 'TO_DAYS ' , 'TRIM ' , 'TRUNCATE ' , 'UCASE ' ,
100+ 'UNCOMPRESS ' , 'UNCOMPRESSED_LENGTH ' , 'UNHEX ' , 'UNIQUE_USERS ' , 'UNIX_TIMESTAMP ' , 'UPDATEXML ' , 'UPPER ' , 'USER ' , 'UTC_DATE ' , 'UTC_TIME ' , 'UTC_TIMESTAMP ' ,
101+ 'UUID ' , 'VARIANCE ' , 'VAR_POP ' , 'VAR_SAMP ' , 'VERSION ' , 'WEEK ' , 'WEEKDAY ' , 'WEEKOFYEAR ' , 'WITHIN ' , 'X ' , 'Y ' , 'YEAR ' , 'YEARWEEK '
102+ );
103+
74104 // Punctuation that can be used as a boundary between other tokens
75105 protected static $ boundaries = array (', ' , '; ' , ') ' , '( ' , '. ' , '= ' , '< ' , '> ' , '+ ' , '- ' , '* ' , '/ ' , '! ' , '^ ' , '% ' , '| ' , '& ' , '# ' );
76106
@@ -85,6 +115,7 @@ class SqlFormatter
85115 public static $ error_attributes = 'style="background-color: red;" ' ;
86116 public static $ comment_attributes = 'style="color: #aaa;" ' ;
87117 public static $ pre_attributes = 'style="color: black; background-color: white;" ' ;
118+ public static $ mysql_functions = 'style="color: red;" ' ;
88119
89120 // Boolean - whether or not the current environment is the CLI
90121 // This affects the type of syntax highlighting
@@ -100,6 +131,7 @@ class SqlFormatter
100131 public static $ cli_word = "" ;
101132 public static $ cli_error = "\x1b[31;1;7m " ;
102133 public static $ cli_comment = "\x1b[30;1m " ;
134+ public static $ cli_functions = "\x1b[37m " ;
103135
104136 // The tab character to use when formatting SQL
105137 public static $ tab = ' ' ;
@@ -115,6 +147,7 @@ class SqlFormatter
115147 protected static $ regex_reserved ;
116148 protected static $ regex_reserved_newline ;
117149 protected static $ regex_reserved_toplevel ;
150+ protected static $ regex_mysql_function ;
118151
119152 // Cache variables
120153 // Only tokens shorter than this size will be cached. Somewhere between 10 and 20 seems to work well for most cases.
@@ -151,6 +184,8 @@ protected static function init() {
151184 self ::$ regex_reserved_toplevel = str_replace (' ' ,'\\s+ ' ,'( ' .implode ('| ' ,array_map (array ('SqlFormatter ' , 'quote_regex ' ),self ::$ reserved_toplevel )).') ' );
152185 self ::$ regex_reserved_newline = str_replace (' ' ,'\\s+ ' ,'( ' .implode ('| ' ,array_map (array ('SqlFormatter ' , 'quote_regex ' ),self ::$ reserved_newline )).') ' );
153186
187+ self ::$ regex_mysql_function = '( ' .implode ('| ' ,array_map (array ('SqlFormatter ' , 'quote_regex ' ),self ::$ mysql_function )).') ' ;
188+
154189 self ::$ init = true ;
155190 }
156191
@@ -255,6 +290,20 @@ protected static function getNextToken($string, $previous = null)
255290 }
256291 }
257292
293+ // A function must be suceeded by '('
294+ // this makes it so in "count(", which considers it as a mysql function.
295+
296+ $ upper = strtoupper ($ string );
297+ // MySQL function
298+ if (preg_match ('/^( ' .self ::$ regex_mysql_function .'[(]|\s|[)])/ ' , $ upper ,$ matches )) {
299+
300+ return array (
301+ self ::TOKEN_TYPE =>self ::TOKEN_TYPE_FUNCTION ,
302+ self ::TOKEN_VALUE =>substr ($ string ,0 ,strlen ($ matches [1 ])-1 )
303+ );
304+ }
305+
306+
258307 // Non reserved word
259308 preg_match ('/^(.*?)($|\s|[" \'`]| ' .self ::$ regex_boundaries .')/ ' ,$ string ,$ matches );
260309
@@ -699,7 +748,7 @@ public static function removeComments($string)
699748
700749 $ result .= $ token [self ::TOKEN_VALUE ];
701750 }
702- $ result = self ::remove_blank_lines ( $ result );
751+ $ result = self ::format ( $ result, false );
703752 return $ result ;
704753 }
705754
@@ -790,6 +839,9 @@ protected static function highlightToken($token)
790839 elseif ($ type ===self ::TOKEN_TYPE_COMMENT || $ type ===self ::TOKEN_TYPE_BLOCK_COMMENT ) {
791840 return self ::highlightComment ($ token );
792841 }
842+ elseif ($ type ===self ::TOKEN_TYPE_FUNCTION ) {
843+ return self ::highlightMySQLFunction ($ token );
844+ }
793845
794846 return $ token ;
795847 }
@@ -843,6 +895,23 @@ protected static function highlightReservedWord($value)
843895 return '<span ' . self ::$ reserved_attributes . '> ' . $ value . '</span> ' ;
844896 }
845897 }
898+
899+ /**
900+ * Highlights mysql functions
901+ *
902+ * @param String $value The token's value
903+ *
904+ * @return String HTML code of the highlighted token.
905+ */
906+ protected static function highlightMySQLFunction ($ value )
907+ {
908+ if (self ::is_cli ()) {
909+ return self ::$ cli_reserved . $ value . "\x1b[0m " ;//not sure as doesn't have this environment for now.Need to check
910+ }
911+ else {
912+ return '<span ' . self ::$ mysql_functions . '> ' . $ value . '</span> ' ;
913+ }
914+ }
846915
847916 /**
848917 * Highlights a boundary token
@@ -982,14 +1051,4 @@ private static function is_cli() {
9821051 else return php_sapi_name () === 'cli ' ;
9831052 }
9841053
985- /**
986- * Removes blank line between and before sql statements.
987- *@param String $sql from which blank lines need to be removed
988- *
989- * @return String sql without blank lines
990- */
991- private static function remove_blank_lines ($ sql )
992- {
993- return preg_replace ('/^\n+|^[\t\s]*\n+/m ' ,'' ,$ sql );
994- }
9951054}
0 commit comments