1f193fffdSBram Moolenaar" Vim OMNI completion script for SQL
2e2f98b95SBram Moolenaar" Language:    SQL
35c73622aSBram Moolenaar" Maintainer:  David Fishburn <dfishburn dot vim at gmail dot com>
4*db7207e6SBram Moolenaar" Version:     12.0
5*db7207e6SBram Moolenaar" Last Change: 2012 Feb 08
6f193fffdSBram Moolenaar" Usage:       For detailed help
7f193fffdSBram Moolenaar"              ":help sql.txt"
8f193fffdSBram Moolenaar"              or ":help ft-sql-omni"
9f193fffdSBram Moolenaar"              or read $VIMRUNTIME/doc/sql.txt
10e2f98b95SBram Moolenaar
115c73622aSBram Moolenaar" History
12*db7207e6SBram Moolenaar" Version 12.0
13*db7207e6SBram Moolenaar"     - Partial column name completion did not work when a table
14*db7207e6SBram Moolenaar"       name or table alias was provided (Jonas Enberg).
15*db7207e6SBram Moolenaar"     - Improved the handling of column completion.  First we match any
16*db7207e6SBram Moolenaar"       columns from a previous completion.  If not matches are found, we
17*db7207e6SBram Moolenaar"       consider the partial name to be a table or table alias for the
18*db7207e6SBram Moolenaar"       query and attempt to match on it.
19*db7207e6SBram Moolenaar"
20*db7207e6SBram Moolenaar" Version 11.0
21*db7207e6SBram Moolenaar"     Added g:omni_sql_default_compl_type variable
22*db7207e6SBram Moolenaar"         - You can specify which type of completion to default to
23*db7207e6SBram Moolenaar"           when pressing <C-X><C-O>.  The entire list of available
24*db7207e6SBram Moolenaar"           choices can be found in the calls to sqlcomplete#Map in:
25*db7207e6SBram Moolenaar"               ftplugin/sql.vim
26*db7207e6SBram Moolenaar"
27f9d5ca1dSBram Moolenaar" Version 10.0
28f9d5ca1dSBram Moolenaar"     Updated PreCacheSyntax()
29f9d5ca1dSBram Moolenaar"         - Now returns a List of the syntax items it finds.
30f9d5ca1dSBram Moolenaar"           This allows other plugins / scripts to use this list for their own
31f9d5ca1dSBram Moolenaar"           purposes.  In this case XPTemplate can use them for a Choose list.
32f9d5ca1dSBram Moolenaar"         - Verifies the parameters are the correct type and displays a
33f9d5ca1dSBram Moolenaar"           warning if not.
34f9d5ca1dSBram Moolenaar"         - Verifies the parameters are the correct type and displays a
35f9d5ca1dSBram Moolenaar"           warning if not.
36f9d5ca1dSBram Moolenaar"     Updated SQLCWarningMsg()
37f9d5ca1dSBram Moolenaar"         - Prepends warning message with SQLComplete so you know who issued
38f9d5ca1dSBram Moolenaar"           the warning.
39f9d5ca1dSBram Moolenaar"     Updated SQLCErrorMsg()
40f9d5ca1dSBram Moolenaar"         - Prepends error message with SQLComplete so you know who issued
41f9d5ca1dSBram Moolenaar"           the error.
42f9d5ca1dSBram Moolenaar"
4300a927d6SBram Moolenaar" Version 9.0
4400a927d6SBram Moolenaar"     This change removes some of the support for tables with spaces in their
4500a927d6SBram Moolenaar"     names in order to simplify the regexes used to pull out query table
4600a927d6SBram Moolenaar"     aliases for more robust table name and column name code completion.
4700a927d6SBram Moolenaar"     Full support for "table names with spaces" can be added in again
4800a927d6SBram Moolenaar"     after 7.3.
49f9d5ca1dSBram Moolenaar"
5000a927d6SBram Moolenaar" Version 8.0
5100a927d6SBram Moolenaar"     Incorrectly re-executed the g:ftplugin_sql_omni_key_right and g:ftplugin_sql_omni_key_left
5200a927d6SBram Moolenaar"     when drilling in and out of a column list for a table.
53f9d5ca1dSBram Moolenaar"
545c73622aSBram Moolenaar" Version 7.0
555c73622aSBram Moolenaar"     Better handling of object names
56f9d5ca1dSBram Moolenaar"
575c73622aSBram Moolenaar" Version 6.0
585c73622aSBram Moolenaar"     Supports object names with spaces "my table name"
595c73622aSBram Moolenaar"
60e2f98b95SBram Moolenaar" Set completion with CTRL-X CTRL-O to autoloaded function.
61e2f98b95SBram Moolenaar" This check is in place in case this script is
62e2f98b95SBram Moolenaar" sourced directly instead of using the autoload feature.
63e2f98b95SBram Moolenaarif exists('&omnifunc')
64e2f98b95SBram Moolenaar    " Do not set the option if already set since this
65e2f98b95SBram Moolenaar    " results in an E117 warning.
66e2f98b95SBram Moolenaar    if &omnifunc == ""
67e2f98b95SBram Moolenaar        setlocal omnifunc=sqlcomplete#Complete
68e2f98b95SBram Moolenaar    endif
69e2f98b95SBram Moolenaarendif
70e2f98b95SBram Moolenaar
71e2f98b95SBram Moolenaarif exists('g:loaded_sql_completion')
72e2f98b95SBram Moolenaar    finish
73e2f98b95SBram Moolenaarendif
74*db7207e6SBram Moolenaarlet g:loaded_sql_completion = 120
75e2f98b95SBram Moolenaar
76e2f98b95SBram Moolenaar" Maintains filename of dictionary
77e2f98b95SBram Moolenaarlet s:sql_file_table        = ""
78e2f98b95SBram Moolenaarlet s:sql_file_procedure    = ""
79e2f98b95SBram Moolenaarlet s:sql_file_view         = ""
80e2f98b95SBram Moolenaar
81e2f98b95SBram Moolenaar" Define various arrays to be used for caching
82e2f98b95SBram Moolenaarlet s:tbl_name              = []
83e2f98b95SBram Moolenaarlet s:tbl_alias             = []
84e2f98b95SBram Moolenaarlet s:tbl_cols              = []
85e2f98b95SBram Moolenaarlet s:syn_list              = []
86e2f98b95SBram Moolenaarlet s:syn_value             = []
87e2f98b95SBram Moolenaar
88e2f98b95SBram Moolenaar" Used in conjunction with the syntaxcomplete plugin
89e2f98b95SBram Moolenaarlet s:save_inc              = ""
90e2f98b95SBram Moolenaarlet s:save_exc              = ""
91e2f98b95SBram Moolenaarif exists('g:omni_syntax_group_include_sql')
92e2f98b95SBram Moolenaar    let s:save_inc = g:omni_syntax_group_include_sql
93e2f98b95SBram Moolenaarendif
94e2f98b95SBram Moolenaarif exists('g:omni_syntax_group_exclude_sql')
95e2f98b95SBram Moolenaar    let s:save_exc = g:omni_syntax_group_exclude_sql
96e2f98b95SBram Moolenaarendif
97e2f98b95SBram Moolenaar
98e2f98b95SBram Moolenaar" Used with the column list
99e2f98b95SBram Moolenaarlet s:save_prev_table       = ""
100e2f98b95SBram Moolenaar
101e2f98b95SBram Moolenaar" Default the option to verify table alias
102e2f98b95SBram Moolenaarif !exists('g:omni_sql_use_tbl_alias')
103e2f98b95SBram Moolenaar    let g:omni_sql_use_tbl_alias = 'a'
104e2f98b95SBram Moolenaarendif
105910f66f9SBram Moolenaar" Default syntax items to precache
106910f66f9SBram Moolenaarif !exists('g:omni_sql_precache_syntax_groups')
107910f66f9SBram Moolenaar    let g:omni_sql_precache_syntax_groups = [
108910f66f9SBram Moolenaar                \ 'syntax',
109910f66f9SBram Moolenaar                \ 'sqlKeyword',
110910f66f9SBram Moolenaar                \ 'sqlFunction',
111910f66f9SBram Moolenaar                \ 'sqlOption',
112910f66f9SBram Moolenaar                \ 'sqlType',
113910f66f9SBram Moolenaar                \ 'sqlStatement'
114910f66f9SBram Moolenaar                \ ]
115910f66f9SBram Moolenaarendif
116eb3593b3SBram Moolenaar" Set ignorecase to the ftplugin standard
117eb3593b3SBram Moolenaarif !exists('g:omni_sql_ignorecase')
118eb3593b3SBram Moolenaar    let g:omni_sql_ignorecase = &ignorecase
119eb3593b3SBram Moolenaarendif
120eb3593b3SBram Moolenaar" During table completion, should the table list also
121eb3593b3SBram Moolenaar" include the owner name
122eb3593b3SBram Moolenaarif !exists('g:omni_sql_include_owner')
123eb3593b3SBram Moolenaar    let g:omni_sql_include_owner = 0
124eb3593b3SBram Moolenaar    if exists('g:loaded_dbext')
125eb3593b3SBram Moolenaar        if g:loaded_dbext >= 300
126eb3593b3SBram Moolenaar            " New to dbext 3.00, by default the table lists include the owner
127eb3593b3SBram Moolenaar            " name of the table.  This is used when determining how much of
128eb3593b3SBram Moolenaar            " whatever has been typed should be replaced as part of the
129eb3593b3SBram Moolenaar            " code replacement.
130eb3593b3SBram Moolenaar            let g:omni_sql_include_owner = 1
131eb3593b3SBram Moolenaar        endif
132eb3593b3SBram Moolenaar    endif
133eb3593b3SBram Moolenaarendif
134*db7207e6SBram Moolenaar" Default type of completion used when <C-X><C-O> is pressed
135*db7207e6SBram Moolenaarif !exists('g:omni_sql_default_compl_type')
136*db7207e6SBram Moolenaar    let g:omni_sql_default_compl_type = 'table'
137*db7207e6SBram Moolenaarendif
138e2f98b95SBram Moolenaar
139e2f98b95SBram Moolenaar" This function is used for the 'omnifunc' option.
140e2f98b95SBram Moolenaarfunction! sqlcomplete#Complete(findstart, base)
141e2f98b95SBram Moolenaar
142e2f98b95SBram Moolenaar    " Default to table name completion
143e2f98b95SBram Moolenaar    let compl_type = 'table'
144e2f98b95SBram Moolenaar    " Allow maps to specify what type of object completion they want
145e2f98b95SBram Moolenaar    if exists('b:sql_compl_type')
146e2f98b95SBram Moolenaar        let compl_type = b:sql_compl_type
147e2f98b95SBram Moolenaar    endif
148e2f98b95SBram Moolenaar
149910f66f9SBram Moolenaar    " First pass through this function determines how much of the line should
150910f66f9SBram Moolenaar    " be replaced by whatever is chosen from the completion list
151e2f98b95SBram Moolenaar    if a:findstart
152e2f98b95SBram Moolenaar        " Locate the start of the item, including "."
153e2f98b95SBram Moolenaar        let line     = getline('.')
154e2f98b95SBram Moolenaar        let start    = col('.') - 1
155e2f98b95SBram Moolenaar        let lastword = -1
156f193fffdSBram Moolenaar        let begindot = 0
157f193fffdSBram Moolenaar        " Check if the first character is a ".", for column completion
158f193fffdSBram Moolenaar        if line[start - 1] == '.'
159f193fffdSBram Moolenaar            let begindot = 1
160f193fffdSBram Moolenaar        endif
161e2f98b95SBram Moolenaar        while start > 0
1625c73622aSBram Moolenaar            " Additional code was required to handle objects which
1635c73622aSBram Moolenaar            " can contain spaces like "my table name".
1645c73622aSBram Moolenaar            if line[start - 1] !~ '\(\w\|\.\)'
1655c73622aSBram Moolenaar                " If the previous character is not a period or word character
1665c73622aSBram Moolenaar                break
1675c73622aSBram Moolenaar            " elseif line[start - 1] =~ '\(\w\|\s\+\)'
1685c73622aSBram Moolenaar            "     let start -= 1
1695c73622aSBram Moolenaar            elseif line[start - 1] =~ '\w'
1705c73622aSBram Moolenaar                " If the previous character is word character continue back
171e2f98b95SBram Moolenaar                let start -= 1
172eb3593b3SBram Moolenaar            elseif line[start - 1] =~ '\.' &&
173eb3593b3SBram Moolenaar                        \ compl_type =~ 'column\|table\|view\|procedure'
1745c73622aSBram Moolenaar                " If the previous character is a period and we are completing
1755c73622aSBram Moolenaar                " an object which can be specified with a period like this:
1765c73622aSBram Moolenaar                "     table_name.column_name
1775c73622aSBram Moolenaar                "     owner_name.table_name
1785c73622aSBram Moolenaar
179eb3593b3SBram Moolenaar                " If lastword has already been set for column completion
180eb3593b3SBram Moolenaar                " break from the loop, since we do not also want to pickup
181eb3593b3SBram Moolenaar                " a table name if it was also supplied.
182f193fffdSBram Moolenaar                if lastword != -1 && compl_type == 'column'
183eb3593b3SBram Moolenaar                    break
184eb3593b3SBram Moolenaar                endif
185f193fffdSBram Moolenaar                " If column completion was specified stop at the "." if
186f193fffdSBram Moolenaar                " a . was specified, otherwise, replace all the way up
187f193fffdSBram Moolenaar                " to the owner name (if included).
188f193fffdSBram Moolenaar                if lastword == -1 && compl_type == 'column' && begindot == 1
189e2f98b95SBram Moolenaar                    let lastword = start
190e2f98b95SBram Moolenaar                endif
191eb3593b3SBram Moolenaar                " If omni_sql_include_owner = 0, do not include the table
192eb3593b3SBram Moolenaar                " name as part of the substitution, so break here
193eb3593b3SBram Moolenaar                if lastword == -1 &&
194f193fffdSBram Moolenaar                            \ compl_type =~ 'table\|view\|procedure\column_csv' &&
195eb3593b3SBram Moolenaar                            \ g:omni_sql_include_owner == 0
196eb3593b3SBram Moolenaar                    let lastword = start
197eb3593b3SBram Moolenaar                    break
198eb3593b3SBram Moolenaar                endif
199e2f98b95SBram Moolenaar                let start -= 1
200e2f98b95SBram Moolenaar            else
201e2f98b95SBram Moolenaar                break
202e2f98b95SBram Moolenaar            endif
203e2f98b95SBram Moolenaar        endwhile
204e2f98b95SBram Moolenaar
205e2f98b95SBram Moolenaar        " Return the column of the last word, which is going to be changed.
206e2f98b95SBram Moolenaar        " Remember the text that comes before it in s:prepended.
207e2f98b95SBram Moolenaar        if lastword == -1
208e2f98b95SBram Moolenaar            let s:prepended = ''
209e2f98b95SBram Moolenaar            return start
210e2f98b95SBram Moolenaar        endif
211e2f98b95SBram Moolenaar        let s:prepended = strpart(line, start, lastword - start)
212e2f98b95SBram Moolenaar        return lastword
213e2f98b95SBram Moolenaar    endif
214e2f98b95SBram Moolenaar
215910f66f9SBram Moolenaar    " Second pass through this function will determine what data to put inside
216910f66f9SBram Moolenaar    " of the completion list
217910f66f9SBram Moolenaar    " s:prepended is set by the first pass
218e2f98b95SBram Moolenaar    let base = s:prepended . a:base
219e2f98b95SBram Moolenaar
220910f66f9SBram Moolenaar    " Default the completion list to an empty list
221e2f98b95SBram Moolenaar    let compl_list = []
222e2f98b95SBram Moolenaar
223e2f98b95SBram Moolenaar    " Default to table name completion
224*db7207e6SBram Moolenaar    let compl_type = g:omni_sql_default_compl_type
225e2f98b95SBram Moolenaar    " Allow maps to specify what type of object completion they want
226e2f98b95SBram Moolenaar    if exists('b:sql_compl_type')
227e2f98b95SBram Moolenaar        let compl_type = b:sql_compl_type
228e2f98b95SBram Moolenaar        unlet b:sql_compl_type
229e2f98b95SBram Moolenaar    endif
230e2f98b95SBram Moolenaar
231e2f98b95SBram Moolenaar    if compl_type == 'tableReset'
232e2f98b95SBram Moolenaar        let compl_type = 'table'
233e2f98b95SBram Moolenaar        let base = ''
234e2f98b95SBram Moolenaar    endif
235e2f98b95SBram Moolenaar
236e2f98b95SBram Moolenaar    if compl_type == 'table' ||
237e2f98b95SBram Moolenaar                \ compl_type == 'procedure' ||
238e2f98b95SBram Moolenaar                \ compl_type == 'view'
239e2f98b95SBram Moolenaar
240e2f98b95SBram Moolenaar        " This type of completion relies upon the dbext.vim plugin
241e2f98b95SBram Moolenaar        if s:SQLCCheck4dbext() == -1
242e2f98b95SBram Moolenaar            return []
243e2f98b95SBram Moolenaar        endif
244e2f98b95SBram Moolenaar
24583e138c6SBram Moolenaar        " Allow the user to override the dbext plugin to specify whether
24683e138c6SBram Moolenaar        " the owner/creator should be included in the list
2478c8de839SBram Moolenaar        if g:loaded_dbext >= 300
2488c8de839SBram Moolenaar            let saveSetting = DB_listOption('dict_show_owner')
2498c8de839SBram Moolenaar            exec 'DBSetOption dict_show_owner='.(g:omni_sql_include_owner==1?'1':'0')
250e2f98b95SBram Moolenaar        endif
25183e138c6SBram Moolenaar
25283e138c6SBram Moolenaar        let compl_type_uc = substitute(compl_type, '\w\+', '\u&', '')
2535c73622aSBram Moolenaar        " Same call below, no need to do it twice
2545c73622aSBram Moolenaar        " if s:sql_file_{compl_type} == ""
2555c73622aSBram Moolenaar        "     let s:sql_file_{compl_type} = DB_getDictionaryName(compl_type_uc)
2565c73622aSBram Moolenaar        " endif
25783e138c6SBram Moolenaar        let s:sql_file_{compl_type} = DB_getDictionaryName(compl_type_uc)
258e2f98b95SBram Moolenaar        if s:sql_file_{compl_type} != ""
259e2f98b95SBram Moolenaar            if filereadable(s:sql_file_{compl_type})
260e2f98b95SBram Moolenaar                let compl_list = readfile(s:sql_file_{compl_type})
261e2f98b95SBram Moolenaar            endif
262e2f98b95SBram Moolenaar        endif
26383e138c6SBram Moolenaar
2648c8de839SBram Moolenaar        if g:loaded_dbext > 300
2658c8de839SBram Moolenaar            exec 'DBSetOption dict_show_owner='.saveSetting
2668c8de839SBram Moolenaar        endif
26783e138c6SBram Moolenaar    elseif compl_type =~? 'column'
268e2f98b95SBram Moolenaar
269e2f98b95SBram Moolenaar        " This type of completion relies upon the dbext.vim plugin
270e2f98b95SBram Moolenaar        if s:SQLCCheck4dbext() == -1
271e2f98b95SBram Moolenaar            return []
272e2f98b95SBram Moolenaar        endif
273e2f98b95SBram Moolenaar
274e2f98b95SBram Moolenaar        if base == ""
275e2f98b95SBram Moolenaar            " The last time we displayed a column list we stored
276e2f98b95SBram Moolenaar            " the table name.  If the user selects a column list
277e2f98b95SBram Moolenaar            " without a table name of alias present, assume they want
278e2f98b95SBram Moolenaar            " the previous column list displayed.
279e2f98b95SBram Moolenaar            let base = s:save_prev_table
280e2f98b95SBram Moolenaar        endif
281e2f98b95SBram Moolenaar
28283e138c6SBram Moolenaar        let owner  = ''
28383e138c6SBram Moolenaar        let column = ''
28483e138c6SBram Moolenaar
28583e138c6SBram Moolenaar        if base =~ '\.'
28683e138c6SBram Moolenaar            " Check if the owner/creator has been specified
28783e138c6SBram Moolenaar            let owner  = matchstr( base, '^\zs.*\ze\..*\..*' )
28883e138c6SBram Moolenaar            let table  = matchstr( base, '^\(.*\.\)\?\zs.*\ze\..*' )
28983e138c6SBram Moolenaar            let column = matchstr( base, '.*\.\zs.*' )
29083e138c6SBram Moolenaar
29183e138c6SBram Moolenaar            " It is pretty well impossible to determine if the user
29283e138c6SBram Moolenaar            " has entered:
29383e138c6SBram Moolenaar            "    owner.table
29483e138c6SBram Moolenaar            "    table.column_prefix
29583e138c6SBram Moolenaar            " So there are a couple of things we can do to mitigate
29683e138c6SBram Moolenaar            " this issue.
29783e138c6SBram Moolenaar            "    1.  Check if the dbext plugin has the option turned
29883e138c6SBram Moolenaar            "        on to even allow owners
29983e138c6SBram Moolenaar            "    2.  Based on 1, if the user is showing a table list
30000a927d6SBram Moolenaar            "        and the DrillIntoTable (using <Right>) then
30183e138c6SBram Moolenaar            "        this will be owner.table.  In this case, we can
30283e138c6SBram Moolenaar            "        check to see the table.column exists in the
30383e138c6SBram Moolenaar            "        cached table list.  If it does, then we have
30483e138c6SBram Moolenaar            "        determined the user has actually chosen
30583e138c6SBram Moolenaar            "        owner.table, not table.column_prefix.
30683e138c6SBram Moolenaar            let found = -1
30783e138c6SBram Moolenaar            if g:omni_sql_include_owner == 1 && owner == ''
30883e138c6SBram Moolenaar                if filereadable(s:sql_file_table)
30983e138c6SBram Moolenaar                    let tbl_list = readfile(s:sql_file_table)
31083e138c6SBram Moolenaar                    let found    = index( tbl_list, ((table != '')?(table.'.'):'').column)
31183e138c6SBram Moolenaar                endif
31283e138c6SBram Moolenaar            endif
31383e138c6SBram Moolenaar            " If the table.column was found in the table list, we can safely assume
31483e138c6SBram Moolenaar            " the owner was not provided and shift the items appropriately.
31583e138c6SBram Moolenaar            " OR
31683e138c6SBram Moolenaar            " If the user has indicated not to use table owners at all and
31783e138c6SBram Moolenaar            " the base ends in a '.' we know they are not providing a column
31883e138c6SBram Moolenaar            " name, so we can shift the items appropriately.
319*db7207e6SBram Moolenaar            " if found != -1 || (g:omni_sql_include_owner == 0 && base !~ '\.$')
320*db7207e6SBram Moolenaar            "     let owner  = table
321*db7207e6SBram Moolenaar            "     let table  = column
322*db7207e6SBram Moolenaar            "     let column = ''
323*db7207e6SBram Moolenaar            " endif
32483e138c6SBram Moolenaar        else
325*db7207e6SBram Moolenaar            " If no "." was provided and the user asked for
326*db7207e6SBram Moolenaar            " column level completion, first attempt the match
327*db7207e6SBram Moolenaar            " on any previous column lists.  If the user asked
328*db7207e6SBram Moolenaar            " for a list of columns comma separated, continue as usual.
329*db7207e6SBram Moolenaar            if compl_type == 'column' && s:save_prev_table != ''
330*db7207e6SBram Moolenaar                " The last time we displayed a column list we stored
331*db7207e6SBram Moolenaar                " the table name.  If the user selects a column list
332*db7207e6SBram Moolenaar                " without a table name of alias present, assume they want
333*db7207e6SBram Moolenaar                " the previous column list displayed.
334*db7207e6SBram Moolenaar                let table     = s:save_prev_table
335*db7207e6SBram Moolenaar                let list_type = ''
336*db7207e6SBram Moolenaar
337*db7207e6SBram Moolenaar                let compl_list  = s:SQLCGetColumns(table, list_type)
338*db7207e6SBram Moolenaar                if ! empty(compl_list)
339*db7207e6SBram Moolenaar                    " If no column prefix has been provided and the table
340*db7207e6SBram Moolenaar                    " name was provided, append it to each of the items
341*db7207e6SBram Moolenaar                    " returned.
342*db7207e6SBram Moolenaar                    let compl_list = filter(deepcopy(compl_list), 'v:val=~"^'.base.'"' )
343*db7207e6SBram Moolenaar
344*db7207e6SBram Moolenaar                    " If not empty, we have a match on columns
345*db7207e6SBram Moolenaar                    " return the list
346*db7207e6SBram Moolenaar                    if ! empty(compl_list)
347*db7207e6SBram Moolenaar                        return compl_list
348*db7207e6SBram Moolenaar                    endif
349*db7207e6SBram Moolenaar                endif
350*db7207e6SBram Moolenaar            endif
351*db7207e6SBram Moolenaar            " Since no columns were found to match the base supplied
352*db7207e6SBram Moolenaar            " assume the user is trying to complete the column list
353*db7207e6SBram Moolenaar            " for a table (and or an alias to a table).
35483e138c6SBram Moolenaar            let table  = base
35583e138c6SBram Moolenaar        endif
35683e138c6SBram Moolenaar
35783e138c6SBram Moolenaar        " Get anything after the . and consider this the table name
35883e138c6SBram Moolenaar        " If an owner has been specified, then we must consider the
35983e138c6SBram Moolenaar        " base to be a partial column name
36083e138c6SBram Moolenaar        " let base  = matchstr( base, '^\(.*\.\)\?\zs.*' )
36183e138c6SBram Moolenaar
36283e138c6SBram Moolenaar        if table != ""
363e2f98b95SBram Moolenaar            let s:save_prev_table = base
36483e138c6SBram Moolenaar            let list_type         = ''
36583e138c6SBram Moolenaar
36683e138c6SBram Moolenaar            if compl_type == 'column_csv'
36783e138c6SBram Moolenaar                " Return one array element, with a comma separated
36883e138c6SBram Moolenaar                " list of values instead of multiple array entries
36983e138c6SBram Moolenaar                " for each column in the table.
37083e138c6SBram Moolenaar                let list_type     = 'csv'
37183e138c6SBram Moolenaar            endif
37283e138c6SBram Moolenaar
37383e138c6SBram Moolenaar            let compl_list  = s:SQLCGetColumns(table, list_type)
37483e138c6SBram Moolenaar            if column != ''
37583e138c6SBram Moolenaar                " If no column prefix has been provided and the table
37683e138c6SBram Moolenaar                " name was provided, append it to each of the items
37783e138c6SBram Moolenaar                " returned.
378*db7207e6SBram Moolenaar                let compl_list = map(compl_list, 'table.".".v:val')
37983e138c6SBram Moolenaar                if owner != ''
38083e138c6SBram Moolenaar                    " If an owner has been provided append it to each of the
38183e138c6SBram Moolenaar                    " items returned.
382*db7207e6SBram Moolenaar                    let compl_list = map(compl_list, 'owner.".".v:val')
38383e138c6SBram Moolenaar                endif
38483e138c6SBram Moolenaar            else
385e2f98b95SBram Moolenaar                let base = ''
386e2f98b95SBram Moolenaar            endif
387e2f98b95SBram Moolenaar
38883e138c6SBram Moolenaar            if compl_type == 'column_csv'
389e2f98b95SBram Moolenaar                " Join the column array into 1 single element array
390e2f98b95SBram Moolenaar                " but make the columns column separated
391e2f98b95SBram Moolenaar                let compl_list        = [join(compl_list, ', ')]
39283e138c6SBram Moolenaar            endif
393e2f98b95SBram Moolenaar        endif
394e2f98b95SBram Moolenaar    elseif compl_type == 'resetCache'
395e2f98b95SBram Moolenaar        " Reset all cached items
396e2f98b95SBram Moolenaar        let s:tbl_name  = []
397e2f98b95SBram Moolenaar        let s:tbl_alias = []
398e2f98b95SBram Moolenaar        let s:tbl_cols  = []
399e2f98b95SBram Moolenaar        let s:syn_list  = []
400e2f98b95SBram Moolenaar        let s:syn_value = []
401f193fffdSBram Moolenaar
402f193fffdSBram Moolenaar        let msg = "All SQL cached items have been removed."
403f193fffdSBram Moolenaar        call s:SQLCWarningMsg(msg)
404f193fffdSBram Moolenaar        " Leave time for the user to read the error message
405f193fffdSBram Moolenaar        :sleep 2
406e2f98b95SBram Moolenaar    else
407910f66f9SBram Moolenaar        let compl_list = s:SQLCGetSyntaxList(compl_type)
408e2f98b95SBram Moolenaar    endif
409e2f98b95SBram Moolenaar
410e2f98b95SBram Moolenaar    if base != ''
4115c73622aSBram Moolenaar        " Filter the list based on the first few characters the user entered.
4125c73622aSBram Moolenaar        " Check if the text matches at the beginning
413*db7207e6SBram Moolenaar        "         \\(^.base.'\\)
4145c73622aSBram Moolenaar        " or
4155c73622aSBram Moolenaar        " Match to a owner.table or alias.column type match
416*db7207e6SBram Moolenaar        "         ^\\(\\w\\+\\.\\)\\?'.base.'\\)
4175c73622aSBram Moolenaar        " or
4185c73622aSBram Moolenaar        " Handle names with spaces "my table name"
419*db7207e6SBram Moolenaar        "         "\\(^'.base.'\\|^\\(\\w\\+\\.\\)\\?'.base.'\\)"'
420*db7207e6SBram Moolenaar        "
4215c73622aSBram Moolenaar        let expr = 'v:val '.(g:omni_sql_ignorecase==1?'=~?':'=~#').' "\\(^'.base.'\\|^\\(\\w\\+\\.\\)\\?'.base.'\\)"'
4225c73622aSBram Moolenaar        " let expr = 'v:val '.(g:omni_sql_ignorecase==1?'=~?':'=~#').' "\\(^'.base.'\\)"'
4235c73622aSBram Moolenaar        " let expr = 'v:val '.(g:omni_sql_ignorecase==1?'=~?':'=~#').' "\\(^'.base.'\\|\\(\\.\\)\\?'.base.'\\)"'
4245c73622aSBram Moolenaar        " let expr = 'v:val '.(g:omni_sql_ignorecase==1?'=~?':'=~#').' "\\(^'.base.'\\|\\([^.]*\\)\\?'.base.'\\)"'
425eb3593b3SBram Moolenaar        let compl_list = filter(deepcopy(compl_list), expr)
426e2f98b95SBram Moolenaar    endif
427e2f98b95SBram Moolenaar
428910f66f9SBram Moolenaar    if exists('b:sql_compl_savefunc') && b:sql_compl_savefunc != ""
429910f66f9SBram Moolenaar        let &omnifunc = b:sql_compl_savefunc
430910f66f9SBram Moolenaar    endif
431910f66f9SBram Moolenaar
432e2f98b95SBram Moolenaar    return compl_list
433e2f98b95SBram Moolenaarendfunc
434e2f98b95SBram Moolenaar
435910f66f9SBram Moolenaarfunction! sqlcomplete#PreCacheSyntax(...)
436910f66f9SBram Moolenaar    let syn_group_arr = []
437f9d5ca1dSBram Moolenaar    let syn_items     = []
438f9d5ca1dSBram Moolenaar
439910f66f9SBram Moolenaar    if a:0 > 0
440f9d5ca1dSBram Moolenaar        if type(a:1) != 3
441f9d5ca1dSBram Moolenaar            call s:SQLCWarningMsg("Parameter is not a list. Example:['syntaxGroup1', 'syntaxGroup2']")
442f9d5ca1dSBram Moolenaar            return ''
443f9d5ca1dSBram Moolenaar        endif
444910f66f9SBram Moolenaar        let syn_group_arr = a:1
445910f66f9SBram Moolenaar    else
446910f66f9SBram Moolenaar        let syn_group_arr = g:omni_sql_precache_syntax_groups
447910f66f9SBram Moolenaar    endif
44883e138c6SBram Moolenaar    " For each group specified in the list, precache all
44983e138c6SBram Moolenaar    " the sytnax items.
450910f66f9SBram Moolenaar    if !empty(syn_group_arr)
451910f66f9SBram Moolenaar        for group_name in syn_group_arr
452f9d5ca1dSBram Moolenaar            let syn_items = extend( syn_items, s:SQLCGetSyntaxList(group_name) )
453f9d5ca1dSBram Moolenaar        endfor
454f9d5ca1dSBram Moolenaar    endif
455f9d5ca1dSBram Moolenaar
456f9d5ca1dSBram Moolenaar    return syn_items
457f9d5ca1dSBram Moolenaarendfunction
458f9d5ca1dSBram Moolenaar
459f9d5ca1dSBram Moolenaarfunction! sqlcomplete#ResetCacheSyntax(...)
460f9d5ca1dSBram Moolenaar    let syn_group_arr = []
461f9d5ca1dSBram Moolenaar
462f9d5ca1dSBram Moolenaar    if a:0 > 0
463f9d5ca1dSBram Moolenaar        if type(a:1) != 3
464f9d5ca1dSBram Moolenaar            call s:SQLCWarningMsg("Parameter is not a list. Example:['syntaxGroup1', 'syntaxGroup2']")
465f9d5ca1dSBram Moolenaar            return ''
466f9d5ca1dSBram Moolenaar        endif
467f9d5ca1dSBram Moolenaar        let syn_group_arr = a:1
468f9d5ca1dSBram Moolenaar    else
469f9d5ca1dSBram Moolenaar        let syn_group_arr = g:omni_sql_precache_syntax_groups
470f9d5ca1dSBram Moolenaar    endif
471f9d5ca1dSBram Moolenaar    " For each group specified in the list, precache all
472f9d5ca1dSBram Moolenaar    " the sytnax items.
473f9d5ca1dSBram Moolenaar    if !empty(syn_group_arr)
474f9d5ca1dSBram Moolenaar        for group_name in syn_group_arr
475f9d5ca1dSBram Moolenaar            let list_idx = index(s:syn_list, group_name, 0, &ignorecase)
476f9d5ca1dSBram Moolenaar            if list_idx > -1
477f9d5ca1dSBram Moolenaar                " Remove from list of groups
478f9d5ca1dSBram Moolenaar                call remove( s:syn_list, list_idx )
479f9d5ca1dSBram Moolenaar                " Remove from list of keywords
480f9d5ca1dSBram Moolenaar                call remove( s:syn_value, list_idx )
481f9d5ca1dSBram Moolenaar            endif
482910f66f9SBram Moolenaar        endfor
483910f66f9SBram Moolenaar    endif
484910f66f9SBram Moolenaarendfunction
485910f66f9SBram Moolenaar
486910f66f9SBram Moolenaarfunction! sqlcomplete#Map(type)
487910f66f9SBram Moolenaar    " Tell the SQL plugin what you want to complete
488910f66f9SBram Moolenaar    let b:sql_compl_type=a:type
489910f66f9SBram Moolenaar    " Record previous omnifunc, if the SQL completion
490910f66f9SBram Moolenaar    " is being used in conjunction with other filetype
491910f66f9SBram Moolenaar    " completion plugins
492910f66f9SBram Moolenaar    if &omnifunc != "" && &omnifunc != 'sqlcomplete#Complete'
493910f66f9SBram Moolenaar        " Record the previous omnifunc, the plugin
494910f66f9SBram Moolenaar        " will automatically set this back so that it
495910f66f9SBram Moolenaar        " does not interfere with other ftplugins settings
496910f66f9SBram Moolenaar        let b:sql_compl_savefunc=&omnifunc
497910f66f9SBram Moolenaar    endif
498910f66f9SBram Moolenaar    " Set the OMNI func for the SQL completion plugin
499910f66f9SBram Moolenaar    let &omnifunc='sqlcomplete#Complete'
500910f66f9SBram Moolenaarendfunction
501910f66f9SBram Moolenaar
502f193fffdSBram Moolenaarfunction! sqlcomplete#DrillIntoTable()
503f193fffdSBram Moolenaar    " If the omni popup window is visible
504f193fffdSBram Moolenaar    if pumvisible()
505f193fffdSBram Moolenaar        call sqlcomplete#Map('column')
506f193fffdSBram Moolenaar        " C-Y, makes the currently highlighted entry active
507f193fffdSBram Moolenaar        " and trigger the omni popup to be redisplayed
50800a927d6SBram Moolenaar        call feedkeys("\<C-Y>\<C-X>\<C-O>", 'n')
509f193fffdSBram Moolenaar    else
510f193fffdSBram Moolenaar	" If the popup is not visible, simple perform the normal
51100a927d6SBram Moolenaar	" key behaviour.
51200a927d6SBram Moolenaar	" Must use exec since they key must be preceeded by "\"
51300a927d6SBram Moolenaar	" or feedkeys will simply push each character of the string
51400a927d6SBram Moolenaar	" rather than the "key press".
51500a927d6SBram Moolenaar        exec 'call feedkeys("\'.g:ftplugin_sql_omni_key_right.'", "n")'
516f193fffdSBram Moolenaar    endif
517f193fffdSBram Moolenaar    return ""
518f193fffdSBram Moolenaarendfunction
519f193fffdSBram Moolenaar
520f193fffdSBram Moolenaarfunction! sqlcomplete#DrillOutOfColumns()
521f193fffdSBram Moolenaar    " If the omni popup window is visible
522f193fffdSBram Moolenaar    if pumvisible()
523f193fffdSBram Moolenaar        call sqlcomplete#Map('tableReset')
524f193fffdSBram Moolenaar        " Trigger the omni popup to be redisplayed
525f193fffdSBram Moolenaar        call feedkeys("\<C-X>\<C-O>")
526f193fffdSBram Moolenaar    else
527f193fffdSBram Moolenaar	" If the popup is not visible, simple perform the normal
52800a927d6SBram Moolenaar	" key behaviour.
52900a927d6SBram Moolenaar	" Must use exec since they key must be preceeded by "\"
53000a927d6SBram Moolenaar	" or feedkeys will simply push each character of the string
53100a927d6SBram Moolenaar	" rather than the "key press".
53200a927d6SBram Moolenaar        exec 'call feedkeys("\'.g:ftplugin_sql_omni_key_left.'", "n")'
533f193fffdSBram Moolenaar    endif
534f193fffdSBram Moolenaar    return ""
535f193fffdSBram Moolenaarendfunction
536f193fffdSBram Moolenaar
537f193fffdSBram Moolenaarfunction! s:SQLCWarningMsg(msg)
538f193fffdSBram Moolenaar    echohl WarningMsg
539f9d5ca1dSBram Moolenaar    echomsg 'SQLComplete:'.a:msg
540f193fffdSBram Moolenaar    echohl None
541f193fffdSBram Moolenaarendfunction
542f193fffdSBram Moolenaar
543f193fffdSBram Moolenaarfunction! s:SQLCErrorMsg(msg)
544f193fffdSBram Moolenaar    echohl ErrorMsg
545f9d5ca1dSBram Moolenaar    echomsg 'SQLComplete:'.a:msg
546f193fffdSBram Moolenaar    echohl None
547f193fffdSBram Moolenaarendfunction
548f193fffdSBram Moolenaar
549910f66f9SBram Moolenaarfunction! s:SQLCGetSyntaxList(syn_group)
550910f66f9SBram Moolenaar    let syn_group  = a:syn_group
551910f66f9SBram Moolenaar    let compl_list = []
552910f66f9SBram Moolenaar
553910f66f9SBram Moolenaar    " Check if we have already cached the syntax list
554910f66f9SBram Moolenaar    let list_idx = index(s:syn_list, syn_group, 0, &ignorecase)
555910f66f9SBram Moolenaar    if list_idx > -1
556910f66f9SBram Moolenaar        " Return previously cached value
557910f66f9SBram Moolenaar        let compl_list = s:syn_value[list_idx]
558910f66f9SBram Moolenaar    else
559910f66f9SBram Moolenaar        " Request the syntax list items from the
560910f66f9SBram Moolenaar        " syntax completion plugin
561910f66f9SBram Moolenaar        if syn_group == 'syntax'
562910f66f9SBram Moolenaar            " Handle this special case.  This allows the user
563910f66f9SBram Moolenaar            " to indicate they want all the syntax items available,
564910f66f9SBram Moolenaar            " so do not specify a specific include list.
565910f66f9SBram Moolenaar            let g:omni_syntax_group_include_sql = ''
566910f66f9SBram Moolenaar        else
567910f66f9SBram Moolenaar            " The user has specified a specific syntax group
568910f66f9SBram Moolenaar            let g:omni_syntax_group_include_sql = syn_group
569910f66f9SBram Moolenaar        endif
570910f66f9SBram Moolenaar        let g:omni_syntax_group_exclude_sql = ''
571f9d5ca1dSBram Moolenaar        let syn_value                       = syntaxcomplete#OmniSyntaxList()
572910f66f9SBram Moolenaar        let g:omni_syntax_group_include_sql = s:save_inc
573910f66f9SBram Moolenaar        let g:omni_syntax_group_exclude_sql = s:save_exc
574910f66f9SBram Moolenaar        " Cache these values for later use
575910f66f9SBram Moolenaar        let s:syn_list  = add( s:syn_list,  syn_group )
576910f66f9SBram Moolenaar        let s:syn_value = add( s:syn_value, syn_value )
577910f66f9SBram Moolenaar        let compl_list  = syn_value
578910f66f9SBram Moolenaar    endif
579910f66f9SBram Moolenaar
580910f66f9SBram Moolenaar    return compl_list
581910f66f9SBram Moolenaarendfunction
582910f66f9SBram Moolenaar
583e2f98b95SBram Moolenaarfunction! s:SQLCCheck4dbext()
584e2f98b95SBram Moolenaar    if !exists('g:loaded_dbext')
585e2f98b95SBram Moolenaar        let msg = "The dbext plugin must be loaded for dynamic SQL completion"
586e2f98b95SBram Moolenaar        call s:SQLCErrorMsg(msg)
587e2f98b95SBram Moolenaar        " Leave time for the user to read the error message
588e2f98b95SBram Moolenaar        :sleep 2
589e2f98b95SBram Moolenaar        return -1
5908c8de839SBram Moolenaar    elseif g:loaded_dbext < 600
5918c8de839SBram Moolenaar        let msg = "The dbext plugin must be at least version 5.30 " .
592e2f98b95SBram Moolenaar                    \ " for dynamic SQL completion"
593e2f98b95SBram Moolenaar        call s:SQLCErrorMsg(msg)
594e2f98b95SBram Moolenaar        " Leave time for the user to read the error message
595e2f98b95SBram Moolenaar        :sleep 2
596e2f98b95SBram Moolenaar        return -1
597e2f98b95SBram Moolenaar    endif
598e2f98b95SBram Moolenaar    return 1
599e2f98b95SBram Moolenaarendfunction
600e2f98b95SBram Moolenaar
601e2f98b95SBram Moolenaarfunction! s:SQLCAddAlias(table_name, table_alias, cols)
602f193fffdSBram Moolenaar    " Strip off the owner if included
603f193fffdSBram Moolenaar    let table_name  = matchstr(a:table_name, '\%(.\{-}\.\)\?\zs\(.*\)' )
604e2f98b95SBram Moolenaar    let table_alias = a:table_alias
605e2f98b95SBram Moolenaar    let cols        = a:cols
606e2f98b95SBram Moolenaar
607e2f98b95SBram Moolenaar    if g:omni_sql_use_tbl_alias != 'n'
608e2f98b95SBram Moolenaar        if table_alias == ''
609e2f98b95SBram Moolenaar            if 'da' =~? g:omni_sql_use_tbl_alias
610e2f98b95SBram Moolenaar                if table_name =~ '_'
611e2f98b95SBram Moolenaar                    " Treat _ as separators since people often use these
612e2f98b95SBram Moolenaar                    " for word separators
613e2f98b95SBram Moolenaar                    let save_keyword = &iskeyword
614e2f98b95SBram Moolenaar                    setlocal iskeyword-=_
615e2f98b95SBram Moolenaar
616e2f98b95SBram Moolenaar                    " Get the first letter of each word
617e2f98b95SBram Moolenaar                    " [[:alpha:]] is used instead of \w
618e2f98b95SBram Moolenaar                    " to catch extended accented characters
619e2f98b95SBram Moolenaar                    "
620e2f98b95SBram Moolenaar                    let table_alias = substitute(
621e2f98b95SBram Moolenaar                                \ table_name,
622e2f98b95SBram Moolenaar                                \ '\<[[:alpha:]]\+\>_\?',
623e2f98b95SBram Moolenaar                                \ '\=strpart(submatch(0), 0, 1)',
624e2f98b95SBram Moolenaar                                \ 'g'
625e2f98b95SBram Moolenaar                                \ )
626e2f98b95SBram Moolenaar                    " Restore original value
627e2f98b95SBram Moolenaar                    let &iskeyword = save_keyword
628e2f98b95SBram Moolenaar                elseif table_name =~ '\u\U'
629f193fffdSBram Moolenaar                    let table_alias = substitute(
630e2f98b95SBram Moolenaar                                \ table_name, '\(\u\)\U*', '\1', 'g')
631e2f98b95SBram Moolenaar                else
632e2f98b95SBram Moolenaar                    let table_alias = strpart(table_name, 0, 1)
633e2f98b95SBram Moolenaar                endif
634e2f98b95SBram Moolenaar            endif
635e2f98b95SBram Moolenaar        endif
636e2f98b95SBram Moolenaar        if table_alias != ''
637e2f98b95SBram Moolenaar            " Following a word character, make sure there is a . and no spaces
638e2f98b95SBram Moolenaar            let table_alias = substitute(table_alias, '\w\zs\.\?\s*$', '.', '')
639e2f98b95SBram Moolenaar            if 'a' =~? g:omni_sql_use_tbl_alias && a:table_alias == ''
640e2f98b95SBram Moolenaar                let table_alias = inputdialog("Enter table alias:", table_alias)
641e2f98b95SBram Moolenaar            endif
642e2f98b95SBram Moolenaar        endif
643e2f98b95SBram Moolenaar        if table_alias != ''
644e2f98b95SBram Moolenaar            let cols = substitute(cols, '\<\w', table_alias.'&', 'g')
645e2f98b95SBram Moolenaar        endif
646e2f98b95SBram Moolenaar    endif
647e2f98b95SBram Moolenaar
648e2f98b95SBram Moolenaar    return cols
649e2f98b95SBram Moolenaarendfunction
650e2f98b95SBram Moolenaar
65183e138c6SBram Moolenaarfunction! s:SQLCGetObjectOwner(object)
65283e138c6SBram Moolenaar    " The owner regex matches a word at the start of the string which is
65383e138c6SBram Moolenaar    " followed by a dot, but doesn't include the dot in the result.
65483e138c6SBram Moolenaar    " ^           - from beginning of line
6558c8de839SBram Moolenaar    " \("\|\[\)\? - ignore any quotes
65683e138c6SBram Moolenaar    " \zs         - start the match now
6578c8de839SBram Moolenaar    " .\{-}       - get owner name
65883e138c6SBram Moolenaar    " \ze         - end the match
6598c8de839SBram Moolenaar    " \("\|\[\)\? - ignore any quotes
66083e138c6SBram Moolenaar    " \.          - must by followed by a .
6618c8de839SBram Moolenaar    " let owner = matchstr( a:object, '^\s*\zs.*\ze\.' )
6628c8de839SBram Moolenaar    let owner = matchstr( a:object, '^\("\|\[\)\?\zs\.\{-}\ze\("\|\]\)\?\.' )
66383e138c6SBram Moolenaar    return owner
66483e138c6SBram Moolenaarendfunction
66583e138c6SBram Moolenaar
666e2f98b95SBram Moolenaarfunction! s:SQLCGetColumns(table_name, list_type)
66783e138c6SBram Moolenaar    " Check if the table name was provided as part of the column name
6688c8de839SBram Moolenaar    let table_name   = matchstr(a:table_name, '^["\[\]a-zA-Z0-9_ ]\+\ze\.\?')
669e2f98b95SBram Moolenaar    let table_cols   = []
670e2f98b95SBram Moolenaar    let table_alias  = ''
671e2f98b95SBram Moolenaar    let move_to_top  = 1
672e2f98b95SBram Moolenaar
6738c8de839SBram Moolenaar    let table_name   = substitute(table_name, '\s*\(.\{-}\)\s*$', '\1', 'g')
6748c8de839SBram Moolenaar
6758c8de839SBram Moolenaar    " If the table name was given as:
6768c8de839SBram Moolenaar    "     where c.
6778c8de839SBram Moolenaar    let table_name   = substitute(table_name, '^\c\(WHERE\|AND\|OR\)\s\+', '', '')
678eb3593b3SBram Moolenaar    if g:loaded_dbext >= 300
679e2f98b95SBram Moolenaar        let saveSettingAlias = DB_listOption('use_tbl_alias')
680e2f98b95SBram Moolenaar        exec 'DBSetOption use_tbl_alias=n'
681e2f98b95SBram Moolenaar    endif
682e2f98b95SBram Moolenaar
6838c8de839SBram Moolenaar    let table_name_stripped = substitute(table_name, '["\[\]]*', '', 'g')
6848c8de839SBram Moolenaar
685e2f98b95SBram Moolenaar    " Check if we have already cached the column list for this table
686e2f98b95SBram Moolenaar    " by its name
6878c8de839SBram Moolenaar    let list_idx = index(s:tbl_name, table_name_stripped, 0, &ignorecase)
688e2f98b95SBram Moolenaar    if list_idx > -1
6898c8de839SBram Moolenaar        let table_cols = split(s:tbl_cols[list_idx], '\n')
690e2f98b95SBram Moolenaar    else
691e2f98b95SBram Moolenaar        " Check if we have already cached the column list for this table
692e2f98b95SBram Moolenaar        " by its alias, assuming the table_name provided was actually
693e2f98b95SBram Moolenaar        " the alias for the table instead
694e2f98b95SBram Moolenaar        "     select *
695e2f98b95SBram Moolenaar        "       from area a
696e2f98b95SBram Moolenaar        "      where a.
6978c8de839SBram Moolenaar        let list_idx = index(s:tbl_alias, table_name_stripped, 0, &ignorecase)
698e2f98b95SBram Moolenaar        if list_idx > -1
6998c8de839SBram Moolenaar            let table_alias = table_name_stripped
700e2f98b95SBram Moolenaar            let table_name  = s:tbl_name[list_idx]
7018c8de839SBram Moolenaar            let table_cols  = split(s:tbl_cols[list_idx], '\n')
702e2f98b95SBram Moolenaar        endif
703e2f98b95SBram Moolenaar    endif
704e2f98b95SBram Moolenaar
705e2f98b95SBram Moolenaar    " If we have not found a cached copy of the table
706e2f98b95SBram Moolenaar    " And the table ends in a "." or we are looking for a column list
707e2f98b95SBram Moolenaar    " if list_idx == -1 && (a:table_name =~ '\.' || b:sql_compl_type =~ 'column')
708e2f98b95SBram Moolenaar    " if list_idx == -1 && (a:table_name =~ '\.' || a:list_type =~ 'csv')
709e2f98b95SBram Moolenaar    if list_idx == -1
710e2f98b95SBram Moolenaar         let saveY      = @y
711e2f98b95SBram Moolenaar         let saveSearch = @/
712e2f98b95SBram Moolenaar         let saveWScan  = &wrapscan
713e2f98b95SBram Moolenaar         let curline    = line(".")
714e2f98b95SBram Moolenaar         let curcol     = col(".")
715e2f98b95SBram Moolenaar
716e2f98b95SBram Moolenaar         " Do not let searchs wrap
717e2f98b95SBram Moolenaar         setlocal nowrapscan
718e2f98b95SBram Moolenaar         " If . was entered, look at the word just before the .
719e2f98b95SBram Moolenaar         " We are looking for something like this:
720e2f98b95SBram Moolenaar         "    select *
721e2f98b95SBram Moolenaar         "      from customer c
722e2f98b95SBram Moolenaar         "     where c.
723e2f98b95SBram Moolenaar         " So when . is pressed, we need to find 'c'
724e2f98b95SBram Moolenaar         "
725e2f98b95SBram Moolenaar
726e2f98b95SBram Moolenaar         " Search backwards to the beginning of the statement
727e2f98b95SBram Moolenaar         " and do NOT wrap
728e2f98b95SBram Moolenaar         " exec 'silent! normal! v?\<\(select\|update\|delete\|;\)\>'."\n".'"yy'
72900a927d6SBram Moolenaar         exec 'silent! normal! ?\<\c\(select\|update\|delete\|;\)\>'."\n"
730e2f98b95SBram Moolenaar
731e2f98b95SBram Moolenaar         " Start characterwise visual mode
732e2f98b95SBram Moolenaar         " Advance right one character
733e2f98b95SBram Moolenaar         " Search foward until one of the following:
734e2f98b95SBram Moolenaar         "     1.  Another select/update/delete statement
735e2f98b95SBram Moolenaar         "     2.  A ; at the end of a line (the delimiter)
736e2f98b95SBram Moolenaar         "     3.  The end of the file (incase no delimiter)
737e2f98b95SBram Moolenaar         " Yank the visually selected text into the "y register.
73800a927d6SBram Moolenaar         exec 'silent! normal! vl/\c\(\<select\>\|\<update\>\|\<delete\>\|;\s*$\|\%$\)'."\n".'"yy'
739e2f98b95SBram Moolenaar
740e2f98b95SBram Moolenaar         let query = @y
741e2f98b95SBram Moolenaar         let query = substitute(query, "\n", ' ', 'g')
742e2f98b95SBram Moolenaar         let found = 0
743e2f98b95SBram Moolenaar
74400a927d6SBram Moolenaar         " if query =~? '^\c\(select\)'
74500a927d6SBram Moolenaar         if query =~? '^\(select\|update\|delete\)'
746e2f98b95SBram Moolenaar             let found = 1
747e2f98b95SBram Moolenaar             "  \(\(\<\w\+\>\)\.\)\?   -
74800a927d6SBram Moolenaar             " '\c\(from\|join\|,\).\{-}'  - Starting at the from clause (case insensitive)
749e2f98b95SBram Moolenaar             " '\zs\(\(\<\w\+\>\)\.\)\?' - Get the owner name (optional)
750e2f98b95SBram Moolenaar             " '\<\w\+\>\ze' - Get the table name
751e2f98b95SBram Moolenaar             " '\s\+\<'.table_name.'\>' - Followed by the alias
752e2f98b95SBram Moolenaar             " '\s*\.\@!.*'  - Cannot be followed by a .
753e2f98b95SBram Moolenaar             " '\(\<where\>\|$\)' - Must be followed by a WHERE clause
754e2f98b95SBram Moolenaar             " '.*'  - Exclude the rest of the line in the match
75500a927d6SBram Moolenaar             " let table_name_new = matchstr(@y,
75600a927d6SBram Moolenaar             "             \ '\c\(from\|join\|,\).\{-}'.
75700a927d6SBram Moolenaar             "             \ '\zs\(\("\|\[\)\?.\{-}\("\|\]\)\.\)\?'.
75800a927d6SBram Moolenaar             "             \ '\("\|\[\)\?.\{-}\("\|\]\)\?\ze'.
75900a927d6SBram Moolenaar             "             \ '\s\+\%(as\s\+\)\?\<'.
76000a927d6SBram Moolenaar             "             \ matchstr(table_name, '.\{-}\ze\.\?$').
76100a927d6SBram Moolenaar             "             \ '\>'.
76200a927d6SBram Moolenaar             "             \ '\s*\.\@!.*'.
76300a927d6SBram Moolenaar             "             \ '\(\<where\>\|$\)'.
76400a927d6SBram Moolenaar             "             \ '.*'
76500a927d6SBram Moolenaar             "             \ )
766*db7207e6SBram Moolenaar             "
767*db7207e6SBram Moolenaar             "
768*db7207e6SBram Moolenaar             " ''\c\(\<from\>\|\<join\>\|,\)\s*'  - Starting at the from clause (case insensitive)
769*db7207e6SBram Moolenaar             " '\zs\(\("\|\[\)\?\w\+\("\|\]\)\?\.\)\?' - Get the owner name (optional)
770*db7207e6SBram Moolenaar             " '\("\|\[\)\?\w\+\("\|\]\)\?\ze' - Get the table name
771*db7207e6SBram Moolenaar             " '\s\+\%(as\s\+\)\?\<'.matchstr(table_name, '.\{-}\ze\.\?$').'\>' - Followed by the alias
772*db7207e6SBram Moolenaar             " '\s*\.\@!.*'  - Cannot be followed by a .
773*db7207e6SBram Moolenaar             " '\(\<where\>\|$\)' - Must be followed by a WHERE clause
774*db7207e6SBram Moolenaar             " '.*'  - Exclude the rest of the line in the match
775e2f98b95SBram Moolenaar             let table_name_new = matchstr(@y,
77600a927d6SBram Moolenaar                         \ '\c\(\<from\>\|\<join\>\|,\)\s*'.
77700a927d6SBram Moolenaar                         \ '\zs\(\("\|\[\)\?\w\+\("\|\]\)\?\.\)\?'.
77800a927d6SBram Moolenaar                         \ '\("\|\[\)\?\w\+\("\|\]\)\?\ze'.
779f193fffdSBram Moolenaar                         \ '\s\+\%(as\s\+\)\?\<'.
780f193fffdSBram Moolenaar                         \ matchstr(table_name, '.\{-}\ze\.\?$').
781f193fffdSBram Moolenaar                         \ '\>'.
782e2f98b95SBram Moolenaar                         \ '\s*\.\@!.*'.
783e2f98b95SBram Moolenaar                         \ '\(\<where\>\|$\)'.
784e2f98b95SBram Moolenaar                         \ '.*'
785e2f98b95SBram Moolenaar                         \ )
7868c8de839SBram Moolenaar
787e2f98b95SBram Moolenaar             if table_name_new != ''
788e2f98b95SBram Moolenaar                 let table_alias = table_name
78900a927d6SBram Moolenaar                 let table_name  = matchstr( table_name_new, '^\(.*\.\)\?\zs.*\ze' )
790e2f98b95SBram Moolenaar
791e2f98b95SBram Moolenaar                 let list_idx = index(s:tbl_name, table_name, 0, &ignorecase)
792e2f98b95SBram Moolenaar                 if list_idx > -1
793e2f98b95SBram Moolenaar                     let table_cols  = split(s:tbl_cols[list_idx])
794e2f98b95SBram Moolenaar                     let s:tbl_name[list_idx]  = table_name
795e2f98b95SBram Moolenaar                     let s:tbl_alias[list_idx] = table_alias
796e2f98b95SBram Moolenaar                 else
797e2f98b95SBram Moolenaar                     let list_idx = index(s:tbl_alias, table_name, 0, &ignorecase)
798e2f98b95SBram Moolenaar                     if list_idx > -1
799e2f98b95SBram Moolenaar                         let table_cols = split(s:tbl_cols[list_idx])
800e2f98b95SBram Moolenaar                         let s:tbl_name[list_idx]  = table_name
801e2f98b95SBram Moolenaar                         let s:tbl_alias[list_idx] = table_alias
802e2f98b95SBram Moolenaar                     endif
803e2f98b95SBram Moolenaar                 endif
804e2f98b95SBram Moolenaar
805e2f98b95SBram Moolenaar             endif
806e2f98b95SBram Moolenaar         else
807e2f98b95SBram Moolenaar             " Simply assume it is a table name provided with a . on the end
808e2f98b95SBram Moolenaar             let found = 1
809e2f98b95SBram Moolenaar         endif
810e2f98b95SBram Moolenaar
811e2f98b95SBram Moolenaar         let @y        = saveY
812e2f98b95SBram Moolenaar         let @/        = saveSearch
813e2f98b95SBram Moolenaar         let &wrapscan = saveWScan
814e2f98b95SBram Moolenaar
815e2f98b95SBram Moolenaar         " Return to previous location
816e2f98b95SBram Moolenaar         call cursor(curline, curcol)
817e2f98b95SBram Moolenaar
818e2f98b95SBram Moolenaar         if found == 0
819eb3593b3SBram Moolenaar             if g:loaded_dbext > 300
820e2f98b95SBram Moolenaar                 exec 'DBSetOption use_tbl_alias='.saveSettingAlias
821e2f98b95SBram Moolenaar             endif
822e2f98b95SBram Moolenaar
823e2f98b95SBram Moolenaar             " Not a SQL statement, do not display a list
824e2f98b95SBram Moolenaar             return []
825e2f98b95SBram Moolenaar         endif
826e2f98b95SBram Moolenaar    endif
827e2f98b95SBram Moolenaar
828e2f98b95SBram Moolenaar    if empty(table_cols)
829e2f98b95SBram Moolenaar        " Specify silent mode, no messages to the user (tbl, 1)
830e2f98b95SBram Moolenaar        " Specify do not comma separate (tbl, 1, 1)
831e2f98b95SBram Moolenaar        let table_cols_str = DB_getListColumn(table_name, 1, 1)
832e2f98b95SBram Moolenaar
833e2f98b95SBram Moolenaar        if table_cols_str != ""
834e2f98b95SBram Moolenaar            let s:tbl_name  = add( s:tbl_name,  table_name )
835e2f98b95SBram Moolenaar            let s:tbl_alias = add( s:tbl_alias, table_alias )
836e2f98b95SBram Moolenaar            let s:tbl_cols  = add( s:tbl_cols,  table_cols_str )
8378c8de839SBram Moolenaar            let table_cols  = split(table_cols_str, '\n')
838e2f98b95SBram Moolenaar        endif
839e2f98b95SBram Moolenaar
840e2f98b95SBram Moolenaar    endif
841e2f98b95SBram Moolenaar
842eb3593b3SBram Moolenaar    if g:loaded_dbext > 300
843e2f98b95SBram Moolenaar        exec 'DBSetOption use_tbl_alias='.saveSettingAlias
844e2f98b95SBram Moolenaar    endif
845e2f98b95SBram Moolenaar
846f193fffdSBram Moolenaar    " If the user has asked for a comma separate list of column
847f193fffdSBram Moolenaar    " values, ask the user if they want to prepend each column
848f193fffdSBram Moolenaar    " with a tablename alias.
849e2f98b95SBram Moolenaar    if a:list_type == 'csv' && !empty(table_cols)
850e2f98b95SBram Moolenaar        let cols       = join(table_cols, ', ')
851e2f98b95SBram Moolenaar        let cols       = s:SQLCAddAlias(table_name, table_alias, cols)
852e2f98b95SBram Moolenaar        let table_cols = [cols]
853e2f98b95SBram Moolenaar    endif
854e2f98b95SBram Moolenaar
855e2f98b95SBram Moolenaar    return table_cols
856e2f98b95SBram Moolenaarendfunction
857