提交 5c1c4257 编写于 作者: C Cosmin Popescu

version 4.0

上级 0a30f28f
......@@ -67,6 +67,10 @@ listen for requests. After this, whenever you want to send a command to the
DBMS from `VIM`, the plugin will connect on the specified port, send the
command and retrieve the result which will be displayed in `VIM`.
In order to work properly, you should keep the settings on default. Settings
like `workbench.console.script.showtime` could affect the functionality of
`VIM sql workbench`.
Connecting to a DBMS
========================================
......@@ -158,13 +162,6 @@ available shortcuts, see the top panel.
The database explorer if fully customizable. You can use the existing one and
extend it or you can create your own from scratch.
_NOTE_: For `PostgreSQL`, you should use the as database explorer the
`resources/dbexplorer-postgresql.vim` file. This is because in `PostgreSQL`
the objects have to be prefixed by the schema. You can achieve this either by
just overwriting the `resources/dbexplorer.vim` file with the
`resources/dbexplorer-postgresql.vim` file, either by following the
documentation bellow.
## Creating a new database explorer from scratch
The database explorer is loaded from the `resources/dbexplorer.vim` file by
......@@ -179,8 +176,41 @@ which the panel will be applied. `*` profile, means that the options appear on
all profiles. If you want to have separate database explorers for separate
profiles, you can create a key in the dictionary for each explorer.
*NOTE:* At the moment you can only create profiles for different profiles, not
for different DBMS.
You can also have profiles per type of DBMS. If you have a profile starting
with a `:` or a '^'.
A `:` means that this options will appear for all the profiles which the DBMS
is of that type. For example `:MySQL` it means that these options will appear
only for `mysql` databases.
A `^` means that this options will appear for all the profiles for which the
DBMS is not of that type. For example `^PostgreSQL` means that there options
will appear for all databases which are not `PostgreSQL`.
For this to work, you have to have the option `g:sw_config_dir` set. The
profile informations are read from the `WbProfiles.xml` file which resides in
this folder. The profile type you can see it in the `SQL Workbench/J`
connection window. It's the driver title.
Starting with version `4.0` you can also have a vimscript function called
instead of a sql query. The function called has to return a string which will
be interpreted as the result of the operation. The function will receive as
parameters the line selected (the complete line which has been selected). In
order to have a function instead of a sql query in the database explorer, the
`command` has to begin with `:`.
For example:
```
{'title': 'Data', 'shortcut': 'D', 'command': ':My_function'}
```
When the shortcut D will be pressed, the result will be fetch by calling
`My_function(getline('.'))`
Of course, the current line is only relevant only for when changing a tab.
When changing a tab, the current line will contain whatever value is on the
currently line in whatever buffer you are at that moment.
The values for each profile, have to be a list which will contain all the
options for the left panel. For example, in the default one, the database
......@@ -376,6 +406,21 @@ is going to be sent to the DBMS.
Also here you can use an exclamation mark to execute the command asynchronous,
which is the default mapping.
## Profiling
Unfortunately, the `SQL Workbench/J` console application does not return the
time that it took for a command to execute. This plugin will try to do some
profiling, but it will report the full time it took for a command to execute.
This means that this time will also include the communication with the
`sqwbconsole` server, the time to display the results in console (if on debug
mode) the time it took `SQL Workbench/J` console application to communicate
with the DBMS via `jdbc` and any other operations involved.
So, if you want to do some profiling, try to either to `select count(*) from
your_table` (this would eliminate some operations, like displaying the results
in console if in debug mode) or to set the maximum number of results to a low
value (like 10). And (of course), send only one query at a time.
## Intellisense
`vim-sqlworkbench` plugin comes with intellisense out of the box. In order to
......
......@@ -366,7 +366,7 @@ endfunction
" Parses the profile xml file to give autocompletion for profiles{{{1
function! sw#parse_profile_xml()
if !exists('g:sw_config_dir')
return []
return {}
endif
let lines = readfile(g:sw_config_dir . 'WbProfiles.xml')
......@@ -375,16 +375,25 @@ function! sw#parse_profile_xml()
let s = s . ' ' . line
endfor
let pattern = '\v\c\<object class\="[^"]{-}"\>.{-}\<void property\="name"\>.{-}\<string\>([^\<]{-})\<'
let result = []
let n = 1
let list = matchlist(s, pattern, 0, n)
let s = substitute(s, '\v\c\<object class\="java\.util\.ArrayList"\>', '', 'g')
let s = substitute(s, '\v\c\<object class\="(workbench\.db\.ConnectionProfile)@![^"]+"\>.{-}\<\/object\>', '', 'g')
let pattern = '\v\c(\<object class\="[^"]{-}"\>.{-}\<\/object\>)'
let result = {}
let n = 0
let list = matchlist(s, pattern, n, 1)
while len(list) > 0
if index(result, list[1]) == -1
call add(result, list[1])
let _pattern = '\v\c^.*\<void property\="#prop#"\>[ \s\r\t]*\<string\>([^\<]+)\<.*$'
let name = substitute(list[1], substitute(_pattern, '#prop#', 'name', 'g'), '\1', 'g')
let driverName = substitute(list[1], substitute(_pattern, '#prop#', 'driverName', 'g'), '\1', 'g')
let group = substitute(list[1], substitute(_pattern, '#prop#', 'group', 'g'), '\1', 'g')
if (group != list[1])
let name = group . '\' . name
endif
let result[name] = driverName
let n = n + 1
let list = matchlist(s, pattern, 0, n)
let s = substitute(s, '\V' . list[0], '', 'g')
let list = matchlist(s, pattern, n, 1)
endwhile
return result
......@@ -395,7 +404,7 @@ function! sw#autocomplete_profile(ArgLead, CmdLine, CursorPos)
let result = []
for profile in profiles
for profile in keys(profiles)
if profile =~ '^' . a:ArgLead
call add(result, profile)
endif
......@@ -431,3 +440,24 @@ function! sw#autocomplete_profile_for_buffer(ArgLead, CmdLine, CursorPos)
endif
return s:autocomplete_path(a:ArgLead, a:CmdLine, a:CursorPos)
endfunction
function! sw#display_error(msg)
echohl WarningMsg
echomsg a:msg
echohl None
endfunction
function! sw#get_sw_setting(setting)
let p1 = '\v\c^[\s \t]*' . substitute(a:setting, '\c\v\.', "\\.", 'g')
if exists('g:sw_config_dir')
let lines = readfile(g:sw_config_dir . 'workbench.settings')
for line in lines
if line =~ p1
let p2 = p1 . '[\s \t]*\=[\s\t ]*(.*)$'
return substitute(line, p2, '\1', 'g')
endif
endfor
endif
return ''
endfunction
......@@ -299,7 +299,8 @@ endfunction
function! sw#autocomplete#perform(findstart, base)
" Check that the cache is alright
if !exists('b:autocomplete_tables') && !exists('g:sw_autocomplete_default_tables')
throw "First you have to clear the completion cache to use autocomplete"
call sw#display_error("First you have to clear the completion cache to use autocomplete")
return []
endif
call sw#session#init_section()
if (exists('b:sql'))
......@@ -473,7 +474,7 @@ function! sw#autocomplete#perform(findstart, base)
elseif b:autocomplete_type == 'wbconnect'
let profiles = sw#parse_profile_xml()
let result = []
for profile in profiles
for profile in keys(profiles)
if profile =~ '^' . a:base
call add(result, profile)
endif
......
......@@ -21,6 +21,8 @@ if !exists('g:SW_Tabs')
let g:SW_Tabs = {}
endif
let s:profiles = {}
" Local functions{{{1
" Iterates in the tabs array{{{2
......@@ -28,11 +30,28 @@ function! s:iterate(f)
for _profile in items(g:SW_Tabs)
let profile = _profile[0]
let tabs = _profile[1]
if (profile == b:profile || profile == '*')
let type_ok = 0
if (profile =~ '^[:\^]')
if (len(s:profiles) == 0)
let s:profiles = sw#parse_profile_xml()
endif
let dbms_type = substitute(profile, '^[:\^]', '', 'g')
let cond = substitute(profile, '\v\c^([:\^]).*$', '\1', 'g')
for xml_profile in items(s:profiles)
if tolower(substitute(xml_profile[0], "\\\\", '___', 'g')) == tolower(b:profile) &&
\ ((tolower(xml_profile[1]) == tolower(dbms_type) && cond == ':') ||
\ (tolower(xml_profile[1]) != tolower(dbms_type) && cond == '^'))
let type_ok = 1
break
endif
endfor
endif
if (profile == b:profile || profile == '*' || type_ok)
for tab in tabs
execute "let r = " . a:f . "(tab)"
if !r
break
return
endif
endfor
endif
......@@ -358,7 +377,7 @@ function! sw#dbexplorer#hide_panel(...)
endif
let name = "__SQL__-" . profile
if !bufexists(name)
echoerr "There is no dbexplorer opened for " . profile
call sw#display_error("There is no dbexplorer opened for " . profile)
return
endif
......@@ -372,7 +391,7 @@ function! sw#dbexplorer#export()
if (exists('b:last_cmd'))
call sw#export_ods(b:profile, b:last_cmd)
else
echoerr "The panel is empty!"
call sw#display_error("The panel is empty!")
endif
endfunction
......@@ -423,12 +442,13 @@ endfunction
" Shows the dbexplorer panel{{{2
function! sw#dbexplorer#show_panel(profile, port, ...)
let result = sw#server#open_dbexplorer(a:profile, a:port)
let profile = substitute(a:profile, '\\', '___', 'g')
let result = sw#server#open_dbexplorer(profile, a:port)
let s_below = &splitbelow
set nosplitbelow
let name = "__SQL__-" . a:profile
let name = "__SQL__-" . profile
if bufexists(name)
echoerr "There is already a dbexplorer opened for " . a:profile
call sw#display_error("There is already a dbexplorer opened for " . profile)
return
endif
......@@ -447,19 +467,19 @@ function! sw#dbexplorer#show_panel(profile, port, ...)
execute "badd " . name
execute "buffer " . name
call s:set_special_buffer(a:profile, a:port)
call s:set_special_buffer(profile, a:port)
call sw#session#set_buffer_variable('unique_id', uid)
nnoremap <buffer> <silent> E :call sw#dbexplorer#export()<cr>
nnoremap <buffer> <silent> B :call <SID>open_in_new_buffer()<cr>
execute "silent! split __Info__-" . a:profile
execute "silent! split __Info__-" . profile
resize 7
"let id = matchadd('SWHighlights', '\v^([^\(]+\([A-Za-z]+\)( \| )?)+$')
call s:set_special_buffer(a:profile, a:port)
call s:set_special_buffer(profile, a:port)
call sw#session#set_buffer_variable('unique_id', uid)
call s:set_highlights()
wincmd b
execute "silent! vsplit __DBExplorer__-" . a:profile
call s:set_special_buffer(a:profile, a:port)
execute "silent! vsplit __DBExplorer__-" . profile
call s:set_special_buffer(profile, a:port)
call sw#session#set_buffer_variable('unique_id', uid)
vertical resize 60
""call s:set_objects_buffer()
......@@ -482,4 +502,14 @@ function! sw#dbexplorer#fix_source_code()
normal gg0G0x
setlocal nomodifiable
endfunction
function! sw#dbexplorer#postgre_proc(line)
let proc = substitute(a:line, '\v\c([^\(]+)\(.*$', '\1', 'g')
let lines = sw#server#dbexplorer('WbProcSource ' . proc)
let result = ''
for line in lines
let result = result . line . "\n"
endfor
return result
endfunction
" vim:fdm=marker
......@@ -89,6 +89,7 @@ function! s:pipe_execute(type, cmd, wait_result, ...)
let uid = b:unique_id
endif
try
python << SCRIPT
import vim
import socket
......@@ -127,6 +128,10 @@ for line in lines:
vim.command("let result = result . '%s\n'" % line.replace("'", "''"))
#end for
SCRIPT
catch
call sw#display_error("There is a problem communicating with the server on port " . port . ". Maybe the server is down?")
return ''
endtry
if len(result) <= 3
let result = ''
endif
......@@ -143,17 +148,22 @@ function! sw#server#fetch_result()
endfunction
function! sw#server#open_dbexplorer(profile, port)
return s:pipe_execute('DBE', a:profile . "\n", 1, a:port)
return s:pipe_execute('DBE', substitute(a:profile, '___', "\\\\", 'g') . "\n", 1, a:port)
endfunction
function! sw#server#dbexplorer(sql)
if !exists('b:profile')
return
endif
let s = s:pipe_execute('DBE', b:profile . "\n" . a:sql . ';', 1)
if a:sql =~ "^:"
let func = substitute(a:sql, '^:', '', 'g')
execute "let s = " . func . "(getline('.'))"
else
let s = s:pipe_execute('DBE', substitute(b:profile, '___', "\\\\", 'g') . "\n" . a:sql . ';', 1)
endif
let lines = split(s, "\n")
let result = []
let rec = 0
let rec = 1
for line in lines
if line =~ '\v\c^[ \s\t\r]*$'
let rec = 0
......@@ -161,7 +171,7 @@ function! sw#server#dbexplorer(sql)
call add(result, '')
endif
endif
if rec
if rec && !(line =~ '\v^[\=]+$')
call add(result, line)
endif
if line =~ '\v\c^[\=]+$'
......@@ -176,7 +186,7 @@ endfunction
function! sw#server#execute_sql(sql, wait_result, port)
let sql = a:sql
if !(substitute(sql, "^\\v\\c\\n", ' ', 'g') =~ b:delimiter . '[ \s\t\r]*$')
if !(substitute(sql, "^\\v\\c\\n", ' ', 'g') =~ b:delimiter . '[ \s\t\r\n]*$')
let sql = sql . b:delimiter . "\n"
endif
return s:pipe_execute('COM', sql, a:wait_result, a:port)
......
......@@ -23,8 +23,10 @@ let s:script_path = expand('<sfile>:p:h') . '/../../'
function! s:check_sql_buffer()
if (!exists('b:port'))
throw "The current buffer is not an SQL Workbench buffer. Open it using the SWOpenSQL command."
call sw#display_error("The current buffer is not an SQL Workbench buffer. Open it using the SWOpenSQL command.")
return 0
endif
return 1
endfunction
function! sw#sqlwindow#goto_statement_buffer()
......@@ -115,9 +117,12 @@ function! sw#sqlwindow#open_buffer(port, file, command)
endfunction
function! sw#sqlwindow#set_delimiter(new_del)
call s:check_sql_buffer()
if (!s:check_sql_buffer())
return
endif
if exists('b:port')
throw 'You cannot change the delimier in server mode. This happens because SQL Workbench does now know another delimiter during console mode. You can only change the delimiter in batch mode (see the documentation). So, if you want to change the delimiter, please open the buffer in batch mode. '
sw#display_error('You cannot change the delimier in server mode. This happens because SQL Workbench does now know another delimiter during console mode. You can only change the delimiter in batch mode (see the documentation). So, if you want to change the delimiter, please open the buffer in batch mode.')
return
endif
call sw#session#set_buffer_variable('delimiter', a:new_del)
endfunction
......@@ -144,6 +149,10 @@ function! sw#sqlwindow#extract_current_sql(...)
let s = s . line . "\n"
endfor
if !exists('b:delimiter')
call sw#display_error("The buffer is not connected to a server. Please use SWSqlConectToServer before running queries")
return ''
endif
let sqls = sw#sql_split(s, b:delimiter)
for sql in sqls
if sql =~ '#CURSOR#'
......@@ -153,7 +162,7 @@ function! sw#sqlwindow#extract_current_sql(...)
return sql
endif
endfor
throw "Could not identifiy the current query"
call sw#display_error("Could not identifiy the current query")
return ""
endfunction
......@@ -459,7 +468,9 @@ function! sw#sqlwindow#execute_sql(wait_result, sql)
let w:auto_added1 = "-- auto\n"
let w:auto_added2 = "-- end auto\n"
call s:check_sql_buffer()
if (!s:check_sql_buffer())
return
endif
let _sql = a:sql
if !exists('b:no_variables')
let vars = sw#variables#extract(_sql)
......
......@@ -19,21 +19,12 @@
function! s:set_delimiters()
if !exists('g:sw_p_suffix') && !exists('g:sw_p_prefix')
let p1 = '\v\c^[\s \t]*workbench\.sql\.parameter\.(suffix|prefix)'
if exists('g:sw_config_dir')
let lines = readfile(g:sw_config_dir . 'workbench.settings')
for line in lines
if line =~ p1
let p2 = p1 . '[\s \t]*\=[\s\t ]*(.*)$'
let type = substitute(line, p2, '\1', 'g')
execute "let g:sw_p_" . type . " = substitute(line, p2, '\\2', 'g')"
endif
endfor
endif
if !exists('g:sw_p_prefix')
let g:sw_prefix = sw#get_sw_setting('workbench.sql.parameter.prefix')
let g:sw_suffix = sw#get_sw_setting('workbench.sql.parameter.suffix')
if g:sw_prefix == ''
let g:sw_p_prefix = '\$\['
endif
if !exists('g:sw_p_suffix')
if g:sw_suffix == ''
let g:sw_p_suffix = '\]'
endif
......
let sw_columns = {'title': 'Columns', 'shortcut': 'C', 'command': 'desc %3%.%0%'}
let sw_sql_source = {'title': 'SQL Source', 'shortcut': 'S', 'command': 'WbGrepSource -searchValues="%object%" -objects=%object% -types=* -useRegex=true -schemas=*; -- AFTERcall sw#dbexplorer#fix_source_code()', 'skip_columns': [0, 1], 'hide_header': 1, 'filetype': 'sql'}
let sw_data = {'title': 'Data', 'shortcut': 'D', 'command': 'select * from %3%.%0%'}
let sw_indexes = {'title': 'Indexes', 'shortcut': 'I', 'command': 'WbListIndexes -tableName=%object% -schema=%3%'}
let sw_referenced_by = {'title': 'Referenced by', 'shortcut': 'R', 'command': 'WbGrepSource -searchValues="references %object%" -types=TABLE -useRegex=false -schemas=*;', 'skip_columns': [2]}
let objects = {'title': 'Objects', 'shortcut': 'O', 'command': 'WbList -objects=% -types=SYNONYM,SEQUENCE,TABLE,TYPE,VIEW', 'panels': [sw_columns, sw_sql_source, sw_data, sw_indexes, sw_referenced_by]}
let procedures = {'title': 'Procedures', 'shortcut': 'P', 'command': 'WbListProcs;', 'panels': [sw_sql_source]}
let triggers = {'title': 'Triggers', 'shortcut': 'T', 'command': 'WbListTriggers;', 'panels': [sw_sql_source]}
let g:SW_Tabs = {'*': [objects, procedures, triggers]}
let sw_columns = {'title': 'Columns', 'shortcut': 'C', 'command': 'desc %object%;'}
" General panel (for all DBMS) with the exception of PostgreSQL
let sw_sql_source = {'title': 'SQL Source', 'shortcut': 'S', 'command': 'WbGrepSource -searchValues="%object%" -objects=%object% -types=* -useRegex=true; -- AFTERcall sw#dbexplorer#fix_source_code()', 'skip_columns': [0, 1], 'hide_header': 1, 'filetype': 'sql'}
let row_counts = {'title': 'Row Counts', 'shortcut': 'W', 'command': 'WbRowCount;', 'panels': []}
let sw_columns = {'title': 'Columns', 'shortcut': 'C', 'command': 'desc %object%;'}
let sw_sql_source = {'title': 'SQL Source', 'shortcut': 'S', 'command': 'WbGenerateScript -objects="%object%"', 'filetype': 'sql'}
let sw_sql_source_triggers = {'title': 'SQL Source', 'shortcut': 'S', 'command': 'WbGrepSource -searchValues="%object%" -objects=%object% -types=* -useRegex=true; -- AFTERcall sw#dbexplorer#fix_source_code()', 'filetype': 'sql', 'skip_columns': [0, 1], 'hide_header': 1}
let sw_data = {'title': 'Data', 'shortcut': 'D', 'command': 'select * from %object%;'}
let sw_indexes = {'title': 'Indexes', 'shortcut': 'I', 'command': 'WbListIndexes -tableName=%object%;'}
let sw_referenced_by = {'title': 'Referenced by', 'shortcut': 'R', 'command': 'WbGrepSource -searchValues="references %object%" -types=TABLE -useRegex=false;', 'skip_columns': [2]}
let objects = {'title': 'Objects', 'shortcut': 'O', 'command': 'WbList -objects=% -types=SYNONYM,SEQUENCE,TABLE,TYPE,VIEW', 'panels': [sw_columns, sw_sql_source, sw_data, sw_indexes, sw_referenced_by]}
let sw_sql_source = {'title': 'SQL Source', 'shortcut': 'S', 'command': 'WbProcSource %object%', 'filetype': 'sql'}
let procedures = {'title': 'Procedures', 'shortcut': 'P', 'command': 'WbListProcs;', 'panels': [sw_sql_source]}
let triggers = {'title': 'Triggers', 'shortcut': 'T', 'command': 'WbListTriggers;', 'panels': [sw_sql_source]}
let g:SW_Tabs = {'*': [objects, procedures, triggers]}
let triggers = {'title': 'Triggers', 'shortcut': 'T', 'command': 'WbListTriggers;', 'panels': [sw_sql_source_triggers]}
let g:SW_Tabs = {'^postgresql': [objects, procedures, triggers, row_counts]}
" PostgreSQL panel
let sw_sql_source = {'title': 'SQL Source', 'shortcut': 'S', 'command': 'WbGenerateScript -objects="%object%"', 'filetype': 'sql'}
let sw_columns = {'title': 'Columns', 'shortcut': 'C', 'command': 'desc %3%.%0%'}
let sw_data = {'title': 'Data', 'shortcut': 'D', 'command': 'select * from %3%.%0%'}
let sw_indexes = {'title': 'Indexes', 'shortcut': 'I', 'command': 'WbListIndexes -tableName=%object% -schema=%3%'}
let sw_referenced_by = {'title': 'Referenced by', 'shortcut': 'R', 'command': 'WbGrepSource -searchValues="references %object%" -types=TABLE -useRegex=false -schemas=*;', 'skip_columns': [2]}
let objects = {'title': 'Objects', 'shortcut': 'O', 'command': 'WbList', 'panels': [sw_columns, sw_sql_source, sw_data, sw_indexes, sw_referenced_by]}
let sw_sql_source_proc = {'title': 'SQL Source', 'shortcut': 'S', 'command': ':sw#dbexplorer#postgre_proc', 'filetype': 'sql'}
let sw_sql_source_triggers = {'title': 'SQL Source', 'shortcut': 'S', 'command': 'WbGrepSource -searchValues="%object%" -objects=%object% -types=* -useRegex=true -schemas=*; -- AFTERcall sw#dbexplorer#fix_source_code()', 'skip_columns': [0, 1], 'hide_header': 1, 'filetype': 'sql'}
let procedures = {'title': 'Procedures', 'shortcut': 'P', 'command': 'WbListProcs;', 'panels': [sw_sql_source_proc]}
let triggers = {'title': 'Triggers', 'shortcut': 'T', 'command': 'WbListTriggers;', 'panels': [sw_sql_source_triggers]}
let schemas = {'title': 'Show schemas', 'shortcut': 'M', 'command': 'wblistschemas;', 'panels': [{'title': 'Select schema', 'shortcut': 'H', 'command': "set search_path to %object%;"}, {'title': 'Select *', 'shortcut': 'A', 'command': "set search_path to '*.*'"}]}
let g:SW_Tabs[':postgresql'] = [objects, procedures, triggers, schemas, row_counts]
" Oracle specific panel
let oracle_dblinks = {'title': 'DB Links', 'shortcut': 'L', 'command': 'select db_link, username, created from user_db_links;', 'panels': [{'title': 'Show the host', 'shortcut': 'H', 'command': "select host from user_db_links where db_link = '%object%'"}]}
let oracle_jobs = {'title': 'User Jobs', 'shortcut': 'J', 'command': 'select job_name, job_creator, start_date, repeat_interval from user_scheduler_jobs', 'panels': [{'title': 'Job source', 'shortcut': 'S', 'command': "select job_action from user_scheduler_jobs where job_name = '%object%'", 'hide_header': 1, 'filetype': 'sql'}]}
let oracle_packages = {'title': 'Packages', 'shortcut': 'K', 'command': "select OBJECT_NAME, OBJECT_TYPE, STATUS from user_objects where object_type in ('PACKAGE');", 'panels': [{'title': 'SQL Source', 'shortcut': 'S', 'command': "wbprocsource %object%", 'filetype': 'sql'}, {'title': 'Compile', 'shortcut': 'E', 'command': 'alter package %object% compile package'}]}
let oracle_schemas = {'title': 'Show schemas', 'shortcut': 'M', 'command': 'wblistschemas;', 'panels': [{'title': 'Select schema', 'shortcut': 'H', 'command': "alter session set current_schema = %object%;"}]}
let g:SW_Tabs[':oracle'] = [oracle_dblinks, oracle_jobs, oracle_packages, oracle_schemas]
......@@ -22,16 +22,18 @@ class SQLWorkbench(object):
port = 5000
results = {}
debug = 0
colwidth = 120
threads_started = 0
vim = 'vim'
tmp = "/tmp"
clock = datetime.datetime.now()
quit = False
lock = thread.allocate_lock()
executing = thread.allocate_lock()
processing = thread.allocate_lock()
new_loop = thread.allocate_lock()
prompt_pattern_begin = '^[a-zA-Z_0-9\\.]+(\\@[a-zA-Z_0-9/]+)?\\>[ \s\t]*'
prompt_pattern = prompt_pattern_begin + '$'
resultset_end_pattern = 'send_to_vim set to'
buff = ''
dbe_connections = {}
identifier = None
......@@ -53,11 +55,13 @@ class SQLWorkbench(object):
def parseCustomCommand(self, command):
if command[0] == 'identifier':
self.identifier = command[1]
elif command[0] == 'colwidth':
self.colwidth = command[1]
#end if
#end def parseCustomCommand
def gotCustomCommand(self, text):
pattern = '^!#(identifier|end)[ \\s\\t]*=[ \\s\\t]*([A-Za-z_0-9#]+)[ \\s\\t\\n\\r]*$'
pattern = '^!#(identifier|end|colwidth)[ \\s\\t]*=[ \\s\\t]*([A-Za-z_0-9#]+)[ \\s\\t\\n\\r]*$'
p = re.search(pattern, text)
if p != None:
return [p.group(1), p.group(2)]
......@@ -145,7 +149,12 @@ class SQLWorkbench(object):
def spawnDbeConnection(self, profile, conn):
self.startThread()
cmd = "%s -feedback=true -showProgress=false -profile=%s" % (self.cmd, profile)
pattern = '^([^\\\\]+)\\\\(.*)$'
_p = profile
if re.match(pattern, profile) != None:
_p = re.sub(pattern, '\\2', profile) + " -profileGroup=" + re.sub(pattern, '\\1', profile)
#end if
cmd = "%s -feedback=true -showProgress=false -profile=%s" % (self.cmd, _p)
pipe = subprocess.Popen(shlex.split(cmd), stdin = subprocess.PIPE, stdout = subprocess.PIPE, bufsize = 1)
pipe.stdin.write('set maxrows = 100;\n')
conn.send('DISCONNECT')
......@@ -181,7 +190,10 @@ class SQLWorkbench(object):
pipe = self.dbe_connections[profile]
data = conn.recv(4096)
if (data):
data += "\nwbvardef send_to_vim = 1;\nwbvardelete send_to_vim;\n"
data += "\nwbsetconfig send_to_vim=1;\n"
if self.debug:
print "SEND TO SERVER: " + data
#end if
pipe.stdin.write(data)
result = self.receiverDbe(pipe)
conn.send(self.prepareResult(result))
......@@ -219,44 +231,46 @@ class SQLWorkbench(object):
#end def readData
def receiveData(self, conn, pipe, n):
with self.processing:
self.identifier = None
buff = self.readData(conn, n)
lines = buff.split("\n")
for line in lines:
if re.search('^!#', line) != None:
command = self.gotCustomCommand(line)
if command != None:
self.parseCustomCommand(command)
#end if
else:
self.clock = datetime.datetime.now()
self.identifier = None
buff = self.readData(conn, n)
lines = buff.split("\n")
for line in lines:
if re.search('^!#', line) != None:
command = self.gotCustomCommand(line)
if command != None:
self.parseCustomCommand(command)
#end if
else:
if self.debug:
print "SENT TO SERVER: " + line
#end if
if line != '':
pipe.stdin.write(line + "\n")
#end if
#end if
#end for
with self.new_loop:
pipe.stdin.write("wbsetconfig send_to_vim=1;\n")
if self.debug:
print "SENT TO SERVER: wbsetconfig send_to_vim=1;"
#end if
if self.identifier == None:
with self.executing:
data = self.prepareResult(self.buff)
conn.send(data)
#end with
else:
with self.executing:
p = self.getCaller()
if self.debug:
print "SENT TO SERVER: " + line
print "RESULT STORED FOR %s" % p.group(1) + "#" + p.group(2)
#end if
if line != '':
pipe.stdin.write(line + "\n")
if p != None:
self.toVim('sw#got_async_result(\\"%s\\")' % p.group(2))
#end if
#end if
#end for
with self.new_loop:
pipe.stdin.write("wbvardef send_to_vim = 1;\nwbvardelete send_to_vim;\n")
if self.identifier == None:
with self.executing:
data = self.prepareResult(self.buff)
conn.send(data)
#end with
else:
with self.executing:
p = self.getCaller()
if self.debug:
print "RESULT STORED FOR %s" % p.group(1) + "#" + p.group(2)
#end if
if p != None:
self.toVim('sw#got_async_result(\\"%s\\")' % p.group(2))
#end if
#end with
#end if
#end with
#end with
#end if
#end with
#end def receiveData
......@@ -280,7 +294,7 @@ class SQLWorkbench(object):
elif data == 'RES':
self.searchResult(conn, n - 3)
elif data == 'DBE':
self.dbExplorer(conn, n)
self.dbExplorer(conn, n - 3)
#end if
conn.close()
#end def newConnection
......@@ -328,7 +342,7 @@ class SQLWorkbench(object):
def receiverDbe(self, pipe):
line = ''
buff = ''
while re.search('using.*send_to_vim', line) == None:
while re.search(self.resultset_end_pattern, line) == None:
line = pipe.stdout.readline()
buff += line
if self.debug:
......@@ -349,8 +363,11 @@ class SQLWorkbench(object):
self.buff = ''
#end with
with self.executing:
while re.search('send_to_vim', line) == None:
while re.search(self.resultset_end_pattern, line) == None:
line = pipe.stdout.readline()
if re.match('^\x1b', line) != None:
continue
#end if
if line:
if re.search(self.prompt_pattern_begin, line) != None:
if not first_prompt:
......@@ -368,11 +385,15 @@ class SQLWorkbench(object):
#end if
#end while
if self.identifier != None:
self.buff += "Total time: %.2g seconds" % (datetime.datetime.now() - self.clock).total_seconds()
self.clock = datetime.datetime.now()
if self.identifier in self.results:
self.results[self.identifier] += "\n" + self.buff
else:
self.results[self.identifier] = self.buff
#end if
self.buff = ''
#end if
#end with
......@@ -391,7 +412,7 @@ class SQLWorkbench(object):
cmd = "%s -feedback=true -showProgress=false" % (self.cmd)
if (self.profile != None):
cmd += " -profile=%s" % self.profile
cmd += " -profile=%s" % profile
#end if
if self.debug:
print "OPENING: " + cmd
......@@ -412,6 +433,22 @@ class SQLWorkbench(object):
with self.lock:
self.quit = True
#end try...except
try:
pipe.stdin.write('exit\n')
for key in self.dbe_connections:
try:
self.dbe_connections[key].stdin.write('exit\n')
except Exception:
if self.debug:
print "No pipe to send exit for " + key
#end if
#end try
#end for
except Exception:
if self.debug:
print "No pipe to send exit"
#end if
#end try
print "Waiting for server to stop..."
while self.threads_started > 0:
time.sleep(0.3)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册