|
4
|
1 let g:db_user = "" " Replace with your default database username
|
|
|
2 let g:db_password = "" " Replace with your default database password
|
|
|
3 let g:db_name = "" " Replace with your default database name
|
|
|
4 let g:db_host = "" " Replace with your default database name
|
|
|
5
|
|
|
6 let s:popup_table = ""
|
|
|
7
|
|
|
8
|
|
|
9 " Helper function to execute a command and handle errors
|
|
|
10 function! s:ExecuteShellCommand(command)
|
|
|
11 let result = system(a:command . ' 2>&1')
|
|
|
12 if v:shell_error != 0
|
|
|
13 return [v:false, result]
|
|
|
14 endif
|
|
|
15 return [v:true, result]
|
|
|
16 endfunction
|
|
|
17
|
|
|
18 function! s:ExecuteDBQuery(query)
|
|
|
19 let db_user = shellescape(g:db_user)
|
|
|
20 let db_password = shellescape(g:db_password)
|
|
|
21 let db_name = shellescape(g:db_name)
|
|
|
22 let db_host = shellescape(g:db_host)
|
|
|
23
|
|
|
24 let command = 'mariadb --user=' . db_user
|
|
|
25 \ . ' --password=' . db_password
|
|
|
26 \ . ' --database=' . db_name
|
|
|
27 \ . ' --host=' . db_host
|
|
|
28 \ . ' -e ' . shellescape(a:query)
|
|
|
29
|
|
|
30 let [success, result] = s:ExecuteShellCommand(command)
|
|
|
31
|
|
|
32 if !success
|
|
|
33 call s:HandleDBError(result, command)
|
|
|
34 return []
|
|
|
35 endif
|
|
|
36 return split(result, "\n")
|
|
|
37 endfunction
|
|
|
38
|
|
|
39 function! s:HandleDBError(result, command)
|
|
|
40 echoerr 'Shell command failed: ' . a:command
|
|
|
41 echoerr a:result
|
|
|
42
|
|
|
43 if a:result =~# 'Access denied'
|
|
|
44 echoerr 'Authentication error: Check your username and password.'
|
|
|
45 elseif a:result =~# 'Unknown database'
|
|
|
46 echoerr 'Database error: The specified database does not exist.'
|
|
|
47 elseif a:result =~# 'Could not connect'
|
|
|
48 echoerr 'Connection error: Verify host and network connectivity.'
|
|
|
49 elseif a:result =~# 'You have an error in your SQL syntax'
|
|
|
50 echoerr 'Syntax error in SQL query.'
|
|
|
51 else
|
|
|
52 echoerr 'Unexpected error: ' . a:result
|
|
|
53 endif
|
|
|
54 endfunction
|
|
|
55
|
|
|
56
|
|
|
57 " Show the structure/schema of the selected table
|
|
|
58 function! s:ShowTableSchema(table)
|
|
|
59 " Open a new tab for schema
|
|
|
60 tabnew
|
|
|
61 enew
|
|
|
62 execute 'file ' . table . '_schema'
|
|
|
63 " Describe the table structure
|
|
|
64 let data = s:ExecuteDBQuery('DESCRIBE ' . table . ';')
|
|
|
65 if len(data) > 0
|
|
|
66 call append(0, data)
|
|
|
67 else
|
|
|
68 call append(0, 'No schema found or an error occurred.')
|
|
|
69 endif
|
|
|
70 " Set buffer options and syntax
|
|
|
71 setlocal filetype=sql buftype=nofile bufhidden=wipe nobuflisted noswapfile nomodifiable
|
|
|
72 endfunction
|
|
|
73
|
|
|
74
|
|
|
75 " Popup selection for table actions
|
|
|
76 function! s:ShowTablePopup()
|
|
|
77 " Use Vim popup_menu if available
|
|
|
78 if exists('*popup_menu')
|
|
|
79 s:popup_table = getline(line('.'))
|
|
|
80 let items = ['View Data', 'View Schema', 'Cancel']
|
|
|
81 popup_menu(items, {})
|
|
|
82
|
|
|
83 nnoremap <buffer> <CR> :call <SID>HandlePopupSelection()<CR>
|
|
|
84 return
|
|
|
85 endif
|
|
|
86 " Popup_menu not available
|
|
|
87 echoerr 'Floating popup requires Vim8.2+.'
|
|
|
88 endfunction
|
|
|
89
|
|
|
90 function! s:HandlePopupSelection()
|
|
|
91 let choice = getline('.')
|
|
|
92 let table = s:popup_table
|
|
|
93 call s:ClosePopup()
|
|
|
94 if choice ==# 'View Data'
|
|
|
95 call s:OpenTableData(table)
|
|
|
96 elseif choice ==# 'View Schema'
|
|
|
97 call s:OpenTableSchema(table)
|
|
|
98 else
|
|
|
99 call s:ClosePopup()
|
|
|
100 endif
|
|
|
101 endfunction
|
|
|
102
|
|
|
103 function! s:ClosePopup()
|
|
|
104 unlet! s:popup_table
|
|
|
105 endfunction
|
|
|
106
|
|
|
107
|
|
|
108 " Modal menu: let user pick Data or Schema from a simple list
|
|
|
109 function! s:ShowTableMenuModal()
|
|
|
110 let table = getline(line('.'))
|
|
|
111 let opts = [ 'Select action for "' . table . '"', 'View Data', 'View Schema', 'Cancel' ]
|
|
|
112 let choice = inputlist(opts)
|
|
|
113 if choice == 1
|
|
|
114 call s:ShowTableData()
|
|
|
115 elseif choice == 2
|
|
|
116 call s:ShowTableSchema()
|
|
|
117 endif
|
|
|
118 endfunction
|
|
|
119
|
|
|
120 " Internal: remove any existing dropdown option lines from the DBTables buffer
|
|
|
121 function! s:ClearTableOptions()
|
|
|
122 let to_del = []
|
|
|
123 for lnum in range(1, line('$'))
|
|
|
124 let ln = getline(lnum)
|
|
|
125 if ln =~# '^\s\+\(Data\|Schema\)$'
|
|
|
126 call add(to_del, lnum)
|
|
|
127 endif
|
|
|
128 endfor
|
|
|
129 if !empty(to_del)
|
|
|
130 for lnum in reverse(to_del)
|
|
|
131 call deletebufline('%', lnum)
|
|
|
132 endfor
|
|
|
133 endif
|
|
|
134 endfunction
|
|
|
135
|
|
|
136 " Internal: insert Data/Schema options under the selected table
|
|
|
137 function! s:InsertTableOptions()
|
|
|
138 call s:ClearTableOptions()
|
|
|
139 let tlnum = line('.')
|
|
|
140 " Insert indented options
|
|
|
141 call append(tlnum, ' Data')
|
|
|
142 call append(tlnum+1, ' Schema')
|
|
|
143 " Move cursor to the 'Data' line
|
|
|
144 call cursor(tlnum+1, 1)
|
|
|
145 endfunction
|
|
|
146
|
|
|
147 " Internal: find the nearest table name above the cursor (first non-indented line)
|
|
|
148 function! s:GetNearestTableName()
|
|
|
149 let lnum = line('.')
|
|
|
150 while lnum > 0
|
|
|
151 let text = getline(lnum)
|
|
|
152 if text =~# '^\S'
|
|
|
153 if text ==# 'Available Tables:'
|
|
|
154 return ''
|
|
|
155 endif
|
|
|
156 return text
|
|
|
157 endif
|
|
|
158 let lnum -= 1
|
|
|
159 endwhile
|
|
|
160 return ''
|
|
|
161 endfunction
|
|
|
162
|
|
|
163
|
|
|
164 " Open table data for a given table name
|
|
|
165 function! s:OpenTableData(table)
|
|
|
166 tabnew
|
|
|
167 enew
|
|
|
168 execute 'file ' . a:table
|
|
|
169 let data = s:ExecuteDBQuery('SELECT * FROM ' . a:table . ';')
|
|
|
170 if !empty(data)
|
|
|
171 call append(0, data)
|
|
|
172 else
|
|
|
173 call append(0, 'No data found.')
|
|
|
174 endif
|
|
|
175 setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nomodifiable
|
|
|
176 endfunction
|
|
|
177
|
|
|
178 " Open table schema for a given table name
|
|
|
179 function! s:OpenTableSchema(table)
|
|
|
180 tabnew
|
|
|
181 enew
|
|
|
182 execute 'file ' . a:table . '_schema'
|
|
|
183 let data = s:ExecuteDBQuery('DESCRIBE ' . a:table . ';')
|
|
|
184 if !empty(data)
|
|
|
185 call append(0, data)
|
|
|
186 else
|
|
|
187 call append(0, 'No schema found or an error occurred.')
|
|
|
188 endif
|
|
|
189 setlocal filetype=sql buftype=nofile bufhidden=wipe nobuflisted noswapfile nomodifiable
|
|
|
190 endfunction
|
|
|
191
|
|
|
192 function! s:OpenDBTablesWindow()
|
|
|
193 " Open a new vertical split window
|
|
|
194 execute '34 vsplit'
|
|
|
195 " Create a new buffer
|
|
|
196 enew
|
|
|
197 " Set buffer name to "DBTables"
|
|
|
198 file DBTables
|
|
|
199
|
|
|
200 let tables = s:ExecuteDBQuery("SHOW TABLES;")
|
|
|
201 if empty(tables)
|
|
|
202 echo "No tables found or an error occurred."
|
|
|
203 return
|
|
|
204 endif
|
|
|
205
|
|
|
206 " Display the tables in the buffer
|
|
|
207 call append(0, 'Available Tables:')
|
|
|
208 call remove(tables, 0)
|
|
|
209 for table in tables
|
|
|
210 call append('$', table)
|
|
|
211 endfor
|
|
|
212
|
|
|
213 " Set buffer options
|
|
|
214 setlocal buftype=nofile
|
|
|
215 setlocal bufhidden=wipe
|
|
|
216 setlocal nobuflisted
|
|
|
217 setlocal noswapfile
|
|
|
218 setlocal nomodifiable
|
|
|
219 setlocal nonumber
|
|
|
220 setlocal norelativenumber
|
|
|
221 setlocal winfixwidth
|
|
|
222
|
|
|
223 " Map <Enter> to a modal menu (data or schema)
|
|
|
224 nnoremap <buffer> <CR> :call <SID>ShowTablePopup()<CR>
|
|
|
225 endfunction
|
|
|
226
|
|
|
227
|
|
|
228 function! s:ShowTableData()
|
|
|
229 " Get the current line (table name)
|
|
|
230 let lnum = line('.')
|
|
|
231 let table_name = getline(lnum)
|
|
|
232
|
|
|
233 " Open a new tab and create a new buffer
|
|
|
234 tabnew
|
|
|
235 enew
|
|
|
236 " Set buffer name to the table name
|
|
|
237 execute 'file ' . table_name
|
|
|
238
|
|
|
239 let data = s:ExecuteDBQuery("SELECT * FROM " . table_name . ";")
|
|
|
240
|
|
|
241 " Display the table data in the buffer
|
|
|
242 if len(data) > 0
|
|
|
243 call append(0, data)
|
|
|
244 else
|
|
|
245 call append(0, 'No data found.')
|
|
|
246 endif
|
|
|
247
|
|
|
248 " Set buffer options
|
|
|
249 setlocal buftype=nofile
|
|
|
250 setlocal bufhidden=wipe
|
|
|
251 setlocal nobuflisted
|
|
|
252 setlocal noswapfile
|
|
|
253 setlocal nomodifiable
|
|
|
254 endfunction
|
|
|
255
|
|
|
256 let s:query_history = []
|
|
|
257
|
|
|
258 function! s:ExecuteSQLQuery()
|
|
|
259 " Get the content of the current buffer (SQL query)
|
|
|
260 let query = join(getline(1, '$'), " ")
|
|
|
261
|
|
|
262 " Append the query to history
|
|
|
263 call add(s:query_history, query)
|
|
|
264
|
|
|
265 let data = s:ExecuteDBQuery(query)
|
|
|
266
|
|
|
267 tabnew
|
|
|
268 enew
|
|
|
269 execute 'file SQLQueryResult'
|
|
|
270 call append(0, data)
|
|
|
271
|
|
|
272 " Set the buffer file type to SQL for syntax highlighting
|
|
|
273 setlocal filetype=sql
|
|
|
274
|
|
|
275 setlocal buftype=nofile
|
|
|
276 setlocal bufhidden=wipe
|
|
|
277 setlocal nobuflisted
|
|
|
278 setlocal noswapfile
|
|
|
279 setlocal nomodifiable
|
|
|
280 endfunction
|
|
|
281
|
|
|
282 " Execute SQL from a visual selection
|
|
|
283 function! s:ExecuteVisualSQLQuery() range
|
|
|
284 " Get the content of the selected lines as a single SQL query
|
|
|
285 let lines = getline(a:firstline, a:lastline)
|
|
|
286 let query = join(lines, " ")
|
|
|
287
|
|
|
288 " Append the query to history
|
|
|
289 call add(s:query_history, query)
|
|
|
290
|
|
|
291 " Execute the query and capture results
|
|
|
292 let data = s:ExecuteDBQuery(query)
|
|
|
293
|
|
|
294 " Open results in a new tab
|
|
|
295 tabnew
|
|
|
296 enew
|
|
|
297 execute 'file SQLQueryResult'
|
|
|
298 call append(0, data)
|
|
|
299
|
|
|
300 " Set buffer options and highlight
|
|
|
301 setlocal filetype=sql
|
|
|
302 setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nomodifiable
|
|
|
303 endfunction
|
|
|
304
|
|
|
305 function! s:OpenQueryHistory()
|
|
|
306 " Open the query history in a new split window
|
|
|
307 execute 'vsplit'
|
|
|
308 enew
|
|
|
309 call setline(1, s:query_history)
|
|
|
310
|
|
|
311 " Allow selecting a query to be put into a new buffer to execute
|
|
|
312 nnoremap <buffer> <CR> :call <SID>ExecuteHistoryQuery(line('.'))<CR>
|
|
|
313
|
|
|
314 " Set buffer options
|
|
|
315 setlocal buftype=nofile
|
|
|
316 setlocal bufhidden=wipe
|
|
|
317 setlocal nobuflisted
|
|
|
318 setlocal noswapfile
|
|
|
319 endfunction
|
|
|
320
|
|
|
321 function! s:ExecuteHistoryQuery(lnum)
|
|
|
322 " Execute the selected query from history
|
|
|
323 let query = getline(a:lnum)
|
|
|
324 execute 'normal! i' . query
|
|
|
325 " Optionally call the execute function directly or process
|
|
|
326 endfunction
|
|
|
327
|
|
|
328
|
|
|
329 function! DBConsole()
|
|
|
330 " Save the current cursor position
|
|
|
331 let save_cursor = getpos(".")
|
|
|
332
|
|
|
333 "Format the files
|
|
|
334 let db_user = g:db_user
|
|
|
335 let db_password = g:db_password
|
|
|
336 let db_name = g:db_name
|
|
|
337 " let db_host = shellescape(g:db_host)
|
|
|
338 let db_host = g:db_host
|
|
|
339
|
|
|
340
|
|
|
341
|
|
|
342 let command = 'mariadb --user=' . db_user . ' --password=' . db_password . ' --database=' . db_name . ' --host=' . db_host . ' '
|
|
|
343 let command = substitute(command, '\n', '', 'g')
|
|
|
344 execute ':term ' . command
|
|
|
345 call setpos(".", save_cursor)
|
|
|
346 endfunction
|
|
|
347
|
|
|
348 function! OpenMariaDBConsole()
|
|
|
349 " The command to connect to MariaDB. Customize it with your actual connection details.
|
|
|
350 let cmd = 'mariadb -u your_username -p your_database_name'
|
|
|
351
|
|
|
352 " Open a new terminal window at the bottom with 10 lines height.
|
|
|
353 " Split the window horizontally; you can adjust the height by changing `10`.
|
|
|
354 botright 10split
|
|
|
355 call termopen(cmd)
|
|
|
356 endfunction
|
|
|
357
|
|
|
358 " Keybinding to open query history
|
|
|
359 nnoremap <Leader>qh :call <SID>OpenQueryHistory()<CR>
|
|
|
360 nnoremap <Leader>db :call DBConsole()<cr>
|
|
|
361
|
|
|
362 command! DBTables call s:OpenDBTablesWindow()
|
|
|
363 command! ExecuteSQL call s:ExecuteSQLQuery()
|
|
|
364
|
|
|
365 " Function to refresh the list of tables
|
|
|
366 nnoremap <Leader>rt :DBTables<CR>
|
|
|
367
|
|
|
368 " Function to execute the contents of the current buffer as an SQL query
|
|
|
369 nnoremap <Leader>eq :ExecuteSQL<CR>
|
|
|
370
|
|
|
371 " Function to open the database tables window
|
|
|
372 nnoremap <Leader>dt :DBTables<CR>
|
|
|
373
|
|
|
374 " Optional: Shortcut to open MariaDB console
|
|
|
375 nnoremap <Leader>mc :call DBConsole()<CR>
|
|
|
376 " Map visual selection to execute selected SQL
|
|
|
377 xnoremap <silent> <Leader>ev :call <SID>ExecuteVisualSQLQuery()<CR>
|