1*f193fffdSBram Moolenaar" Vim OMNI completion script for SQL 2e2f98b95SBram Moolenaar" Language: SQL 3e2f98b95SBram Moolenaar" Maintainer: David Fishburn <[email protected]> 4*f193fffdSBram Moolenaar" Version: 4.0 5*f193fffdSBram Moolenaar" Last Change: Wed Apr 26 2006 3:00:06 PM 6*f193fffdSBram Moolenaar" Usage: For detailed help 7*f193fffdSBram Moolenaar" ":help sql.txt" 8*f193fffdSBram Moolenaar" or ":help ft-sql-omni" 9*f193fffdSBram Moolenaar" or read $VIMRUNTIME/doc/sql.txt 10e2f98b95SBram Moolenaar 11e2f98b95SBram Moolenaar" Set completion with CTRL-X CTRL-O to autoloaded function. 12e2f98b95SBram Moolenaar" This check is in place in case this script is 13e2f98b95SBram Moolenaar" sourced directly instead of using the autoload feature. 14e2f98b95SBram Moolenaarif exists('&omnifunc') 15e2f98b95SBram Moolenaar " Do not set the option if already set since this 16e2f98b95SBram Moolenaar " results in an E117 warning. 17e2f98b95SBram Moolenaar if &omnifunc == "" 18e2f98b95SBram Moolenaar setlocal omnifunc=sqlcomplete#Complete 19e2f98b95SBram Moolenaar endif 20e2f98b95SBram Moolenaarendif 21e2f98b95SBram Moolenaar 22e2f98b95SBram Moolenaarif exists('g:loaded_sql_completion') 23e2f98b95SBram Moolenaar finish 24e2f98b95SBram Moolenaarendif 25*f193fffdSBram Moolenaarlet g:loaded_sql_completion = 40 26e2f98b95SBram Moolenaar 27e2f98b95SBram Moolenaar" Maintains filename of dictionary 28e2f98b95SBram Moolenaarlet s:sql_file_table = "" 29e2f98b95SBram Moolenaarlet s:sql_file_procedure = "" 30e2f98b95SBram Moolenaarlet s:sql_file_view = "" 31e2f98b95SBram Moolenaar 32e2f98b95SBram Moolenaar" Define various arrays to be used for caching 33e2f98b95SBram Moolenaarlet s:tbl_name = [] 34e2f98b95SBram Moolenaarlet s:tbl_alias = [] 35e2f98b95SBram Moolenaarlet s:tbl_cols = [] 36e2f98b95SBram Moolenaarlet s:syn_list = [] 37e2f98b95SBram Moolenaarlet s:syn_value = [] 38e2f98b95SBram Moolenaar 39e2f98b95SBram Moolenaar" Used in conjunction with the syntaxcomplete plugin 40e2f98b95SBram Moolenaarlet s:save_inc = "" 41e2f98b95SBram Moolenaarlet s:save_exc = "" 42e2f98b95SBram Moolenaarif exists('g:omni_syntax_group_include_sql') 43e2f98b95SBram Moolenaar let s:save_inc = g:omni_syntax_group_include_sql 44e2f98b95SBram Moolenaarendif 45e2f98b95SBram Moolenaarif exists('g:omni_syntax_group_exclude_sql') 46e2f98b95SBram Moolenaar let s:save_exc = g:omni_syntax_group_exclude_sql 47e2f98b95SBram Moolenaarendif 48e2f98b95SBram Moolenaar 49e2f98b95SBram Moolenaar" Used with the column list 50e2f98b95SBram Moolenaarlet s:save_prev_table = "" 51e2f98b95SBram Moolenaar 52e2f98b95SBram Moolenaar" Default the option to verify table alias 53e2f98b95SBram Moolenaarif !exists('g:omni_sql_use_tbl_alias') 54e2f98b95SBram Moolenaar let g:omni_sql_use_tbl_alias = 'a' 55e2f98b95SBram Moolenaarendif 56910f66f9SBram Moolenaar" Default syntax items to precache 57910f66f9SBram Moolenaarif !exists('g:omni_sql_precache_syntax_groups') 58910f66f9SBram Moolenaar let g:omni_sql_precache_syntax_groups = [ 59910f66f9SBram Moolenaar \ 'syntax', 60910f66f9SBram Moolenaar \ 'sqlKeyword', 61910f66f9SBram Moolenaar \ 'sqlFunction', 62910f66f9SBram Moolenaar \ 'sqlOption', 63910f66f9SBram Moolenaar \ 'sqlType', 64910f66f9SBram Moolenaar \ 'sqlStatement' 65910f66f9SBram Moolenaar \ ] 66910f66f9SBram Moolenaarendif 67eb3593b3SBram Moolenaar" Set ignorecase to the ftplugin standard 68eb3593b3SBram Moolenaarif !exists('g:omni_sql_ignorecase') 69eb3593b3SBram Moolenaar let g:omni_sql_ignorecase = &ignorecase 70eb3593b3SBram Moolenaarendif 71eb3593b3SBram Moolenaar" During table completion, should the table list also 72eb3593b3SBram Moolenaar" include the owner name 73eb3593b3SBram Moolenaarif !exists('g:omni_sql_include_owner') 74eb3593b3SBram Moolenaar let g:omni_sql_include_owner = 0 75eb3593b3SBram Moolenaar if exists('g:loaded_dbext') 76eb3593b3SBram Moolenaar if g:loaded_dbext >= 300 77eb3593b3SBram Moolenaar " New to dbext 3.00, by default the table lists include the owner 78eb3593b3SBram Moolenaar " name of the table. This is used when determining how much of 79eb3593b3SBram Moolenaar " whatever has been typed should be replaced as part of the 80eb3593b3SBram Moolenaar " code replacement. 81eb3593b3SBram Moolenaar let g:omni_sql_include_owner = 1 82eb3593b3SBram Moolenaar endif 83eb3593b3SBram Moolenaar endif 84eb3593b3SBram Moolenaarendif 85e2f98b95SBram Moolenaar 86e2f98b95SBram Moolenaar" This function is used for the 'omnifunc' option. 87e2f98b95SBram Moolenaarfunction! sqlcomplete#Complete(findstart, base) 88e2f98b95SBram Moolenaar 89e2f98b95SBram Moolenaar " Default to table name completion 90e2f98b95SBram Moolenaar let compl_type = 'table' 91e2f98b95SBram Moolenaar " Allow maps to specify what type of object completion they want 92e2f98b95SBram Moolenaar if exists('b:sql_compl_type') 93e2f98b95SBram Moolenaar let compl_type = b:sql_compl_type 94e2f98b95SBram Moolenaar endif 95e2f98b95SBram Moolenaar 96910f66f9SBram Moolenaar " First pass through this function determines how much of the line should 97910f66f9SBram Moolenaar " be replaced by whatever is chosen from the completion list 98e2f98b95SBram Moolenaar if a:findstart 99e2f98b95SBram Moolenaar " Locate the start of the item, including "." 100e2f98b95SBram Moolenaar let line = getline('.') 101e2f98b95SBram Moolenaar let start = col('.') - 1 102e2f98b95SBram Moolenaar let lastword = -1 103*f193fffdSBram Moolenaar let begindot = 0 104*f193fffdSBram Moolenaar " Check if the first character is a ".", for column completion 105*f193fffdSBram Moolenaar if line[start - 1] == '.' 106*f193fffdSBram Moolenaar let begindot = 1 107*f193fffdSBram Moolenaar endif 108e2f98b95SBram Moolenaar while start > 0 109e2f98b95SBram Moolenaar if line[start - 1] =~ '\w' 110e2f98b95SBram Moolenaar let start -= 1 111eb3593b3SBram Moolenaar elseif line[start - 1] =~ '\.' && 112eb3593b3SBram Moolenaar \ compl_type =~ 'column\|table\|view\|procedure' 113eb3593b3SBram Moolenaar " If lastword has already been set for column completion 114eb3593b3SBram Moolenaar " break from the loop, since we do not also want to pickup 115eb3593b3SBram Moolenaar " a table name if it was also supplied. 116*f193fffdSBram Moolenaar if lastword != -1 && compl_type == 'column' 117eb3593b3SBram Moolenaar break 118eb3593b3SBram Moolenaar endif 119*f193fffdSBram Moolenaar " If column completion was specified stop at the "." if 120*f193fffdSBram Moolenaar " a . was specified, otherwise, replace all the way up 121*f193fffdSBram Moolenaar " to the owner name (if included). 122*f193fffdSBram Moolenaar if lastword == -1 && compl_type == 'column' && begindot == 1 123e2f98b95SBram Moolenaar let lastword = start 124e2f98b95SBram Moolenaar endif 125eb3593b3SBram Moolenaar " If omni_sql_include_owner = 0, do not include the table 126eb3593b3SBram Moolenaar " name as part of the substitution, so break here 127eb3593b3SBram Moolenaar if lastword == -1 && 128*f193fffdSBram Moolenaar \ compl_type =~ 'table\|view\|procedure\column_csv' && 129eb3593b3SBram Moolenaar \ g:omni_sql_include_owner == 0 130eb3593b3SBram Moolenaar let lastword = start 131eb3593b3SBram Moolenaar break 132eb3593b3SBram Moolenaar endif 133e2f98b95SBram Moolenaar let start -= 1 134e2f98b95SBram Moolenaar else 135e2f98b95SBram Moolenaar break 136e2f98b95SBram Moolenaar endif 137e2f98b95SBram Moolenaar endwhile 138e2f98b95SBram Moolenaar 139e2f98b95SBram Moolenaar " Return the column of the last word, which is going to be changed. 140e2f98b95SBram Moolenaar " Remember the text that comes before it in s:prepended. 141e2f98b95SBram Moolenaar if lastword == -1 142e2f98b95SBram Moolenaar let s:prepended = '' 143e2f98b95SBram Moolenaar return start 144e2f98b95SBram Moolenaar endif 145e2f98b95SBram Moolenaar let s:prepended = strpart(line, start, lastword - start) 146e2f98b95SBram Moolenaar return lastword 147e2f98b95SBram Moolenaar endif 148e2f98b95SBram Moolenaar 149910f66f9SBram Moolenaar " Second pass through this function will determine what data to put inside 150910f66f9SBram Moolenaar " of the completion list 151910f66f9SBram Moolenaar " s:prepended is set by the first pass 152e2f98b95SBram Moolenaar let base = s:prepended . a:base 153e2f98b95SBram Moolenaar 154910f66f9SBram Moolenaar " Default the completion list to an empty list 155e2f98b95SBram Moolenaar let compl_list = [] 156e2f98b95SBram Moolenaar 157e2f98b95SBram Moolenaar " Default to table name completion 158e2f98b95SBram Moolenaar let compl_type = 'table' 159e2f98b95SBram Moolenaar " Allow maps to specify what type of object completion they want 160e2f98b95SBram Moolenaar if exists('b:sql_compl_type') 161e2f98b95SBram Moolenaar let compl_type = b:sql_compl_type 162e2f98b95SBram Moolenaar unlet b:sql_compl_type 163e2f98b95SBram Moolenaar endif 164e2f98b95SBram Moolenaar 165e2f98b95SBram Moolenaar if compl_type == 'tableReset' 166e2f98b95SBram Moolenaar let compl_type = 'table' 167e2f98b95SBram Moolenaar let base = '' 168e2f98b95SBram Moolenaar endif 169e2f98b95SBram Moolenaar 170e2f98b95SBram Moolenaar if compl_type == 'table' || 171e2f98b95SBram Moolenaar \ compl_type == 'procedure' || 172e2f98b95SBram Moolenaar \ compl_type == 'view' 173e2f98b95SBram Moolenaar 174e2f98b95SBram Moolenaar " This type of completion relies upon the dbext.vim plugin 175e2f98b95SBram Moolenaar if s:SQLCCheck4dbext() == -1 176e2f98b95SBram Moolenaar return [] 177e2f98b95SBram Moolenaar endif 178e2f98b95SBram Moolenaar 179e2f98b95SBram Moolenaar if s:sql_file_{compl_type} == "" 180e2f98b95SBram Moolenaar let compl_type = substitute(compl_type, '\w\+', '\u&', '') 181e2f98b95SBram Moolenaar let s:sql_file_{compl_type} = DB_getDictionaryName(compl_type) 182e2f98b95SBram Moolenaar endif 183e2f98b95SBram Moolenaar let s:sql_file_{compl_type} = DB_getDictionaryName(compl_type) 184e2f98b95SBram Moolenaar if s:sql_file_{compl_type} != "" 185e2f98b95SBram Moolenaar if filereadable(s:sql_file_{compl_type}) 186e2f98b95SBram Moolenaar let compl_list = readfile(s:sql_file_{compl_type}) 187eb3593b3SBram Moolenaar " let dic_list = readfile(s:sql_file_{compl_type}) 188eb3593b3SBram Moolenaar " if !empty(dic_list) 189eb3593b3SBram Moolenaar " for elem in dic_list 190eb3593b3SBram Moolenaar " let kind = (compl_type=='table'?'m':(compl_type=='procedure'?'f':'v')) 191eb3593b3SBram Moolenaar " let item = {'word':elem, 'menu':elem, 'kind':kind, 'info':compl_type} 192eb3593b3SBram Moolenaar " let compl_list += [item] 193eb3593b3SBram Moolenaar " endfor 194eb3593b3SBram Moolenaar " endif 195e2f98b95SBram Moolenaar endif 196e2f98b95SBram Moolenaar endif 197e2f98b95SBram Moolenaar elseif compl_type == 'column' 198e2f98b95SBram Moolenaar 199e2f98b95SBram Moolenaar " This type of completion relies upon the dbext.vim plugin 200e2f98b95SBram Moolenaar if s:SQLCCheck4dbext() == -1 201e2f98b95SBram Moolenaar return [] 202e2f98b95SBram Moolenaar endif 203e2f98b95SBram Moolenaar 204e2f98b95SBram Moolenaar if base == "" 205e2f98b95SBram Moolenaar " The last time we displayed a column list we stored 206e2f98b95SBram Moolenaar " the table name. If the user selects a column list 207e2f98b95SBram Moolenaar " without a table name of alias present, assume they want 208e2f98b95SBram Moolenaar " the previous column list displayed. 209e2f98b95SBram Moolenaar let base = s:save_prev_table 210e2f98b95SBram Moolenaar endif 211e2f98b95SBram Moolenaar 212e2f98b95SBram Moolenaar if base != "" 213e2f98b95SBram Moolenaar let compl_list = s:SQLCGetColumns(base, '') 214e2f98b95SBram Moolenaar let s:save_prev_table = base 215e2f98b95SBram Moolenaar let base = '' 216e2f98b95SBram Moolenaar endif 217e2f98b95SBram Moolenaar elseif compl_type == 'column_csv' 218e2f98b95SBram Moolenaar 219e2f98b95SBram Moolenaar " This type of completion relies upon the dbext.vim plugin 220e2f98b95SBram Moolenaar if s:SQLCCheck4dbext() == -1 221e2f98b95SBram Moolenaar return [] 222e2f98b95SBram Moolenaar endif 223e2f98b95SBram Moolenaar 224e2f98b95SBram Moolenaar if base == "" 225e2f98b95SBram Moolenaar " The last time we displayed a column list we stored 226e2f98b95SBram Moolenaar " the table name. If the user selects a column list 227e2f98b95SBram Moolenaar " without a table name of alias present, assume they want 228e2f98b95SBram Moolenaar " the previous column list displayed. 229e2f98b95SBram Moolenaar let base = s:save_prev_table 230e2f98b95SBram Moolenaar endif 231e2f98b95SBram Moolenaar 232e2f98b95SBram Moolenaar if base != "" 233e2f98b95SBram Moolenaar let compl_list = s:SQLCGetColumns(base, 'csv') 234e2f98b95SBram Moolenaar let s:save_prev_table = base 235e2f98b95SBram Moolenaar " Join the column array into 1 single element array 236e2f98b95SBram Moolenaar " but make the columns column separated 237e2f98b95SBram Moolenaar let compl_list = [join(compl_list, ', ')] 238e2f98b95SBram Moolenaar let base = '' 239e2f98b95SBram Moolenaar endif 240e2f98b95SBram Moolenaar elseif compl_type == 'resetCache' 241e2f98b95SBram Moolenaar " Reset all cached items 242e2f98b95SBram Moolenaar let s:tbl_name = [] 243e2f98b95SBram Moolenaar let s:tbl_alias = [] 244e2f98b95SBram Moolenaar let s:tbl_cols = [] 245e2f98b95SBram Moolenaar let s:syn_list = [] 246e2f98b95SBram Moolenaar let s:syn_value = [] 247*f193fffdSBram Moolenaar 248*f193fffdSBram Moolenaar let msg = "All SQL cached items have been removed." 249*f193fffdSBram Moolenaar call s:SQLCWarningMsg(msg) 250*f193fffdSBram Moolenaar " Leave time for the user to read the error message 251*f193fffdSBram Moolenaar :sleep 2 252e2f98b95SBram Moolenaar else 253910f66f9SBram Moolenaar let compl_list = s:SQLCGetSyntaxList(compl_type) 254e2f98b95SBram Moolenaar endif 255e2f98b95SBram Moolenaar 256e2f98b95SBram Moolenaar if base != '' 257e2f98b95SBram Moolenaar " Filter the list based on the first few characters the user 258e2f98b95SBram Moolenaar " entered 259eb3593b3SBram Moolenaar let expr = 'v:val '.(g:omni_sql_ignorecase==1?'=~?':'=~#').' "^'.base.'"' 260eb3593b3SBram Moolenaar let compl_list = filter(deepcopy(compl_list), expr) 261e2f98b95SBram Moolenaar endif 262e2f98b95SBram Moolenaar 263910f66f9SBram Moolenaar if exists('b:sql_compl_savefunc') && b:sql_compl_savefunc != "" 264910f66f9SBram Moolenaar let &omnifunc = b:sql_compl_savefunc 265910f66f9SBram Moolenaar endif 266910f66f9SBram Moolenaar 267e2f98b95SBram Moolenaar return compl_list 268e2f98b95SBram Moolenaarendfunc 269e2f98b95SBram Moolenaar 270910f66f9SBram Moolenaarfunction! sqlcomplete#PreCacheSyntax(...) 271910f66f9SBram Moolenaar let syn_group_arr = [] 272910f66f9SBram Moolenaar if a:0 > 0 273910f66f9SBram Moolenaar let syn_group_arr = a:1 274910f66f9SBram Moolenaar else 275910f66f9SBram Moolenaar let syn_group_arr = g:omni_sql_precache_syntax_groups 276910f66f9SBram Moolenaar endif 277910f66f9SBram Moolenaar if !empty(syn_group_arr) 278910f66f9SBram Moolenaar for group_name in syn_group_arr 279910f66f9SBram Moolenaar call s:SQLCGetSyntaxList(group_name) 280910f66f9SBram Moolenaar endfor 281910f66f9SBram Moolenaar endif 282910f66f9SBram Moolenaarendfunction 283910f66f9SBram Moolenaar 284910f66f9SBram Moolenaarfunction! sqlcomplete#Map(type) 285910f66f9SBram Moolenaar " Tell the SQL plugin what you want to complete 286910f66f9SBram Moolenaar let b:sql_compl_type=a:type 287910f66f9SBram Moolenaar " Record previous omnifunc, if the SQL completion 288910f66f9SBram Moolenaar " is being used in conjunction with other filetype 289910f66f9SBram Moolenaar " completion plugins 290910f66f9SBram Moolenaar if &omnifunc != "" && &omnifunc != 'sqlcomplete#Complete' 291910f66f9SBram Moolenaar " Record the previous omnifunc, the plugin 292910f66f9SBram Moolenaar " will automatically set this back so that it 293910f66f9SBram Moolenaar " does not interfere with other ftplugins settings 294910f66f9SBram Moolenaar let b:sql_compl_savefunc=&omnifunc 295910f66f9SBram Moolenaar endif 296910f66f9SBram Moolenaar " Set the OMNI func for the SQL completion plugin 297910f66f9SBram Moolenaar let &omnifunc='sqlcomplete#Complete' 298910f66f9SBram Moolenaarendfunction 299910f66f9SBram Moolenaar 300*f193fffdSBram Moolenaarfunction! sqlcomplete#DrillIntoTable() 301*f193fffdSBram Moolenaar " If the omni popup window is visible 302*f193fffdSBram Moolenaar if pumvisible() 303*f193fffdSBram Moolenaar call sqlcomplete#Map('column') 304*f193fffdSBram Moolenaar " C-Y, makes the currently highlighted entry active 305*f193fffdSBram Moolenaar " and trigger the omni popup to be redisplayed 306*f193fffdSBram Moolenaar call feedkeys("\<C-Y>\<C-X>\<C-O>") 307*f193fffdSBram Moolenaar else 308*f193fffdSBram Moolenaar if has('win32') 309*f193fffdSBram Moolenaar " If the popup is not visible, simple perform the normal 310*f193fffdSBram Moolenaar " <C-Right> behaviour 311*f193fffdSBram Moolenaar exec "normal! \<C-Right>" 312*f193fffdSBram Moolenaar endif 313*f193fffdSBram Moolenaar endif 314*f193fffdSBram Moolenaar return "" 315*f193fffdSBram Moolenaarendfunction 316*f193fffdSBram Moolenaar 317*f193fffdSBram Moolenaarfunction! sqlcomplete#DrillOutOfColumns() 318*f193fffdSBram Moolenaar " If the omni popup window is visible 319*f193fffdSBram Moolenaar if pumvisible() 320*f193fffdSBram Moolenaar call sqlcomplete#Map('tableReset') 321*f193fffdSBram Moolenaar " Trigger the omni popup to be redisplayed 322*f193fffdSBram Moolenaar call feedkeys("\<C-X>\<C-O>") 323*f193fffdSBram Moolenaar else 324*f193fffdSBram Moolenaar if has('win32') 325*f193fffdSBram Moolenaar " If the popup is not visible, simple perform the normal 326*f193fffdSBram Moolenaar " <C-Left> behaviour 327*f193fffdSBram Moolenaar exec "normal! \<C-Left>" 328*f193fffdSBram Moolenaar endif 329*f193fffdSBram Moolenaar endif 330*f193fffdSBram Moolenaar return "" 331*f193fffdSBram Moolenaarendfunction 332*f193fffdSBram Moolenaar 333*f193fffdSBram Moolenaarfunction! s:SQLCWarningMsg(msg) 334*f193fffdSBram Moolenaar echohl WarningMsg 335*f193fffdSBram Moolenaar echomsg a:msg 336*f193fffdSBram Moolenaar echohl None 337*f193fffdSBram Moolenaarendfunction 338*f193fffdSBram Moolenaar 339*f193fffdSBram Moolenaarfunction! s:SQLCErrorMsg(msg) 340*f193fffdSBram Moolenaar echohl ErrorMsg 341*f193fffdSBram Moolenaar echomsg a:msg 342*f193fffdSBram Moolenaar echohl None 343*f193fffdSBram Moolenaarendfunction 344*f193fffdSBram Moolenaar 345910f66f9SBram Moolenaarfunction! s:SQLCGetSyntaxList(syn_group) 346910f66f9SBram Moolenaar let syn_group = a:syn_group 347910f66f9SBram Moolenaar let compl_list = [] 348910f66f9SBram Moolenaar 349910f66f9SBram Moolenaar " Check if we have already cached the syntax list 350910f66f9SBram Moolenaar let list_idx = index(s:syn_list, syn_group, 0, &ignorecase) 351910f66f9SBram Moolenaar if list_idx > -1 352910f66f9SBram Moolenaar " Return previously cached value 353910f66f9SBram Moolenaar let compl_list = s:syn_value[list_idx] 354910f66f9SBram Moolenaar else 355910f66f9SBram Moolenaar " Request the syntax list items from the 356910f66f9SBram Moolenaar " syntax completion plugin 357910f66f9SBram Moolenaar if syn_group == 'syntax' 358910f66f9SBram Moolenaar " Handle this special case. This allows the user 359910f66f9SBram Moolenaar " to indicate they want all the syntax items available, 360910f66f9SBram Moolenaar " so do not specify a specific include list. 361910f66f9SBram Moolenaar let g:omni_syntax_group_include_sql = '' 362910f66f9SBram Moolenaar else 363910f66f9SBram Moolenaar " The user has specified a specific syntax group 364910f66f9SBram Moolenaar let g:omni_syntax_group_include_sql = syn_group 365910f66f9SBram Moolenaar endif 366910f66f9SBram Moolenaar let g:omni_syntax_group_exclude_sql = '' 367910f66f9SBram Moolenaar let syn_value = OmniSyntaxList() 368910f66f9SBram Moolenaar let g:omni_syntax_group_include_sql = s:save_inc 369910f66f9SBram Moolenaar let g:omni_syntax_group_exclude_sql = s:save_exc 370910f66f9SBram Moolenaar " Cache these values for later use 371910f66f9SBram Moolenaar let s:syn_list = add( s:syn_list, syn_group ) 372910f66f9SBram Moolenaar let s:syn_value = add( s:syn_value, syn_value ) 373910f66f9SBram Moolenaar let compl_list = syn_value 374910f66f9SBram Moolenaar endif 375910f66f9SBram Moolenaar 376910f66f9SBram Moolenaar return compl_list 377910f66f9SBram Moolenaarendfunction 378910f66f9SBram Moolenaar 379e2f98b95SBram Moolenaarfunction! s:SQLCCheck4dbext() 380e2f98b95SBram Moolenaar if !exists('g:loaded_dbext') 381e2f98b95SBram Moolenaar let msg = "The dbext plugin must be loaded for dynamic SQL completion" 382e2f98b95SBram Moolenaar call s:SQLCErrorMsg(msg) 383e2f98b95SBram Moolenaar " Leave time for the user to read the error message 384e2f98b95SBram Moolenaar :sleep 2 385e2f98b95SBram Moolenaar return -1 386eb3593b3SBram Moolenaar elseif g:loaded_dbext < 300 387eb3593b3SBram Moolenaar let msg = "The dbext plugin must be at least version 3.00 " . 388e2f98b95SBram Moolenaar \ " for dynamic SQL completion" 389e2f98b95SBram Moolenaar call s:SQLCErrorMsg(msg) 390e2f98b95SBram Moolenaar " Leave time for the user to read the error message 391e2f98b95SBram Moolenaar :sleep 2 392e2f98b95SBram Moolenaar return -1 393e2f98b95SBram Moolenaar endif 394e2f98b95SBram Moolenaar return 1 395e2f98b95SBram Moolenaarendfunction 396e2f98b95SBram Moolenaar 397e2f98b95SBram Moolenaarfunction! s:SQLCAddAlias(table_name, table_alias, cols) 398*f193fffdSBram Moolenaar " Strip off the owner if included 399*f193fffdSBram Moolenaar let table_name = matchstr(a:table_name, '\%(.\{-}\.\)\?\zs\(.*\)' ) 400e2f98b95SBram Moolenaar let table_alias = a:table_alias 401e2f98b95SBram Moolenaar let cols = a:cols 402e2f98b95SBram Moolenaar 403e2f98b95SBram Moolenaar if g:omni_sql_use_tbl_alias != 'n' 404e2f98b95SBram Moolenaar if table_alias == '' 405e2f98b95SBram Moolenaar if 'da' =~? g:omni_sql_use_tbl_alias 406e2f98b95SBram Moolenaar if table_name =~ '_' 407e2f98b95SBram Moolenaar " Treat _ as separators since people often use these 408e2f98b95SBram Moolenaar " for word separators 409e2f98b95SBram Moolenaar let save_keyword = &iskeyword 410e2f98b95SBram Moolenaar setlocal iskeyword-=_ 411e2f98b95SBram Moolenaar 412e2f98b95SBram Moolenaar " Get the first letter of each word 413e2f98b95SBram Moolenaar " [[:alpha:]] is used instead of \w 414e2f98b95SBram Moolenaar " to catch extended accented characters 415e2f98b95SBram Moolenaar " 416e2f98b95SBram Moolenaar let table_alias = substitute( 417e2f98b95SBram Moolenaar \ table_name, 418e2f98b95SBram Moolenaar \ '\<[[:alpha:]]\+\>_\?', 419e2f98b95SBram Moolenaar \ '\=strpart(submatch(0), 0, 1)', 420e2f98b95SBram Moolenaar \ 'g' 421e2f98b95SBram Moolenaar \ ) 422e2f98b95SBram Moolenaar " Restore original value 423e2f98b95SBram Moolenaar let &iskeyword = save_keyword 424e2f98b95SBram Moolenaar elseif table_name =~ '\u\U' 425*f193fffdSBram Moolenaar let table_alias = substitute( 426e2f98b95SBram Moolenaar \ table_name, '\(\u\)\U*', '\1', 'g') 427e2f98b95SBram Moolenaar else 428e2f98b95SBram Moolenaar let table_alias = strpart(table_name, 0, 1) 429e2f98b95SBram Moolenaar endif 430e2f98b95SBram Moolenaar endif 431e2f98b95SBram Moolenaar endif 432e2f98b95SBram Moolenaar if table_alias != '' 433e2f98b95SBram Moolenaar " Following a word character, make sure there is a . and no spaces 434e2f98b95SBram Moolenaar let table_alias = substitute(table_alias, '\w\zs\.\?\s*$', '.', '') 435e2f98b95SBram Moolenaar if 'a' =~? g:omni_sql_use_tbl_alias && a:table_alias == '' 436e2f98b95SBram Moolenaar let table_alias = inputdialog("Enter table alias:", table_alias) 437e2f98b95SBram Moolenaar endif 438e2f98b95SBram Moolenaar endif 439e2f98b95SBram Moolenaar if table_alias != '' 440e2f98b95SBram Moolenaar let cols = substitute(cols, '\<\w', table_alias.'&', 'g') 441e2f98b95SBram Moolenaar endif 442e2f98b95SBram Moolenaar endif 443e2f98b95SBram Moolenaar 444e2f98b95SBram Moolenaar return cols 445e2f98b95SBram Moolenaarendfunction 446e2f98b95SBram Moolenaar 447e2f98b95SBram Moolenaarfunction! s:SQLCGetColumns(table_name, list_type) 448e2f98b95SBram Moolenaar let table_name = matchstr(a:table_name, '^\w\+') 449*f193fffdSBram Moolenaar let table_name = matchstr(a:table_name, '^[a-zA-Z0-9_.]\+') 450e2f98b95SBram Moolenaar let table_cols = [] 451e2f98b95SBram Moolenaar let table_alias = '' 452e2f98b95SBram Moolenaar let move_to_top = 1 453e2f98b95SBram Moolenaar 454eb3593b3SBram Moolenaar if g:loaded_dbext >= 300 455e2f98b95SBram Moolenaar let saveSettingAlias = DB_listOption('use_tbl_alias') 456e2f98b95SBram Moolenaar exec 'DBSetOption use_tbl_alias=n' 457e2f98b95SBram Moolenaar endif 458e2f98b95SBram Moolenaar 459e2f98b95SBram Moolenaar " Check if we have already cached the column list for this table 460e2f98b95SBram Moolenaar " by its name 461e2f98b95SBram Moolenaar let list_idx = index(s:tbl_name, table_name, 0, &ignorecase) 462e2f98b95SBram Moolenaar if list_idx > -1 463e2f98b95SBram Moolenaar let table_cols = split(s:tbl_cols[list_idx]) 464e2f98b95SBram Moolenaar else 465e2f98b95SBram Moolenaar " Check if we have already cached the column list for this table 466e2f98b95SBram Moolenaar " by its alias, assuming the table_name provided was actually 467e2f98b95SBram Moolenaar " the alias for the table instead 468e2f98b95SBram Moolenaar " select * 469e2f98b95SBram Moolenaar " from area a 470e2f98b95SBram Moolenaar " where a. 471e2f98b95SBram Moolenaar let list_idx = index(s:tbl_alias, table_name, 0, &ignorecase) 472e2f98b95SBram Moolenaar if list_idx > -1 473e2f98b95SBram Moolenaar let table_alias = table_name 474e2f98b95SBram Moolenaar let table_name = s:tbl_name[list_idx] 475e2f98b95SBram Moolenaar let table_cols = split(s:tbl_cols[list_idx]) 476e2f98b95SBram Moolenaar endif 477e2f98b95SBram Moolenaar endif 478e2f98b95SBram Moolenaar 479e2f98b95SBram Moolenaar " If we have not found a cached copy of the table 480e2f98b95SBram Moolenaar " And the table ends in a "." or we are looking for a column list 481e2f98b95SBram Moolenaar " if list_idx == -1 && (a:table_name =~ '\.' || b:sql_compl_type =~ 'column') 482e2f98b95SBram Moolenaar " if list_idx == -1 && (a:table_name =~ '\.' || a:list_type =~ 'csv') 483e2f98b95SBram Moolenaar if list_idx == -1 484e2f98b95SBram Moolenaar let saveY = @y 485e2f98b95SBram Moolenaar let saveSearch = @/ 486e2f98b95SBram Moolenaar let saveWScan = &wrapscan 487e2f98b95SBram Moolenaar let curline = line(".") 488e2f98b95SBram Moolenaar let curcol = col(".") 489e2f98b95SBram Moolenaar 490e2f98b95SBram Moolenaar " Do not let searchs wrap 491e2f98b95SBram Moolenaar setlocal nowrapscan 492e2f98b95SBram Moolenaar " If . was entered, look at the word just before the . 493e2f98b95SBram Moolenaar " We are looking for something like this: 494e2f98b95SBram Moolenaar " select * 495e2f98b95SBram Moolenaar " from customer c 496e2f98b95SBram Moolenaar " where c. 497e2f98b95SBram Moolenaar " So when . is pressed, we need to find 'c' 498e2f98b95SBram Moolenaar " 499e2f98b95SBram Moolenaar 500e2f98b95SBram Moolenaar " Search backwards to the beginning of the statement 501e2f98b95SBram Moolenaar " and do NOT wrap 502e2f98b95SBram Moolenaar " exec 'silent! normal! v?\<\(select\|update\|delete\|;\)\>'."\n".'"yy' 503e2f98b95SBram Moolenaar exec 'silent! normal! ?\<\(select\|update\|delete\|;\)\>'."\n" 504e2f98b95SBram Moolenaar 505e2f98b95SBram Moolenaar " Start characterwise visual mode 506e2f98b95SBram Moolenaar " Advance right one character 507e2f98b95SBram Moolenaar " Search foward until one of the following: 508e2f98b95SBram Moolenaar " 1. Another select/update/delete statement 509e2f98b95SBram Moolenaar " 2. A ; at the end of a line (the delimiter) 510e2f98b95SBram Moolenaar " 3. The end of the file (incase no delimiter) 511e2f98b95SBram Moolenaar " Yank the visually selected text into the "y register. 512e2f98b95SBram Moolenaar exec 'silent! normal! vl/\(\<select\>\|\<update\>\|\<delete\>\|;\s*$\|\%$\)'."\n".'"yy' 513e2f98b95SBram Moolenaar 514e2f98b95SBram Moolenaar let query = @y 515e2f98b95SBram Moolenaar let query = substitute(query, "\n", ' ', 'g') 516e2f98b95SBram Moolenaar let found = 0 517e2f98b95SBram Moolenaar 518e2f98b95SBram Moolenaar " if query =~? '^\(select\|update\|delete\)' 519e2f98b95SBram Moolenaar if query =~? '^\(select\)' 520e2f98b95SBram Moolenaar let found = 1 521e2f98b95SBram Moolenaar " \(\(\<\w\+\>\)\.\)\? - 522e2f98b95SBram Moolenaar " 'from.\{-}' - Starting at the from clause 523e2f98b95SBram Moolenaar " '\zs\(\(\<\w\+\>\)\.\)\?' - Get the owner name (optional) 524e2f98b95SBram Moolenaar " '\<\w\+\>\ze' - Get the table name 525e2f98b95SBram Moolenaar " '\s\+\<'.table_name.'\>' - Followed by the alias 526e2f98b95SBram Moolenaar " '\s*\.\@!.*' - Cannot be followed by a . 527e2f98b95SBram Moolenaar " '\(\<where\>\|$\)' - Must be followed by a WHERE clause 528e2f98b95SBram Moolenaar " '.*' - Exclude the rest of the line in the match 529e2f98b95SBram Moolenaar let table_name_new = matchstr(@y, 530e2f98b95SBram Moolenaar \ 'from.\{-}'. 531e2f98b95SBram Moolenaar \ '\zs\(\(\<\w\+\>\)\.\)\?'. 532e2f98b95SBram Moolenaar \ '\<\w\+\>\ze'. 533*f193fffdSBram Moolenaar \ '\s\+\%(as\s\+\)\?\<'. 534*f193fffdSBram Moolenaar \ matchstr(table_name, '.\{-}\ze\.\?$'). 535*f193fffdSBram Moolenaar \ '\>'. 536e2f98b95SBram Moolenaar \ '\s*\.\@!.*'. 537e2f98b95SBram Moolenaar \ '\(\<where\>\|$\)'. 538e2f98b95SBram Moolenaar \ '.*' 539e2f98b95SBram Moolenaar \ ) 540e2f98b95SBram Moolenaar if table_name_new != '' 541e2f98b95SBram Moolenaar let table_alias = table_name 542e2f98b95SBram Moolenaar let table_name = table_name_new 543e2f98b95SBram Moolenaar 544e2f98b95SBram Moolenaar let list_idx = index(s:tbl_name, table_name, 0, &ignorecase) 545e2f98b95SBram Moolenaar if list_idx > -1 546e2f98b95SBram Moolenaar let table_cols = split(s:tbl_cols[list_idx]) 547e2f98b95SBram Moolenaar let s:tbl_name[list_idx] = table_name 548e2f98b95SBram Moolenaar let s:tbl_alias[list_idx] = table_alias 549e2f98b95SBram Moolenaar else 550e2f98b95SBram Moolenaar let list_idx = index(s:tbl_alias, table_name, 0, &ignorecase) 551e2f98b95SBram Moolenaar if list_idx > -1 552e2f98b95SBram Moolenaar let table_cols = split(s:tbl_cols[list_idx]) 553e2f98b95SBram Moolenaar let s:tbl_name[list_idx] = table_name 554e2f98b95SBram Moolenaar let s:tbl_alias[list_idx] = table_alias 555e2f98b95SBram Moolenaar endif 556e2f98b95SBram Moolenaar endif 557e2f98b95SBram Moolenaar 558e2f98b95SBram Moolenaar endif 559e2f98b95SBram Moolenaar else 560e2f98b95SBram Moolenaar " Simply assume it is a table name provided with a . on the end 561e2f98b95SBram Moolenaar let found = 1 562e2f98b95SBram Moolenaar endif 563e2f98b95SBram Moolenaar 564e2f98b95SBram Moolenaar let @y = saveY 565e2f98b95SBram Moolenaar let @/ = saveSearch 566e2f98b95SBram Moolenaar let &wrapscan = saveWScan 567e2f98b95SBram Moolenaar 568e2f98b95SBram Moolenaar " Return to previous location 569e2f98b95SBram Moolenaar call cursor(curline, curcol) 570e2f98b95SBram Moolenaar 571e2f98b95SBram Moolenaar if found == 0 572eb3593b3SBram Moolenaar if g:loaded_dbext > 300 573e2f98b95SBram Moolenaar exec 'DBSetOption use_tbl_alias='.saveSettingAlias 574e2f98b95SBram Moolenaar endif 575e2f98b95SBram Moolenaar 576e2f98b95SBram Moolenaar " Not a SQL statement, do not display a list 577e2f98b95SBram Moolenaar return [] 578e2f98b95SBram Moolenaar endif 579e2f98b95SBram Moolenaar endif 580e2f98b95SBram Moolenaar 581e2f98b95SBram Moolenaar if empty(table_cols) 582e2f98b95SBram Moolenaar " Specify silent mode, no messages to the user (tbl, 1) 583e2f98b95SBram Moolenaar " Specify do not comma separate (tbl, 1, 1) 584e2f98b95SBram Moolenaar let table_cols_str = DB_getListColumn(table_name, 1, 1) 585e2f98b95SBram Moolenaar 586e2f98b95SBram Moolenaar if table_cols_str != "" 587e2f98b95SBram Moolenaar let s:tbl_name = add( s:tbl_name, table_name ) 588e2f98b95SBram Moolenaar let s:tbl_alias = add( s:tbl_alias, table_alias ) 589e2f98b95SBram Moolenaar let s:tbl_cols = add( s:tbl_cols, table_cols_str ) 590e2f98b95SBram Moolenaar let table_cols = split(table_cols_str) 591e2f98b95SBram Moolenaar endif 592e2f98b95SBram Moolenaar 593e2f98b95SBram Moolenaar endif 594e2f98b95SBram Moolenaar 595eb3593b3SBram Moolenaar if g:loaded_dbext > 300 596e2f98b95SBram Moolenaar exec 'DBSetOption use_tbl_alias='.saveSettingAlias 597e2f98b95SBram Moolenaar endif 598e2f98b95SBram Moolenaar 599*f193fffdSBram Moolenaar " If the user has asked for a comma separate list of column 600*f193fffdSBram Moolenaar " values, ask the user if they want to prepend each column 601*f193fffdSBram Moolenaar " with a tablename alias. 602e2f98b95SBram Moolenaar if a:list_type == 'csv' && !empty(table_cols) 603e2f98b95SBram Moolenaar let cols = join(table_cols, ', ') 604e2f98b95SBram Moolenaar let cols = s:SQLCAddAlias(table_name, table_alias, cols) 605e2f98b95SBram Moolenaar let table_cols = [cols] 606e2f98b95SBram Moolenaar endif 607e2f98b95SBram Moolenaar 608e2f98b95SBram Moolenaar return table_cols 609e2f98b95SBram Moolenaarendfunction 610e2f98b95SBram Moolenaar 611