2013-08-28 00:44:27 +00:00
//-*- coding: utf-8 -*-
2009-04-24 23:35:41 +00:00
// Scintilla source code edit control
/** @file LexSQL.cxx
* * Lexer for SQL , including PL / SQL and SQL * Plus .
2013-08-28 00:44:27 +00:00
* * Improved by Jérôme LAFORGE < jerome . laforge_AT_gmail_DOT_com > from 2010 to 2012.
2009-04-24 23:35:41 +00:00
* */
2013-08-28 00:44:27 +00:00
// Copyright 1998-2012 by Neil Hodgson <neilh@scintilla.org>
2009-04-24 23:35:41 +00:00
// The License.txt file describes the conditions under which this software may be distributed.
# include <stdlib.h>
# include <string.h>
# include <stdio.h>
# include <stdarg.h>
2010-08-21 23:59:56 +00:00
# include <assert.h>
# include <ctype.h>
2009-04-24 23:35:41 +00:00
2011-03-22 00:16:49 +00:00
# include <string>
# include <vector>
# include <map>
# include <algorithm>
2010-08-21 23:59:56 +00:00
# include "ILexer.h"
# include "Scintilla.h"
# include "SciLexer.h"
2009-04-24 23:35:41 +00:00
2010-08-21 23:59:56 +00:00
# include "WordList.h"
# include "LexAccessor.h"
2009-04-24 23:35:41 +00:00
# include "Accessor.h"
# include "StyleContext.h"
2010-08-21 23:59:56 +00:00
# include "CharacterSet.h"
# include "LexerModule.h"
2011-03-22 00:16:49 +00:00
# include "OptionSet.h"
2013-08-28 00:44:27 +00:00
# include "SparseState.h"
2019-05-04 18:14:48 +00:00
# include "DefaultLexer.h"
2009-04-24 23:35:41 +00:00
using namespace Scintilla ;
2011-03-22 00:16:49 +00:00
static inline bool IsAWordChar ( int ch , bool sqlAllowDottedWord ) {
if ( ! sqlAllowDottedWord )
return ( ch < 0x80 ) & & ( isalnum ( ch ) | | ch = = ' _ ' ) ;
else
return ( ch < 0x80 ) & & ( isalnum ( ch ) | | ch = = ' _ ' | | ch = = ' . ' ) ;
2009-04-24 23:35:41 +00:00
}
static inline bool IsAWordStart ( int ch ) {
return ( ch < 0x80 ) & & ( isalpha ( ch ) | | ch = = ' _ ' ) ;
}
static inline bool IsADoxygenChar ( int ch ) {
return ( islower ( ch ) | | ch = = ' $ ' | | ch = = ' @ ' | |
ch = = ' \\ ' | | ch = = ' & ' | | ch = = ' < ' | |
ch = = ' > ' | | ch = = ' # ' | | ch = = ' { ' | |
ch = = ' } ' | | ch = = ' [ ' | | ch = = ' ] ' ) ;
}
2015-06-07 21:19:26 +00:00
static inline bool IsANumberChar ( int ch , int chPrev ) {
2009-04-24 23:35:41 +00:00
// Not exactly following number definition (several dots are seen as OK, etc.)
// but probably enough in most cases.
return ( ch < 0x80 ) & &
2011-03-22 00:16:49 +00:00
( isdigit ( ch ) | | toupper ( ch ) = = ' E ' | |
2015-06-07 21:19:26 +00:00
ch = = ' . ' | | ( ( ch = = ' - ' | | ch = = ' + ' ) & & chPrev < 0x80 & & toupper ( chPrev ) = = ' E ' ) ) ;
2009-04-24 23:35:41 +00:00
}
2015-06-07 21:19:26 +00:00
typedef unsigned int sql_state_t ;
2009-04-24 23:35:41 +00:00
2011-03-22 00:16:49 +00:00
class SQLStates {
public :
2019-05-04 18:14:48 +00:00
void Set ( Sci_Position lineNumber , unsigned short int sqlStatesLine ) {
2013-08-28 00:44:27 +00:00
sqlStatement . Set ( lineNumber , sqlStatesLine ) ;
2011-03-22 00:16:49 +00:00
}
2009-04-24 23:35:41 +00:00
2015-06-07 21:19:26 +00:00
sql_state_t IgnoreWhen ( sql_state_t sqlStatesLine , bool enable ) {
2011-03-22 00:16:49 +00:00
if ( enable )
sqlStatesLine | = MASK_IGNORE_WHEN ;
else
sqlStatesLine & = ~ MASK_IGNORE_WHEN ;
return sqlStatesLine ;
}
2015-06-07 21:19:26 +00:00
sql_state_t IntoCondition ( sql_state_t sqlStatesLine , bool enable ) {
2011-03-22 00:16:49 +00:00
if ( enable )
sqlStatesLine | = MASK_INTO_CONDITION ;
else
sqlStatesLine & = ~ MASK_INTO_CONDITION ;
return sqlStatesLine ;
}
2015-06-07 21:19:26 +00:00
sql_state_t IntoExceptionBlock ( sql_state_t sqlStatesLine , bool enable ) {
2011-03-22 00:16:49 +00:00
if ( enable )
sqlStatesLine | = MASK_INTO_EXCEPTION ;
else
sqlStatesLine & = ~ MASK_INTO_EXCEPTION ;
return sqlStatesLine ;
}
2015-06-07 21:19:26 +00:00
sql_state_t IntoDeclareBlock ( sql_state_t sqlStatesLine , bool enable ) {
2011-03-22 00:16:49 +00:00
if ( enable )
sqlStatesLine | = MASK_INTO_DECLARE ;
else
sqlStatesLine & = ~ MASK_INTO_DECLARE ;
return sqlStatesLine ;
}
2015-06-07 21:19:26 +00:00
sql_state_t IntoMergeStatement ( sql_state_t sqlStatesLine , bool enable ) {
2013-08-28 00:44:27 +00:00
if ( enable )
sqlStatesLine | = MASK_MERGE_STATEMENT ;
else
sqlStatesLine & = ~ MASK_MERGE_STATEMENT ;
return sqlStatesLine ;
}
2015-06-07 21:19:26 +00:00
sql_state_t CaseMergeWithoutWhenFound ( sql_state_t sqlStatesLine , bool found ) {
2013-08-28 00:44:27 +00:00
if ( found )
sqlStatesLine | = MASK_CASE_MERGE_WITHOUT_WHEN_FOUND ;
else
sqlStatesLine & = ~ MASK_CASE_MERGE_WITHOUT_WHEN_FOUND ;
return sqlStatesLine ;
}
2015-06-07 21:19:26 +00:00
sql_state_t IntoSelectStatementOrAssignment ( sql_state_t sqlStatesLine , bool found ) {
2013-08-28 00:44:27 +00:00
if ( found )
sqlStatesLine | = MASK_INTO_SELECT_STATEMENT_OR_ASSIGNEMENT ;
else
sqlStatesLine & = ~ MASK_INTO_SELECT_STATEMENT_OR_ASSIGNEMENT ;
return sqlStatesLine ;
}
2015-06-07 21:19:26 +00:00
sql_state_t BeginCaseBlock ( sql_state_t sqlStatesLine ) {
2011-03-22 00:16:49 +00:00
if ( ( sqlStatesLine & MASK_NESTED_CASES ) < MASK_NESTED_CASES ) {
sqlStatesLine + + ;
}
return sqlStatesLine ;
}
2015-06-07 21:19:26 +00:00
sql_state_t EndCaseBlock ( sql_state_t sqlStatesLine ) {
2011-03-22 00:16:49 +00:00
if ( ( sqlStatesLine & MASK_NESTED_CASES ) > 0 ) {
sqlStatesLine - - ;
}
return sqlStatesLine ;
}
2015-06-07 21:19:26 +00:00
sql_state_t IntoCreateStatement ( sql_state_t sqlStatesLine , bool enable ) {
if ( enable )
sqlStatesLine | = MASK_INTO_CREATE ;
else
sqlStatesLine & = ~ MASK_INTO_CREATE ;
return sqlStatesLine ;
}
sql_state_t IntoCreateViewStatement ( sql_state_t sqlStatesLine , bool enable ) {
if ( enable )
sqlStatesLine | = MASK_INTO_CREATE_VIEW ;
else
sqlStatesLine & = ~ MASK_INTO_CREATE_VIEW ;
return sqlStatesLine ;
}
sql_state_t IntoCreateViewAsStatement ( sql_state_t sqlStatesLine , bool enable ) {
if ( enable )
sqlStatesLine | = MASK_INTO_CREATE_VIEW_AS_STATEMENT ;
else
sqlStatesLine & = ~ MASK_INTO_CREATE_VIEW_AS_STATEMENT ;
return sqlStatesLine ;
}
bool IsIgnoreWhen ( sql_state_t sqlStatesLine ) {
2011-03-22 00:16:49 +00:00
return ( sqlStatesLine & MASK_IGNORE_WHEN ) ! = 0 ;
}
2015-06-07 21:19:26 +00:00
bool IsIntoCondition ( sql_state_t sqlStatesLine ) {
2011-03-22 00:16:49 +00:00
return ( sqlStatesLine & MASK_INTO_CONDITION ) ! = 0 ;
}
2015-06-07 21:19:26 +00:00
bool IsIntoCaseBlock ( sql_state_t sqlStatesLine ) {
2011-03-22 00:16:49 +00:00
return ( sqlStatesLine & MASK_NESTED_CASES ) ! = 0 ;
}
2015-06-07 21:19:26 +00:00
bool IsIntoExceptionBlock ( sql_state_t sqlStatesLine ) {
2011-03-22 00:16:49 +00:00
return ( sqlStatesLine & MASK_INTO_EXCEPTION ) ! = 0 ;
}
2015-06-07 21:19:26 +00:00
bool IsIntoSelectStatementOrAssignment ( sql_state_t sqlStatesLine ) {
2013-08-28 00:44:27 +00:00
return ( sqlStatesLine & MASK_INTO_SELECT_STATEMENT_OR_ASSIGNEMENT ) ! = 0 ;
}
2015-06-07 21:19:26 +00:00
bool IsCaseMergeWithoutWhenFound ( sql_state_t sqlStatesLine ) {
2013-08-28 00:44:27 +00:00
return ( sqlStatesLine & MASK_CASE_MERGE_WITHOUT_WHEN_FOUND ) ! = 0 ;
}
2011-03-22 00:16:49 +00:00
2015-06-07 21:19:26 +00:00
bool IsIntoDeclareBlock ( sql_state_t sqlStatesLine ) {
2011-03-22 00:16:49 +00:00
return ( sqlStatesLine & MASK_INTO_DECLARE ) ! = 0 ;
}
2015-06-07 21:19:26 +00:00
bool IsIntoMergeStatement ( sql_state_t sqlStatesLine ) {
2013-08-28 00:44:27 +00:00
return ( sqlStatesLine & MASK_MERGE_STATEMENT ) ! = 0 ;
}
2015-06-07 21:19:26 +00:00
bool IsIntoCreateStatement ( sql_state_t sqlStatesLine ) {
return ( sqlStatesLine & MASK_INTO_CREATE ) ! = 0 ;
}
bool IsIntoCreateViewStatement ( sql_state_t sqlStatesLine ) {
return ( sqlStatesLine & MASK_INTO_CREATE_VIEW ) ! = 0 ;
}
bool IsIntoCreateViewAsStatement ( sql_state_t sqlStatesLine ) {
return ( sqlStatesLine & MASK_INTO_CREATE_VIEW_AS_STATEMENT ) ! = 0 ;
}
2019-05-04 18:14:48 +00:00
sql_state_t ForLine ( Sci_Position lineNumber ) {
2013-08-28 00:44:27 +00:00
return sqlStatement . ValueAt ( lineNumber ) ;
2011-03-22 00:16:49 +00:00
}
SQLStates ( ) { }
private :
2015-06-07 21:19:26 +00:00
SparseState < sql_state_t > sqlStatement ;
2011-03-22 00:16:49 +00:00
enum {
2015-06-07 21:19:26 +00:00
MASK_NESTED_CASES = 0x0001FF ,
MASK_INTO_SELECT_STATEMENT_OR_ASSIGNEMENT = 0x000200 ,
MASK_CASE_MERGE_WITHOUT_WHEN_FOUND = 0x000400 ,
MASK_MERGE_STATEMENT = 0x000800 ,
MASK_INTO_DECLARE = 0x001000 ,
MASK_INTO_EXCEPTION = 0x002000 ,
MASK_INTO_CONDITION = 0x004000 ,
MASK_IGNORE_WHEN = 0x008000 ,
MASK_INTO_CREATE = 0x010000 ,
MASK_INTO_CREATE_VIEW = 0x020000 ,
MASK_INTO_CREATE_VIEW_AS_STATEMENT = 0x040000
2011-03-22 00:16:49 +00:00
} ;
} ;
// Options used for LexerSQL
struct OptionsSQL {
bool fold ;
bool foldAtElse ;
bool foldComment ;
bool foldCompact ;
bool foldOnlyBegin ;
bool sqlBackticksIdentifier ;
bool sqlNumbersignComment ;
bool sqlBackslashEscapes ;
bool sqlAllowDottedWord ;
OptionsSQL ( ) {
fold = false ;
foldAtElse = false ;
foldComment = false ;
foldCompact = false ;
foldOnlyBegin = false ;
sqlBackticksIdentifier = false ;
sqlNumbersignComment = false ;
sqlBackslashEscapes = false ;
sqlAllowDottedWord = false ;
}
} ;
static const char * const sqlWordListDesc [ ] = {
" Keywords " ,
" Database Objects " ,
" PLDoc " ,
" SQL*Plus " ,
" User Keywords 1 " ,
" User Keywords 2 " ,
" User Keywords 3 " ,
" User Keywords 4 " ,
0
} ;
struct OptionSetSQL : public OptionSet < OptionsSQL > {
OptionSetSQL ( ) {
DefineProperty ( " fold " , & OptionsSQL : : fold ) ;
2011-07-17 22:30:49 +00:00
DefineProperty ( " fold.sql.at.else " , & OptionsSQL : : foldAtElse ,
" This option enables SQL folding on a \" ELSE \" and \" ELSIF \" line of an IF statement. " ) ;
2011-03-22 00:16:49 +00:00
DefineProperty ( " fold.comment " , & OptionsSQL : : foldComment ) ;
DefineProperty ( " fold.compact " , & OptionsSQL : : foldCompact ) ;
DefineProperty ( " fold.sql.only.begin " , & OptionsSQL : : foldOnlyBegin ) ;
DefineProperty ( " lexer.sql.backticks.identifier " , & OptionsSQL : : sqlBackticksIdentifier ) ;
DefineProperty ( " lexer.sql.numbersign.comment " , & OptionsSQL : : sqlNumbersignComment ,
" If \" lexer.sql.numbersign.comment \" property is set to 0 a line beginning with '#' will not be a comment. " ) ;
DefineProperty ( " sql.backslash.escapes " , & OptionsSQL : : sqlBackslashEscapes ,
" Enables backslash as an escape character in SQL. " ) ;
DefineProperty ( " lexer.sql.allow.dotted.word " , & OptionsSQL : : sqlAllowDottedWord ,
" Set to 1 to colourise recognized words with dots "
" (recommended for Oracle PL/SQL objects). " ) ;
DefineWordListSets ( sqlWordListDesc ) ;
}
} ;
2019-05-04 18:14:48 +00:00
class LexerSQL : public DefaultLexer {
2011-03-22 00:16:49 +00:00
public :
LexerSQL ( ) { }
2013-08-28 00:44:27 +00:00
virtual ~ LexerSQL ( ) { }
2019-05-04 18:14:48 +00:00
int SCI_METHOD Version ( ) const override {
return lvRelease4 ;
2011-03-22 00:16:49 +00:00
}
2019-05-04 18:14:48 +00:00
void SCI_METHOD Release ( ) override {
2011-03-22 00:16:49 +00:00
delete this ;
}
2019-05-04 18:14:48 +00:00
const char * SCI_METHOD PropertyNames ( ) override {
2011-03-22 00:16:49 +00:00
return osSQL . PropertyNames ( ) ;
}
2019-05-04 18:14:48 +00:00
int SCI_METHOD PropertyType ( const char * name ) override {
2011-03-22 00:16:49 +00:00
return osSQL . PropertyType ( name ) ;
}
2019-05-04 18:14:48 +00:00
const char * SCI_METHOD DescribeProperty ( const char * name ) override {
2011-03-22 00:16:49 +00:00
return osSQL . DescribeProperty ( name ) ;
}
2019-05-04 18:14:48 +00:00
Sci_Position SCI_METHOD PropertySet ( const char * key , const char * val ) override {
2011-03-22 00:16:49 +00:00
if ( osSQL . PropertySet ( & options , key , val ) ) {
return 0 ;
}
return - 1 ;
}
2019-05-04 18:14:48 +00:00
const char * SCI_METHOD DescribeWordListSets ( ) override {
2011-03-22 00:16:49 +00:00
return osSQL . DescribeWordListSets ( ) ;
}
2019-05-04 18:14:48 +00:00
Sci_Position SCI_METHOD WordListSet ( int n , const char * wl ) override ;
2019-07-21 13:26:02 +00:00
void SCI_METHOD Lex ( Sci_PositionU startPos , Sci_Position length , int initStyle , IDocument * pAccess ) override ;
void SCI_METHOD Fold ( Sci_PositionU startPos , Sci_Position length , int initStyle , IDocument * pAccess ) override ;
2011-03-22 00:16:49 +00:00
2019-05-04 18:14:48 +00:00
void * SCI_METHOD PrivateCall ( int , void * ) override {
2011-03-22 00:16:49 +00:00
return 0 ;
}
2019-05-04 18:14:48 +00:00
static ILexer4 * LexerFactorySQL ( ) {
2011-03-22 00:16:49 +00:00
return new LexerSQL ( ) ;
}
private :
bool IsStreamCommentStyle ( int style ) {
return style = = SCE_SQL_COMMENT | |
style = = SCE_SQL_COMMENTDOC | |
style = = SCE_SQL_COMMENTDOCKEYWORD | |
style = = SCE_SQL_COMMENTDOCKEYWORDERROR ;
}
2009-04-24 23:35:41 +00:00
2011-07-17 22:30:49 +00:00
bool IsCommentStyle ( int style ) {
switch ( style ) {
case SCE_SQL_COMMENT :
case SCE_SQL_COMMENTDOC :
case SCE_SQL_COMMENTLINE :
case SCE_SQL_COMMENTLINEDOC :
case SCE_SQL_COMMENTDOCKEYWORD :
case SCE_SQL_COMMENTDOCKEYWORDERROR :
return true ;
default :
return false ;
}
}
2019-05-04 18:14:48 +00:00
bool IsCommentLine ( Sci_Position line , LexAccessor & styler ) {
Sci_Position pos = styler . LineStart ( line ) ;
Sci_Position eol_pos = styler . LineStart ( line + 1 ) - 1 ;
for ( Sci_Position i = pos ; i + 1 < eol_pos ; i + + ) {
2013-08-28 00:44:27 +00:00
int style = styler . StyleAt ( i ) ;
// MySQL needs -- comments to be followed by space or control char
if ( style = = SCE_SQL_COMMENTLINE & & styler . Match ( i , " -- " ) )
return true ;
else if ( ! IsASpaceOrTab ( styler [ i ] ) )
return false ;
}
return false ;
}
2011-03-22 00:16:49 +00:00
OptionsSQL options ;
OptionSetSQL osSQL ;
SQLStates sqlStates ;
2009-06-24 19:09:31 +00:00
2011-03-22 00:16:49 +00:00
WordList keywords1 ;
WordList keywords2 ;
WordList kw_pldoc ;
WordList kw_sqlplus ;
WordList kw_user1 ;
WordList kw_user2 ;
WordList kw_user3 ;
WordList kw_user4 ;
} ;
2019-05-04 18:14:48 +00:00
Sci_Position SCI_METHOD LexerSQL : : WordListSet ( int n , const char * wl ) {
2011-03-22 00:16:49 +00:00
WordList * wordListN = 0 ;
switch ( n ) {
case 0 :
wordListN = & keywords1 ;
break ;
case 1 :
wordListN = & keywords2 ;
break ;
case 2 :
wordListN = & kw_pldoc ;
break ;
case 3 :
wordListN = & kw_sqlplus ;
break ;
case 4 :
wordListN = & kw_user1 ;
break ;
case 5 :
wordListN = & kw_user2 ;
break ;
case 6 :
wordListN = & kw_user3 ;
break ;
case 7 :
wordListN = & kw_user4 ;
}
2019-05-04 18:14:48 +00:00
Sci_Position firstModification = - 1 ;
2011-03-22 00:16:49 +00:00
if ( wordListN ) {
WordList wlNew ;
wlNew . Set ( wl ) ;
if ( * wordListN ! = wlNew ) {
wordListN - > Set ( wl ) ;
firstModification = 0 ;
}
}
return firstModification ;
}
2019-05-04 18:14:48 +00:00
void SCI_METHOD LexerSQL : : Lex ( Sci_PositionU startPos , Sci_Position length , int initStyle , IDocument * pAccess ) {
2011-03-22 00:16:49 +00:00
LexAccessor styler ( pAccess ) ;
StyleContext sc ( startPos , length , initStyle , styler ) ;
2009-04-24 23:35:41 +00:00
int styleBeforeDCKeyword = SCE_SQL_DEFAULT ;
2015-06-07 21:19:26 +00:00
2019-07-21 13:26:02 +00:00
for ( ; sc . More ( ) ; sc . Forward ( ) ) {
2009-04-24 23:35:41 +00:00
// Determine if the current state should terminate.
switch ( sc . state ) {
case SCE_SQL_OPERATOR :
sc . SetState ( SCE_SQL_DEFAULT ) ;
break ;
case SCE_SQL_NUMBER :
// We stop the number definition on non-numerical non-dot non-eE non-sign char
2015-06-07 21:19:26 +00:00
if ( ! IsANumberChar ( sc . ch , sc . chPrev ) ) {
2009-04-24 23:35:41 +00:00
sc . SetState ( SCE_SQL_DEFAULT ) ;
}
break ;
case SCE_SQL_IDENTIFIER :
2011-03-22 00:16:49 +00:00
if ( ! IsAWordChar ( sc . ch , options . sqlAllowDottedWord ) ) {
2009-04-24 23:35:41 +00:00
int nextState = SCE_SQL_DEFAULT ;
char s [ 1000 ] ;
sc . GetCurrentLowered ( s , sizeof ( s ) ) ;
if ( keywords1 . InList ( s ) ) {
sc . ChangeState ( SCE_SQL_WORD ) ;
} else if ( keywords2 . InList ( s ) ) {
sc . ChangeState ( SCE_SQL_WORD2 ) ;
} else if ( kw_sqlplus . InListAbbreviated ( s , ' ~ ' ) ) {
sc . ChangeState ( SCE_SQL_SQLPLUS ) ;
if ( strncmp ( s , " rem " , 3 ) = = 0 ) {
nextState = SCE_SQL_SQLPLUS_COMMENT ;
} else if ( strncmp ( s , " pro " , 3 ) = = 0 ) {
nextState = SCE_SQL_SQLPLUS_PROMPT ;
}
} else if ( kw_user1 . InList ( s ) ) {
sc . ChangeState ( SCE_SQL_USER1 ) ;
} else if ( kw_user2 . InList ( s ) ) {
sc . ChangeState ( SCE_SQL_USER2 ) ;
} else if ( kw_user3 . InList ( s ) ) {
sc . ChangeState ( SCE_SQL_USER3 ) ;
} else if ( kw_user4 . InList ( s ) ) {
sc . ChangeState ( SCE_SQL_USER4 ) ;
}
sc . SetState ( nextState ) ;
}
break ;
case SCE_SQL_QUOTEDIDENTIFIER :
if ( sc . ch = = 0x60 ) {
if ( sc . chNext = = 0x60 ) {
sc . Forward ( ) ; // Ignore it
} else {
sc . ForwardSetState ( SCE_SQL_DEFAULT ) ;
}
}
break ;
case SCE_SQL_COMMENT :
if ( sc . Match ( ' * ' , ' / ' ) ) {
sc . Forward ( ) ;
sc . ForwardSetState ( SCE_SQL_DEFAULT ) ;
}
break ;
case SCE_SQL_COMMENTDOC :
if ( sc . Match ( ' * ' , ' / ' ) ) {
sc . Forward ( ) ;
sc . ForwardSetState ( SCE_SQL_DEFAULT ) ;
} else if ( sc . ch = = ' @ ' | | sc . ch = = ' \\ ' ) { // Doxygen support
// Verify that we have the conditions to mark a comment-doc-keyword
if ( ( IsASpace ( sc . chPrev ) | | sc . chPrev = = ' * ' ) & & ( ! IsASpace ( sc . chNext ) ) ) {
styleBeforeDCKeyword = SCE_SQL_COMMENTDOC ;
sc . SetState ( SCE_SQL_COMMENTDOCKEYWORD ) ;
}
}
break ;
case SCE_SQL_COMMENTLINE :
case SCE_SQL_COMMENTLINEDOC :
case SCE_SQL_SQLPLUS_COMMENT :
case SCE_SQL_SQLPLUS_PROMPT :
if ( sc . atLineStart ) {
sc . SetState ( SCE_SQL_DEFAULT ) ;
}
break ;
case SCE_SQL_COMMENTDOCKEYWORD :
if ( ( styleBeforeDCKeyword = = SCE_SQL_COMMENTDOC ) & & sc . Match ( ' * ' , ' / ' ) ) {
sc . ChangeState ( SCE_SQL_COMMENTDOCKEYWORDERROR ) ;
sc . Forward ( ) ;
sc . ForwardSetState ( SCE_SQL_DEFAULT ) ;
} else if ( ! IsADoxygenChar ( sc . ch ) ) {
char s [ 100 ] ;
sc . GetCurrentLowered ( s , sizeof ( s ) ) ;
if ( ! isspace ( sc . ch ) | | ! kw_pldoc . InList ( s + 1 ) ) {
sc . ChangeState ( SCE_SQL_COMMENTDOCKEYWORDERROR ) ;
}
sc . SetState ( styleBeforeDCKeyword ) ;
}
break ;
case SCE_SQL_CHARACTER :
2011-03-22 00:16:49 +00:00
if ( options . sqlBackslashEscapes & & sc . ch = = ' \\ ' ) {
2009-04-24 23:35:41 +00:00
sc . Forward ( ) ;
} else if ( sc . ch = = ' \' ' ) {
2019-07-21 13:26:02 +00:00
if ( sc . chNext = = ' \' ' ) {
2009-04-24 23:35:41 +00:00
sc . Forward ( ) ;
} else {
sc . ForwardSetState ( SCE_SQL_DEFAULT ) ;
}
}
break ;
case SCE_SQL_STRING :
2019-05-04 18:14:48 +00:00
if ( options . sqlBackslashEscapes & & sc . ch = = ' \\ ' ) {
2009-04-24 23:35:41 +00:00
// Escape sequence
sc . Forward ( ) ;
} else if ( sc . ch = = ' \" ' ) {
if ( sc . chNext = = ' \" ' ) {
sc . Forward ( ) ;
} else {
sc . ForwardSetState ( SCE_SQL_DEFAULT ) ;
}
}
break ;
2015-06-07 21:19:26 +00:00
case SCE_SQL_QOPERATOR :
// Locate the unique Q operator character
sc . Complete ( ) ;
char qOperator = 0x00 ;
2019-05-04 18:14:48 +00:00
for ( Sci_Position styleStartPos = sc . currentPos ; styleStartPos > 0 ; - - styleStartPos ) {
2015-06-07 21:19:26 +00:00
if ( styler . StyleAt ( styleStartPos - 1 ) ! = SCE_SQL_QOPERATOR ) {
qOperator = styler . SafeGetCharAt ( styleStartPos + 2 ) ;
break ;
}
}
2019-05-04 18:14:48 +00:00
char qComplement = 0x00 ;
2015-06-07 21:19:26 +00:00
if ( qOperator = = ' < ' ) {
qComplement = ' > ' ;
} else if ( qOperator = = ' ( ' ) {
qComplement = ' ) ' ;
} else if ( qOperator = = ' { ' ) {
qComplement = ' } ' ;
} else if ( qOperator = = ' [ ' ) {
qComplement = ' ] ' ;
} else {
qComplement = qOperator ;
2019-05-04 18:14:48 +00:00
}
2015-06-07 21:19:26 +00:00
if ( sc . Match ( qComplement , ' \' ' ) ) {
sc . Forward ( ) ;
sc . ForwardSetState ( SCE_SQL_DEFAULT ) ;
}
break ;
2009-04-24 23:35:41 +00:00
}
// Determine if a new state should be entered.
if ( sc . state = = SCE_SQL_DEFAULT ) {
2015-06-07 21:19:26 +00:00
if ( sc . Match ( ' q ' , ' \' ' ) | | sc . Match ( ' Q ' , ' \' ' ) ) {
2019-05-04 18:14:48 +00:00
sc . SetState ( SCE_SQL_QOPERATOR ) ;
2015-06-07 21:19:26 +00:00
sc . Forward ( ) ;
} else if ( IsADigit ( sc . ch ) | | ( sc . ch = = ' . ' & & IsADigit ( sc . chNext ) ) | |
( ( sc . ch = = ' - ' | | sc . ch = = ' + ' ) & & IsADigit ( sc . chNext ) & & ! IsADigit ( sc . chPrev ) ) ) {
2009-04-24 23:35:41 +00:00
sc . SetState ( SCE_SQL_NUMBER ) ;
} else if ( IsAWordStart ( sc . ch ) ) {
sc . SetState ( SCE_SQL_IDENTIFIER ) ;
2011-03-22 00:16:49 +00:00
} else if ( sc . ch = = 0x60 & & options . sqlBackticksIdentifier ) {
2009-04-24 23:35:41 +00:00
sc . SetState ( SCE_SQL_QUOTEDIDENTIFIER ) ;
} else if ( sc . Match ( ' / ' , ' * ' ) ) {
if ( sc . Match ( " /** " ) | | sc . Match ( " /*! " ) ) { // Support of Doxygen doc. style
sc . SetState ( SCE_SQL_COMMENTDOC ) ;
} else {
sc . SetState ( SCE_SQL_COMMENT ) ;
}
sc . Forward ( ) ; // Eat the * so it isn't used for the end of the comment
} else if ( sc . Match ( ' - ' , ' - ' ) ) {
// MySQL requires a space or control char after --
// http://dev.mysql.com/doc/mysql/en/ansi-diff-comments.html
// Perhaps we should enforce that with proper property:
2011-03-22 00:16:49 +00:00
//~ } else if (sc.Match("-- ")) {
2009-04-24 23:35:41 +00:00
sc . SetState ( SCE_SQL_COMMENTLINE ) ;
2011-03-22 00:16:49 +00:00
} else if ( sc . ch = = ' # ' & & options . sqlNumbersignComment ) {
2009-04-24 23:35:41 +00:00
sc . SetState ( SCE_SQL_COMMENTLINEDOC ) ;
} else if ( sc . ch = = ' \' ' ) {
sc . SetState ( SCE_SQL_CHARACTER ) ;
} else if ( sc . ch = = ' \" ' ) {
sc . SetState ( SCE_SQL_STRING ) ;
} else if ( isoperator ( static_cast < char > ( sc . ch ) ) ) {
sc . SetState ( SCE_SQL_OPERATOR ) ;
}
}
}
sc . Complete ( ) ;
}
2019-05-04 18:14:48 +00:00
void SCI_METHOD LexerSQL : : Fold ( Sci_PositionU startPos , Sci_Position length , int initStyle , IDocument * pAccess ) {
2011-03-22 00:16:49 +00:00
if ( ! options . fold )
return ;
LexAccessor styler ( pAccess ) ;
2019-05-04 18:14:48 +00:00
Sci_PositionU endPos = startPos + length ;
2009-04-24 23:35:41 +00:00
int visibleChars = 0 ;
2019-05-04 18:14:48 +00:00
Sci_Position lineCurrent = styler . GetLine ( startPos ) ;
2009-04-24 23:35:41 +00:00
int levelCurrent = SC_FOLDLEVELBASE ;
2013-08-28 00:44:27 +00:00
2009-04-24 23:35:41 +00:00
if ( lineCurrent > 0 ) {
2013-08-28 00:44:27 +00:00
// Backtrack to previous line in case need to fix its fold status for folding block of single-line comments (i.e. '--').
2019-05-04 18:14:48 +00:00
Sci_Position lastNLPos = - 1 ;
2015-06-07 21:19:26 +00:00
// And keep going back until we find an operator ';' followed
// by white-space and/or comments. This will improve folding.
while ( - - startPos > 0 ) {
char ch = styler [ startPos ] ;
if ( ch = = ' \n ' | | ( ch = = ' \r ' & & styler [ startPos + 1 ] ! = ' \n ' ) ) {
lastNLPos = startPos ;
} else if ( ch = = ' ; ' & &
styler . StyleAt ( startPos ) = = SCE_SQL_OPERATOR ) {
bool isAllClear = true ;
2019-05-04 18:14:48 +00:00
for ( Sci_Position tempPos = startPos + 1 ;
2015-06-07 21:19:26 +00:00
tempPos < lastNLPos ;
+ + tempPos ) {
int tempStyle = styler . StyleAt ( tempPos ) ;
if ( ! IsCommentStyle ( tempStyle )
& & tempStyle ! = SCE_SQL_DEFAULT ) {
isAllClear = false ;
break ;
}
}
if ( isAllClear ) {
startPos = lastNLPos + 1 ;
break ;
}
}
}
lineCurrent = styler . GetLine ( startPos ) ;
2013-08-28 00:44:27 +00:00
if ( lineCurrent > 0 )
levelCurrent = styler . LevelAt ( lineCurrent - 1 ) > > 16 ;
2009-04-24 23:35:41 +00:00
}
2015-06-07 21:19:26 +00:00
// And because folding ends at ';', keep going until we find one
// Otherwise if create ... view ... as is split over multiple
// lines the folding won't always update immediately.
2019-05-04 18:14:48 +00:00
Sci_PositionU docLength = styler . Length ( ) ;
2015-06-07 21:19:26 +00:00
for ( ; endPos < docLength ; + + endPos ) {
if ( styler . SafeGetCharAt ( endPos ) = = ' ; ' ) {
break ;
}
}
2009-04-24 23:35:41 +00:00
int levelNext = levelCurrent ;
char chNext = styler [ startPos ] ;
int styleNext = styler . StyleAt ( startPos ) ;
int style = initStyle ;
bool endFound = false ;
2011-03-22 00:16:49 +00:00
bool isUnfoldingIgnored = false ;
// this statementFound flag avoids to fold when the statement is on only one line by ignoring ELSE or ELSIF
// eg. "IF condition1 THEN ... ELSIF condition2 THEN ... ELSE ... END IF;"
bool statementFound = false ;
2015-06-07 21:19:26 +00:00
sql_state_t sqlStatesCurrentLine = 0 ;
2011-03-22 00:16:49 +00:00
if ( ! options . foldOnlyBegin ) {
sqlStatesCurrentLine = sqlStates . ForLine ( lineCurrent ) ;
}
2019-05-04 18:14:48 +00:00
for ( Sci_PositionU i = startPos ; i < endPos ; i + + ) {
2009-04-24 23:35:41 +00:00
char ch = chNext ;
chNext = styler . SafeGetCharAt ( i + 1 ) ;
int stylePrev = style ;
style = styleNext ;
styleNext = styler . StyleAt ( i + 1 ) ;
bool atEOL = ( ch = = ' \r ' & & chNext ! = ' \n ' ) | | ( ch = = ' \n ' ) ;
2011-07-17 22:30:49 +00:00
if ( atEOL | | ( ! IsCommentStyle ( style ) & & ch = = ' ; ' ) ) {
2011-03-22 00:16:49 +00:00
if ( endFound ) {
//Maybe this is the end of "EXCEPTION" BLOCK (eg. "BEGIN ... EXCEPTION ... END;")
sqlStatesCurrentLine = sqlStates . IntoExceptionBlock ( sqlStatesCurrentLine , false ) ;
}
// set endFound and isUnfoldingIgnored to false if EOL is reached or ';' is found
endFound = false ;
isUnfoldingIgnored = false ;
}
2013-08-28 00:44:27 +00:00
if ( ( ! IsCommentStyle ( style ) & & ch = = ' ; ' ) ) {
if ( sqlStates . IsIntoMergeStatement ( sqlStatesCurrentLine ) ) {
// This is the end of "MERGE" statement.
if ( ! sqlStates . IsCaseMergeWithoutWhenFound ( sqlStatesCurrentLine ) )
levelNext - - ;
sqlStatesCurrentLine = sqlStates . IntoMergeStatement ( sqlStatesCurrentLine , false ) ;
levelNext - - ;
}
if ( sqlStates . IsIntoSelectStatementOrAssignment ( sqlStatesCurrentLine ) )
sqlStatesCurrentLine = sqlStates . IntoSelectStatementOrAssignment ( sqlStatesCurrentLine , false ) ;
2015-06-07 21:19:26 +00:00
if ( sqlStates . IsIntoCreateStatement ( sqlStatesCurrentLine ) ) {
if ( sqlStates . IsIntoCreateViewStatement ( sqlStatesCurrentLine ) ) {
if ( sqlStates . IsIntoCreateViewAsStatement ( sqlStatesCurrentLine ) ) {
levelNext - - ;
sqlStatesCurrentLine = sqlStates . IntoCreateViewAsStatement ( sqlStatesCurrentLine , false ) ;
}
sqlStatesCurrentLine = sqlStates . IntoCreateViewStatement ( sqlStatesCurrentLine , false ) ;
}
sqlStatesCurrentLine = sqlStates . IntoCreateStatement ( sqlStatesCurrentLine , false ) ;
}
2013-08-28 00:44:27 +00:00
}
if ( ch = = ' : ' & & chNext = = ' = ' & & ! IsCommentStyle ( style ) )
sqlStatesCurrentLine = sqlStates . IntoSelectStatementOrAssignment ( sqlStatesCurrentLine , true ) ;
2011-03-22 00:16:49 +00:00
if ( options . foldComment & & IsStreamCommentStyle ( style ) ) {
2009-04-24 23:35:41 +00:00
if ( ! IsStreamCommentStyle ( stylePrev ) ) {
levelNext + + ;
} else if ( ! IsStreamCommentStyle ( styleNext ) & & ! atEOL ) {
// Comments don't end at end of line and the next character may be unstyled.
levelNext - - ;
}
}
2011-03-22 00:16:49 +00:00
if ( options . foldComment & & ( style = = SCE_SQL_COMMENTLINE ) ) {
2009-04-24 23:35:41 +00:00
// MySQL needs -- comments to be followed by space or control char
if ( ( ch = = ' - ' ) & & ( chNext = = ' - ' ) ) {
char chNext2 = styler . SafeGetCharAt ( i + 2 ) ;
char chNext3 = styler . SafeGetCharAt ( i + 3 ) ;
if ( chNext2 = = ' { ' | | chNext3 = = ' { ' ) {
levelNext + + ;
} else if ( chNext2 = = ' } ' | | chNext3 = = ' } ' ) {
levelNext - - ;
}
}
}
2013-08-28 00:44:27 +00:00
// Fold block of single-line comments (i.e. '--').
if ( options . foldComment & & atEOL & & IsCommentLine ( lineCurrent , styler ) ) {
if ( ! IsCommentLine ( lineCurrent - 1 , styler ) & & IsCommentLine ( lineCurrent + 1 , styler ) )
levelNext + + ;
else if ( IsCommentLine ( lineCurrent - 1 , styler ) & & ! IsCommentLine ( lineCurrent + 1 , styler ) )
levelNext - - ;
}
2009-04-24 23:35:41 +00:00
if ( style = = SCE_SQL_OPERATOR ) {
if ( ch = = ' ( ' ) {
2011-03-22 00:16:49 +00:00
if ( levelCurrent > levelNext )
levelCurrent - - ;
2011-07-17 22:30:49 +00:00
levelNext + + ;
2009-04-24 23:35:41 +00:00
} else if ( ch = = ' ) ' ) {
levelNext - - ;
2011-03-22 00:16:49 +00:00
} else if ( ( ! options . foldOnlyBegin ) & & ch = = ' ; ' ) {
sqlStatesCurrentLine = sqlStates . IgnoreWhen ( sqlStatesCurrentLine , false ) ;
2009-04-24 23:35:41 +00:00
}
}
// If new keyword (cannot trigger on elseif or nullif, does less tests)
if ( style = = SCE_SQL_WORD & & stylePrev ! = SCE_SQL_WORD ) {
2011-03-22 00:16:49 +00:00
const int MAX_KW_LEN = 9 ; // Maximum length of folding keywords
2009-04-24 23:35:41 +00:00
char s [ MAX_KW_LEN + 2 ] ;
unsigned int j = 0 ;
for ( ; j < MAX_KW_LEN + 1 ; j + + ) {
if ( ! iswordchar ( styler [ i + j ] ) ) {
break ;
}
s [ j ] = static_cast < char > ( tolower ( styler [ i + j ] ) ) ;
}
if ( j = = MAX_KW_LEN + 1 ) {
// Keyword too long, don't test it
s [ 0 ] = ' \0 ' ;
} else {
s [ j ] = ' \0 ' ;
}
2013-08-28 00:44:27 +00:00
if ( ! options . foldOnlyBegin & &
strcmp ( s , " select " ) = = 0 ) {
sqlStatesCurrentLine = sqlStates . IntoSelectStatementOrAssignment ( sqlStatesCurrentLine , true ) ;
} else if ( strcmp ( s , " if " ) = = 0 ) {
2009-04-24 23:35:41 +00:00
if ( endFound ) {
endFound = false ;
2011-03-22 00:16:49 +00:00
if ( options . foldOnlyBegin & & ! isUnfoldingIgnored ) {
// this end isn't for begin block, but for if block ("end if;")
// so ignore previous "end" by increment levelNext.
levelNext + + ;
}
2009-04-24 23:35:41 +00:00
} else {
2011-03-22 00:16:49 +00:00
if ( ! options . foldOnlyBegin )
sqlStatesCurrentLine = sqlStates . IntoCondition ( sqlStatesCurrentLine , true ) ;
if ( levelCurrent > levelNext ) {
// doesn't include this line into the folding block
// because doesn't hide IF (eg "END; IF")
levelCurrent = levelNext ;
}
}
} else if ( ! options . foldOnlyBegin & &
strcmp ( s , " then " ) = = 0 & &
sqlStates . IsIntoCondition ( sqlStatesCurrentLine ) ) {
sqlStatesCurrentLine = sqlStates . IntoCondition ( sqlStatesCurrentLine , false ) ;
if ( ! options . foldOnlyBegin ) {
if ( levelCurrent > levelNext ) {
levelCurrent = levelNext ;
}
if ( ! statementFound )
levelNext + + ;
statementFound = true ;
} else if ( levelCurrent > levelNext ) {
// doesn't include this line into the folding block
// because doesn't hide LOOP or CASE (eg "END; LOOP" or "END; CASE")
levelCurrent = levelNext ;
}
} else if ( strcmp ( s , " loop " ) = = 0 | |
strcmp ( s , " case " ) = = 0 ) {
if ( endFound ) {
endFound = false ;
if ( options . foldOnlyBegin & & ! isUnfoldingIgnored ) {
// this end isn't for begin block, but for loop block ("end loop;") or case block ("end case;")
// so ignore previous "end" by increment levelNext.
levelNext + + ;
}
if ( ( ! options . foldOnlyBegin ) & & strcmp ( s , " case " ) = = 0 ) {
sqlStatesCurrentLine = sqlStates . EndCaseBlock ( sqlStatesCurrentLine ) ;
2013-08-28 00:44:27 +00:00
if ( ! sqlStates . IsCaseMergeWithoutWhenFound ( sqlStatesCurrentLine ) )
levelNext - - ; //again for the "end case;" and block when
2011-03-22 00:16:49 +00:00
}
} else if ( ! options . foldOnlyBegin ) {
if ( strcmp ( s , " case " ) = = 0 ) {
sqlStatesCurrentLine = sqlStates . BeginCaseBlock ( sqlStatesCurrentLine ) ;
2013-08-28 00:44:27 +00:00
sqlStatesCurrentLine = sqlStates . CaseMergeWithoutWhenFound ( sqlStatesCurrentLine , true ) ;
2011-03-22 00:16:49 +00:00
}
2013-08-28 00:44:27 +00:00
if ( levelCurrent > levelNext )
2011-03-22 00:16:49 +00:00
levelCurrent = levelNext ;
2013-08-28 00:44:27 +00:00
2011-03-22 00:16:49 +00:00
if ( ! statementFound )
levelNext + + ;
statementFound = true ;
} else if ( levelCurrent > levelNext ) {
// doesn't include this line into the folding block
// because doesn't hide LOOP or CASE (eg "END; LOOP" or "END; CASE")
levelCurrent = levelNext ;
2009-04-24 23:35:41 +00:00
}
2011-03-22 00:16:49 +00:00
} else if ( ( ! options . foldOnlyBegin ) & & (
// folding for ELSE and ELSIF block only if foldAtElse is set
// and IF or CASE aren't on only one line with ELSE or ELSIF (with flag statementFound)
options . foldAtElse & & ! statementFound ) & & strcmp ( s , " elsif " ) = = 0 ) {
sqlStatesCurrentLine = sqlStates . IntoCondition ( sqlStatesCurrentLine , true ) ;
levelCurrent - - ;
levelNext - - ;
} else if ( ( ! options . foldOnlyBegin ) & & (
// folding for ELSE and ELSIF block only if foldAtElse is set
// and IF or CASE aren't on only one line with ELSE or ELSIF (with flag statementFound)
options . foldAtElse & & ! statementFound ) & & strcmp ( s , " else " ) = = 0 ) {
// prevent also ELSE is on the same line (eg. "ELSE ... END IF;")
statementFound = true ;
2013-08-28 00:44:27 +00:00
if ( sqlStates . IsIntoCaseBlock ( sqlStatesCurrentLine ) & & sqlStates . IsCaseMergeWithoutWhenFound ( sqlStatesCurrentLine ) ) {
sqlStatesCurrentLine = sqlStates . CaseMergeWithoutWhenFound ( sqlStatesCurrentLine , false ) ;
levelNext + + ;
} else {
// we are in same case "} ELSE {" in C language
levelCurrent - - ;
}
2009-04-24 23:35:41 +00:00
} else if ( strcmp ( s , " begin " ) = = 0 ) {
levelNext + + ;
2011-03-22 00:16:49 +00:00
sqlStatesCurrentLine = sqlStates . IntoDeclareBlock ( sqlStatesCurrentLine , false ) ;
2010-07-12 22:19:51 +00:00
} else if ( ( strcmp ( s , " end " ) = = 0 ) | |
2011-03-22 00:16:49 +00:00
// SQL Anywhere permits IF ... ELSE ... ENDIF
// will only be active if "endif" appears in the
// keyword list.
( strcmp ( s , " endif " ) = = 0 ) ) {
2009-04-24 23:35:41 +00:00
endFound = true ;
levelNext - - ;
2013-08-28 00:44:27 +00:00
if ( sqlStates . IsIntoSelectStatementOrAssignment ( sqlStatesCurrentLine ) & & ! sqlStates . IsCaseMergeWithoutWhenFound ( sqlStatesCurrentLine ) )
levelNext - - ;
2009-04-24 23:35:41 +00:00
if ( levelNext < SC_FOLDLEVELBASE ) {
levelNext = SC_FOLDLEVELBASE ;
2011-03-22 00:16:49 +00:00
isUnfoldingIgnored = true ;
2009-04-24 23:35:41 +00:00
}
2011-03-22 00:16:49 +00:00
} else if ( ( ! options . foldOnlyBegin ) & &
strcmp ( s , " when " ) = = 0 & &
! sqlStates . IsIgnoreWhen ( sqlStatesCurrentLine ) & &
2013-08-28 00:44:27 +00:00
! sqlStates . IsIntoExceptionBlock ( sqlStatesCurrentLine ) & & (
sqlStates . IsIntoCaseBlock ( sqlStatesCurrentLine ) | |
sqlStates . IsIntoMergeStatement ( sqlStatesCurrentLine )
)
) {
2011-03-22 00:16:49 +00:00
sqlStatesCurrentLine = sqlStates . IntoCondition ( sqlStatesCurrentLine , true ) ;
// Don't foldind when CASE and WHEN are on the same line (with flag statementFound) (eg. "CASE selector WHEN expression1 THEN sequence_of_statements1;\n")
2013-08-28 00:44:27 +00:00
// and same way for MERGE statement.
2011-03-22 00:16:49 +00:00
if ( ! statementFound ) {
2013-08-28 00:44:27 +00:00
if ( ! sqlStates . IsCaseMergeWithoutWhenFound ( sqlStatesCurrentLine ) ) {
levelCurrent - - ;
levelNext - - ;
}
sqlStatesCurrentLine = sqlStates . CaseMergeWithoutWhenFound ( sqlStatesCurrentLine , false ) ;
2011-03-22 00:16:49 +00:00
}
} else if ( ( ! options . foldOnlyBegin ) & & strcmp ( s , " exit " ) = = 0 ) {
sqlStatesCurrentLine = sqlStates . IgnoreWhen ( sqlStatesCurrentLine , true ) ;
} else if ( ( ! options . foldOnlyBegin ) & & ! sqlStates . IsIntoDeclareBlock ( sqlStatesCurrentLine ) & & strcmp ( s , " exception " ) = = 0 ) {
sqlStatesCurrentLine = sqlStates . IntoExceptionBlock ( sqlStatesCurrentLine , true ) ;
} else if ( ( ! options . foldOnlyBegin ) & &
( strcmp ( s , " declare " ) = = 0 | |
strcmp ( s , " function " ) = = 0 | |
strcmp ( s , " procedure " ) = = 0 | |
strcmp ( s , " package " ) = = 0 ) ) {
sqlStatesCurrentLine = sqlStates . IntoDeclareBlock ( sqlStatesCurrentLine , true ) ;
2013-08-28 00:44:27 +00:00
} else if ( ( ! options . foldOnlyBegin ) & &
strcmp ( s , " merge " ) = = 0 ) {
sqlStatesCurrentLine = sqlStates . IntoMergeStatement ( sqlStatesCurrentLine , true ) ;
sqlStatesCurrentLine = sqlStates . CaseMergeWithoutWhenFound ( sqlStatesCurrentLine , true ) ;
levelNext + + ;
statementFound = true ;
2015-06-07 21:19:26 +00:00
} else if ( ( ! options . foldOnlyBegin ) & &
strcmp ( s , " create " ) = = 0 ) {
sqlStatesCurrentLine = sqlStates . IntoCreateStatement ( sqlStatesCurrentLine , true ) ;
} else if ( ( ! options . foldOnlyBegin ) & &
strcmp ( s , " view " ) = = 0 & &
sqlStates . IsIntoCreateStatement ( sqlStatesCurrentLine ) ) {
sqlStatesCurrentLine = sqlStates . IntoCreateViewStatement ( sqlStatesCurrentLine , true ) ;
} else if ( ( ! options . foldOnlyBegin ) & &
strcmp ( s , " as " ) = = 0 & &
sqlStates . IsIntoCreateViewStatement ( sqlStatesCurrentLine ) & &
! sqlStates . IsIntoCreateViewAsStatement ( sqlStatesCurrentLine ) ) {
sqlStatesCurrentLine = sqlStates . IntoCreateViewAsStatement ( sqlStatesCurrentLine , true ) ;
levelNext + + ;
2009-04-24 23:35:41 +00:00
}
}
if ( atEOL ) {
int levelUse = levelCurrent ;
int lev = levelUse | levelNext < < 16 ;
2011-03-22 00:16:49 +00:00
if ( visibleChars = = 0 & & options . foldCompact )
2009-04-24 23:35:41 +00:00
lev | = SC_FOLDLEVELWHITEFLAG ;
if ( levelUse < levelNext )
lev | = SC_FOLDLEVELHEADERFLAG ;
if ( lev ! = styler . LevelAt ( lineCurrent ) ) {
styler . SetLevel ( lineCurrent , lev ) ;
}
lineCurrent + + ;
levelCurrent = levelNext ;
visibleChars = 0 ;
2011-03-22 00:16:49 +00:00
statementFound = false ;
if ( ! options . foldOnlyBegin )
sqlStates . Set ( lineCurrent , sqlStatesCurrentLine ) ;
2009-04-24 23:35:41 +00:00
}
if ( ! isspacechar ( ch ) ) {
visibleChars + + ;
}
}
}
2011-03-22 00:16:49 +00:00
LexerModule lmSQL ( SCLEX_SQL , LexerSQL : : LexerFactorySQL , " sql " , sqlWordListDesc ) ;