123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997 |
- " Vim OMNI completion script for SQL
- " Language: SQL
- " Maintainer: David Fishburn <dfishburn dot vim at gmail dot com>
- " Version: 16.0
- " Last Change: 2017 Oct 15
- " Homepage: http://www.vim.org/scripts/script.php?script_id=1572
- " Usage: For detailed help
- " ":help sql.txt"
- " or ":help ft-sql-omni"
- " or read $VIMRUNTIME/doc/sql.txt
- " History
- "
- " TODO
- " - Jonas Enberg - if no table is found when using column completion
- " look backwards to a FROM clause and find the first table
- " and complete it.
- "
- " Version 16.0 (Dec 2015)
- " - NF: If resetting the cache and table, procedure or view completion
- " had been used via dbext, have dbext delete or recreate the
- " dictionary so that new objects are picked up for the
- " next completion.
- "
- " Version 15.0 (May 2013)
- " - NF: Changed the SQL precached syntax items, omni_sql_precache_syntax_groups,
- " to use regular expressions to pick up extended syntax group names.
- " This requires an updated SyntaxComplete plugin version 13.0.
- " If the required versions have not been installed, previous
- " behaviour will not be impacted.
- "
- " Version 14.0 (Dec 2012)
- " - BF: Added check for cpo
- "
- " Version 13.0 (Dec 2012)
- " - NF: When completing column lists or drilling into a table
- " and g:omni_sql_include_owner is enabled, the
- " only the table name would be replaced with the column
- " list instead of the table name and owner (if specified).
- " - NF: When completing column lists using table aliases
- " and g:omni_sql_include_owner is enabled, account
- " for the owner name when looking up the table
- " list instead of the table name and owner (if specified).
- " - BF: When completing column lists or drilling into a table
- " and g:omni_sql_include_owner is enabled, the
- " column list could often not be found for the table.
- " - BF: When OMNI popped up, possibly the wrong word
- " would be replaced for column and column list options.
- "
- " Version 12.0 (Feb 2012)
- " - Partial column name completion did not work when a table
- " name or table alias was provided (Jonas Enberg).
- " - Improved the handling of column completion. First we match any
- " columns from a previous completion. If not matches are found, we
- " consider the partial name to be a table or table alias for the
- " query and attempt to match on it.
- "
- " Version 11.0 (Jan 2012)
- " Added g:omni_sql_default_compl_type variable
- " - You can specify which type of completion to default to
- " when pressing <C-X><C-O>. The entire list of available
- " choices can be found in the calls to sqlcomplete#Map in:
- " ftplugin/sql.vim
- "
- " Version 10.0
- " Updated PreCacheSyntax()
- " - Now returns a List of the syntax items it finds.
- " This allows other plugins / scripts to use this list for their own
- " purposes. In this case XPTemplate can use them for a Choose list.
- " - Verifies the parameters are the correct type and displays a
- " warning if not.
- " - Verifies the parameters are the correct type and displays a
- " warning if not.
- " Updated SQLCWarningMsg()
- " - Prepends warning message with SQLComplete so you know who issued
- " the warning.
- " Updated SQLCErrorMsg()
- " - Prepends error message with SQLComplete so you know who issued
- " the error.
- "
- " Version 9.0 (May 2010)
- " This change removes some of the support for tables with spaces in their
- " names in order to simplify the regexes used to pull out query table
- " aliases for more robust table name and column name code completion.
- " Full support for "table names with spaces" can be added in again
- " after 7.3.
- "
- " Version 8.0
- " Incorrectly re-executed the g:ftplugin_sql_omni_key_right and g:ftplugin_sql_omni_key_left
- " when drilling in and out of a column list for a table.
- "
- " Version 7.0 (Jan 2010)
- " Better handling of object names
- "
- " Version 6.0 (Apr 2008)
- " Supports object names with spaces "my table name"
- "
- " Set completion with CTRL-X CTRL-O to autoloaded function.
- " This check is in place in case this script is
- " sourced directly instead of using the autoload feature.
- if exists('&omnifunc')
- " Do not set the option if already set since this
- " results in an E117 warning.
- if &omnifunc == ""
- setlocal omnifunc=sqlcomplete#Complete
- endif
- endif
- if exists('g:loaded_sql_completion')
- finish
- endif
- let g:loaded_sql_completion = 160
- let s:keepcpo= &cpo
- set cpo&vim
- " Maintains filename of dictionary
- let s:sql_file_table = ""
- let s:sql_file_procedure = ""
- let s:sql_file_view = ""
- " Define various arrays to be used for caching
- let s:tbl_name = []
- let s:tbl_alias = []
- let s:tbl_cols = []
- let s:syn_list = []
- let s:syn_value = []
- " Used in conjunction with the syntaxcomplete plugin
- let s:save_inc = ""
- let s:save_exc = ""
- if !exists('g:omni_syntax_group_include_sql')
- let g:omni_syntax_group_include_sql = ''
- endif
- if !exists('g:omni_syntax_group_exclude_sql')
- let g:omni_syntax_group_exclude_sql = ''
- endif
- let s:save_inc = g:omni_syntax_group_include_sql
- let s:save_exc = g:omni_syntax_group_exclude_sql
- " Used with the column list
- let s:save_prev_table = ""
- " Default the option to verify table alias
- if !exists('g:omni_sql_use_tbl_alias')
- let g:omni_sql_use_tbl_alias = 'a'
- endif
- " Default syntax items to precache
- if !exists('g:omni_sql_precache_syntax_groups')
- let g:omni_sql_precache_syntax_groups = [
- \ 'syntax\w*',
- \ 'sqlKeyword\w*',
- \ 'sqlFunction\w*',
- \ 'sqlOption\w*',
- \ 'sqlType\w*',
- \ 'sqlStatement\w*'
- \ ]
- endif
- " Set ignorecase to the ftplugin standard
- if !exists('g:omni_sql_ignorecase')
- let g:omni_sql_ignorecase = &ignorecase
- endif
- " During table completion, should the table list also
- " include the owner name
- if !exists('g:omni_sql_include_owner')
- let g:omni_sql_include_owner = 0
- if exists('g:loaded_dbext')
- if g:loaded_dbext >= 300
- " New to dbext 3.00, by default the table lists include the owner
- " name of the table. This is used when determining how much of
- " whatever has been typed should be replaced as part of the
- " code replacement.
- let g:omni_sql_include_owner = 1
- endif
- endif
- endif
- " Default type of completion used when <C-X><C-O> is pressed
- if !exists('g:omni_sql_default_compl_type')
- let g:omni_sql_default_compl_type = 'table'
- endif
- " This function is used for the 'omnifunc' option.
- " It is called twice by omni and it is responsible
- " for returning the completion list of items.
- " But it must also determine context of what to complete
- " and what to "replace" with the completion.
- " The a:base, is replaced directly with what the user
- " chooses from the choices.
- " The s:prepend provides context for the completion.
- function! sqlcomplete#Complete(findstart, base)
- " Default to table name completion
- let compl_type = 'table'
- " Allow maps to specify what type of object completion they want
- if exists('b:sql_compl_type')
- let compl_type = b:sql_compl_type
- endif
- let begindot = 0
- " First pass through this function determines how much of the line should
- " be replaced by whatever is chosen from the completion list
- if a:findstart
- " Locate the start of the item, including "."
- let line = getline('.')
- let start = col('.') - 1
- let lastword = -1
- " Check if the first character is a ".", for column completion
- if line[start - 1] == '.'
- let begindot = 1
- endif
- while start > 0
- " Additional code was required to handle objects which
- " can contain spaces like "my table name".
- if line[start - 1] !~ '\(\w\|\.\)'
- " If the previous character is not a period or word character
- break
- " elseif line[start - 1] =~ '\(\w\|\s\+\)'
- " let start -= 1
- elseif line[start - 1] =~ '\w'
- " If the previous character is word character continue back
- let start -= 1
- elseif line[start - 1] =~ '\.' &&
- \ compl_type =~ 'column\|table\|view\|procedure'
- " If the previous character is a period and we are completing
- " an object which can be specified with a period like this:
- " table_name.column_name
- " owner_name.table_name
- " If lastword has already been set for column completion
- " break from the loop, since we do not also want to pickup
- " a table name if it was also supplied.
- " Unless g:omni_sql_include_owner == 1, then we can
- " include the ownername.
- if lastword != -1 && compl_type == 'column'
- \ && g:omni_sql_include_owner == 0
- break
- endif
- " If column completion was specified stop at the "." if
- " a . was specified, otherwise, replace all the way up
- " to the owner name (if included).
- if lastword == -1 && compl_type == 'column' && begindot == 1
- let lastword = start
- endif
- " If omni_sql_include_owner = 0, do not include the table
- " name as part of the substitution, so break here
- if lastword == -1 &&
- \ compl_type =~ '\<\(table\|view\|procedure\|column\|column_csv\)\>' &&
- \ g:omni_sql_include_owner == 0
- let lastword = start
- break
- endif
- let start -= 1
- else
- break
- endif
- endwhile
- " Return the column of the last word, which is going to be changed.
- " Remember the text that comes before it in s:prepended.
- if lastword == -1
- let s:prepended = ''
- return start
- endif
- let s:prepended = strpart(line, start, lastword - start)
- return lastword
- endif
- " Second pass through this function will determine what data to put inside
- " of the completion list
- " s:prepended is set by the first pass
- let base = s:prepended . a:base
- " Default the completion list to an empty list
- let compl_list = []
- " Default to table name completion
- let compl_type = g:omni_sql_default_compl_type
- " Allow maps to specify what type of object completion they want
- if exists('b:sql_compl_type')
- let compl_type = b:sql_compl_type
- unlet b:sql_compl_type
- endif
- if compl_type == 'tableReset'
- let compl_type = 'table'
- let base = ''
- endif
- if compl_type == 'table' ||
- \ compl_type == 'procedure' ||
- \ compl_type == 'view'
- " This type of completion relies upon the dbext.vim plugin
- if s:SQLCCheck4dbext() == -1
- return []
- endif
- " Allow the user to override the dbext plugin to specify whether
- " the owner/creator should be included in the list
- if g:loaded_dbext >= 300
- let saveSetting = DB_listOption('dict_show_owner')
- exec 'DBSetOption dict_show_owner='.(g:omni_sql_include_owner==1?'1':'0')
- endif
- let compl_type_uc = substitute(compl_type, '\w\+', '\u&', '')
- " Same call below, no need to do it twice
- " if s:sql_file_{compl_type} == ""
- " let s:sql_file_{compl_type} = DB_getDictionaryName(compl_type_uc)
- " endif
- let s:sql_file_{compl_type} = DB_getDictionaryName(compl_type_uc)
- if s:sql_file_{compl_type} != ""
- if filereadable(s:sql_file_{compl_type})
- let compl_list = readfile(s:sql_file_{compl_type})
- endif
- endif
- if g:loaded_dbext > 300
- exec 'DBSetOption dict_show_owner='.saveSetting
- endif
- elseif compl_type =~? 'column'
- " This type of completion relies upon the dbext.vim plugin
- if s:SQLCCheck4dbext() == -1
- return []
- endif
- if base == ""
- " The last time we displayed a column list we stored
- " the table name. If the user selects a column list
- " without a table name of alias present, assume they want
- " the previous column list displayed.
- let base = s:save_prev_table
- endif
- let owner = ''
- let column = ''
- if base =~ '\.'
- " Check if the owner/creator has been specified
- let owner = matchstr( base, '^\zs.*\ze\..*\..*' )
- let table = matchstr( base, '^\(.*\.\)\?\zs.*\ze\..*' )
- let column = matchstr( base, '.*\.\zs.*' )
- if g:omni_sql_include_owner == 1 && owner == '' && table != '' && column != ''
- let owner = table
- let table = column
- let column = ''
- endif
- " It is pretty well impossible to determine if the user
- " has entered:
- " owner.table
- " table.column_prefix
- " So there are a couple of things we can do to mitigate
- " this issue.
- " 1. Check if the dbext plugin has the option turned
- " on to even allow owners
- " 2. Based on 1, if the user is showing a table list
- " and the DrillIntoTable (using <Right>) then
- " this will be owner.table. In this case, we can
- " check to see the table.column exists in the
- " cached table list. If it does, then we have
- " determined the user has actually chosen
- " owner.table, not table.column_prefix.
- let found = -1
- if g:omni_sql_include_owner == 1 && owner == ''
- if filereadable(s:sql_file_table)
- let tbl_list = readfile(s:sql_file_table)
- let found = index( tbl_list, ((table != '')?(table.'.'):'').column)
- endif
- endif
- " If the table.column was found in the table list, we can safely assume
- " the owner was not provided and shift the items appropriately.
- " OR
- " If the user has indicated not to use table owners at all and
- " the base ends in a '.' we know they are not providing a column
- " name, so we can shift the items appropriately.
- " if found != -1 || (g:omni_sql_include_owner == 0 && base !~ '\.$')
- " let owner = table
- " let table = column
- " let column = ''
- " endif
- else
- " If no "." was provided and the user asked for
- " column level completion, first attempt the match
- " on any previous column lists. If the user asked
- " for a list of columns comma separated, continue as usual.
- if compl_type == 'column' && s:save_prev_table != ''
- " The last time we displayed a column list we stored
- " the table name. If the user selects a column list
- " without a table name of alias present, assume they want
- " the previous column list displayed.
- let table = s:save_prev_table
- let list_type = ''
- let compl_list = s:SQLCGetColumns(table, list_type)
- if ! empty(compl_list)
- " If no column prefix has been provided and the table
- " name was provided, append it to each of the items
- " returned.
- let compl_list = filter(deepcopy(compl_list), 'v:val=~"^'.base.'"' )
- " If not empty, we have a match on columns
- " return the list
- if ! empty(compl_list)
- return compl_list
- endif
- endif
- endif
- " Since no columns were found to match the base supplied
- " assume the user is trying to complete the column list
- " for a table (and or an alias to a table).
- let table = base
- endif
- " Get anything after the . and consider this the table name
- " If an owner has been specified, then we must consider the
- " base to be a partial column name
- " let base = matchstr( base, '^\(.*\.\)\?\zs.*' )
- if table != ""
- let s:save_prev_table = base
- let list_type = ''
- if compl_type == 'column_csv'
- " Return one array element, with a comma separated
- " list of values instead of multiple array entries
- " for each column in the table.
- let list_type = 'csv'
- endif
- " If we are including the OWNER for the objects, then for
- " table completion, if we have it, it should be included
- " as there can be the same table names in a database yet
- " with different owner names.
- if g:omni_sql_include_owner == 1 && owner != '' && table != ''
- let compl_list = s:SQLCGetColumns(owner.'.'.table, list_type)
- else
- let compl_list = s:SQLCGetColumns(table, list_type)
- endif
- if column != ''
- " If no column prefix has been provided and the table
- " name was provided, append it to each of the items
- " returned.
- let compl_list = map(compl_list, 'table.".".v:val')
- if owner != ''
- " If an owner has been provided append it to each of the
- " items returned.
- let compl_list = map(compl_list, 'owner.".".v:val')
- endif
- else
- let base = ''
- endif
- if compl_type == 'column_csv'
- " Join the column array into 1 single element array
- " but make the columns column separated
- let compl_list = [join(compl_list, ', ')]
- endif
- endif
- elseif compl_type == 'resetCache'
- " Reset all cached items
- let s:tbl_name = []
- let s:tbl_alias = []
- let s:tbl_cols = []
- let s:syn_list = []
- let s:syn_value = []
- if s:sql_file_table != ""
- if g:loaded_dbext >= 2300
- call DB_DictionaryDelete("table")
- else
- DBCompleteTables!
- endif
- endif
- if s:sql_file_procedure != ""
- if g:loaded_dbext >= 2300
- call DB_DictionaryDelete("procedure")
- else
- DBCompleteProcedures!
- endif
- endif
- if s:sql_file_view != ""
- if g:loaded_dbext >= 2300
- call DB_DictionaryDelete("view")
- else
- DBCompleteViews!
- endif
- endif
- let s:sql_file_table = ""
- let s:sql_file_procedure = ""
- let s:sql_file_view = ""
- let msg = "All SQL cached items have been removed."
- call s:SQLCWarningMsg(msg)
- " Leave time for the user to read the error message
- :sleep 2
- else
- let compl_list = s:SQLCGetSyntaxList(compl_type)
- endif
- if base != ''
- " Filter the list based on the first few characters the user entered.
- " Check if the text matches at the beginning
- " \\(^.base.'\\)
- " or
- " Match to a owner.table or alias.column type match
- " ^\\(\\w\\+\\.\\)\\?'.base.'\\)
- " or
- " Handle names with spaces "my table name"
- " "\\(^'.base.'\\|^\\(\\w\\+\\.\\)\\?'.base.'\\)"'
- "
- let expr = 'v:val '.(g:omni_sql_ignorecase==1?'=~?':'=~#').' "\\(^'.base.'\\|^\\(\\w\\+\\.\\)\\?'.base.'\\)"'
- " let expr = 'v:val '.(g:omni_sql_ignorecase==1?'=~?':'=~#').' "\\(^'.base.'\\)"'
- " let expr = 'v:val '.(g:omni_sql_ignorecase==1?'=~?':'=~#').' "\\(^'.base.'\\|\\(\\.\\)\\?'.base.'\\)"'
- " let expr = 'v:val '.(g:omni_sql_ignorecase==1?'=~?':'=~#').' "\\(^'.base.'\\|\\([^.]*\\)\\?'.base.'\\)"'
- let compl_list = filter(deepcopy(compl_list), expr)
- if empty(compl_list) && compl_type == 'table' && base =~ '\.$'
- " It is possible we could be looking for column name completion
- " and the user simply hit C-X C-O to lets try it as well
- " since we had no hits with the tables.
- " If the base ends with a . it is hard to know if we are
- " completing table names or column names.
- let list_type = ''
- let compl_list = s:SQLCGetColumns(base, list_type)
- endif
- endif
- if exists('b:sql_compl_savefunc') && b:sql_compl_savefunc != ""
- let &omnifunc = b:sql_compl_savefunc
- endif
- if empty(compl_list)
- call s:SQLCWarningMsg( 'Could not find type['.compl_type.'] using prepend[.'.s:prepended.'] base['.a:base.']' )
- endif
- return compl_list
- endfunc
- function! sqlcomplete#PreCacheSyntax(...)
- let syn_group_arr = []
- let syn_items = []
- if a:0 > 0
- if type(a:1) != 3
- call s:SQLCWarningMsg("Parameter is not a list. Example:['syntaxGroup1', 'syntaxGroup2']")
- return ''
- endif
- let syn_group_arr = a:1
- else
- let syn_group_arr = g:omni_sql_precache_syntax_groups
- endif
- " For each group specified in the list, precache all
- " the syntax items.
- if !empty(syn_group_arr)
- for group_name in syn_group_arr
- let syn_items = extend( syn_items, s:SQLCGetSyntaxList(group_name) )
- endfor
- endif
- return syn_items
- endfunction
- function! sqlcomplete#ResetCacheSyntax(...)
- let syn_group_arr = []
- if a:0 > 0
- if type(a:1) != 3
- call s:SQLCWarningMsg("Parameter is not a list. Example:['syntaxGroup1', 'syntaxGroup2']")
- return ''
- endif
- let syn_group_arr = a:1
- else
- let syn_group_arr = g:omni_sql_precache_syntax_groups
- endif
- " For each group specified in the list, precache all
- " the syntax items.
- if !empty(syn_group_arr)
- for group_name in syn_group_arr
- let list_idx = index(s:syn_list, group_name, 0, &ignorecase)
- if list_idx > -1
- " Remove from list of groups
- call remove( s:syn_list, list_idx )
- " Remove from list of keywords
- call remove( s:syn_value, list_idx )
- endif
- endfor
- endif
- endfunction
- function! sqlcomplete#Map(type)
- " Tell the SQL plugin what you want to complete
- let b:sql_compl_type=a:type
- " Record previous omnifunc, if the SQL completion
- " is being used in conjunction with other filetype
- " completion plugins
- if &omnifunc != "" && &omnifunc != 'sqlcomplete#Complete'
- " Record the previous omnifunc, the plugin
- " will automatically set this back so that it
- " does not interfere with other ftplugins settings
- let b:sql_compl_savefunc=&omnifunc
- endif
- " Set the OMNI func for the SQL completion plugin
- let &omnifunc='sqlcomplete#Complete'
- endfunction
- function! sqlcomplete#DrillIntoTable()
- " If the omni popup window is visible
- if pumvisible()
- call sqlcomplete#Map('column')
- " C-Y, makes the currently highlighted entry active
- " and trigger the omni popup to be redisplayed
- call feedkeys("\<C-Y>\<C-X>\<C-O>", 'n')
- else
- " If the popup is not visible, simple perform the normal
- " key behaviour.
- " Must use exec since the key must be preceded by "\"
- " or feedkeys will simply push each character of the string
- " rather than the "key press".
- exec 'call feedkeys("\'.g:ftplugin_sql_omni_key_right.'", "n")'
- endif
- return ""
- endfunction
- function! sqlcomplete#DrillOutOfColumns()
- " If the omni popup window is visible
- if pumvisible()
- call sqlcomplete#Map('tableReset')
- " Trigger the omni popup to be redisplayed
- call feedkeys("\<C-X>\<C-O>")
- else
- " If the popup is not visible, simple perform the normal
- " key behaviour.
- " Must use exec since the key must be preceded by "\"
- " or feedkeys will simply push each character of the string
- " rather than the "key press".
- exec 'call feedkeys("\'.g:ftplugin_sql_omni_key_left.'", "n")'
- endif
- return ""
- endfunction
- function! s:SQLCWarningMsg(msg)
- echohl WarningMsg
- echomsg 'SQLComplete:'.a:msg
- echohl None
- endfunction
- function! s:SQLCErrorMsg(msg)
- echohl ErrorMsg
- echomsg 'SQLComplete:'.a:msg
- echohl None
- endfunction
- function! s:SQLCGetSyntaxList(syn_group)
- let syn_group = a:syn_group
- let compl_list = []
- " Check if we have already cached the syntax list
- let list_idx = index(s:syn_list, syn_group, 0, &ignorecase)
- if list_idx > -1
- " Return previously cached value
- let compl_list = s:syn_value[list_idx]
- else
- let s:save_inc = g:omni_syntax_group_include_sql
- let s:save_exc = g:omni_syntax_group_exclude_sql
- let g:omni_syntax_group_include_sql = ''
- let g:omni_syntax_group_exclude_sql = ''
- " Request the syntax list items from the
- " syntax completion plugin
- if syn_group == 'syntax'
- " Handle this special case. This allows the user
- " to indicate they want all the syntax items available,
- " so do not specify a specific include list.
- let syn_value = syntaxcomplete#OmniSyntaxList()
- else
- " The user has specified a specific syntax group
- let g:omni_syntax_group_include_sql = syn_group
- let syn_value = syntaxcomplete#OmniSyntaxList(syn_group)
- endif
- let g:omni_syntax_group_include_sql = s:save_inc
- let g:omni_syntax_group_exclude_sql = s:save_exc
- " Cache these values for later use
- let s:syn_list = add( s:syn_list, syn_group )
- let s:syn_value = add( s:syn_value, syn_value )
- let compl_list = syn_value
- endif
- return compl_list
- endfunction
- function! s:SQLCCheck4dbext()
- if !exists('g:loaded_dbext')
- let msg = "The dbext plugin must be loaded for dynamic SQL completion"
- call s:SQLCErrorMsg(msg)
- " Leave time for the user to read the error message
- :sleep 2
- return -1
- elseif g:loaded_dbext < 600
- let msg = "The dbext plugin must be at least version 5.30 " .
- \ " for dynamic SQL completion"
- call s:SQLCErrorMsg(msg)
- " Leave time for the user to read the error message
- :sleep 2
- return -1
- endif
- return 1
- endfunction
- function! s:SQLCAddAlias(table_name, table_alias, cols)
- " Strip off the owner if included
- let table_name = matchstr(a:table_name, '\%(.\{-}\.\)\?\zs\(.*\)' )
- let table_alias = a:table_alias
- let cols = a:cols
- if g:omni_sql_use_tbl_alias != 'n'
- if table_alias == ''
- if 'da' =~? g:omni_sql_use_tbl_alias
- if table_name =~ '_'
- " Treat _ as separators since people often use these
- " for word separators
- let save_keyword = &iskeyword
- setlocal iskeyword-=_
- " Get the first letter of each word
- " [[:alpha:]] is used instead of \w
- " to catch extended accented characters
- "
- let table_alias = substitute(
- \ table_name,
- \ '\<[[:alpha:]]\+\>_\?',
- \ '\=strpart(submatch(0), 0, 1)',
- \ 'g'
- \ )
- " Restore original value
- let &iskeyword = save_keyword
- elseif table_name =~ '\u\U'
- let table_alias = substitute(
- \ table_name, '\(\u\)\U*', '\1', 'g')
- else
- let table_alias = strpart(table_name, 0, 1)
- endif
- endif
- endif
- if table_alias != ''
- " Following a word character, make sure there is a . and no spaces
- let table_alias = substitute(table_alias, '\w\zs\.\?\s*$', '.', '')
- if 'a' =~? g:omni_sql_use_tbl_alias && a:table_alias == ''
- let table_alias = inputdialog("Enter table alias:", table_alias)
- endif
- endif
- if table_alias != ''
- let cols = substitute(cols, '\<\w', table_alias.'&', 'g')
- endif
- endif
- return cols
- endfunction
- function! s:SQLCGetObjectOwner(object)
- " The owner regex matches a word at the start of the string which is
- " followed by a dot, but doesn't include the dot in the result.
- " ^ - from beginning of line
- " \("\|\[\)\? - ignore any quotes
- " \zs - start the match now
- " .\{-} - get owner name
- " \ze - end the match
- " \("\|\[\)\? - ignore any quotes
- " \. - must by followed by a .
- " let owner = matchstr( a:object, '^\s*\zs.*\ze\.' )
- let owner = matchstr( a:object, '^\("\|\[\)\?\zs\.\{-}\ze\("\|\]\)\?\.' )
- return owner
- endfunction
- function! s:SQLCGetColumns(table_name, list_type)
- if a:table_name =~ '\.'
- " Check if the owner/creator has been specified
- let owner = matchstr( a:table_name, '^\zs.*\ze\..*\..*' )
- let table = matchstr( a:table_name, '^\(.*\.\)\?\zs.*\ze\..*' )
- let column = matchstr( a:table_name, '.*\.\zs.*' )
- if g:omni_sql_include_owner == 1 && owner == '' && table != '' && column != ''
- let owner = table
- let table = column
- let column = ''
- endif
- else
- let owner = ''
- let table = matchstr(a:table_name, '^["\[\]a-zA-Z0-9_ ]\+\ze\.\?')
- let column = ''
- endif
- " Check if the table name was provided as part of the column name
- " let table_name = matchstr(a:table_name, '^["\[\]a-zA-Z0-9_ ]\+\ze\.\?')
- let table_name = table
- let table_cols = []
- let table_alias = ''
- let move_to_top = 1
- let table_name = substitute(table_name, '\s*\(.\{-}\)\s*$', '\1', 'g')
- " If the table name was given as:
- " where c.
- let table_name = substitute(table_name, '^\c\(WHERE\|AND\|OR\)\s\+', '', '')
- if g:loaded_dbext >= 300
- let saveSettingAlias = DB_listOption('use_tbl_alias')
- exec 'DBSetOption use_tbl_alias=n'
- endif
- let table_name_stripped = substitute(table_name, '["\[\]]*', '', 'g')
- " Check if we have already cached the column list for this table
- " by its name
- let list_idx = index(s:tbl_name, table_name_stripped, 0, &ignorecase)
- if list_idx > -1
- let table_cols = split(s:tbl_cols[list_idx], '\n')
- else
- " Check if we have already cached the column list for this table
- " by its alias, assuming the table_name provided was actually
- " the alias for the table instead
- " select *
- " from area a
- " where a.
- let list_idx = index(s:tbl_alias, table_name_stripped, 0, &ignorecase)
- if list_idx > -1
- let table_alias = table_name_stripped
- let table_name = s:tbl_name[list_idx]
- let table_cols = split(s:tbl_cols[list_idx], '\n')
- endif
- endif
- " If we have not found a cached copy of the table
- " And the table ends in a "." or we are looking for a column list
- " if list_idx == -1 && (a:table_name =~ '\.' || b:sql_compl_type =~ 'column')
- " if list_idx == -1 && (a:table_name =~ '\.' || a:list_type =~ 'csv')
- if list_idx == -1
- let saveY = @y
- let saveSearch = @/
- let saveWScan = &wrapscan
- let curline = line(".")
- let curcol = col(".")
- " Do not let searches wrap
- setlocal nowrapscan
- " If . was entered, look at the word just before the .
- " We are looking for something like this:
- " select *
- " from customer c
- " where c.
- " So when . is pressed, we need to find 'c'
- "
- " Search backwards to the beginning of the statement
- " and do NOT wrap
- " exec 'silent! normal! v?\<\(select\|update\|delete\|;\)\>'."\n".'"yy'
- exec 'silent! normal! ?\<\c\(select\|update\|delete\|;\)\>'."\n"
- " Start characterwise visual mode
- " Advance right one character
- " Search forward until one of the following:
- " 1. Another select/update/delete statement
- " 2. A ; at the end of a line (the delimiter)
- " 3. The end of the file (in case no delimiter)
- " Yank the visually selected text into the "y register.
- exec 'silent! normal! vl/\c\(\<select\>\|\<update\>\|\<delete\>\|;\s*$\|\%$\)'."\n".'"yy'
- let query = @y
- let query = substitute(query, "\n", ' ', 'g')
- let found = 0
- " if query =~? '^\c\(select\)'
- if query =~? '^\(select\|update\|delete\)'
- let found = 1
- " \(\(\<\w\+\>\)\.\)\? -
- " '\c\(from\|join\|,\).\{-}' - Starting at the from clause (case insensitive)
- " '\zs\(\(\<\w\+\>\)\.\)\?' - Get the owner name (optional)
- " '\<\w\+\>\ze' - Get the table name
- " '\s\+\<'.table_name.'\>' - Followed by the alias
- " '\s*\.\@!.*' - Cannot be followed by a .
- " '\(\<where\>\|$\)' - Must be followed by a WHERE clause
- " '.*' - Exclude the rest of the line in the match
- " let table_name_new = matchstr(@y,
- " \ '\c\(from\|join\|,\).\{-}'.
- " \ '\zs\(\("\|\[\)\?.\{-}\("\|\]\)\.\)\?'.
- " \ '\("\|\[\)\?.\{-}\("\|\]\)\?\ze'.
- " \ '\s\+\%(as\s\+\)\?\<'.
- " \ matchstr(table_name, '.\{-}\ze\.\?$').
- " \ '\>'.
- " \ '\s*\.\@!.*'.
- " \ '\(\<where\>\|$\)'.
- " \ '.*'
- " \ )
- "
- "
- " ''\c\(\<from\>\|\<join\>\|,\)\s*' - Starting at the from clause (case insensitive)
- " '\zs\(\("\|\[\)\?\w\+\("\|\]\)\?\.\)\?' - Get the owner name (optional)
- " '\("\|\[\)\?\w\+\("\|\]\)\?\ze' - Get the table name
- " '\s\+\%(as\s\+\)\?\<'.matchstr(table_name, '.\{-}\ze\.\?$').'\>' - Followed by the alias
- " '\s*\.\@!.*' - Cannot be followed by a .
- " '\(\<where\>\|$\)' - Must be followed by a WHERE clause
- " '.*' - Exclude the rest of the line in the match
- let table_name_new = matchstr(@y,
- \ '\c\(\<from\>\|\<join\>\|,\)\s*'.
- \ '\zs\(\("\|\[\)\?\w\+\("\|\]\)\?\.\)\?'.
- \ '\("\|\[\)\?\w\+\("\|\]\)\?\ze'.
- \ '\s\+\%(as\s\+\)\?\<'.
- \ matchstr(table_name, '.\{-}\ze\.\?$').
- \ '\>'.
- \ '\s*\.\@!.*'.
- \ '\(\<where\>\|$\)'.
- \ '.*'
- \ )
- if table_name_new != ''
- let table_alias = table_name
- if g:omni_sql_include_owner == 1
- let table_name = matchstr( table_name_new, '^\zs\(.\{-}\.\)\?\(.\{-}\.\)\?.*\ze' )
- else
- " let table_name = matchstr( table_name_new, '^\(.*\.\)\?\zs.*\ze' )
- let table_name = matchstr( table_name_new, '^\(.\{-}\.\)\?\zs\(.\{-}\.\)\?.*\ze' )
- endif
- let list_idx = index(s:tbl_name, table_name, 0, &ignorecase)
- if list_idx > -1
- let table_cols = split(s:tbl_cols[list_idx])
- let s:tbl_name[list_idx] = table_name
- let s:tbl_alias[list_idx] = table_alias
- else
- let list_idx = index(s:tbl_alias, table_name, 0, &ignorecase)
- if list_idx > -1
- let table_cols = split(s:tbl_cols[list_idx])
- let s:tbl_name[list_idx] = table_name
- let s:tbl_alias[list_idx] = table_alias
- endif
- endif
- endif
- else
- " Simply assume it is a table name provided with a . on the end
- let found = 1
- endif
- let @y = saveY
- let @/ = saveSearch
- let &wrapscan = saveWScan
- " Return to previous location
- call cursor(curline, curcol)
- if found == 0
- if g:loaded_dbext > 300
- exec 'DBSetOption use_tbl_alias='.saveSettingAlias
- endif
- " Not a SQL statement, do not display a list
- return []
- endif
- endif
- if empty(table_cols)
- " Specify silent mode, no messages to the user (tbl, 1)
- " Specify do not comma separate (tbl, 1, 1)
- " let table_cols_str = DB_getListColumn(table_name, 1, 1)
- let table_cols_str = DB_getListColumn((owner!=''?owner.'.':'').table_name, 1, 1)
- if table_cols_str != ""
- let s:tbl_name = add( s:tbl_name, table_name )
- let s:tbl_alias = add( s:tbl_alias, table_alias )
- let s:tbl_cols = add( s:tbl_cols, table_cols_str )
- let table_cols = split(table_cols_str, '\n')
- endif
- endif
- if g:loaded_dbext > 300
- exec 'DBSetOption use_tbl_alias='.saveSettingAlias
- endif
- " If the user has asked for a comma separate list of column
- " values, ask the user if they want to prepend each column
- " with a tablename alias.
- if a:list_type == 'csv' && !empty(table_cols)
- let cols = join(table_cols, ', ')
- let cols = s:SQLCAddAlias(table_name, table_alias, cols)
- let table_cols = [cols]
- endif
- return table_cols
- endfunction
- " Restore:
- let &cpo= s:keepcpo
- unlet s:keepcpo
- " vim: ts=4 fdm=marker
|