" Vim OMNI completion script for SQL" Language: SQL" Maintainer: David Fishburn <dfishburn dot vim at gmail dot com>" Version: 16.0" Last Change: 2015 Dec 29" 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 reseting 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#Completeendifendifif exists('g:loaded_sql_completion')finishendiflet g:loaded_sql_completion = 160let s:keepcpo= &cposet cpo&vim" Maintains filename of dictionarylet s:sql_file_table = ""let s:sql_file_procedure = ""let s:sql_file_view = """ Define various arrays to be used for cachinglet 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 pluginlet s:save_inc = ""let s:save_exc = ""if !exists('g:omni_syntax_group_include_sql')let g:omni_syntax_group_include_sql = ''endifif !exists('g:omni_syntax_group_exclude_sql')let g:omni_syntax_group_exclude_sql = ''endiflet s:save_inc = g:omni_syntax_group_include_sqllet s:save_exc = g:omni_syntax_group_exclude_sql" Used with the column listlet s:save_prev_table = """ Default the option to verify table aliasif !exists('g:omni_sql_use_tbl_alias')let g:omni_sql_use_tbl_alias = 'a'endif" Default syntax items to precacheif !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 standardif !exists('g:omni_sql_ignorecase')let g:omni_sql_ignorecase = &ignorecaseendif" During table completion, should the table list also" include the owner nameif !exists('g:omni_sql_include_owner')let g:omni_sql_include_owner = 0if 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 = 1endifendifendif" Default type of completion used when <C-X><C-O> is pressedif !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 completionlet compl_type = 'table'" Allow maps to specify what type of object completion they wantif exists('b:sql_compl_type')let compl_type = b:sql_compl_typeendiflet begindot = 0" First pass through this function determines how much of the line should" be replaced by whatever is chosen from the completion listif a:findstart" Locate the start of the item, including "."let line = getline('.')let start = col('.') - 1let lastword = -1" Check if the first character is a ".", for column completionif line[start - 1] == '.'let begindot = 1endifwhile 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 characterbreak" elseif line[start - 1] =~ '\(\w\|\s\+\)'" let start -= 1elseif line[start - 1] =~ '\w'" If the previous character is word character continue backlet start -= 1elseif 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 == 0breakendif" 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 == 1let lastword = startendif" If omni_sql_include_owner = 0, do not include the table" name as part of the substitution, so break hereif lastword == -1 &&\ compl_type =~ '\<\(table\|view\|procedure\|column\|column_csv\)\>' &&\ g:omni_sql_include_owner == 0let lastword = startbreakendiflet start -= 1elsebreakendifendwhile" 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 == -1let s:prepended = ''return startendiflet s:prepended = strpart(line, start, lastword - start)return lastwordendif" Second pass through this function will determine what data to put inside" of the completion list" s:prepended is set by the first passlet base = s:prepended . a:base" Default the completion list to an empty listlet compl_list = []" Default to table name completionlet compl_type = g:omni_sql_default_compl_type" Allow maps to specify what type of object completion they wantif exists('b:sql_compl_type')let compl_type = b:sql_compl_typeunlet b:sql_compl_typeendifif compl_type == 'tableReset'let compl_type = 'table'let base = ''endifif compl_type == 'table' ||\ compl_type == 'procedure' ||\ compl_type == 'view'" This type of completion relies upon the dbext.vim pluginif s:SQLCCheck4dbext() == -1return []endif" Allow the user to override the dbext plugin to specify whether" the owner/creator should be included in the listif g:loaded_dbext >= 300let saveSetting = DB_listOption('dict_show_owner')exec 'DBSetOption dict_show_owner='.(g:omni_sql_include_owner==1?'1':'0')endiflet 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)" endiflet 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})endifendifif g:loaded_dbext > 300exec 'DBSetOption dict_show_owner='.saveSettingendifelseif compl_type =~? 'column'" This type of completion relies upon the dbext.vim pluginif s:SQLCCheck4dbext() == -1return []endifif 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_tableendiflet owner = ''let column = ''if base =~ '\.'" Check if the owner/creator has been specifiedlet 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 = tablelet table = columnlet 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 = -1if 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)endifendif" 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 = ''" endifelse" 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_tablelet 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 listif ! empty(compl_list)return compl_listendifendifendif" 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 = baseendif" 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 = baselet 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)elselet compl_list = s:SQLCGetColumns(table, list_type)endifif 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')endifelselet base = ''endifif compl_type == 'column_csv'" Join the column array into 1 single element array" but make the columns column separatedlet compl_list = [join(compl_list, ', ')]endifendifelseif compl_type == 'resetCache'" Reset all cached itemslet 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 >= 2300call DB_DictionaryDelete("table")elseDBCompleteTables!endifendifif s:sql_file_procedure != ""if g:loaded_dbext >= 2300call DB_DictionaryDelete("procedure")elseDBCompleteProcedures!endifendifif s:sql_file_view != ""if g:loaded_dbext >= 2300call DB_DictionaryDelete("view")elseDBCompleteViews!endifendiflet 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 2elselet compl_list = s:SQLCGetSyntaxList(compl_type)endifif 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)endifendifif exists('b:sql_compl_savefunc') && b:sql_compl_savefunc != ""let &omnifunc = b:sql_compl_savefuncendifif empty(compl_list)call s:SQLCWarningMsg( 'Could not find type['.compl_type.'] using prepend[.'.s:prepended.'] base['.a:base.']' )endifreturn compl_listendfuncfunction! sqlcomplete#PreCacheSyntax(...)let syn_group_arr = []let syn_items = []if a:0 > 0if type(a:1) != 3call s:SQLCWarningMsg("Parameter is not a list. Example:['syntaxGroup1', 'syntaxGroup2']")return ''endiflet syn_group_arr = a:1elselet syn_group_arr = g:omni_sql_precache_syntax_groupsendif" For each group specified in the list, precache all" the sytnax items.if !empty(syn_group_arr)for group_name in syn_group_arrlet syn_items = extend( syn_items, s:SQLCGetSyntaxList(group_name) )endforendifreturn syn_itemsendfunctionfunction! sqlcomplete#ResetCacheSyntax(...)let syn_group_arr = []if a:0 > 0if type(a:1) != 3call s:SQLCWarningMsg("Parameter is not a list. Example:['syntaxGroup1', 'syntaxGroup2']")return ''endiflet syn_group_arr = a:1elselet syn_group_arr = g:omni_sql_precache_syntax_groupsendif" For each group specified in the list, precache all" the sytnax items.if !empty(syn_group_arr)for group_name in syn_group_arrlet list_idx = index(s:syn_list, group_name, 0, &ignorecase)if list_idx > -1" Remove from list of groupscall remove( s:syn_list, list_idx )" Remove from list of keywordscall remove( s:syn_value, list_idx )endifendforendifendfunctionfunction! sqlcomplete#Map(type)" Tell the SQL plugin what you want to completelet b:sql_compl_type=a:type" Record previous omnifunc, if the SQL completion" is being used in conjunction with other filetype" completion pluginsif &omnifunc != "" && &omnifunc != 'sqlcomplete#Complete'" Record the previous omnifunc, the plugin" will automatically set this back so that it" does not interfere with other ftplugins settingslet b:sql_compl_savefunc=&omnifuncendif" Set the OMNI func for the SQL completion pluginlet &omnifunc='sqlcomplete#Complete'endfunctionfunction! sqlcomplete#DrillIntoTable()" If the omni popup window is visibleif pumvisible()call sqlcomplete#Map('column')" C-Y, makes the currently highlighted entry active" and trigger the omni popup to be redisplayedcall 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 they key must be preceeded 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")'endifreturn ""endfunctionfunction! sqlcomplete#DrillOutOfColumns()" If the omni popup window is visibleif pumvisible()call sqlcomplete#Map('tableReset')" Trigger the omni popup to be redisplayedcall feedkeys("\<C-X>\<C-O>")else" If the popup is not visible, simple perform the normal" key behaviour." Must use exec since they key must be preceeded 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")'endifreturn ""endfunctionfunction! s:SQLCWarningMsg(msg)echohl WarningMsgechomsg 'SQLComplete:'.a:msgechohl Noneendfunctionfunction! s:SQLCErrorMsg(msg)echohl ErrorMsgechomsg 'SQLComplete:'.a:msgechohl Noneendfunctionfunction! s:SQLCGetSyntaxList(syn_group)let syn_group = a:syn_grouplet compl_list = []" Check if we have already cached the syntax listlet list_idx = index(s:syn_list, syn_group, 0, &ignorecase)if list_idx > -1" Return previously cached valuelet compl_list = s:syn_value[list_idx]elselet s:save_inc = g:omni_syntax_group_include_sqllet s:save_exc = g:omni_syntax_group_exclude_sqllet g:omni_syntax_group_include_sql = ''let g:omni_syntax_group_exclude_sql = ''" Request the syntax list items from the" syntax completion pluginif 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 grouplet g:omni_syntax_group_include_sql = syn_grouplet syn_value = syntaxcomplete#OmniSyntaxList(syn_group)endiflet g:omni_syntax_group_include_sql = s:save_inclet g:omni_syntax_group_exclude_sql = s:save_exc" Cache these values for later uselet s:syn_list = add( s:syn_list, syn_group )let s:syn_value = add( s:syn_value, syn_value )let compl_list = syn_valueendifreturn compl_listendfunctionfunction! 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 2return -1elseif g:loaded_dbext < 600let 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 2return -1endifreturn 1endfunctionfunction! s:SQLCAddAlias(table_name, table_alias, cols)" Strip off the owner if includedlet table_name = matchstr(a:table_name, '\%(.\{-}\.\)\?\zs\(.*\)' )let table_alias = a:table_aliaslet cols = a:colsif g:omni_sql_use_tbl_alias != 'n'if table_alias == ''if 'da' =~? g:omni_sql_use_tbl_aliasif table_name =~ '_'" Treat _ as separators since people often use these" for word separatorslet save_keyword = &iskeywordsetlocal 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 valuelet &iskeyword = save_keywordelseif table_name =~ '\u\U'let table_alias = substitute(\ table_name, '\(\u\)\U*', '1円', 'g')elselet table_alias = strpart(table_name, 0, 1)endifendifendifif table_alias != ''" Following a word character, make sure there is a . and no spaceslet 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)endifendifif table_alias != ''let cols = substitute(cols, '\<\w', table_alias.'&', 'g')endifendifreturn colsendfunctionfunction! 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 ownerendfunctionfunction! s:SQLCGetColumns(table_name, list_type)if a:table_name =~ '\.'" Check if the owner/creator has been specifiedlet 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 = tablelet table = columnlet column = ''endifelselet 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 = tablelet table_cols = []let table_alias = ''let move_to_top = 1let 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 >= 300let saveSettingAlias = DB_listOption('use_tbl_alias')exec 'DBSetOption use_tbl_alias=n'endiflet table_name_stripped = substitute(table_name, '["\[\]]*', '', 'g')" Check if we have already cached the column list for this table" by its namelet list_idx = index(s:tbl_name, table_name_stripped, 0, &ignorecase)if list_idx > -1let 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 > -1let table_alias = table_name_strippedlet table_name = s:tbl_name[list_idx]let table_cols = split(s:tbl_cols[list_idx], '\n')endifendif" 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 == -1let saveY = @ylet saveSearch = @/let saveWScan = &wrapscanlet curline = line(".")let curcol = col(".")" Do not let searchs wrapsetlocal 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 foward 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 (incase no delimiter)" Yank the visually selected text into the "y register.exec 'silent! normal! vl/\c\(\<select\>\|\<update\>\|\<delete\>\|;\s*$\|\%$\)'."\n".'"yy'let query = @ylet 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 matchlet 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_nameif g:omni_sql_include_owner == 1let 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' )endiflet list_idx = index(s:tbl_name, table_name, 0, &ignorecase)if list_idx > -1let table_cols = split(s:tbl_cols[list_idx])let s:tbl_name[list_idx] = table_namelet s:tbl_alias[list_idx] = table_aliaselselet list_idx = index(s:tbl_alias, table_name, 0, &ignorecase)if list_idx > -1let table_cols = split(s:tbl_cols[list_idx])let s:tbl_name[list_idx] = table_namelet s:tbl_alias[list_idx] = table_aliasendifendifendifelse" Simply assume it is a table name provided with a . on the endlet found = 1endiflet @y = saveYlet @/ = saveSearchlet &wrapscan = saveWScan" Return to previous locationcall cursor(curline, curcol)if found == 0if g:loaded_dbext > 300exec 'DBSetOption use_tbl_alias='.saveSettingAliasendif" Not a SQL statement, do not display a listreturn []endifendifif 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')endifendifif g:loaded_dbext > 300exec 'DBSetOption use_tbl_alias='.saveSettingAliasendif" 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]endifreturn table_colsendfunction" Restore:let &cpo= s:keepcpounlet s:keepcpo" vim: ts=4 fdm=marker
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。