From 5dfe530f1e3a7e41315ee04ed22b349f4548988c Mon Sep 17 00:00:00 2001 From: Connor Duncan Date: Wed, 15 May 2024 10:32:37 -0500 Subject: [PATCH 1/9] initial adapter commit. currently only supports connecting using snowsql config file --- autoload/db/adapter/snowflake.vim | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 autoload/db/adapter/snowflake.vim diff --git a/autoload/db/adapter/snowflake.vim b/autoload/db/adapter/snowflake.vim new file mode 100644 index 0000000..84ab5f1 --- /dev/null +++ b/autoload/db/adapter/snowflake.vim @@ -0,0 +1,40 @@ +if exists('g:autoloaded_db_snowflake') + finish +endif +let g:autoloaded_db_snowflake = 1 + +function! s:command_for_url(url) abort + let cmd = ['snowsql'] + return cmd + db#url#as_argv(a:url, '-c', '', '', '', '', '') +endfunction + +function! db#adapter#snowflake#interactive(url) abort + echomsg "starting snowsql. executing query" + return s:command_for_url(a:url) +endfunction + +function! db#adapter#snowflake#input_flag() abort + return ' -f ' +endfunction + +function! db#adapter#snowflake#complete_opaque(url) abort + return db#adapter#snowflake#complete_database(url) +endfunction + +function! db#adapter#snowflake#complete_database(url) abort + let cmd = s:command_for_url(a:url) + let cmd .= ' --query "show databases"' + let out = system(cmd) + let dbs = [] + for i in split(out, "\n")[6:-1] + let dbname = split(i, "|") + if len(dbname) > 2 + call add(dbs, trim(dbname[1])) + endif + endfor + return dbs +endfunction + +function! db#adapter#snowflake#tables(url) abort + return db#systemlist(s:command_for_url(a:url) + ['-q', "select tbl.table_name from information_schema.tables tbl"]+['-o', 'output_format=plain']) +endfunction From 4f2bebb24728acf786d86ccbfd1d2310540469f4 Mon Sep 17 00:00:00 2001 From: Connor Duncan Date: Wed, 22 May 2024 08:22:34 -0500 Subject: [PATCH 2/9] got snowflake working with reasonable url defaults --- autoload/db/adapter/snowflake.vim | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/autoload/db/adapter/snowflake.vim b/autoload/db/adapter/snowflake.vim index 84ab5f1..a2a0fb3 100644 --- a/autoload/db/adapter/snowflake.vim +++ b/autoload/db/adapter/snowflake.vim @@ -4,8 +4,21 @@ endif let g:autoloaded_db_snowflake = 1 function! s:command_for_url(url) abort - let cmd = ['snowsql'] - return cmd + db#url#as_argv(a:url, '-c', '', '', '', '', '') + " snowflake://username:password@account/database/?warehouse=<+>?schema<+> + " extra parameters that can be passed are connection parameters, _not_ + " options that can be given with `-o option=value`. + " Params here are connection parameters (https://docs.snowflake.com/en/user-guide/snowsql-start) + " NOT configuration options + " (https://docs.snowflake.com/en/user-guide/snowsql-config#connection-parameters-section). + let url = db#url#parse(a:url) + "extra options here turn off nonsense before/after results + let cmd = (has_key(url, 'password') ? ['env', 'SNOWSQL_PWD=' . url.password] : []) + + \ ['snowsql', '-o', 'friendly=false', '-o', 'timing=false'] + + \ db#url#as_argv(a:url, '-a ', '', '', '-u ', '','-d ') + for i in keys(url.params) + let cmd += ['--'.i.'='.url.params[i]] + endfor + return cmd endfunction function! db#adapter#snowflake#interactive(url) abort @@ -24,9 +37,10 @@ endfunction function! db#adapter#snowflake#complete_database(url) abort let cmd = s:command_for_url(a:url) let cmd .= ' --query "show databases"' + " if cmd looks to have no cli args, treat it as a string let out = system(cmd) let dbs = [] - for i in split(out, "\n")[6:-1] + for i in split(out, "\n") let dbname = split(i, "|") if len(dbname) > 2 call add(dbs, trim(dbname[1])) @@ -34,7 +48,3 @@ function! db#adapter#snowflake#complete_database(url) abort endfor return dbs endfunction - -function! db#adapter#snowflake#tables(url) abort - return db#systemlist(s:command_for_url(a:url) + ['-q', "select tbl.table_name from information_schema.tables tbl"]+['-o', 'output_format=plain']) -endfunction From a6a2ea7cada456a4266b229eeb7f3416850595f3 Mon Sep 17 00:00:00 2001 From: Connor Duncan Date: Wed, 22 May 2024 08:34:37 -0500 Subject: [PATCH 3/9] add snowflake connection doc --- doc/dadbod.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/dadbod.txt b/doc/dadbod.txt index ec1cb49..d96ba7f 100644 --- a/doc/dadbod.txt +++ b/doc/dadbod.txt @@ -190,6 +190,20 @@ Redis ~ Redis doesn't have a username, so use a dummy one in the URL if a password is required. + *dadbod-snowflake* +Snowflake ~ +> + snowflake:://[[:]@[]]/[] +< +If password is not given, snowsql will default to the $SNOWSQL_PWD environment +variable. + +Supported query parameters are connection parameters that can be passed to +snowsql. `accountname`, `username` and `database` are already provided by the +url. Other supported options can be found at +`https://docs.snowflake.com/en/user-guide/snowsql-start#connection-syntax` + + *dadbod-sqlserver* SQL Server ~ > From f5ef02d668625c86549f51ed1499ff9a0c076710 Mon Sep 17 00:00:00 2001 From: Connor Duncan Date: Wed, 22 May 2024 08:54:14 -0500 Subject: [PATCH 4/9] add snowflake to readme --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index da36ef8..fe7717a 100644 --- a/README.markdown +++ b/README.markdown @@ -21,6 +21,7 @@ take on [dbext.vim][], improving on it on the following ways: - PostgreSQL - Presto - Redis + - Snowflake - SQL Server - SQLite - Your own easily implemented adapter From 77f6b5eb1c8f488d23390b899045c7c661467cf5 Mon Sep 17 00:00:00 2001 From: Connor Duncan Date: Wed, 22 May 2024 17:53:13 -0500 Subject: [PATCH 5/9] Remove unnecessary comments in snowflake.vim --- autoload/db/adapter/snowflake.vim | 6 ------ 1 file changed, 6 deletions(-) diff --git a/autoload/db/adapter/snowflake.vim b/autoload/db/adapter/snowflake.vim index a2a0fb3..2fdecf0 100644 --- a/autoload/db/adapter/snowflake.vim +++ b/autoload/db/adapter/snowflake.vim @@ -4,12 +4,6 @@ endif let g:autoloaded_db_snowflake = 1 function! s:command_for_url(url) abort - " snowflake://username:password@account/database/?warehouse=<+>?schema<+> - " extra parameters that can be passed are connection parameters, _not_ - " options that can be given with `-o option=value`. - " Params here are connection parameters (https://docs.snowflake.com/en/user-guide/snowsql-start) - " NOT configuration options - " (https://docs.snowflake.com/en/user-guide/snowsql-config#connection-parameters-section). let url = db#url#parse(a:url) "extra options here turn off nonsense before/after results let cmd = (has_key(url, 'password') ? ['env', 'SNOWSQL_PWD=' . url.password] : []) + From d29f7f8d97a9075ab6f0d2240cac2bf28dce05a1 Mon Sep 17 00:00:00 2001 From: Connor Duncan Date: Fri, 31 May 2024 12:19:36 -0500 Subject: [PATCH 6/9] Fix snowflake DB completion, use of outdated methods --- autoload/db/adapter/snowflake.vim | 35 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/autoload/db/adapter/snowflake.vim b/autoload/db/adapter/snowflake.vim index 2fdecf0..07a4339 100644 --- a/autoload/db/adapter/snowflake.vim +++ b/autoload/db/adapter/snowflake.vim @@ -2,12 +2,12 @@ if exists('g:autoloaded_db_snowflake') finish endif let g:autoloaded_db_snowflake = 1 - +let s:no_timing_friendly = ['-o', 'friendly=false', '-o', 'timing=false'] function! s:command_for_url(url) abort let url = db#url#parse(a:url) "extra options here turn off nonsense before/after results let cmd = (has_key(url, 'password') ? ['env', 'SNOWSQL_PWD=' . url.password] : []) + - \ ['snowsql', '-o', 'friendly=false', '-o', 'timing=false'] + + \[ "snowsql" ] + \ db#url#as_argv(a:url, '-a ', '', '', '-u ', '','-d ') for i in keys(url.params) let cmd += ['--'.i.'='.url.params[i]] @@ -15,13 +15,16 @@ function! s:command_for_url(url) abort return cmd endfunction +function! db#adapter#snowflake#filter(url) abort + return s:command_for_url(a:url) + s:no_timing_friendly +endfunction + function! db#adapter#snowflake#interactive(url) abort - echomsg "starting snowsql. executing query" return s:command_for_url(a:url) endfunction -function! db#adapter#snowflake#input_flag() abort - return ' -f ' +function! db#adapter#snowflake#input(url, in) abort + return db#adapter#snowflake#filter(a:url) + ['-f', a:in] endfunction function! db#adapter#snowflake#complete_opaque(url) abort @@ -29,16 +32,14 @@ function! db#adapter#snowflake#complete_opaque(url) abort endfunction function! db#adapter#snowflake#complete_database(url) abort - let cmd = s:command_for_url(a:url) - let cmd .= ' --query "show databases"' - " if cmd looks to have no cli args, treat it as a string - let out = system(cmd) - let dbs = [] - for i in split(out, "\n") - let dbname = split(i, "|") - if len(dbname) > 2 - call add(dbs, trim(dbname[1])) - endif - endfor - return dbs + let pre = matchstr(a:url, '[^:]\+://.\{-\}/') + let cmd = s:command_for_url(pre) + + \['-q', 'show terse databases'] + + \s:no_timing_friendly + + \['-o', 'header=false', '-o', 'output_format=tsv'] + " snowflake does not allow you to get only the database names out. + " querying names from information_schema requires an active warehouse, + " which defeats the purpose of having tab-completion here. + let out = map(db#systemlist(cmd), {_, v -> split(v, "\t")[1]}) + return out endfunction From 60b814de6a05e263f8c48d0efd89f199a432eca2 Mon Sep 17 00:00:00 2001 From: Connor Duncan Date: Tue, 4 Jun 2024 11:46:39 -0500 Subject: [PATCH 7/9] Resolve interactive filter issue, formatting --- autoload/db/adapter/snowflake.vim | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/autoload/db/adapter/snowflake.vim b/autoload/db/adapter/snowflake.vim index 07a4339..5c0be6e 100644 --- a/autoload/db/adapter/snowflake.vim +++ b/autoload/db/adapter/snowflake.vim @@ -1,14 +1,11 @@ -if exists('g:autoloaded_db_snowflake') - finish -endif -let g:autoloaded_db_snowflake = 1 let s:no_timing_friendly = ['-o', 'friendly=false', '-o', 'timing=false'] + function! s:command_for_url(url) abort let url = db#url#parse(a:url) "extra options here turn off nonsense before/after results let cmd = (has_key(url, 'password') ? ['env', 'SNOWSQL_PWD=' . url.password] : []) + - \[ "snowsql" ] + - \ db#url#as_argv(a:url, '-a ', '', '', '-u ', '','-d ') + \ [ "snowsql" ] + + \ db#url#as_argv(a:url, '-a ', '', '', '-u ', '','-d ') for i in keys(url.params) let cmd += ['--'.i.'='.url.params[i]] endfor @@ -20,6 +17,9 @@ function! db#adapter#snowflake#filter(url) abort endfunction function! db#adapter#snowflake#interactive(url) abort + " in neovim, this only spawns a terminal if vim-dispatch and + " vim-dispatch-neovim are installed. it also uses the snowflake LLM to + " handle autocompletion. return s:command_for_url(a:url) endfunction @@ -34,9 +34,9 @@ endfunction function! db#adapter#snowflake#complete_database(url) abort let pre = matchstr(a:url, '[^:]\+://.\{-\}/') let cmd = s:command_for_url(pre) + - \['-q', 'show terse databases'] + - \s:no_timing_friendly + - \['-o', 'header=false', '-o', 'output_format=tsv'] + \ ['-q', 'show terse databases'] + + \ s:no_timing_friendly + + \ ['-o', 'header=false', '-o', 'output_format=tsv'] " snowflake does not allow you to get only the database names out. " querying names from information_schema requires an active warehouse, " which defeats the purpose of having tab-completion here. From 92cab7cb6f3c6b3091b4064f66de7c9e012258b9 Mon Sep 17 00:00:00 2001 From: Tim Pope Date: Mon, 14 Oct 2024 21:11:52 -0400 Subject: [PATCH 8/9] Clean up Snowflake documentation --- doc/dadbod.txt | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/doc/dadbod.txt b/doc/dadbod.txt index d96ba7f..2c37b65 100644 --- a/doc/dadbod.txt +++ b/doc/dadbod.txt @@ -193,16 +193,10 @@ required. *dadbod-snowflake* Snowflake ~ > - snowflake:://[[:]@[]]/[] + snowflake://[[:]@[]]/[] < -If password is not given, snowsql will default to the $SNOWSQL_PWD environment -variable. - -Supported query parameters are connection parameters that can be passed to -snowsql. `accountname`, `username` and `database` are already provided by the -url. Other supported options can be found at -`https://docs.snowflake.com/en/user-guide/snowsql-start#connection-syntax` - +Query parameters can be used to set additional command line options (e.g., +`?warehouse=foo`). *dadbod-sqlserver* SQL Server ~ From 36b22c177671955098ecf9a58c141231eee491dd Mon Sep 17 00:00:00 2001 From: Tim Pope Date: Mon, 14 Oct 2024 21:12:54 -0400 Subject: [PATCH 9/9] Clean up Snowflake implementation --- autoload/db/adapter/snowflake.vim | 36 ++++++++++--------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/autoload/db/adapter/snowflake.vim b/autoload/db/adapter/snowflake.vim index 5c0be6e..26a67fe 100644 --- a/autoload/db/adapter/snowflake.vim +++ b/autoload/db/adapter/snowflake.vim @@ -1,26 +1,17 @@ -let s:no_timing_friendly = ['-o', 'friendly=false', '-o', 'timing=false'] - -function! s:command_for_url(url) abort +function! db#adapter#snowflake#interactive(url) abort let url = db#url#parse(a:url) - "extra options here turn off nonsense before/after results let cmd = (has_key(url, 'password') ? ['env', 'SNOWSQL_PWD=' . url.password] : []) + - \ [ "snowsql" ] + - \ db#url#as_argv(a:url, '-a ', '', '', '-u ', '','-d ') - for i in keys(url.params) - let cmd += ['--'.i.'='.url.params[i]] + \ ["snowsql"] + + \ db#url#as_argv(a:url, '-a ', '', '', '-u ', '','-d ') + for [k, v] in items(url.params) + call add(cmd, '--' . k . '=' . v) endfor return cmd endfunction function! db#adapter#snowflake#filter(url) abort - return s:command_for_url(a:url) + s:no_timing_friendly -endfunction - -function! db#adapter#snowflake#interactive(url) abort - " in neovim, this only spawns a terminal if vim-dispatch and - " vim-dispatch-neovim are installed. it also uses the snowflake LLM to - " handle autocompletion. - return s:command_for_url(a:url) + return db#adapter#snowflake#interactive(a:url) + + \ ['-o', 'friendly=false', '-o', 'timing=false'] endfunction function! db#adapter#snowflake#input(url, in) abort @@ -33,13 +24,8 @@ endfunction function! db#adapter#snowflake#complete_database(url) abort let pre = matchstr(a:url, '[^:]\+://.\{-\}/') - let cmd = s:command_for_url(pre) + - \ ['-q', 'show terse databases'] + - \ s:no_timing_friendly + - \ ['-o', 'header=false', '-o', 'output_format=tsv'] - " snowflake does not allow you to get only the database names out. - " querying names from information_schema requires an active warehouse, - " which defeats the purpose of having tab-completion here. - let out = map(db#systemlist(cmd), {_, v -> split(v, "\t")[1]}) - return out + let cmd = db#adapter#snowflake#filter(pre) + + \ ['-o', 'header=false', '-o', 'output_format=tsv'] + + \ ['-q', 'show terse databases'] + return map(db#systemlist(cmd), { _, v -> split(v, "\t")[1] }) endfunction