1*e2f98b95SBram Moolenaar" Vim completion script
2*e2f98b95SBram Moolenaar" Language:    SQL
3*e2f98b95SBram Moolenaar" Maintainer:  David Fishburn <[email protected]>
4*e2f98b95SBram Moolenaar" Version:     1.0
5*e2f98b95SBram Moolenaar" Last Change: Tue Mar 28 2006 4:39:49 PM
6*e2f98b95SBram Moolenaar
7*e2f98b95SBram Moolenaar" Set completion with CTRL-X CTRL-O to autoloaded function.
8*e2f98b95SBram Moolenaar" This check is in place in case this script is
9*e2f98b95SBram Moolenaar" sourced directly instead of using the autoload feature.
10*e2f98b95SBram Moolenaarif exists('&omnifunc')
11*e2f98b95SBram Moolenaar    " Do not set the option if already set since this
12*e2f98b95SBram Moolenaar    " results in an E117 warning.
13*e2f98b95SBram Moolenaar    if &omnifunc == ""
14*e2f98b95SBram Moolenaar        setlocal omnifunc=sqlcomplete#Complete
15*e2f98b95SBram Moolenaar    endif
16*e2f98b95SBram Moolenaarendif
17*e2f98b95SBram Moolenaar
18*e2f98b95SBram Moolenaarif exists('g:loaded_sql_completion')
19*e2f98b95SBram Moolenaar    finish
20*e2f98b95SBram Moolenaarendif
21*e2f98b95SBram Moolenaarlet g:loaded_sql_completion = 1
22*e2f98b95SBram Moolenaar
23*e2f98b95SBram Moolenaar" Maintains filename of dictionary
24*e2f98b95SBram Moolenaarlet s:sql_file_table             = ""
25*e2f98b95SBram Moolenaarlet s:sql_file_procedure         = ""
26*e2f98b95SBram Moolenaarlet s:sql_file_view              = ""
27*e2f98b95SBram Moolenaar
28*e2f98b95SBram Moolenaar" Define various arrays to be used for caching
29*e2f98b95SBram Moolenaarlet s:tbl_name                   = []
30*e2f98b95SBram Moolenaarlet s:tbl_alias                  = []
31*e2f98b95SBram Moolenaarlet s:tbl_cols                   = []
32*e2f98b95SBram Moolenaarlet s:syn_list                   = []
33*e2f98b95SBram Moolenaarlet s:syn_value                  = []
34*e2f98b95SBram Moolenaar
35*e2f98b95SBram Moolenaar" Used in conjunction with the syntaxcomplete plugin
36*e2f98b95SBram Moolenaarlet s:save_inc = ""
37*e2f98b95SBram Moolenaarlet s:save_exc = ""
38*e2f98b95SBram Moolenaarif exists('g:omni_syntax_group_include_sql')
39*e2f98b95SBram Moolenaar    let s:save_inc = g:omni_syntax_group_include_sql
40*e2f98b95SBram Moolenaarendif
41*e2f98b95SBram Moolenaarif exists('g:omni_syntax_group_exclude_sql')
42*e2f98b95SBram Moolenaar    let s:save_exc = g:omni_syntax_group_exclude_sql
43*e2f98b95SBram Moolenaarendif
44*e2f98b95SBram Moolenaar
45*e2f98b95SBram Moolenaar" Used with the column list
46*e2f98b95SBram Moolenaarlet s:save_prev_table = ""
47*e2f98b95SBram Moolenaar
48*e2f98b95SBram Moolenaar" Default the option to verify table alias
49*e2f98b95SBram Moolenaarif !exists('g:omni_sql_use_tbl_alias')
50*e2f98b95SBram Moolenaar    let g:omni_sql_use_tbl_alias = 'a'
51*e2f98b95SBram Moolenaarendif
52*e2f98b95SBram Moolenaar
53*e2f98b95SBram Moolenaar" This function is used for the 'omnifunc' option.
54*e2f98b95SBram Moolenaarfunction! sqlcomplete#Complete(findstart, base)
55*e2f98b95SBram Moolenaar
56*e2f98b95SBram Moolenaar    " Default to table name completion
57*e2f98b95SBram Moolenaar    let compl_type = 'table'
58*e2f98b95SBram Moolenaar    " Allow maps to specify what type of object completion they want
59*e2f98b95SBram Moolenaar    if exists('b:sql_compl_type')
60*e2f98b95SBram Moolenaar        let compl_type = b:sql_compl_type
61*e2f98b95SBram Moolenaar    endif
62*e2f98b95SBram Moolenaar
63*e2f98b95SBram Moolenaar    if a:findstart
64*e2f98b95SBram Moolenaar        " Locate the start of the item, including "."
65*e2f98b95SBram Moolenaar        let line = getline('.')
66*e2f98b95SBram Moolenaar        let start = col('.') - 1
67*e2f98b95SBram Moolenaar        let lastword = -1
68*e2f98b95SBram Moolenaar        while start > 0
69*e2f98b95SBram Moolenaar            if line[start - 1] =~ '\w'
70*e2f98b95SBram Moolenaar                let start -= 1
71*e2f98b95SBram Moolenaar            elseif line[start - 1] =~ '\.' && compl_type =~ 'column\|table'
72*e2f98b95SBram Moolenaar                " If the completion type is table or column
73*e2f98b95SBram Moolenaar                " Then assume we are looking for column completion
74*e2f98b95SBram Moolenaar                " column_type can be either 'column' or 'column_csv'
75*e2f98b95SBram Moolenaar                if lastword == -1
76*e2f98b95SBram Moolenaar                    let lastword = start
77*e2f98b95SBram Moolenaar                endif
78*e2f98b95SBram Moolenaar                let start -= 1
79*e2f98b95SBram Moolenaar                let b:sql_compl_type = 'column'
80*e2f98b95SBram Moolenaar            else
81*e2f98b95SBram Moolenaar                break
82*e2f98b95SBram Moolenaar            endif
83*e2f98b95SBram Moolenaar        endwhile
84*e2f98b95SBram Moolenaar
85*e2f98b95SBram Moolenaar        " Return the column of the last word, which is going to be changed.
86*e2f98b95SBram Moolenaar        " Remember the text that comes before it in s:prepended.
87*e2f98b95SBram Moolenaar        if lastword == -1
88*e2f98b95SBram Moolenaar            let s:prepended = ''
89*e2f98b95SBram Moolenaar            return start
90*e2f98b95SBram Moolenaar        endif
91*e2f98b95SBram Moolenaar        let s:prepended = strpart(line, start, lastword - start)
92*e2f98b95SBram Moolenaar        return lastword
93*e2f98b95SBram Moolenaar    endif
94*e2f98b95SBram Moolenaar
95*e2f98b95SBram Moolenaar    let base = s:prepended . a:base
96*e2f98b95SBram Moolenaar
97*e2f98b95SBram Moolenaar    let compl_list = []
98*e2f98b95SBram Moolenaar
99*e2f98b95SBram Moolenaar    " Default to table name completion
100*e2f98b95SBram Moolenaar    let compl_type = 'table'
101*e2f98b95SBram Moolenaar    " Allow maps to specify what type of object completion they want
102*e2f98b95SBram Moolenaar    if exists('b:sql_compl_type')
103*e2f98b95SBram Moolenaar        let compl_type = b:sql_compl_type
104*e2f98b95SBram Moolenaar        unlet b:sql_compl_type
105*e2f98b95SBram Moolenaar    endif
106*e2f98b95SBram Moolenaar
107*e2f98b95SBram Moolenaar    if compl_type == 'tableReset'
108*e2f98b95SBram Moolenaar        let compl_type = 'table'
109*e2f98b95SBram Moolenaar        let base = ''
110*e2f98b95SBram Moolenaar    endif
111*e2f98b95SBram Moolenaar
112*e2f98b95SBram Moolenaar    if compl_type == 'table' ||
113*e2f98b95SBram Moolenaar                \ compl_type == 'procedure' ||
114*e2f98b95SBram Moolenaar                \ compl_type == 'view'
115*e2f98b95SBram Moolenaar
116*e2f98b95SBram Moolenaar        " This type of completion relies upon the dbext.vim plugin
117*e2f98b95SBram Moolenaar        if s:SQLCCheck4dbext() == -1
118*e2f98b95SBram Moolenaar            return []
119*e2f98b95SBram Moolenaar        endif
120*e2f98b95SBram Moolenaar
121*e2f98b95SBram Moolenaar        if s:sql_file_{compl_type} == ""
122*e2f98b95SBram Moolenaar            let compl_type = substitute(compl_type, '\w\+', '\u&', '')
123*e2f98b95SBram Moolenaar            let s:sql_file_{compl_type} = DB_getDictionaryName(compl_type)
124*e2f98b95SBram Moolenaar        endif
125*e2f98b95SBram Moolenaar        let s:sql_file_{compl_type} = DB_getDictionaryName(compl_type)
126*e2f98b95SBram Moolenaar        if s:sql_file_{compl_type} != ""
127*e2f98b95SBram Moolenaar            if filereadable(s:sql_file_{compl_type})
128*e2f98b95SBram Moolenaar                let compl_list = readfile(s:sql_file_{compl_type})
129*e2f98b95SBram Moolenaar            endif
130*e2f98b95SBram Moolenaar        endif
131*e2f98b95SBram Moolenaar    elseif compl_type == 'column'
132*e2f98b95SBram Moolenaar
133*e2f98b95SBram Moolenaar        " This type of completion relies upon the dbext.vim plugin
134*e2f98b95SBram Moolenaar        if s:SQLCCheck4dbext() == -1
135*e2f98b95SBram Moolenaar            return []
136*e2f98b95SBram Moolenaar        endif
137*e2f98b95SBram Moolenaar
138*e2f98b95SBram Moolenaar        if base == ""
139*e2f98b95SBram Moolenaar            " The last time we displayed a column list we stored
140*e2f98b95SBram Moolenaar            " the table name.  If the user selects a column list
141*e2f98b95SBram Moolenaar            " without a table name of alias present, assume they want
142*e2f98b95SBram Moolenaar            " the previous column list displayed.
143*e2f98b95SBram Moolenaar            let base = s:save_prev_table
144*e2f98b95SBram Moolenaar        endif
145*e2f98b95SBram Moolenaar
146*e2f98b95SBram Moolenaar        if base != ""
147*e2f98b95SBram Moolenaar            let compl_list        = s:SQLCGetColumns(base, '')
148*e2f98b95SBram Moolenaar            let s:save_prev_table = base
149*e2f98b95SBram Moolenaar            let base              = ''
150*e2f98b95SBram Moolenaar        endif
151*e2f98b95SBram Moolenaar    elseif compl_type == 'column_csv'
152*e2f98b95SBram Moolenaar
153*e2f98b95SBram Moolenaar        " This type of completion relies upon the dbext.vim plugin
154*e2f98b95SBram Moolenaar        if s:SQLCCheck4dbext() == -1
155*e2f98b95SBram Moolenaar            return []
156*e2f98b95SBram Moolenaar        endif
157*e2f98b95SBram Moolenaar
158*e2f98b95SBram Moolenaar        if base == ""
159*e2f98b95SBram Moolenaar            " The last time we displayed a column list we stored
160*e2f98b95SBram Moolenaar            " the table name.  If the user selects a column list
161*e2f98b95SBram Moolenaar            " without a table name of alias present, assume they want
162*e2f98b95SBram Moolenaar            " the previous column list displayed.
163*e2f98b95SBram Moolenaar            let base = s:save_prev_table
164*e2f98b95SBram Moolenaar        endif
165*e2f98b95SBram Moolenaar
166*e2f98b95SBram Moolenaar        if base != ""
167*e2f98b95SBram Moolenaar            let compl_list        = s:SQLCGetColumns(base, 'csv')
168*e2f98b95SBram Moolenaar            let s:save_prev_table = base
169*e2f98b95SBram Moolenaar            " Join the column array into 1 single element array
170*e2f98b95SBram Moolenaar            " but make the columns column separated
171*e2f98b95SBram Moolenaar            let compl_list        = [join(compl_list, ', ')]
172*e2f98b95SBram Moolenaar            let base              = ''
173*e2f98b95SBram Moolenaar        endif
174*e2f98b95SBram Moolenaar    elseif compl_type == 'resetCache'
175*e2f98b95SBram Moolenaar        " Reset all cached items
176*e2f98b95SBram Moolenaar        let s:tbl_name  = []
177*e2f98b95SBram Moolenaar        let s:tbl_alias = []
178*e2f98b95SBram Moolenaar        let s:tbl_cols  = []
179*e2f98b95SBram Moolenaar        let s:syn_list  = []
180*e2f98b95SBram Moolenaar        let s:syn_value = []
181*e2f98b95SBram Moolenaar        return []
182*e2f98b95SBram Moolenaar    else
183*e2f98b95SBram Moolenaar        " Default to empty or not found
184*e2f98b95SBram Moolenaar        let compl_list = []
185*e2f98b95SBram Moolenaar        " Check if we have already cached the syntax list
186*e2f98b95SBram Moolenaar        let list_idx = index(s:syn_list, compl_type, 0, &ignorecase)
187*e2f98b95SBram Moolenaar        if list_idx > -1
188*e2f98b95SBram Moolenaar            " Return previously cached value
189*e2f98b95SBram Moolenaar            let compl_list = s:syn_value[list_idx]
190*e2f98b95SBram Moolenaar        else
191*e2f98b95SBram Moolenaar            " Request the syntax list items from the
192*e2f98b95SBram Moolenaar            " syntax completion plugin
193*e2f98b95SBram Moolenaar            if compl_type == 'syntax'
194*e2f98b95SBram Moolenaar                " Handle this special case.  This allows the user
195*e2f98b95SBram Moolenaar                " to indicate they want all the syntax items available,
196*e2f98b95SBram Moolenaar                " so do not specify a specific include list.
197*e2f98b95SBram Moolenaar                let g:omni_syntax_group_include_sql = ''
198*e2f98b95SBram Moolenaar            else
199*e2f98b95SBram Moolenaar                " The user has specified a specific syntax group
200*e2f98b95SBram Moolenaar                let g:omni_syntax_group_include_sql = compl_type
201*e2f98b95SBram Moolenaar            endif
202*e2f98b95SBram Moolenaar            let g:omni_syntax_group_exclude_sql = ''
203*e2f98b95SBram Moolenaar            let syn_value                       = OmniSyntaxList()
204*e2f98b95SBram Moolenaar            let g:omni_syntax_group_include_sql = s:save_inc
205*e2f98b95SBram Moolenaar            let g:omni_syntax_group_exclude_sql = s:save_exc
206*e2f98b95SBram Moolenaar            " Cache these values for later use
207*e2f98b95SBram Moolenaar            let s:syn_list  = add( s:syn_list,  compl_type )
208*e2f98b95SBram Moolenaar            let s:syn_value = add( s:syn_value, syn_value )
209*e2f98b95SBram Moolenaar            let compl_list  = syn_value
210*e2f98b95SBram Moolenaar        endif
211*e2f98b95SBram Moolenaar    endif
212*e2f98b95SBram Moolenaar
213*e2f98b95SBram Moolenaar    if base != ''
214*e2f98b95SBram Moolenaar        " Filter the list based on the first few characters the user
215*e2f98b95SBram Moolenaar        " entered
216*e2f98b95SBram Moolenaar        let expr = 'v:val =~ "^'.base.'"'
217*e2f98b95SBram Moolenaar        let compl_list = filter(copy(compl_list), expr)
218*e2f98b95SBram Moolenaar    endif
219*e2f98b95SBram Moolenaar
220*e2f98b95SBram Moolenaar    return compl_list
221*e2f98b95SBram Moolenaarendfunc
222*e2f98b95SBram Moolenaar
223*e2f98b95SBram Moolenaarfunction! s:SQLCWarningMsg(msg)
224*e2f98b95SBram Moolenaar    echohl WarningMsg
225*e2f98b95SBram Moolenaar    echomsg a:msg
226*e2f98b95SBram Moolenaar    echohl None
227*e2f98b95SBram Moolenaarendfunction
228*e2f98b95SBram Moolenaar
229*e2f98b95SBram Moolenaarfunction! s:SQLCErrorMsg(msg)
230*e2f98b95SBram Moolenaar    echohl ErrorMsg
231*e2f98b95SBram Moolenaar    echomsg a:msg
232*e2f98b95SBram Moolenaar    echohl None
233*e2f98b95SBram Moolenaarendfunction
234*e2f98b95SBram Moolenaar
235*e2f98b95SBram Moolenaarfunction! s:SQLCCheck4dbext()
236*e2f98b95SBram Moolenaar    if !exists('g:loaded_dbext')
237*e2f98b95SBram Moolenaar        let msg = "The dbext plugin must be loaded for dynamic SQL completion"
238*e2f98b95SBram Moolenaar        call s:SQLCErrorMsg(msg)
239*e2f98b95SBram Moolenaar        " Leave time for the user to read the error message
240*e2f98b95SBram Moolenaar        :sleep 2
241*e2f98b95SBram Moolenaar        return -1
242*e2f98b95SBram Moolenaar    elseif g:loaded_dbext < 210
243*e2f98b95SBram Moolenaar        let msg = "The dbext plugin must be at least version 2.10 " .
244*e2f98b95SBram Moolenaar                    \ " for dynamic SQL completion"
245*e2f98b95SBram Moolenaar        call s:SQLCErrorMsg(msg)
246*e2f98b95SBram Moolenaar        " Leave time for the user to read the error message
247*e2f98b95SBram Moolenaar        :sleep 2
248*e2f98b95SBram Moolenaar        return -1
249*e2f98b95SBram Moolenaar    endif
250*e2f98b95SBram Moolenaar    return 1
251*e2f98b95SBram Moolenaarendfunction
252*e2f98b95SBram Moolenaar
253*e2f98b95SBram Moolenaarfunction! s:SQLCAddAlias(table_name, table_alias, cols)
254*e2f98b95SBram Moolenaar    let table_name  = a:table_name
255*e2f98b95SBram Moolenaar    let table_alias = a:table_alias
256*e2f98b95SBram Moolenaar    let cols        = a:cols
257*e2f98b95SBram Moolenaar
258*e2f98b95SBram Moolenaar    if g:omni_sql_use_tbl_alias != 'n'
259*e2f98b95SBram Moolenaar        if table_alias == ''
260*e2f98b95SBram Moolenaar            if 'da' =~? g:omni_sql_use_tbl_alias
261*e2f98b95SBram Moolenaar                if table_name =~ '_'
262*e2f98b95SBram Moolenaar                    " Treat _ as separators since people often use these
263*e2f98b95SBram Moolenaar                    " for word separators
264*e2f98b95SBram Moolenaar                    let save_keyword = &iskeyword
265*e2f98b95SBram Moolenaar                    setlocal iskeyword-=_
266*e2f98b95SBram Moolenaar
267*e2f98b95SBram Moolenaar                    " Get the first letter of each word
268*e2f98b95SBram Moolenaar                    " [[:alpha:]] is used instead of \w
269*e2f98b95SBram Moolenaar                    " to catch extended accented characters
270*e2f98b95SBram Moolenaar                    "
271*e2f98b95SBram Moolenaar                    let table_alias = substitute(
272*e2f98b95SBram Moolenaar                                \ table_name,
273*e2f98b95SBram Moolenaar                                \ '\<[[:alpha:]]\+\>_\?',
274*e2f98b95SBram Moolenaar                                \ '\=strpart(submatch(0), 0, 1)',
275*e2f98b95SBram Moolenaar                                \ 'g'
276*e2f98b95SBram Moolenaar                                \ )
277*e2f98b95SBram Moolenaar                    " Restore original value
278*e2f98b95SBram Moolenaar                    let &iskeyword = save_keyword
279*e2f98b95SBram Moolenaar                elseif table_name =~ '\u\U'
280*e2f98b95SBram Moolenaar                    let initials = substitute(
281*e2f98b95SBram Moolenaar                                \ table_name, '\(\u\)\U*', '\1', 'g')
282*e2f98b95SBram Moolenaar                else
283*e2f98b95SBram Moolenaar                    let table_alias = strpart(table_name, 0, 1)
284*e2f98b95SBram Moolenaar                endif
285*e2f98b95SBram Moolenaar            endif
286*e2f98b95SBram Moolenaar        endif
287*e2f98b95SBram Moolenaar        if table_alias != ''
288*e2f98b95SBram Moolenaar            " Following a word character, make sure there is a . and no spaces
289*e2f98b95SBram Moolenaar            let table_alias = substitute(table_alias, '\w\zs\.\?\s*$', '.', '')
290*e2f98b95SBram Moolenaar            if 'a' =~? g:omni_sql_use_tbl_alias && a:table_alias == ''
291*e2f98b95SBram Moolenaar                let table_alias = inputdialog("Enter table alias:", table_alias)
292*e2f98b95SBram Moolenaar            endif
293*e2f98b95SBram Moolenaar        endif
294*e2f98b95SBram Moolenaar        if table_alias != ''
295*e2f98b95SBram Moolenaar            let cols = substitute(cols, '\<\w', table_alias.'&', 'g')
296*e2f98b95SBram Moolenaar        endif
297*e2f98b95SBram Moolenaar    endif
298*e2f98b95SBram Moolenaar
299*e2f98b95SBram Moolenaar    return cols
300*e2f98b95SBram Moolenaarendfunction
301*e2f98b95SBram Moolenaar
302*e2f98b95SBram Moolenaarfunction! s:SQLCGetColumns(table_name, list_type)
303*e2f98b95SBram Moolenaar    let table_name   = matchstr(a:table_name, '^\w\+')
304*e2f98b95SBram Moolenaar    let table_cols   = []
305*e2f98b95SBram Moolenaar    let table_alias  = ''
306*e2f98b95SBram Moolenaar    let move_to_top  = 1
307*e2f98b95SBram Moolenaar
308*e2f98b95SBram Moolenaar    if g:loaded_dbext >= 210
309*e2f98b95SBram Moolenaar        let saveSettingAlias = DB_listOption('use_tbl_alias')
310*e2f98b95SBram Moolenaar        exec 'DBSetOption use_tbl_alias=n'
311*e2f98b95SBram Moolenaar    endif
312*e2f98b95SBram Moolenaar
313*e2f98b95SBram Moolenaar    " Check if we have already cached the column list for this table
314*e2f98b95SBram Moolenaar    " by its name
315*e2f98b95SBram Moolenaar    let list_idx = index(s:tbl_name, table_name, 0, &ignorecase)
316*e2f98b95SBram Moolenaar    if list_idx > -1
317*e2f98b95SBram Moolenaar        let table_cols = split(s:tbl_cols[list_idx])
318*e2f98b95SBram Moolenaar    else
319*e2f98b95SBram Moolenaar        " Check if we have already cached the column list for this table
320*e2f98b95SBram Moolenaar        " by its alias, assuming the table_name provided was actually
321*e2f98b95SBram Moolenaar        " the alias for the table instead
322*e2f98b95SBram Moolenaar        "     select *
323*e2f98b95SBram Moolenaar        "       from area a
324*e2f98b95SBram Moolenaar        "      where a.
325*e2f98b95SBram Moolenaar        let list_idx = index(s:tbl_alias, table_name, 0, &ignorecase)
326*e2f98b95SBram Moolenaar        if list_idx > -1
327*e2f98b95SBram Moolenaar            let table_alias = table_name
328*e2f98b95SBram Moolenaar            let table_name  = s:tbl_name[list_idx]
329*e2f98b95SBram Moolenaar            let table_cols  = split(s:tbl_cols[list_idx])
330*e2f98b95SBram Moolenaar        endif
331*e2f98b95SBram Moolenaar    endif
332*e2f98b95SBram Moolenaar
333*e2f98b95SBram Moolenaar    " If we have not found a cached copy of the table
334*e2f98b95SBram Moolenaar    " And the table ends in a "." or we are looking for a column list
335*e2f98b95SBram Moolenaar    " if list_idx == -1 && (a:table_name =~ '\.' || b:sql_compl_type =~ 'column')
336*e2f98b95SBram Moolenaar    " if list_idx == -1 && (a:table_name =~ '\.' || a:list_type =~ 'csv')
337*e2f98b95SBram Moolenaar    if list_idx == -1
338*e2f98b95SBram Moolenaar         let saveY      = @y
339*e2f98b95SBram Moolenaar         let saveSearch = @/
340*e2f98b95SBram Moolenaar         let saveWScan  = &wrapscan
341*e2f98b95SBram Moolenaar         let curline    = line(".")
342*e2f98b95SBram Moolenaar         let curcol     = col(".")
343*e2f98b95SBram Moolenaar
344*e2f98b95SBram Moolenaar         " Do not let searchs wrap
345*e2f98b95SBram Moolenaar         setlocal nowrapscan
346*e2f98b95SBram Moolenaar         " If . was entered, look at the word just before the .
347*e2f98b95SBram Moolenaar         " We are looking for something like this:
348*e2f98b95SBram Moolenaar         "    select *
349*e2f98b95SBram Moolenaar         "      from customer c
350*e2f98b95SBram Moolenaar         "     where c.
351*e2f98b95SBram Moolenaar         " So when . is pressed, we need to find 'c'
352*e2f98b95SBram Moolenaar         "
353*e2f98b95SBram Moolenaar
354*e2f98b95SBram Moolenaar         " Search backwards to the beginning of the statement
355*e2f98b95SBram Moolenaar         " and do NOT wrap
356*e2f98b95SBram Moolenaar         " exec 'silent! normal! v?\<\(select\|update\|delete\|;\)\>'."\n".'"yy'
357*e2f98b95SBram Moolenaar         exec 'silent! normal! ?\<\(select\|update\|delete\|;\)\>'."\n"
358*e2f98b95SBram Moolenaar
359*e2f98b95SBram Moolenaar         " Start characterwise visual mode
360*e2f98b95SBram Moolenaar         " Advance right one character
361*e2f98b95SBram Moolenaar         " Search foward until one of the following:
362*e2f98b95SBram Moolenaar         "     1.  Another select/update/delete statement
363*e2f98b95SBram Moolenaar         "     2.  A ; at the end of a line (the delimiter)
364*e2f98b95SBram Moolenaar         "     3.  The end of the file (incase no delimiter)
365*e2f98b95SBram Moolenaar         " Yank the visually selected text into the "y register.
366*e2f98b95SBram Moolenaar         exec 'silent! normal! vl/\(\<select\>\|\<update\>\|\<delete\>\|;\s*$\|\%$\)'."\n".'"yy'
367*e2f98b95SBram Moolenaar
368*e2f98b95SBram Moolenaar         let query = @y
369*e2f98b95SBram Moolenaar         let query = substitute(query, "\n", ' ', 'g')
370*e2f98b95SBram Moolenaar         let found = 0
371*e2f98b95SBram Moolenaar
372*e2f98b95SBram Moolenaar         " if query =~? '^\(select\|update\|delete\)'
373*e2f98b95SBram Moolenaar         if query =~? '^\(select\)'
374*e2f98b95SBram Moolenaar             let found = 1
375*e2f98b95SBram Moolenaar             "  \(\(\<\w\+\>\)\.\)\?   -
376*e2f98b95SBram Moolenaar             " 'from.\{-}'  - Starting at the from clause
377*e2f98b95SBram Moolenaar             " '\zs\(\(\<\w\+\>\)\.\)\?' - Get the owner name (optional)
378*e2f98b95SBram Moolenaar             " '\<\w\+\>\ze' - Get the table name
379*e2f98b95SBram Moolenaar             " '\s\+\<'.table_name.'\>' - Followed by the alias
380*e2f98b95SBram Moolenaar             " '\s*\.\@!.*'  - Cannot be followed by a .
381*e2f98b95SBram Moolenaar             " '\(\<where\>\|$\)' - Must be followed by a WHERE clause
382*e2f98b95SBram Moolenaar             " '.*'  - Exclude the rest of the line in the match
383*e2f98b95SBram Moolenaar             let table_name_new = matchstr(@y,
384*e2f98b95SBram Moolenaar                         \ 'from.\{-}'.
385*e2f98b95SBram Moolenaar                         \ '\zs\(\(\<\w\+\>\)\.\)\?'.
386*e2f98b95SBram Moolenaar                         \ '\<\w\+\>\ze'.
387*e2f98b95SBram Moolenaar                         \ '\s\+\%(as\s\+\)\?\<'.table_name.'\>'.
388*e2f98b95SBram Moolenaar                         \ '\s*\.\@!.*'.
389*e2f98b95SBram Moolenaar                         \ '\(\<where\>\|$\)'.
390*e2f98b95SBram Moolenaar                         \ '.*'
391*e2f98b95SBram Moolenaar                         \ )
392*e2f98b95SBram Moolenaar             if table_name_new != ''
393*e2f98b95SBram Moolenaar                 let table_alias = table_name
394*e2f98b95SBram Moolenaar                 let table_name  = table_name_new
395*e2f98b95SBram Moolenaar
396*e2f98b95SBram Moolenaar                 let list_idx = index(s:tbl_name, table_name, 0, &ignorecase)
397*e2f98b95SBram Moolenaar                 if list_idx > -1
398*e2f98b95SBram Moolenaar                     let table_cols  = split(s:tbl_cols[list_idx])
399*e2f98b95SBram Moolenaar                     let s:tbl_name[list_idx]  = table_name
400*e2f98b95SBram Moolenaar                     let s:tbl_alias[list_idx] = table_alias
401*e2f98b95SBram Moolenaar                 else
402*e2f98b95SBram Moolenaar                     let list_idx = index(s:tbl_alias, table_name, 0, &ignorecase)
403*e2f98b95SBram Moolenaar                     if list_idx > -1
404*e2f98b95SBram Moolenaar                         let table_cols = split(s:tbl_cols[list_idx])
405*e2f98b95SBram Moolenaar                         let s:tbl_name[list_idx]  = table_name
406*e2f98b95SBram Moolenaar                         let s:tbl_alias[list_idx] = table_alias
407*e2f98b95SBram Moolenaar                     endif
408*e2f98b95SBram Moolenaar                 endif
409*e2f98b95SBram Moolenaar
410*e2f98b95SBram Moolenaar             endif
411*e2f98b95SBram Moolenaar         else
412*e2f98b95SBram Moolenaar             " Simply assume it is a table name provided with a . on the end
413*e2f98b95SBram Moolenaar             let found = 1
414*e2f98b95SBram Moolenaar         endif
415*e2f98b95SBram Moolenaar
416*e2f98b95SBram Moolenaar         let @y        = saveY
417*e2f98b95SBram Moolenaar         let @/        = saveSearch
418*e2f98b95SBram Moolenaar         let &wrapscan = saveWScan
419*e2f98b95SBram Moolenaar
420*e2f98b95SBram Moolenaar         " Return to previous location
421*e2f98b95SBram Moolenaar         call cursor(curline, curcol)
422*e2f98b95SBram Moolenaar
423*e2f98b95SBram Moolenaar         if found == 0
424*e2f98b95SBram Moolenaar             if g:loaded_dbext > 201
425*e2f98b95SBram Moolenaar                 exec 'DBSetOption use_tbl_alias='.saveSettingAlias
426*e2f98b95SBram Moolenaar             endif
427*e2f98b95SBram Moolenaar
428*e2f98b95SBram Moolenaar             " Not a SQL statement, do not display a list
429*e2f98b95SBram Moolenaar             return []
430*e2f98b95SBram Moolenaar         endif
431*e2f98b95SBram Moolenaar    endif
432*e2f98b95SBram Moolenaar
433*e2f98b95SBram Moolenaar    if empty(table_cols)
434*e2f98b95SBram Moolenaar        " Specify silent mode, no messages to the user (tbl, 1)
435*e2f98b95SBram Moolenaar        " Specify do not comma separate (tbl, 1, 1)
436*e2f98b95SBram Moolenaar        let table_cols_str = DB_getListColumn(table_name, 1, 1)
437*e2f98b95SBram Moolenaar
438*e2f98b95SBram Moolenaar        if table_cols_str != ""
439*e2f98b95SBram Moolenaar            let s:tbl_name  = add( s:tbl_name,  table_name )
440*e2f98b95SBram Moolenaar            let s:tbl_alias = add( s:tbl_alias, table_alias )
441*e2f98b95SBram Moolenaar            let s:tbl_cols  = add( s:tbl_cols,  table_cols_str )
442*e2f98b95SBram Moolenaar            let table_cols  = split(table_cols_str)
443*e2f98b95SBram Moolenaar        endif
444*e2f98b95SBram Moolenaar
445*e2f98b95SBram Moolenaar    endif
446*e2f98b95SBram Moolenaar
447*e2f98b95SBram Moolenaar    if g:loaded_dbext > 201
448*e2f98b95SBram Moolenaar        exec 'DBSetOption use_tbl_alias='.saveSettingAlias
449*e2f98b95SBram Moolenaar    endif
450*e2f98b95SBram Moolenaar
451*e2f98b95SBram Moolenaar    if a:list_type == 'csv' && !empty(table_cols)
452*e2f98b95SBram Moolenaar        let cols = join(table_cols, ', ')
453*e2f98b95SBram Moolenaar        let cols = s:SQLCAddAlias(table_name, table_alias, cols)
454*e2f98b95SBram Moolenaar        let table_cols = [cols]
455*e2f98b95SBram Moolenaar    endif
456*e2f98b95SBram Moolenaar
457*e2f98b95SBram Moolenaar    return table_cols
458*e2f98b95SBram Moolenaarendfunction
459*e2f98b95SBram Moolenaar
460