l0bsterssg

node.js static responsive blog post generator
Log | Files | Refs | README

pgsql.js (29308B)


      1 /*
      2 Language: PostgreSQL and PL/pgSQL
      3 Author: Egor Rogov (e.rogov@postgrespro.ru)
      4 Website: https://www.postgresql.org/docs/11/sql.html
      5 Description:
      6     This language incorporates both PostgreSQL SQL dialect and PL/pgSQL language.
      7     It is based on PostgreSQL version 11. Some notes:
      8     - Text in double-dollar-strings is _always_ interpreted as some programming code. Text
      9       in ordinary quotes is _never_ interpreted that way and highlighted just as a string.
     10     - There are quite a bit "special cases". That's because many keywords are not strictly
     11       they are keywords in some contexts and ordinary identifiers in others. Only some
     12       of such cases are handled; you still can get some of your identifiers highlighted
     13       wrong way.
     14     - Function names deliberately are not highlighted. There is no way to tell function
     15       call from other constructs, hence we can't highlight _all_ function names. And
     16       some names highlighted while others not looks ugly.
     17 */
     18 
     19 function pgsql(hljs) {
     20   var COMMENT_MODE = hljs.COMMENT('--', '$');
     21   var UNQUOTED_IDENT = '[a-zA-Z_][a-zA-Z_0-9$]*';
     22   var DOLLAR_STRING = '\\$([a-zA-Z_]?|[a-zA-Z_][a-zA-Z_0-9]*)\\$';
     23   var LABEL = '<<\\s*' + UNQUOTED_IDENT + '\\s*>>';
     24 
     25   var SQL_KW =
     26     // https://www.postgresql.org/docs/11/static/sql-keywords-appendix.html
     27     // https://www.postgresql.org/docs/11/static/sql-commands.html
     28     // SQL commands (starting words)
     29     'ABORT ALTER ANALYZE BEGIN CALL CHECKPOINT|10 CLOSE CLUSTER COMMENT COMMIT COPY CREATE DEALLOCATE DECLARE ' +
     30     'DELETE DISCARD DO DROP END EXECUTE EXPLAIN FETCH GRANT IMPORT INSERT LISTEN LOAD LOCK MOVE NOTIFY ' +
     31     'PREPARE REASSIGN|10 REFRESH REINDEX RELEASE RESET REVOKE ROLLBACK SAVEPOINT SECURITY SELECT SET SHOW ' +
     32     'START TRUNCATE UNLISTEN|10 UPDATE VACUUM|10 VALUES ' +
     33     // SQL commands (others)
     34     'AGGREGATE COLLATION CONVERSION|10 DATABASE DEFAULT PRIVILEGES DOMAIN TRIGGER EXTENSION FOREIGN ' +
     35     'WRAPPER|10 TABLE FUNCTION GROUP LANGUAGE LARGE OBJECT MATERIALIZED VIEW OPERATOR CLASS ' +
     36     'FAMILY POLICY PUBLICATION|10 ROLE RULE SCHEMA SEQUENCE SERVER STATISTICS SUBSCRIPTION SYSTEM ' +
     37     'TABLESPACE CONFIGURATION DICTIONARY PARSER TEMPLATE TYPE USER MAPPING PREPARED ACCESS ' +
     38     'METHOD CAST AS TRANSFORM TRANSACTION OWNED TO INTO SESSION AUTHORIZATION ' +
     39     'INDEX PROCEDURE ASSERTION ' +
     40     // additional reserved key words
     41     'ALL ANALYSE AND ANY ARRAY ASC ASYMMETRIC|10 BOTH CASE CHECK ' +
     42     'COLLATE COLUMN CONCURRENTLY|10 CONSTRAINT CROSS ' +
     43     'DEFERRABLE RANGE ' +
     44     'DESC DISTINCT ELSE EXCEPT FOR FREEZE|10 FROM FULL HAVING ' +
     45     'ILIKE IN INITIALLY INNER INTERSECT IS ISNULL JOIN LATERAL LEADING LIKE LIMIT ' +
     46     'NATURAL NOT NOTNULL NULL OFFSET ON ONLY OR ORDER OUTER OVERLAPS PLACING PRIMARY ' +
     47     'REFERENCES RETURNING SIMILAR SOME SYMMETRIC TABLESAMPLE THEN ' +
     48     'TRAILING UNION UNIQUE USING VARIADIC|10 VERBOSE WHEN WHERE WINDOW WITH ' +
     49     // some of non-reserved (which are used in clauses or as PL/pgSQL keyword)
     50     'BY RETURNS INOUT OUT SETOF|10 IF STRICT CURRENT CONTINUE OWNER LOCATION OVER PARTITION WITHIN ' +
     51     'BETWEEN ESCAPE EXTERNAL INVOKER DEFINER WORK RENAME VERSION CONNECTION CONNECT ' +
     52     'TABLES TEMP TEMPORARY FUNCTIONS SEQUENCES TYPES SCHEMAS OPTION CASCADE RESTRICT ADD ADMIN ' +
     53     'EXISTS VALID VALIDATE ENABLE DISABLE REPLICA|10 ALWAYS PASSING COLUMNS PATH ' +
     54     'REF VALUE OVERRIDING IMMUTABLE STABLE VOLATILE BEFORE AFTER EACH ROW PROCEDURAL ' +
     55     'ROUTINE NO HANDLER VALIDATOR OPTIONS STORAGE OIDS|10 WITHOUT INHERIT DEPENDS CALLED ' +
     56     'INPUT LEAKPROOF|10 COST ROWS NOWAIT SEARCH UNTIL ENCRYPTED|10 PASSWORD CONFLICT|10 ' +
     57     'INSTEAD INHERITS CHARACTERISTICS WRITE CURSOR ALSO STATEMENT SHARE EXCLUSIVE INLINE ' +
     58     'ISOLATION REPEATABLE READ COMMITTED SERIALIZABLE UNCOMMITTED LOCAL GLOBAL SQL PROCEDURES ' +
     59     'RECURSIVE SNAPSHOT ROLLUP CUBE TRUSTED|10 INCLUDE FOLLOWING PRECEDING UNBOUNDED RANGE GROUPS ' +
     60     'UNENCRYPTED|10 SYSID FORMAT DELIMITER HEADER QUOTE ENCODING FILTER OFF ' +
     61     // some parameters of VACUUM/ANALYZE/EXPLAIN
     62     'FORCE_QUOTE FORCE_NOT_NULL FORCE_NULL COSTS BUFFERS TIMING SUMMARY DISABLE_PAGE_SKIPPING ' +
     63     //
     64     'RESTART CYCLE GENERATED IDENTITY DEFERRED IMMEDIATE LEVEL LOGGED UNLOGGED ' +
     65     'OF NOTHING NONE EXCLUDE ATTRIBUTE ' +
     66     // from GRANT (not keywords actually)
     67     'USAGE ROUTINES ' +
     68     // actually literals, but look better this way (due to IS TRUE, IS FALSE, ISNULL etc)
     69     'TRUE FALSE NAN INFINITY ';
     70 
     71   var ROLE_ATTRS = // only those not in keywrods already
     72     'SUPERUSER NOSUPERUSER CREATEDB NOCREATEDB CREATEROLE NOCREATEROLE INHERIT NOINHERIT ' +
     73     'LOGIN NOLOGIN REPLICATION NOREPLICATION BYPASSRLS NOBYPASSRLS ';
     74 
     75   var PLPGSQL_KW =
     76     'ALIAS BEGIN CONSTANT DECLARE END EXCEPTION RETURN PERFORM|10 RAISE GET DIAGNOSTICS ' +
     77     'STACKED|10 FOREACH LOOP ELSIF EXIT WHILE REVERSE SLICE DEBUG LOG INFO NOTICE WARNING ASSERT ' +
     78     'OPEN ';
     79 
     80   var TYPES =
     81     // https://www.postgresql.org/docs/11/static/datatype.html
     82     'BIGINT INT8 BIGSERIAL SERIAL8 BIT VARYING VARBIT BOOLEAN BOOL BOX BYTEA CHARACTER CHAR VARCHAR ' +
     83     'CIDR CIRCLE DATE DOUBLE PRECISION FLOAT8 FLOAT INET INTEGER INT INT4 INTERVAL JSON JSONB LINE LSEG|10 ' +
     84     'MACADDR MACADDR8 MONEY NUMERIC DEC DECIMAL PATH POINT POLYGON REAL FLOAT4 SMALLINT INT2 ' +
     85     'SMALLSERIAL|10 SERIAL2|10 SERIAL|10 SERIAL4|10 TEXT TIME ZONE TIMETZ|10 TIMESTAMP TIMESTAMPTZ|10 TSQUERY|10 TSVECTOR|10 ' +
     86     'TXID_SNAPSHOT|10 UUID XML NATIONAL NCHAR ' +
     87     'INT4RANGE|10 INT8RANGE|10 NUMRANGE|10 TSRANGE|10 TSTZRANGE|10 DATERANGE|10 ' +
     88     // pseudotypes
     89     'ANYELEMENT ANYARRAY ANYNONARRAY ANYENUM ANYRANGE CSTRING INTERNAL ' +
     90     'RECORD PG_DDL_COMMAND VOID UNKNOWN OPAQUE REFCURSOR ' +
     91     // spec. type
     92     'NAME ' +
     93     // OID-types
     94     'OID REGPROC|10 REGPROCEDURE|10 REGOPER|10 REGOPERATOR|10 REGCLASS|10 REGTYPE|10 REGROLE|10 ' +
     95     'REGNAMESPACE|10 REGCONFIG|10 REGDICTIONARY|10 ';// +
     96 
     97   var TYPES_RE =
     98     TYPES.trim()
     99          .split(' ')
    100          .map( function(val) { return val.split('|')[0]; } )
    101          .join('|');
    102 
    103   var SQL_BI =
    104     'CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURRENT_CATALOG|10 CURRENT_DATE LOCALTIME LOCALTIMESTAMP ' +
    105     'CURRENT_ROLE|10 CURRENT_SCHEMA|10 SESSION_USER PUBLIC ';
    106 
    107   var PLPGSQL_BI =
    108     'FOUND NEW OLD TG_NAME|10 TG_WHEN|10 TG_LEVEL|10 TG_OP|10 TG_RELID|10 TG_RELNAME|10 ' +
    109     'TG_TABLE_NAME|10 TG_TABLE_SCHEMA|10 TG_NARGS|10 TG_ARGV|10 TG_EVENT|10 TG_TAG|10 ' +
    110     // get diagnostics
    111     'ROW_COUNT RESULT_OID|10 PG_CONTEXT|10 RETURNED_SQLSTATE COLUMN_NAME CONSTRAINT_NAME ' +
    112     'PG_DATATYPE_NAME|10 MESSAGE_TEXT TABLE_NAME SCHEMA_NAME PG_EXCEPTION_DETAIL|10 ' +
    113     'PG_EXCEPTION_HINT|10 PG_EXCEPTION_CONTEXT|10 ';
    114 
    115   var PLPGSQL_EXCEPTIONS =
    116     // exceptions https://www.postgresql.org/docs/current/static/errcodes-appendix.html
    117     'SQLSTATE SQLERRM|10 ' +
    118     'SUCCESSFUL_COMPLETION WARNING DYNAMIC_RESULT_SETS_RETURNED IMPLICIT_ZERO_BIT_PADDING ' +
    119     'NULL_VALUE_ELIMINATED_IN_SET_FUNCTION PRIVILEGE_NOT_GRANTED PRIVILEGE_NOT_REVOKED ' +
    120     'STRING_DATA_RIGHT_TRUNCATION DEPRECATED_FEATURE NO_DATA NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED ' +
    121     'SQL_STATEMENT_NOT_YET_COMPLETE CONNECTION_EXCEPTION CONNECTION_DOES_NOT_EXIST CONNECTION_FAILURE ' +
    122     'SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION ' +
    123     'TRANSACTION_RESOLUTION_UNKNOWN PROTOCOL_VIOLATION TRIGGERED_ACTION_EXCEPTION FEATURE_NOT_SUPPORTED ' +
    124     'INVALID_TRANSACTION_INITIATION LOCATOR_EXCEPTION INVALID_LOCATOR_SPECIFICATION INVALID_GRANTOR ' +
    125     'INVALID_GRANT_OPERATION INVALID_ROLE_SPECIFICATION DIAGNOSTICS_EXCEPTION ' +
    126     'STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER CASE_NOT_FOUND CARDINALITY_VIOLATION ' +
    127     'DATA_EXCEPTION ARRAY_SUBSCRIPT_ERROR CHARACTER_NOT_IN_REPERTOIRE DATETIME_FIELD_OVERFLOW ' +
    128     'DIVISION_BY_ZERO ERROR_IN_ASSIGNMENT ESCAPE_CHARACTER_CONFLICT INDICATOR_OVERFLOW ' +
    129     'INTERVAL_FIELD_OVERFLOW INVALID_ARGUMENT_FOR_LOGARITHM INVALID_ARGUMENT_FOR_NTILE_FUNCTION ' +
    130     'INVALID_ARGUMENT_FOR_NTH_VALUE_FUNCTION INVALID_ARGUMENT_FOR_POWER_FUNCTION ' +
    131     'INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION INVALID_CHARACTER_VALUE_FOR_CAST ' +
    132     'INVALID_DATETIME_FORMAT INVALID_ESCAPE_CHARACTER INVALID_ESCAPE_OCTET INVALID_ESCAPE_SEQUENCE ' +
    133     'NONSTANDARD_USE_OF_ESCAPE_CHARACTER INVALID_INDICATOR_PARAMETER_VALUE INVALID_PARAMETER_VALUE ' +
    134     'INVALID_REGULAR_EXPRESSION INVALID_ROW_COUNT_IN_LIMIT_CLAUSE ' +
    135     'INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE INVALID_TABLESAMPLE_ARGUMENT INVALID_TABLESAMPLE_REPEAT ' +
    136     'INVALID_TIME_ZONE_DISPLACEMENT_VALUE INVALID_USE_OF_ESCAPE_CHARACTER MOST_SPECIFIC_TYPE_MISMATCH ' +
    137     'NULL_VALUE_NOT_ALLOWED NULL_VALUE_NO_INDICATOR_PARAMETER NUMERIC_VALUE_OUT_OF_RANGE ' +
    138     'SEQUENCE_GENERATOR_LIMIT_EXCEEDED STRING_DATA_LENGTH_MISMATCH STRING_DATA_RIGHT_TRUNCATION ' +
    139     'SUBSTRING_ERROR TRIM_ERROR UNTERMINATED_C_STRING ZERO_LENGTH_CHARACTER_STRING ' +
    140     'FLOATING_POINT_EXCEPTION INVALID_TEXT_REPRESENTATION INVALID_BINARY_REPRESENTATION ' +
    141     'BAD_COPY_FILE_FORMAT UNTRANSLATABLE_CHARACTER NOT_AN_XML_DOCUMENT INVALID_XML_DOCUMENT ' +
    142     'INVALID_XML_CONTENT INVALID_XML_COMMENT INVALID_XML_PROCESSING_INSTRUCTION ' +
    143     'INTEGRITY_CONSTRAINT_VIOLATION RESTRICT_VIOLATION NOT_NULL_VIOLATION FOREIGN_KEY_VIOLATION ' +
    144     'UNIQUE_VIOLATION CHECK_VIOLATION EXCLUSION_VIOLATION INVALID_CURSOR_STATE ' +
    145     'INVALID_TRANSACTION_STATE ACTIVE_SQL_TRANSACTION BRANCH_TRANSACTION_ALREADY_ACTIVE ' +
    146     'HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION ' +
    147     'INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION ' +
    148     'NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION READ_ONLY_SQL_TRANSACTION ' +
    149     'SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED NO_ACTIVE_SQL_TRANSACTION ' +
    150     'IN_FAILED_SQL_TRANSACTION IDLE_IN_TRANSACTION_SESSION_TIMEOUT INVALID_SQL_STATEMENT_NAME ' +
    151     'TRIGGERED_DATA_CHANGE_VIOLATION INVALID_AUTHORIZATION_SPECIFICATION INVALID_PASSWORD ' +
    152     'DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST DEPENDENT_OBJECTS_STILL_EXIST ' +
    153     'INVALID_TRANSACTION_TERMINATION SQL_ROUTINE_EXCEPTION FUNCTION_EXECUTED_NO_RETURN_STATEMENT ' +
    154     'MODIFYING_SQL_DATA_NOT_PERMITTED PROHIBITED_SQL_STATEMENT_ATTEMPTED ' +
    155     'READING_SQL_DATA_NOT_PERMITTED INVALID_CURSOR_NAME EXTERNAL_ROUTINE_EXCEPTION ' +
    156     'CONTAINING_SQL_NOT_PERMITTED MODIFYING_SQL_DATA_NOT_PERMITTED ' +
    157     'PROHIBITED_SQL_STATEMENT_ATTEMPTED READING_SQL_DATA_NOT_PERMITTED ' +
    158     'EXTERNAL_ROUTINE_INVOCATION_EXCEPTION INVALID_SQLSTATE_RETURNED NULL_VALUE_NOT_ALLOWED ' +
    159     'TRIGGER_PROTOCOL_VIOLATED SRF_PROTOCOL_VIOLATED EVENT_TRIGGER_PROTOCOL_VIOLATED ' +
    160     'SAVEPOINT_EXCEPTION INVALID_SAVEPOINT_SPECIFICATION INVALID_CATALOG_NAME ' +
    161     'INVALID_SCHEMA_NAME TRANSACTION_ROLLBACK TRANSACTION_INTEGRITY_CONSTRAINT_VIOLATION ' +
    162     'SERIALIZATION_FAILURE STATEMENT_COMPLETION_UNKNOWN DEADLOCK_DETECTED ' +
    163     'SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION SYNTAX_ERROR INSUFFICIENT_PRIVILEGE CANNOT_COERCE ' +
    164     'GROUPING_ERROR WINDOWING_ERROR INVALID_RECURSION INVALID_FOREIGN_KEY INVALID_NAME ' +
    165     'NAME_TOO_LONG RESERVED_NAME DATATYPE_MISMATCH INDETERMINATE_DATATYPE COLLATION_MISMATCH ' +
    166     'INDETERMINATE_COLLATION WRONG_OBJECT_TYPE GENERATED_ALWAYS UNDEFINED_COLUMN ' +
    167     'UNDEFINED_FUNCTION UNDEFINED_TABLE UNDEFINED_PARAMETER UNDEFINED_OBJECT ' +
    168     'DUPLICATE_COLUMN DUPLICATE_CURSOR DUPLICATE_DATABASE DUPLICATE_FUNCTION ' +
    169     'DUPLICATE_PREPARED_STATEMENT DUPLICATE_SCHEMA DUPLICATE_TABLE DUPLICATE_ALIAS ' +
    170     'DUPLICATE_OBJECT AMBIGUOUS_COLUMN AMBIGUOUS_FUNCTION AMBIGUOUS_PARAMETER AMBIGUOUS_ALIAS ' +
    171     'INVALID_COLUMN_REFERENCE INVALID_COLUMN_DEFINITION INVALID_CURSOR_DEFINITION ' +
    172     'INVALID_DATABASE_DEFINITION INVALID_FUNCTION_DEFINITION ' +
    173     'INVALID_PREPARED_STATEMENT_DEFINITION INVALID_SCHEMA_DEFINITION INVALID_TABLE_DEFINITION ' +
    174     'INVALID_OBJECT_DEFINITION WITH_CHECK_OPTION_VIOLATION INSUFFICIENT_RESOURCES DISK_FULL ' +
    175     'OUT_OF_MEMORY TOO_MANY_CONNECTIONS CONFIGURATION_LIMIT_EXCEEDED PROGRAM_LIMIT_EXCEEDED ' +
    176     'STATEMENT_TOO_COMPLEX TOO_MANY_COLUMNS TOO_MANY_ARGUMENTS OBJECT_NOT_IN_PREREQUISITE_STATE ' +
    177     'OBJECT_IN_USE CANT_CHANGE_RUNTIME_PARAM LOCK_NOT_AVAILABLE OPERATOR_INTERVENTION ' +
    178     'QUERY_CANCELED ADMIN_SHUTDOWN CRASH_SHUTDOWN CANNOT_CONNECT_NOW DATABASE_DROPPED ' +
    179     'SYSTEM_ERROR IO_ERROR UNDEFINED_FILE DUPLICATE_FILE SNAPSHOT_TOO_OLD CONFIG_FILE_ERROR ' +
    180     'LOCK_FILE_EXISTS FDW_ERROR FDW_COLUMN_NAME_NOT_FOUND FDW_DYNAMIC_PARAMETER_VALUE_NEEDED ' +
    181     'FDW_FUNCTION_SEQUENCE_ERROR FDW_INCONSISTENT_DESCRIPTOR_INFORMATION ' +
    182     'FDW_INVALID_ATTRIBUTE_VALUE FDW_INVALID_COLUMN_NAME FDW_INVALID_COLUMN_NUMBER ' +
    183     'FDW_INVALID_DATA_TYPE FDW_INVALID_DATA_TYPE_DESCRIPTORS ' +
    184     'FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER FDW_INVALID_HANDLE FDW_INVALID_OPTION_INDEX ' +
    185     'FDW_INVALID_OPTION_NAME FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH ' +
    186     'FDW_INVALID_STRING_FORMAT FDW_INVALID_USE_OF_NULL_POINTER FDW_TOO_MANY_HANDLES ' +
    187     'FDW_OUT_OF_MEMORY FDW_NO_SCHEMAS FDW_OPTION_NAME_NOT_FOUND FDW_REPLY_HANDLE ' +
    188     'FDW_SCHEMA_NOT_FOUND FDW_TABLE_NOT_FOUND FDW_UNABLE_TO_CREATE_EXECUTION ' +
    189     'FDW_UNABLE_TO_CREATE_REPLY FDW_UNABLE_TO_ESTABLISH_CONNECTION PLPGSQL_ERROR ' +
    190     'RAISE_EXCEPTION NO_DATA_FOUND TOO_MANY_ROWS ASSERT_FAILURE INTERNAL_ERROR DATA_CORRUPTED ' +
    191     'INDEX_CORRUPTED ';
    192 
    193   var FUNCTIONS =
    194     // https://www.postgresql.org/docs/11/static/functions-aggregate.html
    195     'ARRAY_AGG AVG BIT_AND BIT_OR BOOL_AND BOOL_OR COUNT EVERY JSON_AGG JSONB_AGG JSON_OBJECT_AGG ' +
    196     'JSONB_OBJECT_AGG MAX MIN MODE STRING_AGG SUM XMLAGG ' +
    197     'CORR COVAR_POP COVAR_SAMP REGR_AVGX REGR_AVGY REGR_COUNT REGR_INTERCEPT REGR_R2 REGR_SLOPE ' +
    198     'REGR_SXX REGR_SXY REGR_SYY STDDEV STDDEV_POP STDDEV_SAMP VARIANCE VAR_POP VAR_SAMP ' +
    199     'PERCENTILE_CONT PERCENTILE_DISC ' +
    200     // https://www.postgresql.org/docs/11/static/functions-window.html
    201     'ROW_NUMBER RANK DENSE_RANK PERCENT_RANK CUME_DIST NTILE LAG LEAD FIRST_VALUE LAST_VALUE NTH_VALUE ' +
    202     // https://www.postgresql.org/docs/11/static/functions-comparison.html
    203     'NUM_NONNULLS NUM_NULLS ' +
    204     // https://www.postgresql.org/docs/11/static/functions-math.html
    205     'ABS CBRT CEIL CEILING DEGREES DIV EXP FLOOR LN LOG MOD PI POWER RADIANS ROUND SCALE SIGN SQRT ' +
    206     'TRUNC WIDTH_BUCKET ' +
    207     'RANDOM SETSEED ' +
    208     'ACOS ACOSD ASIN ASIND ATAN ATAND ATAN2 ATAN2D COS COSD COT COTD SIN SIND TAN TAND ' +
    209     // https://www.postgresql.org/docs/11/static/functions-string.html
    210     'BIT_LENGTH CHAR_LENGTH CHARACTER_LENGTH LOWER OCTET_LENGTH OVERLAY POSITION SUBSTRING TREAT TRIM UPPER ' +
    211     'ASCII BTRIM CHR CONCAT CONCAT_WS CONVERT CONVERT_FROM CONVERT_TO DECODE ENCODE INITCAP ' +
    212     'LEFT LENGTH LPAD LTRIM MD5 PARSE_IDENT PG_CLIENT_ENCODING QUOTE_IDENT|10 QUOTE_LITERAL|10 ' +
    213     'QUOTE_NULLABLE|10 REGEXP_MATCH REGEXP_MATCHES REGEXP_REPLACE REGEXP_SPLIT_TO_ARRAY ' +
    214     'REGEXP_SPLIT_TO_TABLE REPEAT REPLACE REVERSE RIGHT RPAD RTRIM SPLIT_PART STRPOS SUBSTR ' +
    215     'TO_ASCII TO_HEX TRANSLATE ' +
    216     // https://www.postgresql.org/docs/11/static/functions-binarystring.html
    217     'OCTET_LENGTH GET_BIT GET_BYTE SET_BIT SET_BYTE ' +
    218     // https://www.postgresql.org/docs/11/static/functions-formatting.html
    219     'TO_CHAR TO_DATE TO_NUMBER TO_TIMESTAMP ' +
    220     // https://www.postgresql.org/docs/11/static/functions-datetime.html
    221     'AGE CLOCK_TIMESTAMP|10 DATE_PART DATE_TRUNC ISFINITE JUSTIFY_DAYS JUSTIFY_HOURS JUSTIFY_INTERVAL ' +
    222     'MAKE_DATE MAKE_INTERVAL|10 MAKE_TIME MAKE_TIMESTAMP|10 MAKE_TIMESTAMPTZ|10 NOW STATEMENT_TIMESTAMP|10 ' +
    223     'TIMEOFDAY TRANSACTION_TIMESTAMP|10 ' +
    224     // https://www.postgresql.org/docs/11/static/functions-enum.html
    225     'ENUM_FIRST ENUM_LAST ENUM_RANGE ' +
    226     // https://www.postgresql.org/docs/11/static/functions-geometry.html
    227     'AREA CENTER DIAMETER HEIGHT ISCLOSED ISOPEN NPOINTS PCLOSE POPEN RADIUS WIDTH ' +
    228     'BOX BOUND_BOX CIRCLE LINE LSEG PATH POLYGON ' +
    229     // https://www.postgresql.org/docs/11/static/functions-net.html
    230     'ABBREV BROADCAST HOST HOSTMASK MASKLEN NETMASK NETWORK SET_MASKLEN TEXT INET_SAME_FAMILY ' +
    231     'INET_MERGE MACADDR8_SET7BIT ' +
    232     // https://www.postgresql.org/docs/11/static/functions-textsearch.html
    233     'ARRAY_TO_TSVECTOR GET_CURRENT_TS_CONFIG NUMNODE PLAINTO_TSQUERY PHRASETO_TSQUERY WEBSEARCH_TO_TSQUERY ' +
    234     'QUERYTREE SETWEIGHT STRIP TO_TSQUERY TO_TSVECTOR JSON_TO_TSVECTOR JSONB_TO_TSVECTOR TS_DELETE ' +
    235     'TS_FILTER TS_HEADLINE TS_RANK TS_RANK_CD TS_REWRITE TSQUERY_PHRASE TSVECTOR_TO_ARRAY ' +
    236     'TSVECTOR_UPDATE_TRIGGER TSVECTOR_UPDATE_TRIGGER_COLUMN ' +
    237     // https://www.postgresql.org/docs/11/static/functions-xml.html
    238     'XMLCOMMENT XMLCONCAT XMLELEMENT XMLFOREST XMLPI XMLROOT ' +
    239     'XMLEXISTS XML_IS_WELL_FORMED XML_IS_WELL_FORMED_DOCUMENT XML_IS_WELL_FORMED_CONTENT ' +
    240     'XPATH XPATH_EXISTS XMLTABLE XMLNAMESPACES ' +
    241     'TABLE_TO_XML TABLE_TO_XMLSCHEMA TABLE_TO_XML_AND_XMLSCHEMA ' +
    242     'QUERY_TO_XML QUERY_TO_XMLSCHEMA QUERY_TO_XML_AND_XMLSCHEMA ' +
    243     'CURSOR_TO_XML CURSOR_TO_XMLSCHEMA ' +
    244     'SCHEMA_TO_XML SCHEMA_TO_XMLSCHEMA SCHEMA_TO_XML_AND_XMLSCHEMA ' +
    245     'DATABASE_TO_XML DATABASE_TO_XMLSCHEMA DATABASE_TO_XML_AND_XMLSCHEMA ' +
    246     'XMLATTRIBUTES ' +
    247     // https://www.postgresql.org/docs/11/static/functions-json.html
    248     'TO_JSON TO_JSONB ARRAY_TO_JSON ROW_TO_JSON JSON_BUILD_ARRAY JSONB_BUILD_ARRAY JSON_BUILD_OBJECT ' +
    249     'JSONB_BUILD_OBJECT JSON_OBJECT JSONB_OBJECT JSON_ARRAY_LENGTH JSONB_ARRAY_LENGTH JSON_EACH ' +
    250     'JSONB_EACH JSON_EACH_TEXT JSONB_EACH_TEXT JSON_EXTRACT_PATH JSONB_EXTRACT_PATH ' +
    251     'JSON_OBJECT_KEYS JSONB_OBJECT_KEYS JSON_POPULATE_RECORD JSONB_POPULATE_RECORD JSON_POPULATE_RECORDSET ' +
    252     'JSONB_POPULATE_RECORDSET JSON_ARRAY_ELEMENTS JSONB_ARRAY_ELEMENTS JSON_ARRAY_ELEMENTS_TEXT ' +
    253     'JSONB_ARRAY_ELEMENTS_TEXT JSON_TYPEOF JSONB_TYPEOF JSON_TO_RECORD JSONB_TO_RECORD JSON_TO_RECORDSET ' +
    254     'JSONB_TO_RECORDSET JSON_STRIP_NULLS JSONB_STRIP_NULLS JSONB_SET JSONB_INSERT JSONB_PRETTY ' +
    255     // https://www.postgresql.org/docs/11/static/functions-sequence.html
    256     'CURRVAL LASTVAL NEXTVAL SETVAL ' +
    257     // https://www.postgresql.org/docs/11/static/functions-conditional.html
    258     'COALESCE NULLIF GREATEST LEAST ' +
    259     // https://www.postgresql.org/docs/11/static/functions-array.html
    260     'ARRAY_APPEND ARRAY_CAT ARRAY_NDIMS ARRAY_DIMS ARRAY_FILL ARRAY_LENGTH ARRAY_LOWER ARRAY_POSITION ' +
    261     'ARRAY_POSITIONS ARRAY_PREPEND ARRAY_REMOVE ARRAY_REPLACE ARRAY_TO_STRING ARRAY_UPPER CARDINALITY ' +
    262     'STRING_TO_ARRAY UNNEST ' +
    263     // https://www.postgresql.org/docs/11/static/functions-range.html
    264     'ISEMPTY LOWER_INC UPPER_INC LOWER_INF UPPER_INF RANGE_MERGE ' +
    265     // https://www.postgresql.org/docs/11/static/functions-srf.html
    266     'GENERATE_SERIES GENERATE_SUBSCRIPTS ' +
    267     // https://www.postgresql.org/docs/11/static/functions-info.html
    268     'CURRENT_DATABASE CURRENT_QUERY CURRENT_SCHEMA|10 CURRENT_SCHEMAS|10 INET_CLIENT_ADDR INET_CLIENT_PORT ' +
    269     'INET_SERVER_ADDR INET_SERVER_PORT ROW_SECURITY_ACTIVE FORMAT_TYPE ' +
    270     'TO_REGCLASS TO_REGPROC TO_REGPROCEDURE TO_REGOPER TO_REGOPERATOR TO_REGTYPE TO_REGNAMESPACE TO_REGROLE ' +
    271     'COL_DESCRIPTION OBJ_DESCRIPTION SHOBJ_DESCRIPTION ' +
    272     'TXID_CURRENT TXID_CURRENT_IF_ASSIGNED TXID_CURRENT_SNAPSHOT TXID_SNAPSHOT_XIP TXID_SNAPSHOT_XMAX ' +
    273     'TXID_SNAPSHOT_XMIN TXID_VISIBLE_IN_SNAPSHOT TXID_STATUS ' +
    274     // https://www.postgresql.org/docs/11/static/functions-admin.html
    275     'CURRENT_SETTING SET_CONFIG BRIN_SUMMARIZE_NEW_VALUES BRIN_SUMMARIZE_RANGE BRIN_DESUMMARIZE_RANGE ' +
    276     'GIN_CLEAN_PENDING_LIST ' +
    277     // https://www.postgresql.org/docs/11/static/functions-trigger.html
    278     'SUPPRESS_REDUNDANT_UPDATES_TRIGGER ' +
    279     // ihttps://www.postgresql.org/docs/devel/static/lo-funcs.html
    280     'LO_FROM_BYTEA LO_PUT LO_GET LO_CREAT LO_CREATE LO_UNLINK LO_IMPORT LO_EXPORT LOREAD LOWRITE ' +
    281     //
    282     'GROUPING CAST ';
    283 
    284     var FUNCTIONS_RE =
    285       FUNCTIONS.trim()
    286                .split(' ')
    287                .map( function(val) { return val.split('|')[0]; } )
    288                .join('|');
    289 
    290     return {
    291         name: 'PostgreSQL',
    292         aliases: ['postgres','postgresql'],
    293         case_insensitive: true,
    294         keywords: {
    295           keyword:
    296             SQL_KW + PLPGSQL_KW + ROLE_ATTRS,
    297           built_in:
    298             SQL_BI + PLPGSQL_BI + PLPGSQL_EXCEPTIONS,
    299         },
    300         // Forbid some cunstructs from other languages to improve autodetect. In fact
    301         // "[a-z]:" is legal (as part of array slice), but improbabal.
    302         illegal: /:==|\W\s*\(\*|(^|\s)\$[a-z]|{{|[a-z]:\s*$|\.\.\.|TO:|DO:/,
    303         contains: [
    304           // special handling of some words, which are reserved only in some contexts
    305           {
    306             className: 'keyword',
    307             variants: [
    308               { begin: /\bTEXT\s*SEARCH\b/ },
    309               { begin: /\b(PRIMARY|FOREIGN|FOR(\s+NO)?)\s+KEY\b/ },
    310               { begin: /\bPARALLEL\s+(UNSAFE|RESTRICTED|SAFE)\b/ },
    311               { begin: /\bSTORAGE\s+(PLAIN|EXTERNAL|EXTENDED|MAIN)\b/ },
    312               { begin: /\bMATCH\s+(FULL|PARTIAL|SIMPLE)\b/ },
    313               { begin: /\bNULLS\s+(FIRST|LAST)\b/ },
    314               { begin: /\bEVENT\s+TRIGGER\b/ },
    315               { begin: /\b(MAPPING|OR)\s+REPLACE\b/ },
    316               { begin: /\b(FROM|TO)\s+(PROGRAM|STDIN|STDOUT)\b/ },
    317               { begin: /\b(SHARE|EXCLUSIVE)\s+MODE\b/ },
    318               { begin: /\b(LEFT|RIGHT)\s+(OUTER\s+)?JOIN\b/ },
    319               { begin: /\b(FETCH|MOVE)\s+(NEXT|PRIOR|FIRST|LAST|ABSOLUTE|RELATIVE|FORWARD|BACKWARD)\b/ },
    320               { begin: /\bPRESERVE\s+ROWS\b/ },
    321               { begin: /\bDISCARD\s+PLANS\b/ },
    322               { begin: /\bREFERENCING\s+(OLD|NEW)\b/ },
    323               { begin: /\bSKIP\s+LOCKED\b/ },
    324               { begin: /\bGROUPING\s+SETS\b/ },
    325               { begin: /\b(BINARY|INSENSITIVE|SCROLL|NO\s+SCROLL)\s+(CURSOR|FOR)\b/ },
    326               { begin: /\b(WITH|WITHOUT)\s+HOLD\b/ },
    327               { begin: /\bWITH\s+(CASCADED|LOCAL)\s+CHECK\s+OPTION\b/ },
    328               { begin: /\bEXCLUDE\s+(TIES|NO\s+OTHERS)\b/ },
    329               { begin: /\bFORMAT\s+(TEXT|XML|JSON|YAML)\b/ },
    330               { begin: /\bSET\s+((SESSION|LOCAL)\s+)?NAMES\b/ },
    331               { begin: /\bIS\s+(NOT\s+)?UNKNOWN\b/ },
    332               { begin: /\bSECURITY\s+LABEL\b/ },
    333               { begin: /\bSTANDALONE\s+(YES|NO|NO\s+VALUE)\b/ },
    334               { begin: /\bWITH\s+(NO\s+)?DATA\b/ },
    335               { begin: /\b(FOREIGN|SET)\s+DATA\b/ },
    336               { begin: /\bSET\s+(CATALOG|CONSTRAINTS)\b/ },
    337               { begin: /\b(WITH|FOR)\s+ORDINALITY\b/ },
    338               { begin: /\bIS\s+(NOT\s+)?DOCUMENT\b/ },
    339               { begin: /\bXML\s+OPTION\s+(DOCUMENT|CONTENT)\b/ },
    340               { begin: /\b(STRIP|PRESERVE)\s+WHITESPACE\b/ },
    341               { begin: /\bNO\s+(ACTION|MAXVALUE|MINVALUE)\b/ },
    342               { begin: /\bPARTITION\s+BY\s+(RANGE|LIST|HASH)\b/ },
    343               { begin: /\bAT\s+TIME\s+ZONE\b/ },
    344               { begin: /\bGRANTED\s+BY\b/ },
    345               { begin: /\bRETURN\s+(QUERY|NEXT)\b/ },
    346               { begin: /\b(ATTACH|DETACH)\s+PARTITION\b/ },
    347               { begin: /\bFORCE\s+ROW\s+LEVEL\s+SECURITY\b/ },
    348               { begin: /\b(INCLUDING|EXCLUDING)\s+(COMMENTS|CONSTRAINTS|DEFAULTS|IDENTITY|INDEXES|STATISTICS|STORAGE|ALL)\b/ },
    349               { begin: /\bAS\s+(ASSIGNMENT|IMPLICIT|PERMISSIVE|RESTRICTIVE|ENUM|RANGE)\b/ }
    350             ]
    351           },
    352           // functions named as keywords, followed by '('
    353           {
    354             begin: /\b(FORMAT|FAMILY|VERSION)\s*\(/,
    355             //keywords: { built_in: 'FORMAT FAMILY VERSION' }
    356           },
    357           // INCLUDE ( ... ) in index_parameters in CREATE TABLE
    358           {
    359             begin: /\bINCLUDE\s*\(/,
    360             keywords: 'INCLUDE'
    361           },
    362           // not highlight RANGE if not in frame_clause (not 100% correct, but seems satisfactory)
    363           {
    364             begin: /\bRANGE(?!\s*(BETWEEN|UNBOUNDED|CURRENT|[-0-9]+))/
    365           },
    366           // disable highlighting in commands CREATE AGGREGATE/COLLATION/DATABASE/OPERTOR/TEXT SEARCH .../TYPE
    367           // and in PL/pgSQL RAISE ... USING
    368           {
    369             begin: /\b(VERSION|OWNER|TEMPLATE|TABLESPACE|CONNECTION\s+LIMIT|PROCEDURE|RESTRICT|JOIN|PARSER|COPY|START|END|COLLATION|INPUT|ANALYZE|STORAGE|LIKE|DEFAULT|DELIMITER|ENCODING|COLUMN|CONSTRAINT|TABLE|SCHEMA)\s*=/
    370           },
    371           // PG_smth; HAS_some_PRIVILEGE
    372           {
    373             //className: 'built_in',
    374             begin: /\b(PG_\w+?|HAS_[A-Z_]+_PRIVILEGE)\b/,
    375             relevance: 10
    376           },
    377           // extract
    378           {
    379             begin: /\bEXTRACT\s*\(/,
    380             end: /\bFROM\b/,
    381             returnEnd: true,
    382             keywords: {
    383               //built_in: 'EXTRACT',
    384               type:     'CENTURY DAY DECADE DOW DOY EPOCH HOUR ISODOW ISOYEAR MICROSECONDS ' +
    385                         'MILLENNIUM MILLISECONDS MINUTE MONTH QUARTER SECOND TIMEZONE TIMEZONE_HOUR ' +
    386                         'TIMEZONE_MINUTE WEEK YEAR'
    387             }
    388           },
    389           // xmlelement, xmlpi - special NAME
    390           {
    391             begin: /\b(XMLELEMENT|XMLPI)\s*\(\s*NAME/,
    392             keywords: {
    393               //built_in: 'XMLELEMENT XMLPI',
    394               keyword:  'NAME'
    395             }
    396           },
    397           // xmlparse, xmlserialize
    398           {
    399             begin: /\b(XMLPARSE|XMLSERIALIZE)\s*\(\s*(DOCUMENT|CONTENT)/,
    400             keywords: {
    401               //built_in: 'XMLPARSE XMLSERIALIZE',
    402               keyword:  'DOCUMENT CONTENT'
    403             }
    404           },
    405           // Sequences. We actually skip everything between CACHE|INCREMENT|MAXVALUE|MINVALUE and
    406           // nearest following numeric constant. Without with trick we find a lot of "keywords"
    407           // in 'avrasm' autodetection test...
    408           {
    409             beginKeywords: 'CACHE INCREMENT MAXVALUE MINVALUE',
    410             end: hljs.C_NUMBER_RE,
    411             returnEnd: true,
    412             keywords: 'BY CACHE INCREMENT MAXVALUE MINVALUE'
    413           },
    414           // WITH|WITHOUT TIME ZONE as part of datatype
    415           {
    416             className: 'type',
    417             begin: /\b(WITH|WITHOUT)\s+TIME\s+ZONE\b/
    418           },
    419           // INTERVAL optional fields
    420           {
    421             className: 'type',
    422             begin: /\bINTERVAL\s+(YEAR|MONTH|DAY|HOUR|MINUTE|SECOND)(\s+TO\s+(MONTH|HOUR|MINUTE|SECOND))?\b/
    423           },
    424           // Pseudo-types which allowed only as return type
    425           {
    426             begin: /\bRETURNS\s+(LANGUAGE_HANDLER|TRIGGER|EVENT_TRIGGER|FDW_HANDLER|INDEX_AM_HANDLER|TSM_HANDLER)\b/,
    427             keywords: {
    428               keyword: 'RETURNS',
    429               type: 'LANGUAGE_HANDLER TRIGGER EVENT_TRIGGER FDW_HANDLER INDEX_AM_HANDLER TSM_HANDLER'
    430             }
    431           },
    432           // Known functions - only when followed by '('
    433           {
    434             begin: '\\b(' + FUNCTIONS_RE + ')\\s*\\('
    435             //keywords: { built_in: FUNCTIONS }
    436           },
    437           // Types
    438           {
    439             begin: '\\.(' + TYPES_RE + ')\\b' // prevent highlight as type, say, 'oid' in 'pgclass.oid'
    440           },
    441           {
    442             begin: '\\b(' + TYPES_RE + ')\\s+PATH\\b', // in XMLTABLE
    443             keywords: {
    444               keyword: 'PATH', // hopefully no one would use PATH type in XMLTABLE...
    445               type: TYPES.replace('PATH ','')
    446             }
    447           },
    448           {
    449             className: 'type',
    450             begin: '\\b(' + TYPES_RE + ')\\b'
    451           },
    452           // Strings, see https://www.postgresql.org/docs/11/static/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS
    453           {
    454             className: 'string',
    455             begin: '\'', end: '\'',
    456             contains: [{begin: '\'\''}]
    457           },
    458           {
    459             className: 'string',
    460             begin: '(e|E|u&|U&)\'', end: '\'',
    461             contains: [{begin: '\\\\.'}],
    462             relevance: 10
    463           },
    464           hljs.END_SAME_AS_BEGIN({
    465             begin: DOLLAR_STRING,
    466             end: DOLLAR_STRING,
    467             contains: [
    468               {
    469                 // actually we want them all except SQL; listed are those with known implementations
    470                 // and XML + JSON just in case
    471                 subLanguage: ['pgsql','perl','python','tcl','r','lua','java','php','ruby','bash','scheme','xml','json'],
    472                 endsWithParent: true
    473               }
    474             ]
    475           }),
    476           // identifiers in quotes
    477           {
    478             begin: '"', end: '"',
    479             contains: [{begin: '""'}]
    480           },
    481           // numbers
    482           hljs.C_NUMBER_MODE,
    483           // comments
    484           hljs.C_BLOCK_COMMENT_MODE,
    485           COMMENT_MODE,
    486           // PL/pgSQL staff
    487           // %ROWTYPE, %TYPE, $n
    488           {
    489             className: 'meta',
    490             variants: [
    491               {begin: '%(ROW)?TYPE', relevance: 10}, // %TYPE, %ROWTYPE
    492               {begin: '\\$\\d+'},                    // $n
    493               {begin: '^#\\w', end: '$'}             // #compiler option
    494             ]
    495           },
    496           // <<labeles>>
    497           {
    498             className: 'symbol',
    499             begin: LABEL,
    500             relevance: 10
    501           }
    502         ]
    503   };
    504 }
    505 
    506 module.exports = pgsql;