xref: /vim-8.2.3635/runtime/ftplugin/sql.vim (revision 8e52a593)
1" SQL filetype plugin file
2" Language:    SQL (Common for Oracle, Microsoft SQL Server, Sybase)
3" Version:     8.0
4" Maintainer:  David Fishburn <dfishburn dot vim at gmail dot com>
5" Last Change: 2012 May 18
6" Download:    http://vim.sourceforge.net/script.php?script_id=454
7
8" For more details please use:
9"        :h sql.txt
10"
11" This file should only contain values that are common to all SQL languages
12" Oracle, Microsoft SQL Server, Sybase ASA/ASE, MySQL, and so on
13" If additional features are required create:
14"        vimfiles/after/ftplugin/sql.vim (Windows)
15"        .vim/after/ftplugin/sql.vim     (Unix)
16" to override and add any of your own settings.
17
18
19" This file also creates a command, SQLSetType, which allows you to change
20" SQL dialects on the fly.  For example, if I open an Oracle SQL file, it
21" is color highlighted appropriately.  If I open an Informix SQL file, it
22" will still be highlighted according to Oracles settings.  By running:
23"     :SQLSetType sqlinformix
24"
25" All files called sqlinformix.vim will be loaded from the indent and syntax
26" directories.  This allows you to easily flip SQL dialects on a per file
27" basis.  NOTE: you can also use completion:
28"     :SQLSetType <tab>
29"
30" To change the default dialect, add the following to your vimrc:
31"    let g:sql_type_default = 'sqlanywhere'
32"
33" This file also creates a command, SQLGetType, which allows you to
34" determine what the current dialect is in use.
35"     :SQLGetType
36"
37" History
38"
39" Version 8.0
40"
41" NF: Improved the matchit plugin regex (Talek)
42"
43" Version 7.0
44"
45" NF: Calls the sqlcomplete#ResetCacheSyntax() function when calling
46"     SQLSetType.
47"
48" Version 6.0
49"
50" NF: Adds the command SQLGetType
51"
52" Version 5.0
53"
54" NF: Adds the ability to choose the keys to control SQL completion, just add
55"     the following to your .vimrc:
56"    let g:ftplugin_sql_omni_key       = '<C-C>'
57"    let g:ftplugin_sql_omni_key_right = '<Right>'
58"    let g:ftplugin_sql_omni_key_left  = '<Left>'
59"
60" BF: format-options - Auto-wrap comments using textwidth was turned off
61"                      by mistake.
62
63
64" Only do this when not done yet for this buffer
65if exists("b:did_ftplugin")
66  finish
67endif
68
69let s:save_cpo = &cpo
70set cpo&vim
71
72" Disable autowrapping for code, but enable for comments
73" t	Auto-wrap text using textwidth
74" c     Auto-wrap comments using textwidth, inserting the current comment
75"       leader automatically.
76setlocal formatoptions-=t
77setlocal formatoptions+=c
78
79" Functions/Commands to allow the user to change SQL syntax dialects
80" through the use of :SQLSetType <tab> for completion.
81" This works with both Vim 6 and 7.
82
83if !exists("*SQL_SetType")
84    " NOTE: You cannot use function! since this file can be
85    " sourced from within this function.  That will result in
86    " an error reported by Vim.
87    function SQL_GetList(ArgLead, CmdLine, CursorPos)
88
89        if !exists('s:sql_list')
90            " Grab a list of files that contain "sql" in their names
91            let list_indent   = globpath(&runtimepath, 'indent/*sql*')
92            let list_syntax   = globpath(&runtimepath, 'syntax/*sql*')
93            let list_ftplugin = globpath(&runtimepath, 'ftplugin/*sql*')
94
95            let sqls = "\n".list_indent."\n".list_syntax."\n".list_ftplugin."\n"
96
97            " Strip out everything (path info) but the filename
98            " Regex
99            "    From between two newline characters
100            "    Non-greedily grab all characters
101            "    Followed by a valid filename \w\+\.\w\+ (sql.vim)
102            "    Followed by a newline, but do not include the newline
103            "
104            "    Replace it with just the filename (get rid of PATH)
105            "
106            "    Recursively, since there are many filenames that contain
107            "    the word SQL in the indent, syntax and ftplugin directory
108            let sqls = substitute( sqls,
109                        \ '[\n]\%(.\{-}\)\(\w\+\.\w\+\)\n\@=',
110                        \ '\1\n',
111                        \ 'g'
112                        \ )
113
114            " Remove duplicates, since sqlanywhere.vim can exist in the
115            " sytax, indent and ftplugin directory, yet we only want
116            " to display the option once
117            let index = match(sqls, '.\{-}\ze\n')
118            while index > -1
119                " Get the first filename
120                let file = matchstr(sqls, '.\{-}\ze\n', index)
121                " Recursively replace any *other* occurrence of that
122                " filename with nothing (ie remove it)
123                let sqls = substitute(sqls, '\%>'.(index+strlen(file)).'c\<'.file.'\>\n', '', 'g')
124                " Move on to the next filename
125                let index = match(sqls, '.\{-}\ze\n', (index+strlen(file)+1))
126            endwhile
127
128            " Sort the list if using version 7
129            if v:version >= 700
130                let mylist = split(sqls, "\n")
131                let mylist = sort(mylist)
132                let sqls   = join(mylist, "\n")
133            endif
134
135            let s:sql_list = sqls
136        endif
137
138        return s:sql_list
139
140    endfunction
141
142    function SQL_SetType(name)
143
144        " User has decided to override default SQL scripts and
145        " specify a vendor specific version
146        " (ie Oracle, Informix, SQL Anywhere, ...)
147        " So check for an remove any settings that prevent the
148        " scripts from being executed, and then source the
149        " appropriate Vim scripts.
150        if exists("b:did_ftplugin")
151            unlet b:did_ftplugin
152        endif
153        if exists("b:current_syntax")
154            " echomsg 'SQLSetType - clearing syntax'
155            syntax clear
156        endif
157        if exists("b:did_indent")
158            " echomsg 'SQLSetType - clearing indent'
159            unlet b:did_indent
160            " Set these values to their defaults
161            setlocal indentkeys&
162            setlocal indentexpr&
163        endif
164
165        " Ensure the name is in the correct format
166        let new_sql_type = substitute(a:name,
167                    \ '\s*\([^\.]\+\)\(\.\w\+\)\?', '\L\1', '')
168
169        " Do not specify a buffer local variable if it is
170        " the default value
171        if new_sql_type == 'sql'
172          let new_sql_type = 'sqloracle'
173        endif
174        let b:sql_type_override = new_sql_type
175
176        " Remove any cached SQL since a new sytax will have different
177        " items and groups
178        if !exists('g:loaded_sql_completion') || 100 == g:loaded_sql_completion
179            call sqlcomplete#ResetCacheSyntax()
180        endif
181
182        " Vim will automatically source the correct files if we
183        " change the filetype.  You cannot do this with setfiletype
184        " since that command will only execute if a filetype has
185        " not already been set.  In this case we want to override
186        " the existing filetype.
187        let &filetype = 'sql'
188
189        if b:sql_compl_savefunc != ""
190            " We are changing the filetype to SQL from some other filetype
191            " which had OMNI completion defined.  We need to activate the
192            " SQL completion plugin in order to cache some of the syntax items
193            " while the syntax rules for SQL are active.
194            call sqlcomplete#PreCacheSyntax()
195        endif
196    endfunction
197    command! -nargs=* -complete=custom,SQL_GetList SQLSetType :call SQL_SetType(<q-args>)
198
199endif
200
201" Functions/Commands to allow the user determine current SQL syntax dialect
202" This works with both Vim 6 and 7.
203
204if !exists("*SQL_GetType")
205    function SQL_GetType()
206        if exists('b:sql_type_override')
207            echomsg "Current SQL dialect in use:".b:sql_type_override
208        else
209            echomsg "Current SQL dialect in use:".g:sql_type_default
210        endif
211    endfunction
212    command! -nargs=0 SQLGetType :call SQL_GetType()
213endif
214
215if exists("b:sql_type_override")
216    " echo 'sourcing buffer ftplugin/'.b:sql_type_override.'.vim'
217    if globpath(&runtimepath, 'ftplugin/'.b:sql_type_override.'.vim') != ''
218        exec 'runtime ftplugin/'.b:sql_type_override.'.vim'
219    " else
220    "     echomsg 'ftplugin/'.b:sql_type_override.' not exist, using default'
221    endif
222elseif exists("g:sql_type_default")
223    " echo 'sourcing global ftplugin/'.g:sql_type_default.'.vim'
224    if globpath(&runtimepath, 'ftplugin/'.g:sql_type_default.'.vim') != ''
225        exec 'runtime ftplugin/'.g:sql_type_default.'.vim'
226    " else
227    "     echomsg 'ftplugin/'.g:sql_type_default.'.vim not exist, using default'
228    endif
229endif
230
231" If the above runtime command succeeded, do not load the default settings
232if exists("b:did_ftplugin")
233  finish
234endif
235
236let b:undo_ftplugin = "setl comments<"
237
238" Don't load another plugin for this buffer
239let b:did_ftplugin     = 1
240let b:current_ftplugin = 'sql'
241
242" Win32 can filter files in the browse dialog
243if has("gui_win32") && !exists("b:browsefilter")
244    let b:browsefilter = "SQL Files (*.sql)\t*.sql\n" .
245	  \ "All Files (*.*)\t*.*\n"
246endif
247
248" Some standard expressions for use with the matchit strings
249let s:notend = '\%(\<end\s\+\)\@<!'
250let s:when_no_matched_or_others = '\%(\<when\>\%(\s\+\%(\%(\<not\>\s\+\)\?<matched\>\)\|\<others\>\)\@!\)'
251let s:or_replace = '\%(or\s\+replace\s\+\)\?'
252
253" Define patterns for the matchit macro
254if !exists("b:match_words")
255    " SQL is generally case insensitive
256    let b:match_ignorecase = 1
257
258    " Handle the following:
259    " if
260    " elseif | elsif
261    " else [if]
262    " end if
263    "
264    " [while condition] loop
265    "     leave
266    "     break
267    "     continue
268    "     exit
269    " end loop
270    "
271    " for
272    "     leave
273    "     break
274    "     continue
275    "     exit
276    " end loop
277    "
278    " do
279    "     statements
280    " doend
281    "
282    " case
283    " when
284    " when
285    " default
286    " end case
287    "
288    " merge
289    " when not matched
290    " when matched
291    "
292    " EXCEPTION
293    " WHEN column_not_found THEN
294    " WHEN OTHERS THEN
295    "
296    " create[ or replace] procedure|function|event
297                " \ '^\s*\<\%(do\|for\|while\|loop\)\>.*:'.
298
299    let b:match_words =
300		\ '\<begin\>:\<end\>\W*$,'.
301		\
302                \ s:notend . '\<if\>:'.
303                \ '\<elsif\>\|\<elseif\>\|\<else\>:'.
304                \ '\<end\s\+if\>,'.
305                \
306                \ '\(^\s*\)\@<=\(\<\%(do\|for\|while\|loop\)\>.*\):'.
307                \ '\%(\<exit\>\|\<leave\>\|\<break\>\|\<continue\>\):'.
308                \ '\%(\<doend\>\|\%(\<end\s\+\%(for\|while\|loop\>\)\)\),'.
309                \
310                \ '\%('. s:notend . '\<case\>\):'.
311                \ '\%('.s:when_no_matched_or_others.'\):'.
312                \ '\%(\<when\s\+others\>\|\<end\s\+case\>\),' .
313                \
314                \ '\<merge\>:' .
315                \ '\<when\s\+not\s\+matched\>:' .
316                \ '\<when\s\+matched\>,' .
317                \
318                \ '\%(\<create\s\+' . s:or_replace . '\)\?'.
319                \ '\%(function\|procedure\|event\):'.
320                \ '\<returns\?\>'
321                " \ '\<begin\>\|\<returns\?\>:'.
322                " \ '\<end\>\(;\)\?\s*$'
323                " \ '\<exception\>:'.s:when_no_matched_or_others.
324                " \ ':\<when\s\+others\>,'.
325		"
326                " \ '\%(\<exception\>\|\%('. s:notend . '\<case\>\)\):'.
327                " \ '\%(\<default\>\|'.s:when_no_matched_or_others.'\):'.
328                " \ '\%(\%(\<when\s\+others\>\)\|\<end\s\+case\>\),' .
329endif
330
331" Define how to find the macro definition of a variable using the various
332" [d, [D, [_CTRL_D and so on features
333" Match these values ignoring case
334" ie  DECLARE varname INTEGER
335let &l:define = '\c\<\(VARIABLE\|DECLARE\|IN\|OUT\|INOUT\)\>'
336
337
338" Mappings to move to the next BEGIN ... END block
339" \W - no characters or digits
340nmap <buffer> <silent> ]] :call search('\\c^\\s*begin\\>', 'W' )<CR>
341nmap <buffer> <silent> [[ :call search('\\c^\\s*begin\\>', 'bW' )<CR>
342nmap <buffer> <silent> ][ :call search('\\c^\\s*end\\W*$', 'W' )<CR>
343nmap <buffer> <silent> [] :call search('\\c^\\s*end\\W*$', 'bW' )<CR>
344vmap <buffer> <silent> ]] :<C-U>exec "normal! gv"<Bar>call search('\\c^\\s*begin\\>', 'W' )<CR>
345vmap <buffer> <silent> [[ :<C-U>exec "normal! gv"<Bar>call search('\\c^\\s*begin\\>', 'bW' )<CR>
346vmap <buffer> <silent> ][ :<C-U>exec "normal! gv"<Bar>call search('\\c^\\s*end\\W*$', 'W' )<CR>
347vmap <buffer> <silent> [] :<C-U>exec "normal! gv"<Bar>call search('\\c^\\s*end\\W*$', 'bW' )<CR>
348
349
350" By default only look for CREATE statements, but allow
351" the user to override
352if !exists('g:ftplugin_sql_statements')
353    let g:ftplugin_sql_statements = 'create'
354endif
355
356" Predefined SQL objects what are used by the below mappings using
357" the ]} style maps.
358" This global variable allows the users to override it's value
359" from within their vimrc.
360" Note, you cannot use \?, since these patterns can be used to search
361" backwards, you must use \{,1}
362if !exists('g:ftplugin_sql_objects')
363    let g:ftplugin_sql_objects = 'function,procedure,event,' .
364                \ '\\(existing\\\\|global\\s\\+temporary\\s\\+\\)\\\{,1}' .
365                \ 'table,trigger' .
366                \ ',schema,service,publication,database,datatype,domain' .
367                \ ',index,subscription,synchronization,view,variable'
368endif
369
370" Key to trigger SQL completion
371if !exists('g:ftplugin_sql_omni_key')
372    let g:ftplugin_sql_omni_key = '<C-C>'
373endif
374" Key to trigger drill into column list
375if !exists('g:ftplugin_sql_omni_key_right')
376    let g:ftplugin_sql_omni_key_right = '<Right>'
377endif
378" Key to trigger drill out of column list
379if !exists('g:ftplugin_sql_omni_key_left')
380    let g:ftplugin_sql_omni_key_left = '<Left>'
381endif
382
383" Replace all ,'s with bars, except ones with numbers after them.
384" This will most likely be a \{,1} string.
385let s:ftplugin_sql_objects =
386            \ '\\c^\\s*' .
387            \ '\\(\\(' .
388            \ substitute(g:ftplugin_sql_statements, ',\d\@!', '\\\\\\|', 'g') .
389            \ '\\)\\s\\+\\(or\\s\\+replace\\\s\+\\)\\{,1}\\)\\{,1}' .
390            \ '\\<\\(' .
391            \ substitute(g:ftplugin_sql_objects, ',\d\@!', '\\\\\\|', 'g') .
392            \ '\\)\\>'
393
394" Mappings to move to the next CREATE ... block
395exec "nmap <buffer> <silent> ]} :call search('".s:ftplugin_sql_objects."', 'W')<CR>"
396exec "nmap <buffer> <silent> [{ :call search('".s:ftplugin_sql_objects."', 'bW')<CR>"
397" Could not figure out how to use a :call search() string in visual mode
398" without it ending visual mode
399" Unfortunately, this will add a entry to the search history
400exec 'vmap <buffer> <silent> ]} /'.s:ftplugin_sql_objects.'<CR>'
401exec 'vmap <buffer> <silent> [{ ?'.s:ftplugin_sql_objects.'<CR>'
402
403" Mappings to move to the next COMMENT
404"
405" Had to double the \ for the \| separator since this has a special
406" meaning on maps
407let b:comment_leader = '\\(--\\\|\\/\\/\\\|\\*\\\|\\/\\*\\\|\\*\\/\\)'
408" Find the start of the next comment
409let b:comment_start  = '^\\(\\s*'.b:comment_leader.'.*\\n\\)\\@<!'.
410            \ '\\(\\s*'.b:comment_leader.'\\)'
411" Find the end of the previous comment
412let b:comment_end = '\\(^\\s*'.b:comment_leader.'.*\\n\\)'.
413            \ '\\(^\\s*'.b:comment_leader.'\\)\\@!'
414" Skip over the comment
415let b:comment_jump_over  = "call search('".
416            \ '^\\(\\s*'.b:comment_leader.'.*\\n\\)\\@<!'.
417            \ "', 'W')"
418let b:comment_skip_back  = "call search('".
419            \ '^\\(\\s*'.b:comment_leader.'.*\\n\\)\\@<!'.
420            \ "', 'bW')"
421" Move to the start and end of comments
422exec 'nnoremap <silent><buffer> ]" :call search('."'".b:comment_start."'".', "W" )<CR>'
423exec 'nnoremap <silent><buffer> [" :call search('."'".b:comment_end."'".', "W" )<CR>'
424exec 'vnoremap <silent><buffer> ]" :<C-U>exec "normal! gv"<Bar>call search('."'".b:comment_start."'".', "W" )<CR>'
425exec 'vnoremap <silent><buffer> [" :<C-U>exec "normal! gv"<Bar>call search('."'".b:comment_end."'".', "W" )<CR>'
426
427" Comments can be of the form:
428"   /*
429"    *
430"    */
431" or
432"   --
433" or
434"   //
435setlocal comments=s1:/*,mb:*,ex:*/,:--,://
436
437" Set completion with CTRL-X CTRL-O to autoloaded function.
438if exists('&omnifunc')
439    " Since the SQL completion plugin can be used in conjunction
440    " with other completion filetypes it must record the previous
441    " OMNI function prior to setting up the SQL OMNI function
442    let b:sql_compl_savefunc = &omnifunc
443
444    " This is used by the sqlcomplete.vim plugin
445    " Source it for it's global functions
446    runtime autoload/syntaxcomplete.vim
447
448    setlocal omnifunc=sqlcomplete#Complete
449    " Prevent the intellisense plugin from loading
450    let b:sql_vis = 1
451    if !exists('g:omni_sql_no_default_maps')
452        " Static maps which use populate the completion list
453        " using Vim's syntax highlighting rules
454        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'a <C-\><C-O>:call sqlcomplete#Map("syntax")<CR><C-X><C-O>'
455        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'k <C-\><C-O>:call sqlcomplete#Map("sqlKeyword")<CR><C-X><C-O>'
456        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'f <C-\><C-O>:call sqlcomplete#Map("sqlFunction")<CR><C-X><C-O>'
457        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'o <C-\><C-O>:call sqlcomplete#Map("sqlOption")<CR><C-X><C-O>'
458        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'T <C-\><C-O>:call sqlcomplete#Map("sqlType")<CR><C-X><C-O>'
459        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'s <C-\><C-O>:call sqlcomplete#Map("sqlStatement")<CR><C-X><C-O>'
460        " Dynamic maps which use populate the completion list
461        " using the dbext.vim plugin
462        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'t <C-\><C-O>:call sqlcomplete#Map("table")<CR><C-X><C-O>'
463        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'p <C-\><C-O>:call sqlcomplete#Map("procedure")<CR><C-X><C-O>'
464        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'v <C-\><C-O>:call sqlcomplete#Map("view")<CR><C-X><C-O>'
465        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'c <C-\><C-O>:call sqlcomplete#Map("column")<CR><C-X><C-O>'
466        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'l <C-\><C-O>:call sqlcomplete#Map("column_csv")<CR><C-X><C-O>'
467        " The next 3 maps are only to be used while the completion window is
468        " active due to the <CR> at the beginning of the map
469        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'L <C-Y><C-\><C-O>:call sqlcomplete#Map("column_csv")<CR><C-X><C-O>'
470        " <C-Right> is not recognized on most Unix systems, so only create
471        " these additional maps on the Windows platform.
472        " If you would like to use these maps, choose a different key and make
473        " the same map in your vimrc.
474        " if has('win32')
475        exec 'imap <buffer> '.g:ftplugin_sql_omni_key_right.' <C-R>=sqlcomplete#DrillIntoTable()<CR>'
476        exec 'imap <buffer> '.g:ftplugin_sql_omni_key_left.'  <C-R>=sqlcomplete#DrillOutOfColumns()<CR>'
477        " endif
478        " Remove any cached items useful for schema changes
479        exec 'imap <buffer> '.g:ftplugin_sql_omni_key.'R <C-\><C-O>:call sqlcomplete#Map("resetCache")<CR><C-X><C-O>'
480    endif
481
482    if b:sql_compl_savefunc != ""
483        " We are changing the filetype to SQL from some other filetype
484        " which had OMNI completion defined.  We need to activate the
485        " SQL completion plugin in order to cache some of the syntax items
486        " while the syntax rules for SQL are active.
487        call sqlcomplete#ResetCacheSyntax()
488        call sqlcomplete#PreCacheSyntax()
489    endif
490endif
491
492let &cpo = s:save_cpo
493unlet s:save_cpo
494
495" vim:sw=4:
496
497