comparison plugins/dbtables/dbtables.vim @ 6:3017fd33ad8b

Better support for db tables. Adding some simple diffing support for hg.
author Luka Sitas <lsitas@avatarasoftware.com>
date Tue, 28 Oct 2025 15:26:12 -0400
parents 4a7bc1c8551b
children
comparison
equal deleted inserted replaced
5:4a7bc1c8551b 6:3017fd33ad8b
1 let g:db_user = "" " Replace with your default database username 1 let g:db_user = ""
2 let g:db_password = "" " Replace with your default database password 2 let g:db_password = ""
3 let g:db_name = "" " Replace with your default database name 3 let g:db_name = ""
4 let g:db_host = "" " Replace with your default database name 4 let g:db_host = ""
5 5
6 6 " Execute shell commands
7 " Helper function to execute a command and handle errors
8 function! s:ExecuteShellCommand(command) 7 function! s:ExecuteShellCommand(command)
9 let result = system(a:command . ' 2>&1') 8 let result = system(a:command . ' 2>&1')
10 if v:shell_error != 0 9 return [v:shell_error == 0, result]
11 return [v:false, result] 10 endfunction
12 endif 11
13 return [v:true, result] 12 " Execute a SQL query
14 endfunction
15
16 function! s:ExecuteDBQuery(query) 13 function! s:ExecuteDBQuery(query)
17 let db_user = shellescape(g:db_user) 14 let command = printf('mariadb --user=%s --password=%s --database=%s --host=%s -e %s',
18 let db_password = shellescape(g:db_password) 15 \ shellescape(g:db_user), shellescape(g:db_password),
19 let db_name = shellescape(g:db_name) 16 \ shellescape(g:db_name), shellescape(g:db_host),
20 let db_host = shellescape(g:db_host) 17 \ shellescape(a:query))
21 18
22 let command = 'mariadb --user=' . db_user
23 \ . ' --password=' . db_password
24 \ . ' --database=' . db_name
25 \ . ' --host=' . db_host
26 \ . ' -e ' . shellescape(a:query)
27
28 let [success, result] = s:ExecuteShellCommand(command) 19 let [success, result] = s:ExecuteShellCommand(command)
29 20 if success
30 if !success 21 return split(result, "\n")
22 else
31 call s:HandleDBError(result, command) 23 call s:HandleDBError(result, command)
32 return [] 24 return []
33 endif 25 endif
34 return split(result, "\n") 26 endfunction
35 endfunction 27
36 28 " Handle database command errors
37 function! s:HandleDBError(result, command) 29 function! s:HandleDBError(result, command)
38 echoerr 'Shell command failed: ' . a:command 30 echoerr 'Shell command failed: ' . a:command
39 echoerr a:result
40
41 if a:result =~# 'Access denied' 31 if a:result =~# 'Access denied'
42 echoerr 'Authentication error: Check your username and password.' 32 echoerr 'Authentication error: Check your username and password.'
43 elseif a:result =~# 'Unknown database' 33 elseif a:result =~# 'Unknown database'
44 echoerr 'Database error: The specified database does not exist.' 34 echoerr 'Database error: The specified database does not exist.'
45 elseif a:result =~# 'Could not connect' 35 elseif a:result =~# 'Could not connect'
49 else 39 else
50 echoerr 'Unexpected error: ' . a:result 40 echoerr 'Unexpected error: ' . a:result
51 endif 41 endif
52 endfunction 42 endfunction
53 43
54 44 " Display schema or data in a new buffer
55 " Show the structure/schema of the selected table 45 function! s:OpenInNewTab(title, data)
56 function! s:ShowTableSchema(table)
57 " Open a new tab for schema
58 tabnew 46 tabnew
59 enew 47 enew
60 execute 'file ' . table . '_schema' 48 execute 'file ' . a:title
61 " Describe the table structure 49 if !empty(a:data)
62 let data = s:ExecuteDBQuery('DESCRIBE ' . table . ';') 50 call append(0, a:data)
63 if len(data) > 0 51 else
64 call append(0, data) 52 call append(0, 'No data found or an error occurred.')
65 else 53 endif
66 call append(0, 'No schema found or an error occurred.')
67 endif
68 " Set buffer options and syntax
69 setlocal filetype=sql buftype=nofile bufhidden=wipe nobuflisted noswapfile nomodifiable 54 setlocal filetype=sql buftype=nofile bufhidden=wipe nobuflisted noswapfile nomodifiable
70 endfunction 55 endfunction
71 56
57 " Open the database schema
58 function! s:OpenTableSchema(table)
59 call s:OpenInNewTab(a:table . '_schema', s:ExecuteDBQuery('DESCRIBE ' . a:table . ';'))
60 endfunction
61
62 " Open the table data
63 function! s:OpenTableData(table)
64 call s:OpenInNewTab(a:table, s:ExecuteDBQuery('SELECT * FROM ' . a:table . ';'))
65 endfunction
72 66
73 let s:popup_table = "" 67 let s:popup_table = ""
74 " Popup selection for table actions 68 " Popup selection for table actions
75 function! s:ShowTablePopup() 69 function! s:ShowTablePopup()
76 " Use Vim popup_menu if available 70 " Use Vim popup_menu if available
99 93
100 function! s:ClosePopup() 94 function! s:ClosePopup()
101 unlet! s:popup_table 95 unlet! s:popup_table
102 endfunction 96 endfunction
103 97
104 98 " Open the database tables list
105 " Internal: remove any existing dropdown option lines from the DBTables buffer 99 function! s:OpenDBTablesWindow()
106 function! s:ClearTableOptions() 100 execute '34 vsplit'
107 let to_del = []
108 for lnum in range(1, line('$'))
109 let ln = getline(lnum)
110 if ln =~# '^\s\+\(Data\|Schema\)$'
111 call add(to_del, lnum)
112 endif
113 endfor
114 if !empty(to_del)
115 for lnum in reverse(to_del)
116 call deletebufline('%', lnum)
117 endfor
118 endif
119 endfunction
120
121
122 " Open table data for a given table name
123 function! s:OpenTableData(table)
124 tabnew
125 enew 101 enew
126 execute 'file ' . a:table
127 let data = s:ExecuteDBQuery('SELECT * FROM ' . a:table . ';')
128 if !empty(data)
129 call append(0, data)
130 else
131 call append(0, 'No data found.')
132 endif
133 setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nomodifiable
134 endfunction
135
136 " Open table schema for a given table name
137 function! s:OpenTableSchema(table)
138 tabnew
139 enew
140 execute 'file ' . a:table . '_schema'
141 let data = s:ExecuteDBQuery('DESCRIBE ' . a:table . ';')
142 if !empty(data)
143 call append(0, data)
144 else
145 call append(0, 'No schema found or an error occurred.')
146 endif
147 setlocal filetype=sql buftype=nofile bufhidden=wipe nobuflisted noswapfile nomodifiable
148 endfunction
149
150 function! s:OpenDBTablesWindow()
151 " Open a new vertical split window
152 execute '34 vsplit'
153 " Create a new buffer
154 enew
155 " Set buffer name to "DBTables"
156 file DBTables 102 file DBTables
157
158 let tables = s:ExecuteDBQuery("SHOW TABLES;") 103 let tables = s:ExecuteDBQuery("SHOW TABLES;")
159 if empty(tables) 104 if empty(tables)
160 echo "No tables found or an error occurred." 105 echo "No tables found or an error occurred."
161 return 106 else
162 endif 107 call append(0, ['Available Tables:'] + tables[1:])
163 108 setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nomodifiable nonumber norelativenumber winfixwidth
164 " Display the tables in the buffer 109 nnoremap <buffer> <CR> :call <SID>ShowTablePopup()<CR>
165 call append(0, 'Available Tables:') 110 endif
166 call remove(tables, 0)
167 for table in tables
168 call append('$', table)
169 endfor
170
171 " Set buffer options
172 setlocal buftype=nofile
173 setlocal bufhidden=wipe
174 setlocal nobuflisted
175 setlocal noswapfile
176 setlocal nomodifiable
177 setlocal nonumber
178 setlocal norelativenumber
179 setlocal winfixwidth
180
181 " Map <Enter> to a modal menu (data or schema)
182 nnoremap <buffer> <CR> :call <SID>ShowTablePopup()<CR>
183 endfunction
184
185
186 function! s:ShowTableData()
187 " Get the current line (table name)
188 let lnum = line('.')
189 let table_name = getline(lnum)
190
191 " Open a new tab and create a new buffer
192 tabnew
193 enew
194 " Set buffer name to the table name
195 execute 'file ' . table_name
196
197 let data = s:ExecuteDBQuery("SELECT * FROM " . table_name . ";")
198
199 " Display the table data in the buffer
200 if len(data) > 0
201 call append(0, data)
202 else
203 call append(0, 'No data found.')
204 endif
205
206 " Set buffer options
207 setlocal buftype=nofile
208 setlocal bufhidden=wipe
209 setlocal nobuflisted
210 setlocal noswapfile
211 setlocal nomodifiable
212 endfunction 111 endfunction
213 112
214 let s:query_history = [] 113 let s:query_history = []
215 114
216 " Function to execute SQL from the current buffer with parameter prompt 115 " Function to execute SQL from the current buffer with parameter prompt
217 function! s:ExecuteSQLQuery() 116 function! s:ExecuteSQLQuery()
218 " Get the content of the current buffer (SQL query)
219 let query = join(getline(1, '$'), "\n") 117 let query = join(getline(1, '$'), "\n")
220
221 " Execute query with prompt for parameters
222 call s:PromptAndExecuteQuery(query) 118 call s:PromptAndExecuteQuery(query)
223 endfunction 119 endfunction
224 120
225 " Function to execute SQL from a visual selection with parameter prompt 121 " Function to execute SQL from a visual selection with parameter prompt
226 function! s:ExecuteVisualSQLQuery() range 122 function! s:ExecuteVisualSQLQuery() range
230 126
231 " Execute query with prompt for parameters 127 " Execute query with prompt for parameters
232 call s:PromptAndExecuteQuery(query) 128 call s:PromptAndExecuteQuery(query)
233 endfunction 129 endfunction
234 130
235 131 " Handle parameter prompts and execute query
236 " Function to prompt user for parameter values and execute query
237 function! s:PromptAndExecuteQuery(query) 132 function! s:PromptAndExecuteQuery(query)
238 " Identify parameters in the form of :parameter_name 133 " Identify parameters in the form of :parameter_name
239 let pattern = ':\(\k\+\)' 134 let pattern = ':\(\k\+\)'
240 let params = [] 135 let params = []
241 136
259 endfor 154 endfor
260 155
261 " Replace parameters in the query with user-provided values 156 " Replace parameters in the query with user-provided values
262 let updated_query = a:query 157 let updated_query = a:query
263 for [param, value] in items(param_values) 158 for [param, value] in items(param_values)
264 let updated_query = substitute(updated_query, param, shellescape(value), 'g') 159 let updated_query = substitute(updated_query, param, value, 'g')
265 endfor 160 endfor
266 161
267 " Append the query to history
268 call add(s:query_history, updated_query) 162 call add(s:query_history, updated_query)
269 163 call s:OpenInNewTab('SQLQueryResult', s:ExecuteDBQuery(updated_query))
270 " Execute the updated query 164 endfunction
271 let data = s:ExecuteDBQuery(updated_query) 165
272 166 " View query history
273 " Open results in a new tab
274 tabnew
275 enew
276 execute 'file SQLQueryResult'
277 call append(0, data)
278
279 " Set buffer options and highlight
280 setlocal filetype=sql
281 setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nomodifiable
282 endfunction
283
284
285 function! s:OpenQueryHistory() 167 function! s:OpenQueryHistory()
286 " Open the query history in a new split window 168 " Open the query history in a new split window
287 execute 'vsplit' 169 execute 'vsplit'
288 enew 170 enew
289 call setline(1, s:query_history) 171 call setline(1, s:query_history)
290
291 " Allow selecting a query to be put into a new buffer to execute
292 nnoremap <buffer> <CR> :call <SID>ExecuteHistoryQuery(line('.'))<CR> 172 nnoremap <buffer> <CR> :call <SID>ExecuteHistoryQuery(line('.'))<CR>
293 173 setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile
294 " Set buffer options
295 setlocal buftype=nofile
296 setlocal bufhidden=wipe
297 setlocal nobuflisted
298 setlocal noswapfile
299 endfunction 174 endfunction
300 175
301 function! s:ExecuteHistoryQuery(lnum) 176 function! s:ExecuteHistoryQuery(lnum)
302 " Execute the selected query from history
303 let query = getline(a:lnum) 177 let query = getline(a:lnum)
304 execute 'normal! i' . query 178 execute 'normal! i' . query
305 " Optionally call the execute function directly or process 179 " Optional execution or further processing
306 endfunction 180 endfunction
307 181
308 182 " Open MariaDB console
309 function! DBConsole() 183 function! DBConsole()
310 " Save the current cursor position 184 " Save the current cursor position
311 let save_cursor = getpos(".") 185 let save_cursor = getpos(".")
312 186 let command = printf('mariadb --user=%s --password=%s --database=%s --host=%s',
313 "Format the files 187 \ g:db_user, g:db_password,
314 let db_user = g:db_user 188 \ g:db_name, g:db_host)
315 let db_password = g:db_password 189
316 let db_name = g:db_name 190 let command = substitute(command, '\n', '', 'g')
317 " let db_host = shellescape(g:db_host) 191 execute ':term ' . command
318 let db_host = g:db_host 192 call setpos(".", save_cursor)
319
320
321
322 let command = 'mariadb --user=' . db_user . ' --password=' . db_password . ' --database=' . db_name . ' --host=' . db_host . ' '
323 let command = substitute(command, '\n', '', 'g')
324 execute ':term ' . command
325 call setpos(".", save_cursor)
326 endfunction 193 endfunction
327 194
328 " Keybinding to open query history 195 " Keybinding to open query history
329 nnoremap <Leader>qh :call <SID>OpenQueryHistory()<CR> 196 nnoremap <Leader>qh :call <SID>OpenQueryHistory()<CR>
330 nnoremap <Leader>db :call DBConsole()<cr> 197 nnoremap <Leader>db :call DBConsole()<CR>
331
332 command! DBTables call s:OpenDBTablesWindow() 198 command! DBTables call s:OpenDBTablesWindow()
333 command! ExecuteSQL call s:ExecuteSQLQuery() 199 command! ExecuteSQL call s:ExecuteSQLQuery()
334 200
335 " Function to refresh the list of tables 201 " Function to refresh the list of tables
336 nnoremap <Leader>rt :DBTables<CR> 202 nnoremap <Leader>rt :DBTables<CR>