#!/usr/bin/env python # -*- coding: latin-1; -*- # # PgWorksheet - PostgreSQL Front End # http://pgworksheet.projects.postgresql.org/ # # Copyright © 2004-2005 Henri Michelon & CML http://www.e-cml.org/ # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details (read LICENSE.txt). # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # $Id: Syntax.py,v 1.27 2005/06/10 15:14:33 hmichelon Exp $ # import gtk.gdk import pango import pgw import pgw.Lexical # built-in data types and extensions TYPES = [ 'BIGINT', 'INT8', 'BIGSERIAL', 'SERIAL8', 'BIT', 'VARYING', 'VARBIT', 'BOOL', 'BOOLEAN', 'BOX', 'BYTEA', 'CHARACTER', 'VARCHAR', 'CHAR', 'CIDR', 'CIRCLE', 'DATE', 'DOUBLE', 'PRECISION', 'INET', 'INTEGER', 'FLOAT8', 'INT', 'INT4', 'INTERVAL', 'LINE', 'LSEG', 'MACADDR', 'MONEY', 'NUMERIC', 'DECIMAL', 'PATH', 'POINT', 'POLYGON', 'REAL', 'FLOAT4', 'SMALLINT', 'INT2', 'SERIAL', 'SERIAL4', 'TEXT','TIME', 'TIMESTAMP', 'TIMETZ', 'TIMESTAMPTZ', 'WITHOUT', 'TIME', 'ZONE' ] # special constants SPECIALS = [ 'FALSE', 'NULL', 'TRUE', 'UNKNOWN', 'ALL', 'ANY', 'SOME' ] # named operators, constructs, conditionals and subqueries OPERATORS2 = [ 'OVERLAPS', 'AND', 'OR', 'NOT', 'BETWEEN', 'IS', 'ISNULL', 'NOTNULL', 'CAST', 'LIKE', 'ILIKE', 'SIMILAR', 'EXISTS', 'IN', 'CASE', 'WHEN', 'THEN', 'ELSE', 'END', 'UNION', 'ARRAY', ] # SQL and PostgreSQL statements STATEMENTS = [ 'ABORT', 'ALTER', 'ANALYSE', 'BEGIN', 'CHECKPOINT', 'CLOSE', 'CLUSTER', 'COMMENT', 'COMMIT', 'COPY', 'CREATE', 'DEALLOCATE', 'DECLARE', 'DELETE', 'DROP', 'END', 'EXECUTE', 'EXPLAIN', 'FETCH', 'GRANT', 'INSERT', 'LISTEN', 'LOAD', 'LOCK', 'MOVE', 'NOTIFY', 'PREPARE', 'REINDEX', 'RELEASE', 'RESET', 'REVOKE', 'ROLLBACK', 'SAVEPOINT', 'SELECT', 'SET', 'SHOW', 'START', 'TRUNCATE', 'UNLISTEN', 'UPDATE', 'VACUUM' ] # built-in functions BUILTINS = [ # MATH 'ABS', 'CBTR', 'CEIL', 'CEILING', 'DEGREES', 'EXP', 'FLOOR', 'LN', 'LOG', 'MOD', 'PI', 'POWER', 'RADIANS', 'RANDOM', 'ROUND', 'SETSEED', 'SIGN', 'SQRT', 'TRUNC', 'WIDTH_BUCKET', 'ACOS', 'ASIN', 'ATAN', 'ATAN2', 'COS', 'COT', 'SIN', 'TAN', # STRING 'BIT_LENGTH', 'CHAR_LENGTH', 'CONVERT', 'LOWER', 'OCTET_LENGTH', 'OVERLAY', 'POSITION', 'SUBSTRING', 'TRIM', 'UPPER', 'ASCII', 'BTRIM', 'CHR', 'DECODE', 'ENCODE', 'INITCAP', 'LENGTH', 'LPAD', 'LTRIM', 'MD5', 'PG_CLIENT_ENCODING', 'QUOTE_IDENT', 'QUOTE_LITERAL', 'REPEAT', 'RPAD', 'RTRIM', 'SPLIT_PART', 'STRPOS', 'TO_ASCII', 'TO_HEX', 'TRANSLATE', # BSTRING 'GET_BYTE', 'SET_BYTE', 'GET_BIT', 'SET_BIT', # DATE 'TO_CHAR', 'TO_DATE', 'TO_TIMESTAMP', 'TO_NUMBER', 'AGE', 'DATE_PART', 'DATE_TRUNC', 'EXTRACT', 'ISFINITE', 'NOW', 'TIMEOFDAY', # GEOMETRIC 'AREA', 'BOX_INTERSECT', 'CENTER', 'DIAMETER', 'HEIGHT', 'ISCLOSED', 'ISOPEN', 'LENGTH', 'NPOINTS', 'PCLOSE', 'POPEN', 'RADIUS', 'WIDTH', 'BOX', 'CIRCLE', 'LSEG', 'PATH', 'POINT', 'POLYGON', # NETWORK 'BROADCAST', 'HOST', 'MASKLEN', 'SET_MASKLEN', 'NETMASK', 'HOSTMASK', 'NETWORK', 'TEXT', 'ABBREV', 'FAMILY', 'TRUNC', # SEQUENCES 'NEXTVAL', 'CURRVAL', # CONDITIONAL 'COALESCE', 'NULLIF', # ARRAY 'ARRAY_CAT', 'ARRAY_APPEND', 'ARRAY_PREPEND', 'ARRAY_DIMS', 'ARRAY_LOWER', 'ARRAY_UPPER', 'ARRAY_TO_STRING', 'STRING_TO_ARRAY' # AGGREGATE 'AVG', 'BIT_AND', 'BIT_OR', 'BOOL_AND', 'BOOL_OR', 'COUNT', 'EVERY', 'MAX', 'MIN', 'STDDEV', 'SUM', 'VARIANCE' # SETS 'GENERATE_SERIES', # SYSTEM 'CURRENT_DATABASE', 'CURRENT_SCHEMA', 'INET_CLIENT_ADDR', 'INET_CLIENT_PORT', 'INET_SERVER_ADDR', 'INET_SERVER_PORT', 'VERSION', 'HAS_TABLE_PRIVILEGE', 'HAS_DATABASE_PRIVILEGE', 'HAS_FUNCTION_PRIVILEGE', 'HAS_LANGUAGE_PRIVILEGE', 'HAS_SCHEMA_PRIVILEGE', 'HAS_TABLESPACE_PRIVILEGE' 'PG_TABLE_IS_VISIBLE', 'PG_TYPE_IS_VISIBLE', 'PG_FUNCTION_IS_VISIBLE', 'PG_OPERATOR_IS_VISIBLE', 'PG_OPCLASS_IS_VISIBLE', 'PG_CONVERSION_IS_VISIBLE', 'FORMAT_TYPE', 'PG_GET_VIEWDEF', 'PG_GET_RULEGET', 'PG_GET_INDEXDEF', 'PG_GET_TRIGGERDEF', 'PG_GET_CONSTRAINTDEF', 'PG_GET_EXPR', 'PG_GET_USERBYID', 'PG_GET_SERIAL_SEQUENCE', 'PG_TABLESPACE_DATABASES', 'OBJ_DESCRIPITION', # SYSTEM ADMIN 'CURRENT_SETTINGS', 'SET_CONFIG', 'PG_CANCEL_BACKEND', 'PG_START_BACKUP', 'PG_STOP_BACKUP', ] # built-in functions that can be used without () # or conditional expressions BUILTINS2 = [ # DATE 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'LOCALTIME', 'LOCALTIMESTAMP', # SYSTEM 'CURRENT_USER', 'SESSION_USER', 'USER', ] """ # PL/PgSQL keywords PLPGSQL = [ # structure 'DECLARE', 'BEGIN', 'END', # declarations 'RECORD', 'DEFAULT', 'CONSTANT', 'ALIAS', 'FOR', 'TYPE', 'ROWTYPE', 'RENAME', 'TO', # Statements 'FOUND', 'PERFORM', 'GET', 'DIAGNOSTICS', # Control Structures 'RETURN', 'NEXT', 'IF', 'THEN', 'ELSE', 'END', 'ELSIF', 'LOOP', 'EXIT', 'WHILE', 'REVERSE', 'IN', 'EXCEPTION', 'WHEN', # Cursors 'CURSOR', 'OPEN', 'EXECUTE', 'FETCH', 'INTO', 'CLOSE', # Errors 'RAISE', 'DEBUG', 'LOG', 'INFO', 'NOTICE', 'WARNING', 'EXCEPTION', # Trigger Procedures 'NEW', 'OLD', 'TG_NAME', 'TG_WHEN', 'TG_LEVEL', 'TG_OP', 'TG_RELID', 'TG_RELNAME', 'TG_NARGS', 'TG_ARGV', ] """ # keywords for each statement KEYWORDS = { 'ABORT' : [ 'WORK', 'TRANSACTION' ], 'ALTER' : { 'AGGREGATE' : [ [ 'RENAME', 'TO' ], [ 'OWNER', 'TO' ] ], 'CONVERSION' : [ [ 'RENAME', 'TO' ], [ 'OWNER', 'TO' ] ], 'DATABASE' : [ 'SET', 'TO', 'DEFAULT', 'RESET', [ 'RENAME', 'TO' ], [ 'OWNER', 'TO' ] ], 'DOMAIN' : [ [ 'SET', 'DEFAULT' ], [ 'DROP', 'DEFAULT' ], 'ADD', [ 'DROP', 'CONSTRAINT' ], 'RESTRICT', 'CASCADE', [ 'OWNER', 'TO' ] ], 'FUNCTION' : [ [ 'RENAME', 'TO' ], [ 'OWNER', 'TO' ] ], 'GROUP' : [ [ 'ADD', 'USER' ], [ 'DROP', 'USER' ], [ 'RENAME', 'TO' ] ], 'INDEX' : [ [ 'RENAME', 'TO' ], [ 'OWNER', 'TO' ], [ 'SET', 'TABLESPACE' ] ], 'LANGUAGE' : [ [ 'RENAME', 'TO' ] ], 'OPERATOR' : [ 'NONE', [ 'OWNER', 'TO' ], 'CLASS', 'USING' ], 'SCHEMA' : [ [ 'RENAME', 'TO' ], [ 'OWNER', 'TO' ] ], 'SEQUENCE' : [ [ 'INCREMENT', 'BY' ], 'MINVALUE', 'MAXVALUE', [ 'RESTART', 'WITH' ], 'CACHE', 'NO', 'CYCLE' ], 'TABLE' : [ 'ONLY', [ 'RENAME', 'COLUMN' ], [ 'RENAME', 'TO' ], 'TO', [ 'ADD', 'COLUMN' ], [ 'DROP', 'COLUMN' ], 'RESTRICT', 'CASCADE', 'TYPE', 'USING', [ 'ALTER', 'COLUMN' ], [ 'SET', 'DEFAULT' ], [ 'DROP', 'DEFAULT' ], 'SET', 'DROP', [ 'SET', 'STATISTICS' ], [ 'SET', 'STORAGE' ], 'PLAIN', 'EXTERNAL', 'EXTERNAL', 'MAIN', [ 'DROP', 'CONSTRAINT' ], [ 'CLUSTER', 'ON' ], [ 'SET', 'WITHOUT', 'CLUSTER' ], [ 'SET', 'WITHOUT', 'OIDS' ], [ 'OWNER', 'TO' ], [ 'SET', 'TABLESPACE' ], 'CHECK', [ 'FOREIGN', 'KEY' ], 'CASCADE', [ 'PRIMARY', 'KEY' ], [ 'ON', 'DELETE' ], [ 'ON', 'UPDATE' ], 'REFERENCES', ], 'TABLESPACE' : [ [ 'RENAME', 'TO' ], [ 'OWNER', 'TO' ] ], 'TRIGGER' : [ 'ON', [ 'RENAME', 'TO' ] ], 'TYPE' : [ [ 'OWNER', 'TO' ] ], 'USER' : [ 'WITH', 'CREATEDB', 'NOCREATEDB', 'CREATEUSER', 'NOCREATEUSER', 'ENCRYPTED', 'UNENCRYPTED', 'PASSWORD', [ 'VALID', 'UNTIL' ], [ 'RENAME', 'TO' ], 'SET', 'TO', 'DEFAULT', 'RESET' ], }, 'ANALYZE' : [ 'VERBOSE' ], 'BEGIN' : [ 'WORK', 'TRANSACTION', [ 'ISOLATION', 'LEVEL' ], 'SERIALIZABLE', [ 'REPEATABLE', 'READ' ], [ 'READ', 'COMMITTED' ], [ 'READ', 'UNCOMMITTED' ], [ 'READ', 'WRITE' ], [ 'READ', 'ONLY' ] ], 'CHECKPOINT' : [], 'CLOSE' : [], 'CLUSTER' : [ 'ON' ], 'COMMENT' : { 'ON' : [ 'TABLE', 'COLUMN', 'AGGREGATE', 'CAST', 'AS', 'CONSTRAINT', 'ON', 'CONVERSION', 'DATABASE', 'DOMAIN', 'FUNCTION', 'INDEX', [ 'LARGE', 'OBJECT' ], 'OPERATOR', [ 'OPERATOR', 'CLASS' ], 'USING', 'PROCEDURAL', 'LANGUAGE', 'RULE', 'SCHEMA', 'SEQUENCE', 'TRIGGER', 'TYPE', 'VIEW', 'IS' ] }, 'COMMIT' : [ 'WORK', 'TRANSACTION' ], 'COPY' : [ 'FROM', 'STDIN', 'WITH', 'BINARY', 'OIDS', 'DELIMITER', 'CSV', 'AS', 'ESCAPE' 'FORCE', 'TO', 'STDOUT', 'QUOTE' ], 'CREATE' : { 'AGGREGATE' : [ 'BASETYPE', 'SFUNC', 'STYPE', 'FINALFUNC', 'INITCOND' ], 'CAST' : [ [ 'WITH', 'FUNCTION' ], [ 'AS', 'ASSIGNMENT' ], [ 'AS', 'IMPLICIT' ], [ 'WITHOUT', 'FUNCTION'] ], 'CONSTRAINT' : [ 'TRIGGER', 'AFTER', 'ON', [ 'FOR', 'EACH', 'ROW', 'EXECUTE' 'PROCEDURE' ] ], 'CONVERSION' : [ 'FOR', 'TO', 'FROM' ], 'DEFAULT' : [ 'CONVERSION', 'FOR', 'TO', 'FROM' ], 'DATABASE' : [ 'WITH', 'OWNER', 'TEMPLATE', 'ENCODING', 'TABLESPACE', 'DEFAULT' ], 'DOMAIN' : [ 'AS', 'DEFAULT', 'CONSTRAINT', 'CHECK' ], 'OR' : [ 'REPLACE', 'FUNCTION', 'RETURNS', 'LANGUAGE', 'AS', 'IMMUTABLE', 'STABLE', 'VOLATILE', [ 'CALLED', 'ON', 'NULL', 'INPUT' ], [ 'RETURNS', 'NULL', 'ON', 'NULL', 'INPUT' ], 'STRICT', 'EXTERNAL', [ 'SECURITY', 'INVOKER' ], [ 'SECURITY', 'DEFINER' ], 'WITH', # XXX: for RULE 'RULE', 'AS', 'ON', 'TO', 'WHERE', 'DO', 'ALSO', 'INSTEAD', 'NOTHING', 'VIEW' ], 'FUNCTION' : [ 'RETURNS', 'LANGUAGE', 'AS', 'IMMUTABLE', 'STABLE', 'VOLATILE', [ 'CALLED', 'ON', 'NULL', 'INPUT' ], [ 'RETURNS', 'NULL', 'ON', 'NULL', 'INPUT' ], 'STRICT', 'EXTERNAL', [ 'SECURITY', 'INVOKER' ], [ 'SECURITY', 'DEFINER' ], 'WITH' ], 'GROUP' : [ 'WITH', 'SYSID', 'USER' ], 'UNIQUE' : [ 'ON', 'USING', 'TABLESPACE', 'WHERE', 'INDEX' ], 'INDEX' : [ 'ON', 'USING', 'TABLESPACE', 'WHERE', 'RTREE', 'HASH' ], 'LANGUAGE' : [ 'HANDLER', 'VALIDATOR' ], 'PROCEDURAL' : [ 'HANDLER', 'VALIDATOR', 'LANGUAGE' ], 'TRUSTED' : [ 'HANDLER', 'VALIDATOR', 'LANGUAGE' ], 'OPERATOR' : [ 'PROCEDURE', 'LEFTARG', 'RIGHTARG', 'COMMUTATOR', 'NEGATOR', 'RESTRICT', 'JOIN', 'HASHES', 'MERGES', 'SORT1', 'SORT2', 'LTCMP', 'GTCMP', 'CLASS', 'DEFAULT', [ 'FOR', 'TYPE' ], 'USING', 'AS', 'OPERATOR', 'RECHECK', 'FUNCTION', 'STORAGE' ], 'RULE' : [ 'AS', 'ON', 'TO', 'WHERE', 'DO', 'ALSO', 'INSTEAD', 'NOTHING' ], 'SCHEMA' : [ 'AUTHORIZATION' ], 'SEQUENCE' : [ 'INCREMENT', 'BY', 'MINVALUE', 'NO', 'MAXVALUE', [ 'START', 'WITH' ], 'CACHE', 'CYCLE' ], 'TEMPORARY' : [ 'SEQUENCE', 'INCREMENT', 'BY', 'MINVALUE', 'NO', 'MAXVALUE', [ 'START', 'WITH' ], 'CACHE', 'CYCLE', # CREATE TABLE 'TABLE', 'DEFAULT', 'INCLUDING', 'EXCLUDING', 'DEFAULTS', 'INHERITS', 'WITH', 'WITHOUT', 'OIDS', [ 'ON', 'COMMIT' ], [ 'PRESERVE', 'ROWS' ], [ 'DELETE', 'ROWS' ], 'DROP', 'TABLESPACE', 'CONSTRAINT', 'UNIQUE', [ 'USING', 'INDEX', 'TABLESPACE'], [ 'PRIMARY', 'KEY' ], 'CHECK', 'REFERENCES', [ 'MATCH', 'FULL' ], [ 'MATCH', 'PARTIAL' ], [ 'MATCH', 'SIMPLE' ], [ 'ON', 'DELETE' ], [ 'ON', 'UPDATE' ], 'DEFERRABLE', [ 'INITIALLY', 'DEFERRED' ], [ 'INITIALLY', 'IMMEDIATE' ], [ 'FOREIGN', 'KEY' ], 'CHECK', ], 'TEMP' : [ 'SEQUENCE', 'INCREMENT', 'BY', 'MINVALUE', 'NO', 'MAXVALUE', [ 'START', 'WITH' ], 'CACHE', 'CYCLE', # CREATE TABLE 'TABLE', 'DEFAULT', 'INCLUDING', 'EXCLUDING', 'DEFAULTS', 'INHERITS', 'WITH', 'OIDS', 'WITHOUT', [ 'ON', 'COMMIT' ], [ 'PRESERVE', 'ROWS' ], [ 'DELETE', 'ROWS' ], 'DROP', 'TABLESPACE', 'CONSTRAINT', 'UNIQUE', [ 'USING', 'INDEX', 'TABLESPACE'], [ 'PRIMARY', 'KEY' ], 'CHECK', 'REFERENCES', [ 'MATCH', 'FULL' ], [ 'MATCH', 'PARTIAL' ], [ 'MATCH', 'SIMPLE' ], [ 'ON', 'DELETE' ], [ 'ON', 'UPDATE' ], 'DEFERRABLE', [ 'INITIALLY', 'DEFERRED' ], [ 'INITIALLY', 'IMMEDIATE' ], [ 'FOREIGN', 'KEY' ], 'CHECK', ], 'LOCAL' : [ 'TABLE', 'DEFAULT', 'INCLUDING', 'EXCLUDING', 'DEFAULTS', 'INHERITS', 'WITH', 'WITHOUT', 'OIDS', [ 'ON', 'COMMIT' ], [ 'PRESERVE', 'ROWS' ], [ 'DELETE', 'ROWS' ], 'DROP', 'TABLESPACE', 'CONSTRAINT', 'UNIQUE', [ 'USING', 'INDEX', 'TABLESPACE'], [ 'PRIMARY', 'KEY' ], 'CHECK', 'REFERENCES', [ 'MATCH', 'FULL' ], [ 'MATCH', 'PARTIAL' ], [ 'MATCH', 'SIMPLE' ], [ 'ON', 'DELETE' ], [ 'ON', 'UPDATE' ], 'DEFERRABLE', [ 'INITIALLY', 'DEFERRED' ], [ 'INITIALLY', 'IMMEDIATE' ], [ 'FOREIGN', 'KEY' ], 'CHECK', ], 'GLOBAL' : [ 'TABLE', 'DEFAULT', 'INCLUDING', 'EXCLUDING', 'DEFAULTS', 'INHERITS', 'WITH', 'OIDS', 'WITHOUT', [ 'ON', 'COMMIT' ], [ 'PRESERVE', 'ROWS' ], [ 'DELETE', 'ROWS' ], 'DROP', 'TABLESPACE', 'CONSTRAINT', 'UNIQUE', [ 'USING', 'INDEX', 'TABLESPACE'], [ 'PRIMARY', 'KEY' ], 'CHECK', 'REFERENCES', [ 'MATCH', 'FULL' ], [ 'MATCH', 'PARTIAL' ], [ 'MATCH', 'SIMPLE' ], [ 'ON', 'DELETE' ], [ 'ON', 'UPDATE' ], 'DEFERRABLE', [ 'INITIALLY', 'DEFERRED' ], [ 'INITIALLY', 'IMMEDIATE' ], [ 'FOREIGN', 'KEY' ], 'CHECK', ], 'TABLE' : [ 'DEFAULT', 'INCLUDING', 'EXCLUDING', 'DEFAULTS', 'INHERITS', 'WITH', 'OIDS', 'WITHOUT', [ 'ON', 'COMMIT' ], [ 'PRESERVE', 'ROWS' ], [ 'DELETE', 'ROWS' ], 'DROP', 'TABLESPACE', 'CONSTRAINT', 'UNIQUE', [ 'USING', 'INDEX', 'TABLESPACE'], [ 'PRIMARY', 'KEY' ], 'CHECK', 'REFERENCES', [ 'MATCH', 'FULL' ], [ 'MATCH', 'PARTIAL' ], [ 'MATCH', 'SIMPLE' ], [ 'ON', 'DELETE' ], [ 'ON', 'UPDATE' ], 'DEFERRABLE', 'INITIALLY', 'DEFERRED', 'IMMEDIATE', 'RESTRICT', [ 'FOREIGN', 'KEY' ], 'CASCADE' 'CHECK', ], 'TABLESPACE' : [ 'OWNER', 'LOCATION' ], 'TRIGGER' : [ 'BEFORE', 'AFTER', 'OR', 'ON', 'FOR', 'EACH', 'ROW', 'STATEMENT', [ 'EXECUTE', 'PROCEDURE' ] ], 'TYPE' : [ 'AS', 'INPUT', 'OUTPUT', 'RECEIVE', 'SEND', 'ANALYZE', 'INTERNALLENGTH', 'VARIABLE', 'PASSEDBYVALUE', 'ALIGNMENT', 'STORAGE', 'DEFAULT', 'ELEMENT', 'DELIMITER' ], 'USER' : [ 'WITH', 'SYSID', 'CREATEDB', 'NOCREATEDB', 'CREATEUSER', 'NOCREATEUSER', [ 'IN', 'GROUP' ], 'ENCRYPTED', 'UNENCRYPTED', 'PASSWORD', [ 'VALID', 'UNTIL' ] ], 'VIEW' : [ 'AS' , # select 'SELECT', 'DISTINCT', 'ON', 'AS', 'FROM', 'WHERE', [ 'GROUP', 'BY' ], 'HAVING', 'UNION', 'INTERSECT', 'EXCEPT', [ 'ORDER', 'BY' ], 'ASC', 'DESC', 'USING', 'LIMIT', 'OFFSET', [ 'FOR', 'UPDATE', 'OF' ], 'ONLY', 'NATURAL', 'USING', 'INNER', 'LEFT', 'OUTER', 'RIGHT', 'FULL', 'JOIN', 'CROSS', 'INTO' ], }, 'DEALLOCATE': [ 'PREPARE' ], 'DECLARE' : [ 'BINARY', 'INSENSITIVE', 'NO', 'SCROLL', 'CURSOR', 'WITH', 'WITHOUT', 'HOLD', 'FOR', [ 'READ', 'ONLY' ], 'UPDATE', 'OF' ], 'DELETE' : { 'FROM' : [ 'ONLY', 'WHERE' ] }, 'DROP' : { 'AGGREGATE' : [ 'CASCADE', 'RESTRICT' ], 'CAST' : [ 'AS', 'CASCADE', 'RESTRICT' ], 'CONVERSION' : [ 'CASCADE', 'RESTRICT' ], 'DATABASE' : [], 'DOMAIN' : [ 'CASCADE', 'RESTRICT' ], 'FUNCTION' : [ 'CASCADE', 'RESTRICT' ], 'GROUP' : [], 'INDEX' : [ 'CASCADE', 'RESTRICT' ], 'LANGUAGE' : [ 'CASCADE', 'RESTRICT' ], 'PROCEDURAL' : ['LANGUAGE', 'CASCADE', 'RESTRICT'], 'OPERATOR' : [ 'NONE', 'CASCADE', 'RESTRICT', 'CLASS', 'USING' ], 'RULE' : [ 'ON', 'CASCADE', 'RESTRICT' ], 'SCHEMA' : [ 'CASCADE', 'RESTRICT' ], 'SEQUENCE' : [ 'CASCADE', 'RESTRICT' ], 'TABLE' : [ 'CASCADE', 'RESTRICT' ], 'TABLESPACE' : [], 'TRIGGER' : [ 'ON', 'CASCADE', 'RESTRICT' ], 'TYPE' : [ 'CASCADE', 'RESTRICT' ], 'USER' : [], 'VIEW' : [ 'CASCADE', 'RESTRICT' ], }, 'END' : [ 'WORK', 'TRANSACTION' ], 'EXECUTE' : [], 'EXPLAIN' : [ 'ANALYZE', 'VERBOSE' ], 'FETCH' : [ 'FROM', 'IN', 'NEXT', 'PRIOR', 'FIRST', 'LAST', 'ABSOLUTE', 'RELATIVE', 'FORWARD', 'BACKWARD' ], 'GRANT' : [ 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'RULE', 'REFERENCES', 'TRIGGER', 'PRIVILEGES', 'ON', 'TABLE', 'TO', 'GROUP', 'PUBLIC', [ 'WITH', 'GRANT', 'OPTION' ], 'CREATE', 'TEMPORARY', 'TEMP', 'PRIVILEGES', 'DATABASE', 'EXECUTE', 'FUNCTION', 'USAGE', 'LANGUAGE', 'SCHEMA', 'TABLESPACE' ], 'INSERT' : { 'INTO' : [ 'DEFAULT', 'VALUES', 'SELECT', 'DISTINCT', 'ON', 'AS', 'FROM', 'WHERE', [ 'GROUP', 'BY' ], 'HAVING', 'UNION', 'INTERSECT', 'EXCEPT', [ 'ORDER', 'BY' ], 'ASC', 'DESC', 'USING', 'LIMIT', 'OFFSET', [ 'FOR', 'UPDATE', 'OF' ], 'ONLY', 'NATURAL', 'USING', 'INNER', 'LEFT', 'OUTER', 'RIGHT', 'FULL', 'JOIN', 'CROSS', 'INTO', ] }, 'LISTEN' : [], 'LOAD' : [], 'LOCK' : [ 'TABLE', 'IN', 'MODE', 'NOWAIT', [ 'ACCESS', 'SHARE' ], [ 'ROW', 'SHARE' ], [ 'ROW', 'EXCLUSIVE' ], [ 'SHARE', 'UPDATE', 'EXCLUSIVE' ], 'SHARE', [ 'SHARE', 'ROW', 'EXCLUSIVE' ], 'EXCLUSIVE', [ 'ACCESS', 'EXCLUSIVE' ] ], 'MOVE' : [ 'FROM', 'IN' ], 'NOTIFY' : [], 'PREPARE' : [ 'AS' ], 'REINDEX' : [ 'DATABASE', 'TABLE', 'TABLE', 'FORCE' ], 'RELEASE' : [ 'SAVEPOINT' ], 'RESET' : [ ], 'REVOKE' : [ [ 'GRANT', 'OPTION', 'FOR' ], 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'RULE', 'REFERENCES', 'TRIGGER', 'PRIVILEGES', 'ON', 'TABLE', 'FROM', 'GROUP', 'PUBLIC', 'CASCADE', 'RESTRICT', 'CREATE', 'TEMPORARY', 'TEMP', 'EXECUTE', 'USAGE', 'SCHEMA', 'LANGUAGE', 'TABLESPACE' ], 'ROLLBACK' : [ 'WORK', 'TRANSACTION', 'TO', 'SAVEPOINT' ], 'SAVEPOINT': [], 'SELECT' : [ 'SELECT', 'INTO', 'DISTINCT', 'ON', 'AS', 'FROM', 'WHERE', [ 'GROUP', 'BY' ], 'HAVING', 'UNION', 'INTERSECT', 'EXCEPT', [ 'ORDER', 'BY' ], 'ASC', 'DESC', 'USING', 'LIMIT', 'OFFSET', [ 'FOR', 'UPDATE', 'OF' ], 'ONLY', 'NATURAL', 'USING', 'INNER', 'LEFT', 'OUTER', 'RIGHT', 'FULL', 'JOIN', 'CROSS', 'INTO' ], 'SET' : [ 'SESSION', 'LOCAL', 'TO', 'DEFAULT', 'LOCAL', [ 'TIME', 'ZONE' ], 'CONSTRAINTS', 'DEFERRED', 'IMMEDIATE', 'AUTHORIZATION', 'TRANSACTION', 'CHARACTERISTICS', [ 'ISOLATION', 'LEVEL' ], 'SERIALIZABLE', [ 'REPEATABLE', 'READ' ], [ 'READ', 'COMMITTED' ], [ 'READ', 'UNCOMMITTED' ], [ 'READ', 'WRITE' ], [ 'READ', 'ONLY' ] ], 'SHOW' : [ ], 'START' : { 'TRANSACTION' : [ [ 'ISOLATION', 'LEVEL' ], 'SERIALIZABLE', [ 'REPEATABLE', 'READ' ], [ 'READ', 'COMMITTED' ], [ 'READ', 'UNCOMMITTED' ], [ 'READ', 'WRITE' ], [ 'READ', 'ONLY' ] ], }, 'TRUNCATE' : [ 'TABLE' ], 'UNLISTEN' : [], 'UPDATE' : [ 'ONLY', 'SET', 'DEFAULT', 'FROM', 'WHERE' ], 'VACUUM' : [ 'FULL', 'FREEZE', 'VERBOSE', 'ANALYSE' ] } class Syntax: """Syntax highlight""" def __init__(self, buffer): self.lexical = pgw.Lexical.Lexical() self.buffer = buffer self.last = None # default colors self.tag = {} self.tag['font'] = self.buffer.create_tag("font") if (pgw.mswindows()): self.tag['font'].set_property('font', 'Courier New 10') else: self.tag['font'].set_property('family', 'monospace') self.tag['function'] = self.buffer.create_tag("function") self.tag['function'].set_property('foreground', '#009999') self.tag['dollarquote'] = self.buffer.create_tag("dollarquote") self.tag['dollarquote'].set_property('foreground', '#000000') self.tag['identifier'] = self.buffer.create_tag("identifier") self.tag['identifier'].set_property('foreground', '#000000') self.tag['keyword'] = self.buffer.create_tag("keyword") self.tag['keyword'].set_property('foreground', '#0000FF') self.tag['type'] = self.buffer.create_tag("type") self.tag['type'].set_property('foreground', '#009900') self.tag['string'] = self.buffer.create_tag("string") self.tag['string'].set_property('foreground', '#F700BF') self.tag['numeric_constant'] = self.buffer.create_tag("numeric_constant") self.tag['numeric_constant'].set_property('foreground', '#c53838') self.tag['special'] = self.buffer.create_tag("special") self.tag['special'].set_property('foreground', '#c53838') self.tag['comment'] = self.buffer.create_tag("comment") self.tag['comment'].set_property('foreground', '#999999') self.tag['comment2'] = self.buffer.create_tag("comment2") self.tag['comment2'].set_property('style', pango.STYLE_ITALIC) self.tag['operator'] = self.buffer.create_tag("operator") self.tag['operator'].set_property('foreground', '#555555') self.tag['psql'] = self.buffer.create_tag("psql") self.tag['psql'].set_property('background', '#d0d4df') def start_of_prev_statement(self, iter): """Find the first character of a statement""" if (self.last is not None): self.found = None for token in self.last: if (token.start_iter.compare(iter) >= 0): if (self.found is None): break return self.found.start_iter if (token.value == ';'): self.found = token if (self.found): return self.found.start_iter return iter.get_buffer().get_start_iter() def start_of_next_statement(self, iter): """Find the last character of a statement""" if (self.last is not None): self.found = None for token in reversed(self.last): if (token.end_iter.compare(iter) <= 0): if (self.found is None): break return self.found.end_iter if (token.value == ';'): self.found = token if (self.found): return self.found.end_iter return iter.get_buffer().get_end_iter() def text_inserted(self, buffer, iter, text, length): """Called by Gtk when text is inserted in the buffer: prepare 'start' and 'end' for text_changed()""" self.start = self.start_of_prev_statement(iter.copy()).get_offset() self.end = self.start_of_next_statement(iter.copy()).get_offset() + length def text_deleted(self, buffer, start, end): """Called by Gtk when text is deleted from the buffer: prepare 'start' and 'end' for text_changed()""" self.start = self.start_of_prev_statement(start.copy()).get_offset() self.end = self.start_of_next_statement(end.copy()).get_offset() def text_changed(self, buffer): """Called bu Gtk when (after) text is deleted or inserted in the buffer. Uses 'start' and 'end' prepared in text_inserted and text_deleted then run the analyse""" start = self.buffer.get_iter_at_offset(self.start) end = self.buffer.get_iter_at_offset(self.end) self.analyse(start, end) def refresh(self): """Used when you want to manually refresh the syntax highlight a the whole buffer""" start = self.buffer.get_start_iter() end = self.buffer.get_end_iter() self.analyse(start, end) def analyse(self, start, end): """Run the lexical and syntaxical analysers then apply the syntax highlight to the buffer""" self.tokens = self.lexical.analyse(self.buffer, start, end) self.syntaxical_analyser() self.buffer.remove_all_tags(start, end) self.buffer.apply_tag(self.tag['font'], start, end) self.last = self.tokens for token in self.tokens: self.buffer.apply_tag(self.tag[token.token], \ token.start_iter, \ token.end_iter) if (token.token == 'comment'): self.buffer.apply_tag(self.tag['comment2'], \ token.start_iter, \ token.end_iter) def syntaxical_analyser(self): """Find keywords""" tokens = self.tokens self.tokens = [] try: while (len(tokens) > 0): token = tokens.pop(0) # only statements, other tokens # are analysed below or already founds in # the lexical analyser if (token.value in STATEMENTS): token.token = 'keyword' self.tokens.append(token) statement = token.value token = tokens.pop(0) # get the list containing the # keywords for this statement try: keywords = KEYWORDS[statement] except KeyError: continue if (type(keywords) is dict): try: keywords = keywords[token.value] token.token = 'keyword' self.tokens.append(token) token = tokens.pop(0) except KeyError: pass self.tokens.append(token) # identify each token inside the statement while (token.value != ';'): # only identifiers, other tokens are # analysed in the lexical analyser if (token.token == 'identifier'): # special constants if (token.value in SPECIALS): token.token = 'special' # buit-in data types elif (token.value in TYPES): # TODO : manager composed types names token.token = 'type' # names operators elif (token.value in OPERATORS2): token.token = 'operator' # built-in functions elif (token.value in BUILTINS): next = tokens.pop(0) if (next.value == '('): token.token = 'function' self.tokens.append(next) else: tokens.insert(0, next) # built-in function that can be used without () if (token.value in BUILTINS2): token.token = 'function' # everything else : keywords or indentifiers else: for keyword in keywords: if (type(keyword) is list): # TODO : write the right code here # to manage composed keywords if (token.value in keyword): token.token = 'keyword' elif (token.value == keyword): token.token = 'keyword' self.tokens.append(token) token = tokens.pop(0) self.tokens.append(token) except IndexError: pass