├── README ├── autoload └── SQLUtilities.vim ├── doc └── SQLUtilities.txt └── plugin └── SQLUtilities.vim /README: -------------------------------------------------------------------------------- 1 | This is a mirror of http://www.vim.org/scripts/script.php?script_id=492 2 | 3 | Various SQL Utilities. 4 | 5 | Version 2.0 requires Vim 7. 6 | 7 | 1. A SQL formatter, to make SQL statements (select, insert, update, delete...) more readable. 8 | 2. Based on create table statements, will generate select lists for a table, as long as the definition exists in some open buffer. 9 | 3. Creates a generic procedure that will perform an insert, update, delete and select based on the definition of a table (if already open in some buffer). The format is ANSI. 10 | 4. Returns the column datatype definition for a specified column name (or supplied) based on the definition of a table (if already open in some buffer). 11 | 12 | Functions: 13 | [range]SQLUFormatter(..list..) 14 | 15 | Formats SQL statements into a easily readable form. 16 | Breaks keywords onto new lines. 17 | Forces column lists to be split over as many lines as 18 | necessary to fit the current textwidth of the buffer, 19 | so that lines do not wrap. 20 | If parentheses are unbalanced (ie a subselect) it will 21 | indent everything within the unbalanced paranthesis. 22 | Works for SELECT, INSERT, UPDATE, DELETE statements. 23 | 24 | Global variables to customization some aspects of the formatting: 25 | sqlutil_align_where - aligns the =, >=, <=, ... 26 | sqlutil_align_comma - places the column lists in select statement on new lines 27 | sqlutil_align_first_word - see examples 28 | 29 | You can change the case of the keywords while formatting. 30 | 31 | 32 | Examples (these would look much better when using a fixed font): 33 | 34 | Original: 35 | SELECT m.MSG_ID, m.PRIORITY_ID, CUST.CUST_NBR, CUST.CUST_NM, 36 | CUST.CUST_LEGAL_NM, CUST.STORE_ADDR_1, CUST.STORE_ADDR_2, 37 | CUST.CROSS_STREET, XMLELEMENT( 'Alerts', XMLELEMENT( 'Alert_alert_id', 38 | alert_id ), XMLELEMENT( 'Alert_agent_id', agent_id ), XMLELEMENT( 39 | 'Alert_alert_type_id', alert_type_desc), XMLELEMENT( 40 | 'Alert_alert_date', alert_date), XMLELEMENT( 41 | 'Alert_url_reference', url_reference), XMLELEMENT( 42 | 'Alert_read_status', read_status )) CUST.STORE_CITY, 43 | CUST.STORE_ST, CUST.POST_CODE, CUST.STORE_MGR_NM, FROM MESSAGES m JOIN 44 | PRIORITY_CD P WHERE m.to_person_id = ? AND p.NAME = 'PRI_EMERGENCY' AND 45 | p.JOB = 'Plumber' AND m.status_id < ( SELECT s.STATUS_ID FROM 46 | MSG_STATUS_CD s WHERE s.NAME = 'MSG_READ') ORDER BY m.msg_id desc 47 | 48 | 49 | Formatted: 50 | SELECT m.MSG_ID, m.PRIORITY_ID, CUST.CUST_NBR, CUST.CUST_NM, 51 | CUST.CUST_LEGAL_NM, CUST.STORE_ADDR_1, CUST.STORE_ADDR_2, 52 | CUST.CROSS_STREET, 53 | XMLELEMENT( 54 | 'Alerts', XMLELEMENT( 'Alert_alert_id', alert_id ), 55 | XMLELEMENT( 'Alert_agent_id', agent_id ), 56 | XMLELEMENT( 'Alert_alert_type_id', alert_type_desc), 57 | XMLELEMENT( 'Alert_alert_date', alert_date), 58 | XMLELEMENT( 59 | 'Alert_url_reference', url_reference 60 | ), XMLELEMENT( 'Alert_read_status', read_status ) 61 | ) CUST.STORE_CITY, CUST.STORE_ST, CUST.POST_CODE, 62 | CUST.STORE_MGR_NM 63 | FROM MESSAGES m 64 | JOIN PRIORITY_CD P 65 | WHERE m.to_person_id = ? 66 | AND p.NAME = 'PRI_EMERGENCY' 67 | AND p.JOB = 'Plumber' 68 | AND m.status_id < ( 69 | SELECT s.STATUS_ID 70 | FROM MSG_STATUS_CD s 71 | WHERE s.NAME = 'MSG_READ' 72 | ) 73 | ORDER BY m.msg_id desc 74 | 75 | 76 | 77 | Original: 78 | UPDATE "SERVICE_REQUEST" SET "BUILDING_ID" = ?, "UNIT_ID" = ?, 79 | "REASON_ID" = ?, "PERSON_ID" = ?, "PRIORITY_ID" = ?, "STATUS_ID" = ?, 80 | "CREATED" = ?, "REQUESTED" = ?, "ARRIVED" = ? WHERE "REQUEST_ID" = ? 81 | 82 | 83 | Formatted: 84 | UPDATE "SERVICE_REQUEST" 85 | SET "BUILDING_ID" = ?, 86 | "UNIT_ID" = ?, 87 | "REASON_ID" = ?, 88 | "PERSON_ID" = ?, 89 | "PRIORITY_ID" = ?, 90 | "STATUS_ID" = ?, 91 | "CREATED" = ?, 92 | "REQUESTED" = ?, 93 | "ARRIVED" = ?, 94 | WHERE "REQUEST_ID" = ? 95 | 96 | 97 | 98 | Original: 99 | INSERT INTO "MESSAGES" ( "MSG_ID", "TO_PERSON_ID", 100 | "FROM_PERSON_ID", "REQUEST_ID", "CREATED", "PRIORITY_ID", 101 | "MSG_TYPE_ID", "STATUS_ID", "READ_WHEN", "TIMEOUT", 102 | "MSG_TXT", "RESEND_COUNT" ) VALUES ( ?, ?, ?, 103 | ?, ?, ?, ?, ?, ?, ?, ?, ? ) 104 | 105 | 106 | Formatted: 107 | INSERT INTO "MESSAGES" ( "MSG_ID", "TO_PERSON_ID", 108 | "FROM_PERSON_ID", "REQUEST_ID", "CREATED", 109 | "PRIORITY_ID", "MSG_TYPE_ID", "STATUS_ID", 110 | "READ_WHEN", "TIMEOUT", "MSG_TXT", "RESEND_COUNT" ) 111 | VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 112 | 113 | 114 | Functions: 115 | SQLUCreateColumnList( optional parameter ) 116 | 117 | Assumes either the current file, or any other open buffer, 118 | has a CREATE TABLE statement in a format similar to this: 119 | CREATE TABLE customer ( 120 | id INT DEFAULT AUTOINCREMENT, 121 | last_modified TIMESTAMP NULL, 122 | first_name VARCHAR(30) NOT NULL, 123 | last_name VARCHAR(60) NOT NULL, 124 | balance NUMERIC(10,2), 125 | PRIMARY KEY( id ) 126 | ); 127 | If you place the cursor on the word customer, then the 128 | unnamed buffer (also displayed by an echo statement) will 129 | contain: 130 | id, last_modified, first_name, last_name, balance 131 | 132 | Optionally, it will replace the word with the above and place 133 | the word in the unnamed buffer. Calling the function with 134 | a parameter enables this feature. 135 | 136 | This also uses the g:sqlutil_cmd_terminator to determine when 137 | the create table statement ends if none of the following terms 138 | are found before the final ); 139 | primary,reference,unique,check,foreign 140 | sqlutil_cmd defaults to ";" 141 | 142 | 143 | Functions: 144 | SQLUGetColumnDef( optional parameter ) 145 | SQLUGetColumnDataType( expand(""), 1 ) 146 | 147 | Assumes either the current file, or any other open buffer, 148 | has a CREATE TABLE statement in a format similar to this: 149 | CREATE TABLE customer ( 150 | id INT DEFAULT AUTOINCREMENT, 151 | last_modified TIMESTAMP NULL, 152 | first_name VARCHAR(30) NOT NULL, 153 | last_name VARCHAR(60) NOT NULL, 154 | balance NUMERIC(10,2), 155 | PRIMARY KEY( id ) 156 | ); 157 | If you place the cursor on the word first_name, then the 158 | column definition will be placed in the unnamed buffer (and also 159 | displayed by an echo statement). 160 | VARCHAR(30) NOT NULL 161 | 162 | If the command is called as SQLUGetColumnDef( expand(""), 1 ) 163 | or using the default mapping \scdt, just the datatype (instead 164 | of the column definition) will be returned. A separate command 165 | SQLUGetColumnDataType has been created for this. 166 | VARCHAR(30) 167 | 168 | 169 | Functions: 170 | SQLUCreateProcedure() 171 | 172 | Assumes either the current file, or any other open buffer, 173 | has a CREATE TABLE statement in a format similar to this: 174 | CREATE TABLE customer ( 175 | id INT DEFAULT AUTOINCREMENT, 176 | last_modified TIMESTAMP NULL, 177 | first_name VARCHAR(30) NOT NULL, 178 | last_name VARCHAR(60) NOT NULL, 179 | balance NUMERIC(10,2), 180 | PRIMARY KEY( id ) 181 | ); 182 | By calling SQLUCreateProcedure while on the name of a table 183 | the unnamed buffer will contain the create procedure statement 184 | for insert, update, delete and select statements. 185 | Once pasted into the buffer, unneeded functionality can be 186 | removed. 187 | 188 | 189 | 190 | Commands: 191 | [range]SQLUFormatter ..list.. 192 | : Reformats the SQL statements over the specified 193 | range. Statement will lined up given the 194 | existing indent of the first word. 195 | SQLUCreateColumnList: Creates a comma separated list of column names 196 | for the table name under the cursor, assuming 197 | the table definition exists in any open 198 | buffer. The column list is placed in the unnamed 199 | buffer. 200 | This also uses the g:sqlutil_cmd_terminator. 201 | By default a table alias will be added to each of the columns, this is 202 | configurable, see documentation (new 1.3.7). 203 | This routine can optionally take 2 parameters 204 | SQLUCreateColumnList T1 205 | Creates a column list for T1 206 | SQLUCreateColumnList T1 1 207 | Creates a column list for T1 but only for 208 | the primary keys for that table. 209 | SQLUGetColumnDef : Displays the column definition of the column name 210 | under the cursor. It assumes the CREATE TABLE 211 | statement is in an open buffer. 212 | SQLUGetColumnDataType 213 | : Displays the column datatype of the column name 214 | under the cursor. It assumes the CREATE TABLE 215 | statement is in an open buffer. 216 | SQLUCreateProcedure : Creates a stored procedure to perform standard 217 | operations against the table that the cursor 218 | is currently under. 219 | 220 | 221 | 222 | Suggested Mappings: 223 | vmap sf SQLU_Formatter 224 | nmap scl SQLU_CreateColumnList 225 | nmap scd SQLU_GetColumnDef 226 | nmap scdt SQLU_GetColumnDataType 227 | nmap scp SQLU_CreateProcedure 228 | 229 | mnemonic explanation 230 | s - sql 231 | f - format 232 | cl - column list 233 | cd - column definition 234 | cdt - column datatype 235 | cp - create procedure 236 | 237 | To prevent the default mappings from being created, place the 238 | following in your _vimrc: 239 | let g:sqlutil_load_default_maps = 0 240 | 241 | Customization: 242 | By default this script assumes a command is terminated by a ; 243 | If you are using Microsoft SQL Server a command terminator 244 | would be "go", or perhaps "\ngo". 245 | To permenantly override the terminator in your _vimrc file you can add 246 | let g:sqlutil_cmd_terminator = "\ngo" 247 | 248 | 249 | When building a column list from a script file (ie CREATE TABLE 250 | statements), you can customize the script to detect when the 251 | column list finishes by creating the following in your _vimrc: 252 | let g:sqlutil_col_list_terminators = 253 | \ 'primary,reference,unique,check,foreign' 254 | 255 | This can be necessary in the following example: 256 | CREATE TABLE customer ( 257 | id INT DEFAULT AUTOINCREMENT, 258 | first_name VARCHAR(30) NOT NULL, 259 | last_name VARCHAR(60) NOT NULL, 260 | PRIMARY KEY( id ) 261 | ); 262 | 263 | Dependencies: 264 | Align.vim - Version 15 265 | - Author: Charles E. Campbell, Jr. 266 | - http://www.vim.org/script.php?script_id=294 267 | 268 | Suggested (Complementary) Plugins: 269 | dbext.vim - Author: Peter Bagyinszki and David Fishburn 270 | - http://www.vim.org/script.php?script_id=356 271 | 272 | -------------------------------------------------------------------------------- /autoload/SQLUtilities.vim: -------------------------------------------------------------------------------- 1 | " SQLUtilities: Variety of tools for writing SQL 2 | " Author: David Fishburn 3 | " Date: Nov 23, 2002 4 | " Last Changed: 2012 Oct 09 5 | " Version: 6.0.0 6 | " Script: http://www.vim.org/script.php?script_id=492 7 | " License: GPL (http://www.gnu.org/licenses/gpl.html) 8 | " 9 | " Dependencies: 10 | " Align.vim - Version 15 (as a minimum) 11 | " - Author: Charles E. Campbell, Jr. 12 | " - http://www.vim.org/script.php?script_id=294 13 | " Documentation: 14 | " :h SQLUtilities.txt 15 | " 16 | 17 | " Prevent duplicate loading 18 | if exists("g:loaded_sqlutilities_auto") 19 | finish 20 | endif 21 | if v:version < 700 22 | echomsg "SQLUtilities: Version 2.0.0 or higher requires Vim7. Version 1.4.1 can stil be used with Vim6." 23 | finish 24 | endif 25 | let g:loaded_sqlutilities_auto = 600 26 | 27 | " Turn on support for line continuations when creating the script 28 | let s:cpo_save = &cpo 29 | set cpo&vim 30 | 31 | " SQLU_Formatter: align selected text based on alignment pattern(s) 32 | function! SQLUtilities#SQLU_Formatter(...) range 33 | let mode = 'n' 34 | if a:0 > 0 35 | let mode = (a:1 == ''?'n':(a:1)) 36 | endif 37 | 38 | if ! exists( ':AlignCtrl' ) 39 | call s:SQLU_WarningMsg( 40 | \ 'SQLU_Formatter - The Align plugin cannot be found' 41 | \ ) 42 | return -1 43 | endif 44 | 45 | call s:SQLU_WrapperStart( a:firstline, a:lastline, mode ) 46 | " Store pervious value of highlight search 47 | let hlsearch = &hlsearch 48 | let &hlsearch = 0 49 | 50 | " Store pervious value of gdefault 51 | let gdefault = &gdefault 52 | let &gdefault = 0 53 | 54 | " save previous search string 55 | let saveSearch = @/ 56 | 57 | " save previous format options and turn off automatic formating 58 | let saveFormatOptions = &formatoptions 59 | silent execute 'setlocal formatoptions-=a' 60 | 61 | " Use the mark locations instead of storing the line numbers 62 | " since these values can changes based on the reformatting 63 | " of the lines 64 | let ret = s:SQLU_ReformatStatement() 65 | if ret > -1 66 | if g:sqlutil_wrap_expressions == 1 67 | let ret = s:SQLU_WrapExpressions() 68 | endif 69 | if ret > -1 70 | let ret = s:SQLU_IndentNestedBlocks() 71 | if ret > -1 72 | let ret = s:SQLU_WrapLongLines() 73 | endif 74 | endif 75 | endif 76 | 77 | " Restore default value 78 | " And restore cursor position 79 | let &hlsearch = hlsearch 80 | call s:SQLU_WrapperEnd(mode) 81 | 82 | " restore previous format options 83 | let &formatoptions = saveFormatOptions 84 | 85 | " restore previous search string 86 | let @/ = saveSearch 87 | let &gdefault = gdefault 88 | 89 | endfunction 90 | 91 | " SQLU_FormatStmts: 92 | " For a given range (default entire file), it find each SQL 93 | " statement an run SQLFormatter against it. 94 | " 95 | function! SQLUtilities#SQLU_FormatStmts(...) range 96 | let mode = 'n' 97 | if a:0 > 0 98 | let mode = (a:1 == ''?'n':(a:1)) 99 | endif 100 | 101 | let curline = line(".") 102 | let curcol = virtcol(".") 103 | let keepline_ms = line("'s") 104 | let keepcol_ms = virtcol("'s") 105 | let keepline_me = line("'e") 106 | let keepcol_me = virtcol("'e") 107 | 108 | silent! exec 'normal! '.a:lastline."G\0\" 109 | " Add a new line to the bottom of the mark to be removed latter 110 | put ='' 111 | silent! exec "ma e" 112 | silent! exec 'normal! '.a:firstline."G\0\" 113 | " Add a new line above the mark to be removed latter 114 | put! = '' 115 | silent! exec "ma s" 116 | silent! exec "normal! 'sj" 117 | 118 | " Store pervious value of highlight search 119 | let hlsearch = &hlsearch 120 | let &hlsearch = 0 121 | 122 | " save previous search string 123 | let saveSearch = @/ 124 | 125 | " save previous format options and turn off automatic formating 126 | let saveFormatOptions = &formatoptions 127 | silent execute 'setlocal formatoptions-=a' 128 | 129 | " Must default the statements to query 130 | let stmt_keywords = g:sqlutil_stmt_keywords 131 | 132 | " Verify the string is in the correct format 133 | " Strip off any trailing commas 134 | let stmt_keywords = 135 | \ substitute(stmt_keywords, ',$','','') 136 | " Convert commas to regex ors 137 | let stmt_keywords = 138 | \ substitute(stmt_keywords, '\s*,\s*', '\\|', 'g') 139 | 140 | let sql_commands = '\c\<\('.stmt_keywords.'\)\>' 141 | 142 | " Find a line starting with SELECT|UPDATE|DELETE 143 | " .,- - From that line backup one line due to :g 144 | " /; - find the ending command delimiter 145 | " SQLUFormatter - Use the SQLUtilities plugin to format it 146 | let cmd = a:firstline.','.a:lastline.'g/^\s*\<\(' . 147 | \ stmt_keywords . '\)\>/.,-/' . 148 | \ g:sqlutil_cmd_terminator . '/SQLUFormatter' 149 | exec cmd 150 | 151 | " Restore default value 152 | " And restore cursor position 153 | let &hlsearch = hlsearch 154 | 155 | " restore previous format options 156 | let &formatoptions = saveFormatOptions 157 | 158 | " restore previous search string 159 | let @/ = saveSearch 160 | 161 | silent! exe 'normal! '.curline."G\".(curcol-1). 162 | \ ((curcol-1)>0 ? 'l' : '' ) 163 | 164 | if (mode != 'n') 165 | " Reselect the visual area, so the user can us gv 166 | " to operate over the region again 167 | exec 'normal! '.(line("'s")+1).'gg'.'|'. 168 | \ 'V'.(line("'e")-2-line("'s")).'j|'."\" 169 | endif 170 | 171 | " Delete blanks lines added around the visually selected range 172 | silent! exe "normal! 'sdd'edd" 173 | 174 | silent! exe 'normal! '.curline."G\".(curcol-1). 175 | \ ((curcol-1)>0 ? 'l' : '' ) 176 | 177 | endfunction 178 | 179 | " This function will return a count of unmatched parenthesis 180 | " ie ( this ( funtion ) - will return 1 in this case 181 | function! s:SQLU_CountUnbalancedParan( line, paran_to_check ) 182 | let l = a:line 183 | let lp = substitute(l, '[^(]', '', 'g') 184 | let l = a:line 185 | let rp = substitute(l, '[^)]', '', 'g') 186 | 187 | if a:paran_to_check =~ ')' 188 | " echom 'SQLU_CountUnbalancedParan ) returning: ' 189 | " \ . (strlen(rp) - strlen(lp)) 190 | return (strlen(rp) - strlen(lp)) 191 | elseif a:paran_to_check =~ '(' 192 | " echom 'SQLU_CountUnbalancedParan ( returning: ' 193 | " \ . (strlen(lp) - strlen(rp)) 194 | return (strlen(lp) - strlen(rp)) 195 | else 196 | " echom 'SQLU_CountUnbalancedParan unknown paran to check: ' . 197 | " \ a:paran_to_check 198 | return 0 199 | endif 200 | endfunction 201 | 202 | " WS: wrapper start (internal) Creates guard lines, 203 | " stores marks y and z, and saves search pattern 204 | function! s:SQLU_WrapperStart( beginline, endline, mode ) 205 | let b:curline = line(".") 206 | let b:curcol = virtcol(".") 207 | let b:keepsearch = @/ 208 | let b:keepline_my = line("'y") 209 | let b:keepcol_my = virtcol("'y") 210 | let b:keepline_mz = line("'z") 211 | let b:keepcol_mz = virtcol("'z") 212 | 213 | silent! exec 'normal! '.a:endline."G\0\" 214 | " Add a new line to the bottom of the mark to be removed later 215 | put ='' 216 | silent! exec "ma z" 217 | silent! exec 'normal! '.a:beginline."G\0\" 218 | " Add a new line above the mark to be removed later 219 | put! = '' 220 | silent! exec "ma y" 221 | let b:cmdheight= &cmdheight 222 | set cmdheight=2 223 | silent! exec "normal! 'zk" 224 | endfunction 225 | 226 | " WE: wrapper end (internal) Removes guard lines, 227 | " restores marks y and z, and restores search pattern 228 | function! s:SQLU_WrapperEnd(mode) 229 | if (a:mode != 'n') 230 | " Reselect the visual area, so the user can us gv 231 | " to operate over the region again 232 | exec 'normal! '.(line("'y")+1).'gg'.'|'. 233 | \ 'V'.(line("'z")-2-line("'y")).'j|'."\" 234 | endif 235 | 236 | " Delete blanks lines added around the visually selected range 237 | silent! exe "normal! 'ydd'zdd" 238 | silent! exe "set cmdheight=".b:cmdheight 239 | unlet b:cmdheight 240 | let @/= b:keepsearch 241 | 242 | silent! exe 'normal! '.b:curline."G\".(b:curcol-1). 243 | \ ((b:curcol-1)>0 ? 'l' : '' ) 244 | 245 | unlet b:keepline_my b:keepcol_my 246 | unlet b:keepline_mz b:keepcol_mz 247 | unlet b:curline b:curcol 248 | endfunction 249 | 250 | " Generic Search and Replace uses syntax ID {{{ 251 | function! s:SQLU_SearchReplace(exp_find_str, exp_rplc_str) 252 | 253 | " Find the string index position of the first match 254 | " 'c' accept a match at the cursor position 255 | " 'W' don't wrap around the end of the file 256 | let index = search(a:exp_find_str, 'cW', (line("'z"))) 257 | while index > 0 258 | " Verify the cursor is within the range 259 | if index >= line("'y") && index <= line("'z") 260 | 261 | " Useful debug statment to see where on the line 262 | " and which keyword you are working on 263 | " echo line(".") strpart(getline("."), col(".")-1) 264 | 265 | let syn_element_list = split(g:sqlutil_syntax_elements, ',') 266 | 267 | if !empty(syn_element_list) 268 | let found_in_str = 0 269 | for syn_element_name in syn_element_list 270 | " Determine the ID for the name in the CSV list 271 | let syn_element_id = hlID(syn_element_name) 272 | 273 | " Grab the current syntax ID of the match 274 | let childsynid = synID(line("."),col("."),1) 275 | let parentsynid = synIDtrans(synID(line("."),col("."),1)) 276 | 277 | if childsynid == syn_element_id || parentsynid == syn_element_id 278 | let found_in_str = 1 279 | break 280 | endif 281 | endfor 282 | if found_in_str == 1 283 | " Advance the cursor 1 position since we use 284 | " 'c' in the flags 285 | call cursor( line("."), (col(".") + 1) ) 286 | let index = search(a:exp_find_str, 'cW', (line("'z"))) 287 | continue 288 | endif 289 | endif 290 | 291 | " At the current cursor position 292 | exec 's/\%#/' . a:exp_rplc_str 293 | 294 | let index = search(a:exp_find_str, 'cW', (line("'z"))) 295 | endif 296 | endwhile 297 | 298 | endfunction 299 | " }}} 300 | 301 | 302 | " Reformats the statements 303 | " 1. Keywords (FROM, WHERE, AND, ... ) " are on new lines 304 | " 2. Keywords are right justified 305 | " 3. CASE statements are setup for alignment. 306 | " 4. Operators are lined up 307 | " 308 | function! s:SQLU_ReformatStatement() 309 | " Remove any lines that have comments on them since the comments 310 | " could spill onto new lines and no longer have comment markers 311 | " which would result in syntax errors 312 | " Comments could also contain keywords, which would be split 313 | " on to new lines 314 | let srch_exp = '.*\zs--.*' 315 | if exists("b:current_syntax") == 0 || g:sqlutil_use_syntax_support == 0 316 | let cmd = "'y+1,'z-1s/". srch_exp . 317 | \ '//ge' 318 | " Decho cmd 319 | silent! exec cmd 320 | else 321 | " This uses Vim's syntax support to determine if 322 | " a match is found within a string or not. 323 | " Therefore only do it if syntax support is on 324 | " which can be tested checking for the existance 325 | " of the buffer local variable b:current_syntax 326 | call s:SQLU_SearchReplace(srch_exp, '') 327 | endif 328 | 329 | " Join block of text into 1 line 330 | silent! 'y+1,'z-1j 331 | " Reformat the commas, to remove any spaces before them 332 | silent! 'y+1,'z-1s/\s*,/,/ge 333 | " And add a space following them, this allows the line to be 334 | " split using gqq 335 | silent! 'y+1,'z-1s/,\(\w\)/, \1/ge 336 | " Change more than 1 space with just one except spaces at 337 | " the beginning of the range 338 | " silent! 'y+1,'z-1s/\s\+/ /ge 339 | silent! 'y+1,'z-1s/\(\S\+\)\(\s\+\)/\1 /g 340 | " Go to the start of the block 341 | silent! 'y+1 342 | 343 | " Place an UPDATE on a newline, but not if it is preceeded by 344 | " the existing statement. Example: 345 | " INSERT INTO T1 (...) 346 | " ON EXISTING UPDATE 347 | " VALUES (...); 348 | " SELECT ... 349 | " FOR UPDATE 350 | let sql_update_keywords = '' . 351 | \ '\%(\%(\<\%(for\|existing\)\s\+\)\@AND 369 | let sql_and_between_keywords = '' . 370 | \ '\%(\%(\\|'. 444 | \ sql_window_keywords . '\|' . 445 | \ 'having\|for\|insert\|using\|' . 446 | \ 'intersect\|except\|window\|' . 447 | \ '\%(union\%(\s\+all\)\?\)\|' . 448 | \ 'start\s\+with\|' . 449 | \ '\%(\%(\' 450 | " The user can specify whether to align the statements based on 451 | " the first word, or on the matching string. 452 | " let g:sqlutil_align_first_word = 0 453 | " select 454 | " from 455 | " union all 456 | " let g:sqlutil_align_first_word = 1 457 | " select 458 | " from 459 | " union all 460 | let srch_exp = '\c\%(^\s*\)\@\s*' 463 | 464 | if exists("b:current_syntax") == 0 || g:sqlutil_use_syntax_support == 0 465 | let cmd = "'y+1,'z-1s/". srch_exp . 466 | \ '/\r\1' . 467 | \ ( g:sqlutil_align_first_word==0 ? '-@-' : ' ' ) . 468 | \ '/ge' 469 | " Decho cmd 470 | silent! exec cmd 471 | else 472 | " This uses Vim's syntax support to determine if 473 | " a match is found within a string or not. 474 | " Therefore only do it if syntax support is on 475 | " which can be tested checking for the existance 476 | " of the buffer local variable b:current_syntax 477 | call s:SQLU_SearchReplace(srch_exp, '\r\1' . (g:sqlutil_align_first_word==0 ? '-@-' : ' ') ) 478 | endif 479 | 480 | " Ensure keywords at the beginning of a line have a space after them 481 | " This will ensure the Align program lines them up correctly 482 | " silent! 'y+1,'z-1s/^\([a-zA-Z0-9_]*\)(/\1 (/e 483 | " Delete any non empty lines 484 | " Do NOT delete empty lines, since that can affect the marks 485 | " and change which lines get formatted 486 | " 'y+1,'z-1g/^\s*$/d 487 | 488 | " If g:sqlutil_align_first_word == 0, then we need only add the -@- 489 | " on the first word, else we need to do it to the first word 490 | " on each line 491 | silent! exec "'y+1," . 492 | \ ( g:sqlutil_align_first_word==0 ? "'y+1" : "'z-1" ) . 493 | \ 's/^\s*\<\w\+\>\zs\s*/-@-' 494 | 495 | " Ensure CASE statements also start on new lines 496 | " CASE statements can also be nested, but we want these to align 497 | " with column lists, not keywords, so the -@- is placed BEFORE 498 | " the CASE keywords, not after 499 | " 500 | " The CASE statement and the Oracle MERGE statement are very similar. 501 | " I have changed the WHEN clause to check to see if it is followed 502 | " by [NOT] MATCHED, if so, do not match the WHEN 503 | let sql_case_keywords = '\(\\(\%(-@-\)\?\s*\%(not\s\+\)\?matched\)\@!' . 505 | \ '\|else\|end\(\s\+case\)\?' 506 | 507 | " echom 'case: '.sql_case_keywords 508 | " The case keywords must not be proceeded by a -@- 509 | " silent! exec "'y+1,'z-1".'s/'. 510 | " \ '\%(-@-\)\@/\r-@-\1/gei' 514 | let srch_exp = '\c\%(-@-\)\@' 518 | 519 | if exists("b:current_syntax") == 0 || g:sqlutil_use_syntax_support == 0 520 | let cmd = "'y+1,'z-1s/". srch_exp . 521 | \ '/\r-@-\1' . 522 | \ '/ge' 523 | " Decho cmd 524 | silent! exec cmd 525 | else 526 | " This uses Vim's syntax support to determine if 527 | " a match is found within a string or not. 528 | " Therefore only do it if syntax support is on 529 | " which can be tested checking for the existance 530 | " of the buffer local variable b:current_syntax 531 | call s:SQLU_SearchReplace(srch_exp, '\r-@-\1' ) 532 | endif 533 | 534 | " AlignPush 535 | 536 | " Using the Align.vim plugin, reformat the lines 537 | " so that the keywords are RIGHT justified 538 | AlignCtrl default 539 | 540 | if g:sqlutil_align_comma == 1 541 | call s:SQLU_WrapAtCommas() 542 | endif 543 | 544 | call s:SQLU_WrapFunctionCalls() 545 | 546 | let ret = s:SQLU_SplitUnbalParan() 547 | if ret < 0 548 | " Undo any changes made so far since an error occurred 549 | " silent! exec 'u' 550 | return ret 551 | endif 552 | 553 | " Align these based on the special charater 554 | " and the column names are LEFT justified 555 | let align_ctrl = 'Ip0P0'.(g:sqlutil_align_keyword_right==1?'r':'l').'l:' 556 | silent! exec 'AlignCtrl '.align_ctrl 557 | silent! 'y+1,'z-1Align -@- 558 | silent! 'y+1,'z-1s/-@-/ /ge 559 | 560 | " Now that we have removed the special alignment marker 561 | " upper or lower case all the keywords only if the user 562 | " has specified an override. 563 | if g:sqlutil_keyword_case != '' 564 | let cmd = "'y+1,'z-1".'s/\<\(' . 565 | \ sql_keywords . 566 | \ '\|' . 567 | \ sql_case_keywords . 568 | \ '\|' . 569 | \ sql_join_type_keywords . 570 | \ '\)\>/' . 571 | \ g:sqlutil_keyword_case . 572 | \ '\1/gei' 573 | silent! exec cmd 574 | endif 575 | 576 | " Now align the operators 577 | " and the operators are CENTER justified 578 | if g:sqlutil_align_where == 1 579 | AlignCtrl default 580 | AlignCtrl g [!<>=] 581 | AlignCtrl Wp1P1l 582 | 583 | " Change this to only attempt to align the last WHERE clause 584 | " and not the entire SQL statement 585 | " Valid operators are: 586 | " =, =, >, <, >=, <=, !=, !<, !>, <> 587 | " The align below was extended to allow the last character 588 | " to be either =,<,> 589 | silent! 'y+1,'z-1Align [!<>=]\(<\|>\|=\)\= 590 | endif 591 | 592 | " Reset back to defaults 593 | AlignCtrl default 594 | 595 | " Reset the alignment to what it was prior to 596 | " this function 597 | " AlignPop 598 | 599 | return 1 600 | endfunction 601 | 602 | " Check through the selected text for open ( and 603 | " indent if necessary 604 | function! s:SQLU_IndentNestedBlocks() 605 | 606 | let org_textwidth = &textwidth 607 | if &textwidth == 0 608 | " Get the width of the window 609 | let &textwidth = winwidth(winnr()) 610 | endif 611 | 612 | let sql_keywords = '\<\%(select\|set\|\%(insert\s\+\)\?into\|from\|values'. 613 | \ '\|order\|group\|having\|return\|call\)\>' 614 | 615 | " Indent nested blocks surrounded by ()s. 616 | let linenum = line("'y+1") 617 | while linenum <= line("'z-1") 618 | let line = getline(linenum) 619 | if line =~ '(\s*$' 620 | let begin_paran = match( line, '(\s*$' ) 621 | if begin_paran > -1 622 | let curline = line(".") 623 | let curcol = begin_paran + 1 624 | " echom 'begin_paran: '.begin_paran. 625 | " \ ' line: '.curline. 626 | " \ ' col: '.curcol 627 | silent! exe 'normal! '.linenum."G\".curcol."l" 628 | " v - visual 629 | " ib - inner block 630 | " k - backup on line 631 | " > - right shift 632 | " . - shift again 633 | " silent! exe 'normal! vibk>.' 634 | silent! exe 'normal! vibk>' 635 | 636 | " If the following line begins with a keyword, 637 | " indent one additional time. This is necessary since 638 | " keywords are right justified, so they need an extra 639 | " indent 640 | if getline(linenum+1) =~? '^\s*\('.sql_keywords.'\)' 641 | silent! exe 'normal! .' 642 | endif 643 | " echom 'SQLU_IndentNestedBlocks - from: '.line("'<").' to: ' . 644 | " \ line("'>") 645 | " echom 'SQLU_IndentNestedBlocks - no match: '.getline(linenum) 646 | endif 647 | endif 648 | 649 | let linenum = linenum + 1 650 | endwhile 651 | 652 | let ret = linenum 653 | 654 | " 655 | " Indent nested CASE blocks 656 | " 657 | let linenum = line("'y+1") 658 | " Search for the beginning of a CASE statement 659 | let begin_case = '\<\(\' 660 | 661 | silent! exe 'normal! '.linenum."G\0\" 662 | 663 | while( search( begin_case, 'W' ) > 0 ) 664 | " Check to see if the CASE statement is inside a string 665 | if synID(line("."),col("."),1) > 0 666 | continue 667 | endif 668 | let curline = line(".") 669 | if( (curline < line("'y+1")) || (curline > line("'z-1" )) ) 670 | " echom 'No case statements, leaving loop' 671 | silent! exe 'normal! '.line("'y+1")."G\0\" 672 | break 673 | endif 674 | " echom 'begin CASE found at: '.curline 675 | let curline = curline + 1 676 | let end_of_case = s:SQLU_IndentNestedCase( begin_case, curline, 677 | \ line("'z-1") ) 678 | let end_of_case = end_of_case + 1 679 | let ret = end_of_case 680 | if( ret < 0 ) 681 | break 682 | endif 683 | silent! exe 'normal! '.end_of_case."G\0\" 684 | endwhile 685 | 686 | " 687 | " Indent Oracle nested MERGE blocks 688 | " 689 | let linenum = line("'y+1") 690 | " Search for the beginning of a CASE statement 691 | let begin_merge = '\' 692 | 693 | silent! exe 'normal! '.linenum."G\0\" 694 | 695 | if( search( begin_merge, 'W' ) > 0 ) 696 | let curline = line(".") 697 | if( (curline < line("'y+1")) || (curline > line("'z-1" )) ) 698 | " echom 'No case statements, leaving loop' 699 | silent! exe 'normal! '.line("'y+1")."G\0\" 700 | else 701 | " echom 'begin CASE found at: '.curline 702 | let curline = curline + 1 703 | 704 | while 1==1 705 | " Find the matching when statement 706 | " let match_merge = searchpair('\', 707 | let match_merge = searchpair('\', '', 708 | \ '\<\%(when\s\+\%(not\s\+\)\?matched\)', 709 | \ 'W', '' ) 710 | if( (match_merge < curline) || (match_merge > line("'z-1")) ) 711 | silent! exec curline . "," . line("'z-1") . ">>" 712 | break 713 | else 714 | if match_merge > (curline+1) 715 | let savePos = 'normal! '.line(".").'G'.col(".")."\" 716 | silent! exec curline . "," . (match_merge-1) . ">>" 717 | silent! exec savePos 718 | endif 719 | let curline = match_merge + 1 720 | endif 721 | endwhile 722 | endif 723 | endif 724 | 725 | let &textwidth = org_textwidth 726 | return ret 727 | endfunction 728 | 729 | " Recursively indent nested case statements 730 | function! s:SQLU_IndentNestedCase( begin_case, start_line, end_line ) 731 | 732 | " Indent nested CASE blocks 733 | let linenum = a:start_line 734 | 735 | " Find the matching end case statement 736 | let end_of_prev_case = searchpair(a:begin_case, '', 737 | \ '\', 'W', '' ) 738 | 739 | if( (end_of_prev_case < a:start_line) || (end_of_prev_case > a:end_line) ) 740 | call s:SQLU_WarningMsg( 741 | \ 'SQLU_IndentNestedCase - No matching end case for: ' . 742 | \ getline((linenum-1)) 743 | \ ) 744 | return -1 745 | " else 746 | " echom 'Matching END found at: '.end_of_prev_case 747 | endif 748 | 749 | silent! exe 'normal! '.linenum."G\0\" 750 | 751 | if( search( a:begin_case, 'W' ) > 0 ) 752 | let curline = line(".") 753 | if( (curline > a:start_line) && (curline < end_of_prev_case) ) 754 | let curline = curline + 1 755 | let end_of_case = s:SQLU_IndentNestedCase( a:begin_case, curline, 756 | \ line("'z-1") ) 757 | " echom 'SQLU_IndentNestedCase from: '.linenum.' to: '.end_of_case 758 | silent! exec (curline-1) . "," . end_of_case . ">>" 759 | " else 760 | " echom 'SQLU_IndentNestedCase No case statements, '. 761 | " \ 'leaving SQLU_IndentNestedCase: '.linenum 762 | endif 763 | endif 764 | 765 | return end_of_prev_case 766 | endfunction 767 | 768 | " For certain keyword lines (SELECT, ORDER BY, GROUP BY, ...) 769 | " Ensure the lines fit in the textwidth (or default 80), wrap 770 | " the lines where necessary and left justify the column names 771 | function! s:SQLU_WrapFunctionCalls() 772 | " Check if this is a statement that can often by longer than 80 characters 773 | " (select, set and so on), if so, ensure the column list is broken over as 774 | " many lines as necessary and lined up with the other columns 775 | let linenum = line("'y+1") 776 | 777 | return 778 | 779 | let org_textwidth = &textwidth 780 | if org_textwidth == 0 781 | " Get the width of the window 782 | let curr_textwidth = winwidth(winnr()) 783 | else 784 | let curr_textwidth = org_textwidth 785 | endif 786 | 787 | let sql_keywords = '\<\%(select\|set\|\%(insert\(-@-\)\?\)into' . 788 | \ '\|from\|values'. 789 | \ '\|order\|group\|having\|return\|with\)\>' 790 | 791 | " Useful in the debugger 792 | " echo linenum.' '.func_call.' '.virtcol(".").' 793 | " '.','.substitute(getline("."), '^ .*\(\%'.(func_call-1).'c...\).*', 794 | " '\1', '' ).', '.getline(linenum) 795 | 796 | " call Decho(" Before column splitter 'y+1=".line("'<"). 797 | " \ ":".col("'<")." 'z-1=".line("'>").":".col("'>")) 798 | while linenum <= line("'z-1") 799 | let line = getline(linenum) 800 | 801 | if strlen(line) < curr_textwidth 802 | let linenum = linenum + 1 803 | continue 804 | endif 805 | 806 | let get_func_nm = '[a-zA-Z_.]\+\s*(' 807 | 808 | " Use a special line textwidth, since if we split function calls 809 | " any text within the parantheses will be indented 2 &shiftwidths 810 | " so when calculating where to split, we must take that into 811 | " account 812 | let keyword_str = matchstr( 813 | \ getline(linenum), '^\s*\('.sql_keywords.'\)' ) 814 | 815 | let line_textwidth = curr_textwidth - strlen(keyword_str) 816 | let func_call = 0 817 | while( strlen(getline(linenum)) > line_textwidth ) 818 | 819 | " Find the column # of the start of the function name 820 | let func_call = match( getline(linenum), get_func_nm, func_call ) 821 | if func_call < 0 822 | " If no functions found, move on to next line 823 | break 824 | endif 825 | 826 | let prev_func_call = func_call 827 | 828 | " Position cursor at func_call 829 | silent! exe 'normal! '.linenum."G\".func_call."l" 830 | 831 | if search('(', 'W') > linenum 832 | call s:SQLU_WarningMsg( 833 | \ 'SQLU_WrapFunctionCalls - should have found a (' 834 | \ ) 835 | let linenum = linenum + 1 836 | break 837 | endif 838 | 839 | " Check to ensure the paran is not part of a string 840 | " Otherwise ignore and move on to the next paran 841 | if synID(line("."),col("."),1) == 0 842 | " let end_paran = searchpair( '(', '', ')', '' ) 843 | " Ignore parans that are inside of strings 844 | let end_paran = searchpair( '(', '', ')', '', 845 | \ 'synID(line("."),col("."),1)>0' ) 846 | if end_paran < linenum || end_paran > linenum 847 | " call s:SQLU_WarningMsg( 848 | " \ 'SQLU_WrapFunctionCalls - ' . 849 | " \ 'should have found a matching ) for :' . 850 | " \ getline(linenum) 851 | " \ ) 852 | let linenum = linenum + 1 853 | break 854 | endif 855 | 856 | " If the matching ) is past the textwidth 857 | if virtcol(".") > line_textwidth 858 | if (virtcol(".")-func_call) > line_textwidth 859 | " Place the closing brace on a new line only if 860 | " the entire length of the function call and 861 | " parameters is longer than a line 862 | silent! exe "normal! i\r-@-\" 863 | endif 864 | " If the SQL keyword preceeds the function name dont 865 | " bother placing it on a new line 866 | let preceeded_by_keyword = 867 | \ '^\s*' . 868 | \ '\(' . 869 | \ sql_keywords . 870 | \ '\|,' . 871 | \ '\)' . 872 | \ '\(-@-\)\?' . 873 | \ '\s*' . 874 | \ '\%'.(func_call+1).'c' 875 | " echom 'preceeded_by_keyword: '.preceeded_by_keyword 876 | " echom 'func_call:'.func_call.' Current 877 | " character:"'.getline(linenum)[virtcol(func_call)].'" - 878 | " '.getline(linenum) 879 | if getline(linenum) !~? preceeded_by_keyword 880 | " if line =~? '^\s*\('.sql_keywords.'\)' 881 | " Place the function name on a new line 882 | silent! exe linenum.'s/\%'.(func_call+1).'c/\r-@-' 883 | let linenum = linenum + 1 884 | " These lines will be indented since they are wrapped 885 | " in parantheses. Decrease the line_textwidth by 886 | " that amount to determine where to split nested 887 | " function calls 888 | let line_textwidth = line_textwidth - (2 * &shiftwidth) 889 | let func_call = 0 890 | " Get the new offset of this function from the start 891 | " of the newline it is on 892 | let prev_func_call = match( 893 | \ getline(linenum),get_func_nm,func_call) 894 | endif 895 | endif 896 | endif 897 | 898 | " Get the name of the previous function 899 | let prev_func_call_str = matchstr( 900 | \ getline(linenum), get_func_nm, prev_func_call ) 901 | " Advance the column by its length to find the next function 902 | let func_call = prev_func_call + 903 | \ strlen(prev_func_call_str) 904 | 905 | endwhile 906 | 907 | let linenum = linenum + 1 908 | endwhile 909 | 910 | let &textwidth = org_textwidth 911 | return linenum 912 | endfunction 913 | 914 | " For certain keyword lines (SELECT, SET, INTO, FROM, VALUES) 915 | " put each comma on a new line and align it with the keyword 916 | " SELECT c1 917 | " , c2 918 | " , c3 919 | function! s:SQLU_WrapAtCommas() 920 | let linenum = line("'y+1") 921 | 922 | let sql_keywords = '\<\%(select\|set\|into\|from\|values\|insert\)\>' 923 | 924 | " call Decho(" Before column splitter 'y+1=".line("'<"). 925 | " \ ":".col("'<")." 'z-1=".line("'>").":".col("'>")) 926 | while linenum <= line("'z-1") 927 | let line = getline(linenum) 928 | " if line =~? '^\s*\('.sql_keywords.'\)' 929 | if line =~? '\w' 930 | " if line =~? '^\s*\<\('.sql_keywords.'\)\>' 931 | silent! exec linenum 932 | " Mark the start of the line 933 | silent! exec "normal! mb" 934 | " echom "line b - ".getline("'b") 935 | " Mark the next line 936 | silent! exec "normal! jmek" 937 | 938 | let saved_linenum = linenum 939 | " let index = match(getline(linenum), '[,(]') 940 | " Find the first , or ( 941 | let index = match(getline(linenum), (g:sqlutil_align_comma==1?'[,(]':'[,]')) 942 | while index > -1 943 | " Go to the , or ( 944 | call cursor(linenum, (index+1)) 945 | 946 | " Assuming syntax is on, check to ensure the , or ( 947 | " is not a string 948 | if getline(linenum)[col(".")-1] == '(' && 949 | \ synID(line("."),col("."),1) == 0 950 | " if searchpair( '(', '', ')', '' ) > 0 951 | " Ignore parans that are inside of strings 952 | if searchpair( '(', '', ')', '', 953 | \ 'synID(line("."),col("."),1)>0' ) > 0 954 | let linenum = line(".") 955 | let index = col(".") 956 | endif 957 | else 958 | " Only do this if the comma at this offset 959 | " is not already at the start of the line 960 | if match(getline(linenum), '\S') != index 961 | " Given the current cursor position, replace 962 | " the , and any following whitespace 963 | " with a newline and the special -@- character 964 | " for Align 965 | silent! exec linenum . ',' . linenum . 966 | \ 's/\%' . (index + 1) . 'c,\s*' . 967 | \ '/\r' . 968 | \ (g:sqlutil_align_keyword_right == 1 ? ',-@-' : '-@-, ') 969 | let linenum = linenum + 1 970 | 971 | let index = 0 972 | if g:sqlutil_align_keyword_right == 0 973 | " If aligning the commas with the left justified 974 | " column names, we must skip ahead the index 975 | " to be infront of the -@- 976 | let index = 3 977 | endif 978 | endif 979 | " Find the index of the first non-white space 980 | " which should be the , we just put on the 981 | " newline 982 | let index = match(getline(linenum), '\S', index) 983 | let index = index + 1 984 | endif 985 | 986 | " then continue on for the remainder of the line 987 | " looking for the next , or ( 988 | " 989 | " Must figure out what index value to start from 990 | let index = match( getline(linenum), '[,(]', index ) 991 | endwhile 992 | let linenum = saved_linenum 993 | 994 | " Go to the end of the new lines 995 | silent! exec "'e-" 996 | let linenum = line("'e")-1 997 | " endif 998 | endif 999 | 1000 | let linenum = linenum + 1 1001 | endwhile 1002 | 1003 | return linenum 1004 | endfunction 1005 | 1006 | " For certain keyword lines (SELECT, ORDER BY, GROUP BY, ...) 1007 | " Ensure the lines fit in the textwidth (or default 80), wrap 1008 | " the lines where necessary and left justify the column names 1009 | function! s:SQLU_WrapExpressions() 1010 | " Check if this is a statement that can often by longer than 80 characters 1011 | " (select, set and so on), if so, ensure the column list is broken over as 1012 | " many lines as necessary and lined up with the other columns 1013 | let linenum = line("'y+1") 1014 | 1015 | return 1016 | 1017 | let sql_keywords = '\<\%(select\)\>' 1018 | let sql_expression_operator = '' . 1019 | \ '\<\%(' . 1020 | \ '\%(end\s\+\)\@' 1022 | 1023 | " call Decho(" Before column splitter 'y+1=".line("'<"). 1024 | " \ ":".col("'<")." 'z-1=".line("'>").":".col("'>")) 1025 | while linenum <= line("'z-1") 1026 | let line = getline(linenum) 1027 | " if line =~? '^\s*\('.sql_keywords.'\)' 1028 | if line =~? '\w' 1029 | " if line =~? '^\s*\('.sql_keywords.'\)' 1030 | " Decho 'linenum: ' . linenum . ' strlen: ' . 1031 | " \ strlen(line) . ' textwidth: ' . &textwidth . 1032 | " \ ' line: ' . line 1033 | " go to the current line 1034 | silent! exec linenum 1035 | " Mark the start of the wide line 1036 | silent! exec "normal! mb" 1037 | let markb = linenum 1038 | " echom "line b - ".getline("'b") 1039 | " Mark the next line 1040 | silent! exec "normal! jmek" 1041 | " echom "line e - ".getline("'e") 1042 | 1043 | 1044 | if line =~? '\('.sql_expression_operator.'\)' 1045 | silent! exec linenum . ',' . linenum . 1046 | \ 's/^\s*\('.sql_keywords.'\)\s*'. 1047 | \ '/\1-@-' 1048 | " Create a special marker for Align.vim 1049 | " to line up the columns with 1050 | silent! exec linenum . ',' . linenum . 1051 | \ 's/'.sql_expression_operator.'/'. 1052 | \ '\r-@-&' 1053 | 1054 | endif 1055 | 1056 | " echom "end_line_nbr - ".end_line_nbr 1057 | " echom "normal! end_line_nbr - ".line(end_line_nbr) 1058 | 1059 | " Append the special marker to the beginning of the line 1060 | " for Align.vim 1061 | " silent! exec "'b+," .end_line_nbr. 's/\s*\(.*\)/-@-\1' 1062 | " silent! exec "'b+," .end_line_nbr. 's/^\s*/-@-' 1063 | silent! exec ''.(markb+1)."," .end_line_nbr. 's/^\s*/-@-/g' 1064 | " silent! exec "'b+,'e-" . 's/\s*\(.*\)/-@-\1' 1065 | AlignCtrl Ip0P0rl: 1066 | " silent! 'b,'e-Align -@- 1067 | " silent! exec "'b,".end_line_nbr.'Align -@-' 1068 | silent! exec markb.",'e".'Align -@-' 1069 | " silent! 'b,'e-s/-@-/ / 1070 | silent! exec markb.",'e".'s/-@-/ /ge' 1071 | AlignCtrl default 1072 | 1073 | " Advance the linenum to the end of the range 1074 | let linenum = line("'e") 1075 | " endif 1076 | endif 1077 | 1078 | let linenum = linenum + 1 1079 | endwhile 1080 | 1081 | return linenum 1082 | endfunction 1083 | 1084 | " For certain keyword lines (SELECT, ORDER BY, GROUP BY, ...) 1085 | " Ensure the lines fit in the textwidth (or default 80), wrap 1086 | " the lines where necessary and left justify the column names 1087 | function! s:SQLU_WrapLongLines() 1088 | " Check if this is a statement that can often by longer than 80 characters 1089 | " (select, set and so on), if so, ensure the column list is broken over as 1090 | " many lines as necessary and lined up with the other columns 1091 | let linenum = line("'y+1") 1092 | 1093 | return 1094 | 1095 | let org_textwidth = &textwidth 1096 | if &textwidth == 0 1097 | " Get the width of the window 1098 | let &textwidth = winwidth(winnr()) 1099 | endif 1100 | 1101 | let sql_keywords = '\<\%(select\|set\|into\|from\|values'. 1102 | \ '\|order\|group\|having\|call\|with\)\>' 1103 | 1104 | " call Decho(" Before column splitter 'y+1=".line("'<"). 1105 | " \ ":".col("'<")." 'z-1=".line("'>").":".col("'>")) 1106 | while linenum <= line("'z-1") 1107 | let line = getline(linenum) 1108 | " if line =~? '^\s*\('.sql_keywords.'\)' 1109 | if line =~? '\w' 1110 | " Set the textwidth to current value 1111 | " minus an adjustment for select and set 1112 | " minus any indent value this may have 1113 | " echo 'tw: '.&textwidth.' indent: '.indent(line) 1114 | " Decho 'line: '.line 1115 | " Decho 'tw: '.&textwidth.' match at: '. 1116 | " \ matchend(line, sql_keywords ) 1117 | " let &textwidth = &textwidth - 10 - indent(line) 1118 | if line =~? '^\s*\('.sql_keywords.'\)' 1119 | let &textwidth = &textwidth - matchend(line, sql_keywords ) - 2 1120 | let line_length = strlen(line) - matchend(line, sql_keywords ) 1121 | else 1122 | let line_length = strlen(line) 1123 | endif 1124 | 1125 | if( line_length > &textwidth ) 1126 | " Decho 'linenum: ' . linenum . ' strlen: ' . 1127 | " \ strlen(line) . ' textwidth: ' . &textwidth . 1128 | " \ ' line: ' . line 1129 | " go to the current line 1130 | silent! exec linenum 1131 | " Mark the start of the wide line 1132 | silent! exec "normal! mb" 1133 | let markb = linenum 1134 | " echom "line b - ".getline("'b") 1135 | " Mark the next line 1136 | silent! exec "normal! jmek" 1137 | " echom "line e - ".getline("'e") 1138 | " echom "line length- ".strlen(getline(".")). 1139 | " \ " tw=".&textwidth 1140 | 1141 | 1142 | if line =~? '^\s*\('.sql_keywords.'\)' 1143 | " Create a special marker for Align.vim 1144 | " to line up the columns with 1145 | silent! exec linenum . ',' . linenum . 's/\(\w\) /\1-@-' 1146 | 1147 | " If the line begins with SET then force each 1148 | " column on a newline, instead of breaking them apart 1149 | " this will ensure that the col_name = ... is on the 1150 | " same line 1151 | if line =~? '^\s*\' 1152 | silent! 'b,'e-1s/,/,\r/ge 1153 | endif 1154 | else 1155 | " Place the special marker that the first non-whitespace 1156 | " characeter 1157 | if g:sqlutil_align_comma == 1 && line =~ '^\s*,' 1158 | " silent! exec linenum . ',' . linenum . 1159 | " \ 's/^\s*\zs,\s*/, -@-' 1160 | if g:sqlutil_align_keyword_right == 1 1161 | silent! exec linenum . ',' . linenum . 1162 | \ 's/^\s*\zs,\s*/, -@-' 1163 | else 1164 | silent! exec linenum . ',' . linenum . 1165 | \ 's/^\s*\zs,\s*/-@-, ' 1166 | endif 1167 | else 1168 | silent! exec linenum . ',' . linenum . 's/\S/-@-&' 1169 | endif 1170 | endif 1171 | 1172 | silent! exec linenum 1173 | " Reformat the line based on the textwidth 1174 | silent! exec "normal! gqq" 1175 | 1176 | " echom "normal! mb - ".line("'b") 1177 | " echom "normal! me - ".line("'e") 1178 | " Sometimes reformatting does not change the line 1179 | " so we need to double check the end range to 1180 | " ensure it does go backwards 1181 | let begin_line_nbr = (line("'b") + 1) 1182 | let begin_line_nbr = (markb + 1) 1183 | let end_line_nbr = (line("'e") - 1) 1184 | " echom "b- ".begin_line_nbr." e- ".end_line_nbr 1185 | if end_line_nbr < begin_line_nbr 1186 | let end_line_nbr = end_line_nbr + 1 1187 | " echom "end_line_nbr adding 1 " 1188 | endif 1189 | " echom "end_line_nbr - ".end_line_nbr 1190 | " echom "normal! end_line_nbr - ".line(end_line_nbr) 1191 | 1192 | " Reformat the commas 1193 | " silent! 'b,'e-s/\s*,/,/ge 1194 | " silent! exec "'b,".end_line_nbr.'s/\s*,/,/ge' 1195 | " Add a space after the comma 1196 | " silent! 'b,'e-s/,\(\w\)/, \1/ge 1197 | " silent! exec "'b,".end_line_nbr.'s/,\(\w\)/, \1/ge' 1198 | silent! exec markb.",".end_line_nbr.'s/,\(\w\)/, \1/ge' 1199 | 1200 | " Append the special marker to the beginning of the line 1201 | " for Align.vim 1202 | " silent! exec "'b+," .end_line_nbr. 's/\s*\(.*\)/-@-\1' 1203 | " silent! exec "'b+," .end_line_nbr. 's/^\s*/-@-' 1204 | silent! exec ''.(markb+1)."," .end_line_nbr. 's/^\s*/-@-' 1205 | " silent! exec "'b+,'e-" . 's/\s*\(.*\)/-@-\1' 1206 | AlignCtrl Ip0P0rl: 1207 | " silent! 'b,'e-Align -@- 1208 | " silent! exec "'b,".end_line_nbr.'Align -@-' 1209 | silent! exec markb.",".end_line_nbr.'Align -@-' 1210 | " silent! 'b,'e-s/-@-/ / 1211 | if line =~? '^\s*\('.sql_keywords.'\)' 1212 | silent! exec markb.",".end_line_nbr.'s/-@-/ /ge' 1213 | else 1214 | silent! exec markb.",".end_line_nbr.'s/-@-/'.(g:sqlutil_align_comma == 1 ? ' ' : '' ).'/ge' 1215 | endif 1216 | AlignCtrl default 1217 | 1218 | " Dont move to the end of the reformatted text 1219 | " since we also want to check for CASE statemtns 1220 | " let linenum = line("'e") - 1 1221 | " let linenum = line("'e") 1222 | endif 1223 | endif 1224 | 1225 | let &textwidth = org_textwidth 1226 | if &textwidth == 0 1227 | " Get the width of the window 1228 | let &textwidth = winwidth(winnr()) 1229 | endif 1230 | let linenum = linenum + 1 1231 | endwhile 1232 | 1233 | let &textwidth = org_textwidth 1234 | return linenum 1235 | endfunction 1236 | 1237 | " Finds unbalanced paranthesis and put each one on a new line 1238 | function! s:SQLU_SplitUnbalParan() 1239 | let linenum = line("'y+1") 1240 | while linenum <= line("'z-1") 1241 | let line = getline(linenum) 1242 | " echom 'SQLU_SplitUnbalParan: l: ' . linenum . ' t: '. getline(linenum) 1243 | if line !~ '(' 1244 | " echom 'SQLU_SplitUnbalParan: no (s: '.linenum.' : '. 1245 | " \ getline(linenum) 1246 | let linenum = linenum + 1 1247 | continue 1248 | endif 1249 | 1250 | " echom 'SQLU_SplitUnbalParan: start line: '.linenum.' : '.line 1251 | 1252 | let begin_paran = match( line, "(" ) 1253 | while begin_paran > -1 1254 | " Check if the paran is inside a string 1255 | if synID(linenum,(begin_paran+1),1) > 0 1256 | " If it is, skip to the next paran 1257 | let begin_paran = match( getline(linenum), "(", (begin_paran+1) ) 1258 | continue 1259 | endif 1260 | 1261 | " let curcol = begin_paran + 1 1262 | let curcol = begin_paran 1263 | " echom 'begin_paran: '.begin_paran. 1264 | " \ ' line: '.linenum. 1265 | " \ ' col: '.curcol. 1266 | " \ ' : '.line 1267 | 1268 | " Place the cursor on the ( 1269 | "silent! exe 'normal! '.linenum."G\".(curcol-1)."l" 1270 | " silent! exe 'normal! '.linenum."G\".curcol."l" 1271 | call cursor(linenum,(curcol+1)) 1272 | 1273 | " let indent_to = searchpair( '(', '', ')', '' ) 1274 | " Find the matching closing ) 1275 | " Ignore parans that are inside of strings 1276 | let indent_to = searchpair( '(', '', ')', 'W', 1277 | \ 'synID(line("."),col("."),1)>0' ) 1278 | 1279 | " If the match is outside of the range, this is an unmatched ( 1280 | if indent_to < 1 || indent_to > line("'z-1") 1281 | " Return to previous location 1282 | " echom 'Unmatched parentheses on line: ' . getline(linenum) 1283 | call s:SQLU_WarningMsg( 1284 | \ 'SQLU_SplitUnbalParan: Unmatched parentheses' . 1285 | \ ' at line/col: (' . (linenum-1).','.(curcol+1). 1286 | \ ') on line: ' . 1287 | \ getline(linenum) 1288 | \ ) 1289 | " echom 'Unmatched parentheses: Returning to: '. 1290 | " \ linenum."G\".curcol."l" 1291 | " \ " #: ".line(".") 1292 | " \ " text: ".getline(".") 1293 | " silent! exe 'normal! '.linenum."G\".(curcol-1)."l" 1294 | silent! exe 'normal! '.linenum."G\".curcol."l" 1295 | return -1 1296 | endif 1297 | 1298 | let matchline = line(".") 1299 | let matchcol = virtcol(".") 1300 | " echom 'SQLU_SplitUnbalParan searchpair: ' . indent_to. 1301 | " \ ' col: '.matchcol. 1302 | " \ ' line: '.getline(indent_to) 1303 | 1304 | " If the match is on a DIFFERENT line 1305 | if indent_to != linenum 1306 | " If a ) is NOT the only thing on the line 1307 | " I have relaxed this, so it must be the first 1308 | " thing on the line 1309 | " if getline(indent_to) !~ '^\s*\(-@-\)\?)\s*$' 1310 | if getline(indent_to) !~ '^\s*\(-@-\)\?)' 1311 | " Place the paranethesis on a new line 1312 | silent! exec "normal! i\n\" 1313 | let indent_to = indent_to + 1 1314 | " echom 'Indented closing line: '.getline(".") 1315 | endif 1316 | " Remove leading spaces 1317 | " echom "Removing leading spaces" 1318 | " exec 'normal! '.indent_to.','.indent_to. 1319 | " \'s/^\s*//e'."\n" 1320 | silent! exec 's/^\s*//e'."\n" 1321 | 1322 | " Place a marker at the beginning of the line so 1323 | " it can be Aligned with its matching paranthesis 1324 | if getline(".") !~ '^\s*-@-' 1325 | silent! exec "normal! i-@-\" 1326 | endif 1327 | " echom 'Replacing ) with newline: '.line("."). 1328 | " \ ' indent: '.curcol.' ' 1329 | " \ getline(indent_to) 1330 | 1331 | " echom 'line:' . linenum . ' col:' . curcol 1332 | "echom linenum . ' ' . getline(linenum) . curcol . 1333 | "\ ' ' . matchstr( getline(linenum), 1334 | "\ '^.\{'.(curcol).'}\zs.*' ) 1335 | 1336 | 1337 | " Return to the original line 1338 | " Check if the line with the ( needs splitting 1339 | " as well 1340 | " Since the closing ) is on a different line, make sure 1341 | " this ( is the last character on the line, this is 1342 | " necessary so that the blocks are correctly indented 1343 | " .\{8} - match any characters up to the 8th column 1344 | " \zs - start the search in column 9 1345 | " \s*$ - If the line only has whitespace dont split 1346 | 1347 | if getline(linenum) !~ '^.\{'.(curcol+1).'}\zs\s*$' 1348 | " Return to previous location 1349 | silent! exe 'normal! '.linenum."G\".curcol."l" 1350 | 1351 | " Place the paranethesis on a new line 1352 | " with the marker at the beginning so 1353 | " it can be Aligned with its matching paranthesis 1354 | silent! exec "normal! a\n-@-\" 1355 | 1356 | " Add 1 to the linenum since the remainder of this 1357 | " line has been moved 1358 | let linenum = linenum + 1 1359 | " Reset begin_paran since we are on a new line 1360 | let begin_paran = -1 1361 | 1362 | endif 1363 | endif 1364 | 1365 | " We have potentially changed the line we are on 1366 | " so get a new copy of the row to perform the match 1367 | " Add one to the curcol to look for the next ( 1368 | let begin_paran = match( getline(linenum), "(", (begin_paran+1) ) 1369 | 1370 | endwhile 1371 | 1372 | let linenum = linenum + 1 1373 | endwhile 1374 | 1375 | " Never found matching close parenthesis 1376 | " return end of range 1377 | return linenum 1378 | endfunction 1379 | 1380 | " Puts a command separate list of columns given a table name 1381 | " Will search through the file looking for the create table command 1382 | " It assumes that each column is on a separate line 1383 | " It places the column list in unnamed buffer 1384 | function! SQLUtilities#SQLU_CreateColumnList(...) 1385 | 1386 | " Mark the current line to return to 1387 | let curline = line(".") 1388 | let curcol = virtcol(".") 1389 | let curbuf = bufnr(expand("")) 1390 | let found = 0 1391 | 1392 | if(a:0 > 0) 1393 | let table_name = a:1 1394 | else 1395 | let table_name = expand("") 1396 | endif 1397 | 1398 | if(a:0 > 1) 1399 | let only_primary_key = 1 1400 | else 1401 | let only_primary_key = 0 1402 | endif 1403 | 1404 | let add_alias = '' 1405 | if(a:0 > 2) 1406 | let add_alias = a:2 1407 | else 1408 | if 'da' =~? g:sqlutil_use_tbl_alias 1409 | if table_name =~ '_' 1410 | " Treat _ as separators since people often use these 1411 | " for word separators 1412 | let save_keyword = &iskeyword 1413 | setlocal iskeyword-=_ 1414 | 1415 | " Get the first letter of each word 1416 | " [[:alpha:]] is used instead of \w 1417 | " to catch extended accented characters 1418 | " 1419 | let initials = substitute( 1420 | \ table_name, 1421 | \ '\<[[:alpha:]]\+\>_\?', 1422 | \ '\=strpart(submatch(0), 0, 1)', 1423 | \ 'g' 1424 | \ ) 1425 | " Restore original value 1426 | let &iskeyword = save_keyword 1427 | elseif table_name =~ '\u\U' 1428 | let initials = substitute( 1429 | \ table_name, '\(\u\)\U*', '\1', 'g') 1430 | else 1431 | let initials = strpart(table_name, 0, 1) 1432 | endif 1433 | 1434 | if 'a' =~? g:sqlutil_use_tbl_alias 1435 | let add_alias = inputdialog("Enter table alias:", initials) 1436 | else 1437 | let add_alias = initials 1438 | endif 1439 | endif 1440 | endif 1441 | " Following a word character, make sure there is a . and no spaces 1442 | let add_alias = substitute(add_alias, '\w\zs\.\?\s*$', '.', '') 1443 | 1444 | " save previous search string 1445 | let saveSearch = @/ 1446 | let saveZ = @z 1447 | let columns = "" 1448 | " Prevent the alternate buffer () from being set to this 1449 | " temporary file 1450 | let l:old_cpoptions = &cpoptions 1451 | setlocal cpo-=a 1452 | 1453 | " ignore case 1454 | if( only_primary_key == 0 ) 1455 | let srch_table = '\c^[ \t]*create.*table.*\<'.table_name.'\>' 1456 | else 1457 | " Regular expression breakdown 1458 | " Ingore case and spaces 1459 | " line begins with either create or alter 1460 | " followed by table and table_name (on the same line) 1461 | " Could be other lines inbetween these 1462 | " Look for the primary key clause (must be one) 1463 | " Start the match after the open paran 1464 | " The column list could span multiple lines 1465 | " End the match on the closing paran 1466 | " Could be other lines in between these 1467 | " Remove any newline characters for the command 1468 | " terminator (ie "\ngo" ) 1469 | " Besides a CREATE TABLE statement, this expression 1470 | " should find statements like: 1471 | " ALTER TABLE SSD.D_CENTR_ALLOWABLE_DAYS 1472 | " ADD PRIMARY KEY (CUST_NBR, CAL_NBR, GRP_NBR, 1473 | " EVENT_NBR, ALLOW_REVIS_NBR, ROW_REVIS_NBR); 1474 | let srch_table = '\c^[ \t]*' . 1475 | \ '\(create\|alter\)' . 1476 | \ '.*table.*' . 1477 | \ table_name . 1478 | \ '\_.\{-}' . 1479 | \ '\%(primary key\)\{-1,}' . 1480 | \ '\s*(\zs' . 1481 | \ '\_.\{-}' . 1482 | \ '\ze)' . 1483 | \ '\_.\{-}' . 1484 | \ substitute( g:sqlutil_cmd_terminator, 1485 | \ "[\n]", '', "g" ) 1486 | endif 1487 | 1488 | " Loop through all currenly open buffers to look for the 1489 | " CREATE TABLE statement, if found build the column list 1490 | " or display a message saying the table wasn't found 1491 | " I am assuming a create table statement is of this format 1492 | " CREATE TABLE "cons"."sync_params" ( 1493 | " "id" integer NOT NULL, 1494 | " "last_sync" timestamp NULL, 1495 | " "sync_required" char(1) NOT NULL DEFAULT 'N', 1496 | " "retries" smallint NOT NULL , 1497 | " PRIMARY KEY ("id") 1498 | " ); 1499 | while( 1==1 ) 1500 | " Mark the current line to return to 1501 | let buf_curline = line(".") 1502 | let buf_curcol = virtcol(".") 1503 | " From the top of the file 1504 | silent! exe "normal! 1G\0\" 1505 | if( search( srch_table, "W" ) ) > 0 1506 | if( only_primary_key == 0 ) 1507 | " Find the create table statement 1508 | " let cmd = '/'.srch_create_table."\n" 1509 | " Find the opening ( that starts the column list 1510 | let cmd = 'normal! /('."\n".'Vib'."\" 1511 | silent! exe cmd 1512 | " Decho 'end: '.getline(line("'>")) 1513 | let start_line = line("'<") 1514 | let end_line = line("'>") 1515 | silent! exe 'noh' 1516 | let found = 1 1517 | 1518 | " Visually select until the following keyword are the beginning 1519 | " of the line, this should be at the bottom of the column list 1520 | " Start visually selecting columns 1521 | " let cmd = 'silent! normal! V'."\n" 1522 | let find_end_of_cols = 1523 | \ '\(' . 1524 | \ g:sqlutil_cmd_terminator . 1525 | \ '\|' . 1526 | \ substitute( 1527 | \ g:sqlutil_col_list_terminators, 1528 | \ ',', '\\|\1', 'g' ) . 1529 | \ '\)' 1530 | 1531 | let separator = "" 1532 | let columns = "" 1533 | 1534 | " Build comma separated list of input parameters 1535 | while start_line <= end_line 1536 | let line = getline(start_line) 1537 | 1538 | " If the line has no words on it, skip it 1539 | if line !~ '\w' || line =~ '^\s*$' 1540 | let start_line = start_line + 1 1541 | continue 1542 | endif 1543 | 1544 | 1545 | " if any of the find_end_of_cols is found, leave this loop. 1546 | " This test is case insensitive. 1547 | if line =~? '^\s*\w\+\s\+\w\+\s\+'.find_end_of_cols 1548 | " Special case, the column name definition 1549 | " is part of the line 1550 | elseif line =~? find_end_of_cols 1551 | let end_line = start_line - 1 1552 | break 1553 | endif 1554 | 1555 | let column_name = substitute( line, 1556 | \ '[ \t"]*\(\<\w\+\>\).*', '\1', "g" ) 1557 | let column_def = SQLU_GetColumnDatatype( line, 1 ) 1558 | 1559 | let columns = columns . separator . add_alias . column_name 1560 | let separator = ", " 1561 | let start_line = start_line + 1 1562 | endwhile 1563 | 1564 | else 1565 | " Find the primary key statement 1566 | " Visually select all the text until the 1567 | " closing paranthesis 1568 | silent! exe 'silent! normal! v/)/e-1'."\n".'"zy' 1569 | let columns = @z 1570 | " Strip newlines characters 1571 | let columns = substitute( columns, 1572 | \ "[\n]", '', "g" ) 1573 | " Strip everything but the column list 1574 | let columns = substitute( columns, 1575 | \ '\s*\(.*\)\s*', '\1', "g" ) 1576 | " Remove double quotes 1577 | let columns = substitute( columns, '"', '', "g" ) 1578 | let columns = substitute( columns, ',\s*', ', ', "g" ) 1579 | let columns = substitute( columns, '^\s*', '', "g" ) 1580 | let columns = substitute( columns, '\s*$', '', "g" ) 1581 | let found = 1 1582 | silent! exe 'noh' 1583 | endif 1584 | 1585 | endif 1586 | 1587 | " Return to previous location 1588 | silent! exe 'normal! '.buf_curline."G\".buf_curcol."l" 1589 | 1590 | if found == 1 1591 | break 1592 | endif 1593 | 1594 | if &hidden == 0 1595 | call s:SQLU_WarningMsg( 1596 | \ "Cannot search other buffers with set nohidden" 1597 | \ ) 1598 | break 1599 | endif 1600 | 1601 | " Switch buffers to check to see if the create table 1602 | " statement exists 1603 | silent! exec "bnext" 1604 | if bufnr(expand("")) == curbuf 1605 | break 1606 | endif 1607 | endwhile 1608 | 1609 | silent! exec "buffer " . curbuf 1610 | 1611 | " Return to previous location 1612 | silent! exe 'normal! '.curline."G\".(curcol-1).(((curcol-1) > 0)?"l":'') 1613 | silent! exe 'noh' 1614 | 1615 | " restore previous search 1616 | let @/ = saveSearch 1617 | let @z = saveZ 1618 | 1619 | " Restore previous cpoptions 1620 | let &cpoptions = l:old_cpoptions 1621 | 1622 | 1623 | redraw 1624 | 1625 | if found == 0 1626 | let @@ = "" 1627 | if( only_primary_key == 0 ) 1628 | call s:SQLU_WarningMsg( 1629 | \ "SQLU_CreateColumnList - Table: " . 1630 | \ table_name . 1631 | \ " was not found" 1632 | \ ) 1633 | else 1634 | call s:SQLU_WarningMsg( 1635 | \ "SQLU_CreateColumnList - Table: " . 1636 | \ table_name . 1637 | \ " does not have a primary key" 1638 | \ ) 1639 | endif 1640 | return "" 1641 | endif 1642 | 1643 | " If clipboard is pointing to the windows clipboard 1644 | " copy the results there. 1645 | if &clipboard == 'unnamed' 1646 | let @* = columns 1647 | else 1648 | let @@ = columns 1649 | endif 1650 | 1651 | echo "Paste register: " . columns 1652 | 1653 | return columns 1654 | 1655 | endfunction 1656 | 1657 | 1658 | " Strip the datatype from a column definition line 1659 | function! SQLUtilities#SQLU_GetColumnDatatype( line, need_type ) 1660 | 1661 | let pattern = '\c^\s*' " case insensitve, white space at start of line 1662 | let pattern = pattern . '\S\+\w\+[ "\t]\+' " non white space (name with 1663 | " quotes) 1664 | 1665 | if a:need_type == 1 1666 | let pattern = pattern . '\zs' " Start matching the datatype 1667 | let pattern = pattern . '.\{-}' " include anything 1668 | let pattern = pattern . '\ze\s*' " Stop matching when ... 1669 | let pattern = pattern . '\(NOT\|NULL\|DEFAULT\|' 1670 | let pattern = pattern . '\(\s*,\s*$\)' " Line ends with a comma 1671 | let pattern = pattern . '\)' 1672 | else 1673 | let pattern = pattern . '\zs' " Start matching the datatype 1674 | let pattern = pattern . '.\{-}' " include anything 1675 | let pattern = pattern . '\ze' " Stop matching when ... 1676 | let pattern = pattern . '\s*,\s*$' " Line ends with a comma 1677 | endif 1678 | 1679 | let datatype = matchstr( a:line, pattern ) 1680 | 1681 | return datatype 1682 | endfunction 1683 | 1684 | 1685 | " Puts a comma separated list of columns given a table name 1686 | " Will search through the file looking for the create table command 1687 | " It assumes that each column is on a separate line 1688 | " It places the column list in unnamed buffer 1689 | function! SQLUtilities#SQLU_GetColumnDef( ... ) 1690 | 1691 | " Mark the current line to return to 1692 | let curline = line(".") 1693 | let curcol = virtcol(".") 1694 | let curbuf = bufnr(expand("")) 1695 | let found = 0 1696 | 1697 | if(a:0 > 0) 1698 | let col_name = a:1 1699 | else 1700 | let col_name = expand("") 1701 | endif 1702 | 1703 | if(a:0 > 1) 1704 | let need_type = a:2 1705 | else 1706 | let need_type = 0 1707 | endif 1708 | 1709 | let srch_column_name = '^[ \t]*["]\?\<' . col_name . '\>["]\?\s\+\<\w\+\>' 1710 | let column_def = "" 1711 | 1712 | " Loop through all currenly open buffers to look for the 1713 | " CREATE TABLE statement, if found build the column list 1714 | " or display a message saying the table wasn't found 1715 | " I am assuming a create table statement is of this format 1716 | " CREATE TABLE "cons"."sync_params" ( 1717 | " "id" integer NOT NULL, 1718 | " "last_sync" timestamp NULL, 1719 | " "sync_required" char(1) NOT NULL DEFAULT 'N', 1720 | " "retries" smallint NOT NULL , 1721 | " PRIMARY KEY ("id") 1722 | " ); 1723 | while( 1==1 ) 1724 | " Mark the current line to return to 1725 | let buf_curline = line(".") 1726 | let buf_curcol = virtcol(".") 1727 | 1728 | " From the top of the file 1729 | silent! exe "normal! 1G\0\" 1730 | 1731 | if( search( srch_column_name, "w" ) ) > 0 1732 | silent! exe 'noh' 1733 | let found = 1 1734 | let column_def = SQLU_GetColumnDatatype( getline("."), need_type ) 1735 | endif 1736 | 1737 | " Return to previous location 1738 | silent! exe 'normal! '.buf_curline."G\".buf_curcol."l" 1739 | 1740 | if found == 1 1741 | break 1742 | endif 1743 | 1744 | if &hidden == 0 1745 | call s:SQLU_WarningMsg( 1746 | \ "Cannot search other buffers with set nohidden" 1747 | \ ) 1748 | break 1749 | endif 1750 | 1751 | " Switch buffers to check to see if the create table 1752 | " statement exists 1753 | silent! exec "bnext" 1754 | if bufnr(expand("")) == curbuf 1755 | break 1756 | endif 1757 | endwhile 1758 | 1759 | silent! exec "buffer " . curbuf 1760 | 1761 | " Return to previous location 1762 | silent! exe 'normal! '.curline."G\".curcol."l" 1763 | 1764 | if found == 0 1765 | let @@ = "" 1766 | echo "Column: " . col_name . " was not found" 1767 | return "" 1768 | endif 1769 | 1770 | if &clipboard == 'unnamed' 1771 | let @* = column_def 1772 | else 1773 | let @@ = column_def 1774 | endif 1775 | 1776 | " If a parameter has been passed, this means replace the 1777 | " current word, with the column list 1778 | " if (a:0 > 0) && (found == 1) 1779 | " exec "silent! normal! viwp" 1780 | " if &clipboard == 'unnamed' 1781 | " let @* = col_name 1782 | " else 1783 | " let @@ = col_name 1784 | " endif 1785 | " echo "Paste register: " . col_name 1786 | " else 1787 | echo "Paste register: " . column_def 1788 | " endif 1789 | 1790 | return column_def 1791 | 1792 | endfunction 1793 | 1794 | 1795 | 1796 | " Creates a procedure defintion into the unnamed buffer for the 1797 | " table that the cursor is currently under. 1798 | function! SQLUtilities#SQLU_CreateProcedure(...) 1799 | 1800 | " Mark the current line to return to 1801 | let curline = line(".") 1802 | let curcol = virtcol(".") 1803 | let curbuf = bufnr(expand("")) 1804 | let found = 0 1805 | " save previous search string 1806 | let saveSearch=@/ 1807 | " Prevent the alternate buffer () from being set to this 1808 | " temporary file 1809 | let l:old_cpoptions = &cpoptions 1810 | let l:old_eventignore = &eventignore 1811 | setlocal cpo-=A 1812 | setlocal eventignore=BufRead,BufReadPre,BufEnter,BufNewFile 1813 | 1814 | 1815 | 1816 | if(a:0 > 0) 1817 | let table_name = a:1 1818 | else 1819 | let table_name = expand("") 1820 | endif 1821 | 1822 | let i = 0 1823 | let indent_spaces = '' 1824 | while( i < &shiftwidth ) 1825 | let indent_spaces = indent_spaces . ' ' 1826 | let i = i + 1 1827 | endwhile 1828 | 1829 | " ignore case 1830 | " let srch_create_table = '\c^[ \t]*create.*table.*\<' . table_name . '\>' 1831 | let srch_create_table = '\c^[ \t]*create.*table.*\<' . 1832 | \ table_name . 1833 | \ '\>' 1834 | let procedure_def = "CREATE PROCEDURE sp_" . table_name . "(\n" 1835 | 1836 | " Loop through all currenly open buffers to look for the 1837 | " CREATE TABLE statement, if found build the column list 1838 | " or display a message saying the table wasn't found 1839 | " I am assuming a create table statement is of this format 1840 | " CREATE TABLE "cons"."sync_params" ( 1841 | " "id" integer NOT NULL, 1842 | " "last_sync" timestamp NULL, 1843 | " "sync_required" char(1) NOT NULL DEFAULT 'N', 1844 | " "retries" smallint NOT NULL, 1845 | " PRIMARY KEY ("id") 1846 | " ); 1847 | while( 1==1 ) 1848 | " Mark the current line to return to 1849 | let buf_curline = line(".") 1850 | let buf_curcol = virtcol(".") 1851 | 1852 | " From the top of the file 1853 | silent! exe "normal! 1G\0\" 1854 | 1855 | if( search( srch_create_table, "w" ) ) > 0 1856 | " Find the create table statement 1857 | " let cmd = '/'.srch_create_table."\n" 1858 | " Find the opening ( that starts the column list 1859 | let cmd = 'normal! /('."\n".'Vib'."\" 1860 | silent! exe cmd 1861 | " Decho 'end: '.getline(line("'>")) 1862 | let start_line = line("'<") 1863 | let end_line = line("'>") 1864 | silent! exe 'noh' 1865 | let found = 1 1866 | 1867 | " Visually select until the following keyword are the beginning 1868 | " of the line, this should be at the bottom of the column list 1869 | " Start visually selecting columns 1870 | " let cmd = 'silent! normal! V'."\n" 1871 | let find_end_of_cols = 1872 | \ '\(' . 1873 | \ g:sqlutil_cmd_terminator . 1874 | \ '\|' . 1875 | \ substitute( 1876 | \ g:sqlutil_col_list_terminators, 1877 | \ ',', '\\|\1', 'g' ) . 1878 | \ '\)' 1879 | 1880 | let separator = " " 1881 | let column_list = "" 1882 | 1883 | " Build comma separated list of input parameters 1884 | while start_line <= end_line 1885 | let line = getline(start_line) 1886 | 1887 | " If the line has no words on it, skip it 1888 | if line !~ '\w' || line =~ '^\s*$' 1889 | let start_line = start_line + 1 1890 | continue 1891 | endif 1892 | 1893 | " if any of the find_end_of_cols is found, leave this loop. 1894 | " This test is case insensitive. 1895 | if line =~? find_end_of_cols 1896 | let end_line = start_line - 1 1897 | break 1898 | endif 1899 | 1900 | let column_name = substitute( line, 1901 | \ '[ \t"]*\(\<\w\+\>\).*', '\1', "g" ) 1902 | let column_def = SQLU_GetColumnDatatype( line, 1 ) 1903 | 1904 | let column_list = column_list . separator . column_name 1905 | let procedure_def = procedure_def . 1906 | \ indent_spaces . 1907 | \ separator . 1908 | \ "IN @" . column_name . 1909 | \ ' ' . column_def . "\n" 1910 | 1911 | let separator = "," 1912 | let start_line = start_line + 1 1913 | endwhile 1914 | 1915 | let procedure_def = procedure_def . ")\n" 1916 | let procedure_def = procedure_def . "RESULT(\n" 1917 | 1918 | let start_line = line("'<") 1919 | let separator = " " 1920 | 1921 | " Build comma separated list of datatypes 1922 | while start_line <= end_line 1923 | let line = getline(start_line) 1924 | 1925 | " If the line has no words on it, skip it 1926 | if line !~ '\w' || line =~ '^\s*$' 1927 | let start_line = start_line + 1 1928 | continue 1929 | endif 1930 | 1931 | let column_def = SQLU_GetColumnDatatype( line, 1 ) 1932 | 1933 | let procedure_def = procedure_def . 1934 | \ indent_spaces . 1935 | \ separator . 1936 | \ column_def . 1937 | \ "\n" 1938 | 1939 | let separator = "," 1940 | let start_line = start_line + 1 1941 | endwhile 1942 | 1943 | let procedure_def = procedure_def . ")\n" 1944 | " Strip off any spaces 1945 | let column_list = substitute( column_list, ' ', '', 'g' ) 1946 | " Ensure there is one space after each , 1947 | let column_list = substitute( column_list, ',', ', ', 'g' ) 1948 | let save_tbl_alias = g:sqlutil_use_tbl_alias 1949 | " Disable the prompt for the table alias 1950 | let g:sqlutil_use_tbl_alias = 'n' 1951 | let pk_column_list = SQLU_CreateColumnList( 1952 | \ table_name, 'primary_keys') 1953 | let g:sqlutil_use_tbl_alias = save_tbl_alias 1954 | 1955 | let procedure_def = procedure_def . "BEGIN\n\n" 1956 | 1957 | " Create a sample SELECT statement 1958 | let procedure_def = procedure_def . 1959 | \ indent_spaces . 1960 | \ "SELECT " . column_list . "\n" . 1961 | \ indent_spaces . 1962 | \ " FROM " . table_name . "\n" 1963 | let where_clause = indent_spaces . 1964 | \ substitute( column_list, 1965 | \ '^\(\<\w\+\>\)\(.*\)', " WHERE \\1 = \@\\1\\2", "g" ) 1966 | let where_clause = 1967 | \ substitute( where_clause, 1968 | \ ', \(\<\w\+\>\)', 1969 | \ "\n" . indent_spaces . " AND \\1 = @\\1", "g" ) 1970 | let procedure_def = procedure_def . where_clause . ";\n\n" 1971 | 1972 | " Create a sample INSERT statement 1973 | let procedure_def = procedure_def . 1974 | \ indent_spaces . 1975 | \ "INSERT INTO " . table_name . "( " . 1976 | \ column_list . 1977 | \ " )\n" 1978 | let procedure_def = procedure_def . 1979 | \ indent_spaces . 1980 | \ "VALUES( " . 1981 | \ substitute( column_list, '\(\<\w\+\>\)', '@\1', "g" ). 1982 | \ " );\n\n" 1983 | 1984 | " Create a sample UPDATE statement 1985 | let procedure_def = procedure_def . 1986 | \ indent_spaces . 1987 | \ "UPDATE " . table_name . "\n" 1988 | 1989 | " Now we must remove each of the columns in the pk_column_list 1990 | " from the column_list, to create the no_pk_column_list. This is 1991 | " used by the UPDATE statement, since we do not SET columns in the 1992 | " primary key. 1993 | " The order of the columns in the pk_column_list is not guaranteed 1994 | " to be in the same order as the table list in the CREATE TABLE 1995 | " statement. So we must remove each word one at a time. 1996 | let no_pk_column_list = SQLU_RemoveMatchingColumns( 1997 | \ column_list, pk_column_list ) 1998 | 1999 | " Check for the special case where there is no 2000 | " primary key for the table (ie ,\? \? ) 2001 | let set_clause = 2002 | \ indent_spaces . 2003 | \ substitute( no_pk_column_list, 2004 | \ ',\? \?\(\<\w\+\>\)', 2005 | \ ' SET \1 = @\1', '' ) 2006 | let set_clause = 2007 | \ substitute( set_clause, 2008 | \ ', \(\<\w\+\>\)', 2009 | \ ",\n" . indent_spaces . ' \1 = @\1', "g" ) 2010 | 2011 | " Check for the special case where there is no 2012 | " primary key for the table 2013 | if strlen(pk_column_list) > 0 2014 | let where_clause = 2015 | \ indent_spaces . 2016 | \ substitute( pk_column_list, 2017 | \ '^\(\<\w\+\>\)', ' WHERE \1 = @\1', "" ) 2018 | let where_clause = 2019 | \ substitute( where_clause, 2020 | \ ', \(\<\w\+\>\)', 2021 | \ "\n" . indent_spaces . ' AND \1 = @\1', "g" ) 2022 | else 2023 | " If there is no primary key for the table place 2024 | " all columns in the WHERE clause 2025 | let where_clause = 2026 | \ indent_spaces . 2027 | \ substitute( column_list, 2028 | \ '^\(\<\w\+\>\)', ' WHERE \1 = @\1', "" ) 2029 | let where_clause = 2030 | \ substitute( where_clause, 2031 | \ ', \(\<\w\+\>\)', 2032 | \ "\n" . indent_spaces . ' AND \1 = @\1', "g" ) 2033 | endif 2034 | let procedure_def = procedure_def . set_clause . "\n" 2035 | let procedure_def = procedure_def . where_clause . ";\n\n" 2036 | 2037 | " Create a sample DELETE statement 2038 | let procedure_def = procedure_def . 2039 | \ indent_spaces . 2040 | \ "DELETE FROM " . table_name . "\n" 2041 | let procedure_def = procedure_def . where_clause . ";\n\n" 2042 | 2043 | let procedure_def = procedure_def . "END;\n\n" 2044 | 2045 | endif 2046 | 2047 | " Return to previous location 2048 | silent! exe 'normal! '.buf_curline."G\".buf_curcol."l" 2049 | 2050 | if found == 1 2051 | break 2052 | endif 2053 | 2054 | if &hidden == 0 2055 | call s:SQLU_WarningMsg( 2056 | \ "Cannot search other buffers with set nohidden" 2057 | \ ) 2058 | break 2059 | endif 2060 | 2061 | " Switch buffers to check to see if the create table 2062 | " statement exists 2063 | silent! exec "bnext" 2064 | if bufnr(expand("")) == curbuf 2065 | break 2066 | endif 2067 | endwhile 2068 | 2069 | silent! exec "buffer " . curbuf 2070 | 2071 | " restore previous search string 2072 | let @/ = saveSearch 2073 | " Restore previous cpoptions 2074 | let &cpoptions = l:old_cpoptions 2075 | let &eventignore = l:old_eventignore 2076 | 2077 | 2078 | " Return to previous location 2079 | silent! exe 'normal! '.curline."G\".curcol."l" 2080 | 2081 | if found == 0 2082 | let @@ = "" 2083 | echo "Table: " . table_name . " was not found" 2084 | return "" 2085 | endif 2086 | 2087 | echo 'Procedure: sp_' . table_name . ' in unnamed buffer' 2088 | if &clipboard == 'unnamed' 2089 | let @* = procedure_def 2090 | else 2091 | let @@ = procedure_def 2092 | endif 2093 | 2094 | return "" 2095 | 2096 | endfunction 2097 | 2098 | 2099 | 2100 | " Compares two strings, and will remove all names from the first 2101 | " parameter, if the same name exists in the second column name. 2102 | " The 2 parameters take comma separated lists 2103 | function! SQLUtilities#SQLU_RemoveMatchingColumns( full_col_list, dup_col_list ) 2104 | 2105 | let stripped_col_list = a:full_col_list 2106 | let pos = 0 2107 | " Find the string index position of the first match 2108 | let index = match( a:dup_col_list, '\w\+' ) 2109 | while index > -1 2110 | " Get name of column 2111 | let dup_col_name = matchstr( a:dup_col_list, '\w\+', index ) 2112 | let stripped_col_list = substitute( stripped_col_list, 2113 | \ dup_col_name.'[, ]*', '', 'g' ) 2114 | " Advance the search after the word we just found and look for 2115 | " others. 2116 | let index = match( a:dup_col_list, '\w\+', 2117 | \ index + strlen(dup_col_name) ) 2118 | endwhile 2119 | 2120 | return stripped_col_list 2121 | 2122 | endfunction 2123 | 2124 | function! s:SQLU_WarningMsg(msg) "{{{ 2125 | echohl WarningMsg 2126 | echomsg a:msg 2127 | echohl None 2128 | endfunction "}}} 2129 | 2130 | let &cpo = s:cpo_save 2131 | unlet s:cpo_save 2132 | 2133 | " vim:fdm=marker:nowrap:ts=4:expandtab:ff=unix: 2134 | -------------------------------------------------------------------------------- /doc/SQLUtilities.txt: -------------------------------------------------------------------------------- 1 | *SQLUtilities.txt* For Vim version 7.0. 2 | 3 | Author: David Fishburn October 10, 2012 4 | 5 | SQLUtilities: Variety of tools for working with SQL 6 | Version: 6.0.0 7 | Homepage: http://www.vim.org/scripts/script.php?script_id=492 8 | Feedback: David Fishburn 9 | 10 | For instructions on installing this file, type 11 | :help add-local-help |add-local-help| inside Vim. 12 | 13 | 14 | ============================================================================== 15 | 1. Contents *sqlutil* *sqlutil-contents* 16 | 17 | 1. Contents...............................: |sqlutil-contents| 18 | 2. Tutorial...............................: |sqlutil-tutorial| 19 | 3. Commands...............................: |sqlutil-commands| 20 | 3.1 SQLUFormatter......................: |sqlutil-formatter| 21 | 3.1.1 Formatting Examples..........: |sqlutil-examples| 22 | 3.1.2 Formatting Options...........: |sqlutil-format-options| 23 | 3.1.2.1 Align Where Clause...: |sqlutil-align-where| 24 | 3.1.2.2 Align Comma..........: |sqlutil-align-comma| 25 | 3.1.2.3 Align First Word.....: |sqlutil-align-first-word| 26 | 3.1.2.4 Align Keyword Right..: |sqlutil-align-keyword-right| 27 | 3.1.2.5 Change Keyword Case..: |sqlutil-change_keyword-case| 28 | 3.2 SQLUCreateColumnList...............: |sqlutil-column-list| 29 | 3.3 SQLUGetColumnDef...................: |sqlutil-column-definition| 30 | SQLUGetColumnDataType..............: |sqlutil-column-datatype| 31 | 3.4 SQLUCreateProcedure................: |sqlutil-procedure| 32 | 4. Suggested Mappings.....................: |sqlutil-mappings| 33 | 5. Global Options.........................: |sqlutil-options| 34 | 6. Customization..........................: |sqlutil-customization| 35 | 6.1 Cmd Terminator....................: |sqlutil-customization| 36 | 6.2 Vim Menu..........................: |sqlutil-customization| 37 | 6.3 Vim's Syntax Support..............: |sqlutil-customization| 38 | 7. History................................: |sqlutil-history| 39 | 8. Dependencies...........................: |sqlutil-dependencies| 40 | 9. Complementary Plugins..................: |sqlutil-complementary-plugins| 41 | 10.TODO...................................: |sqlutil-todo| 42 | 43 | 44 | ============================================================================== 45 | 2. Tutorial *sqlutil-tutorial* 46 | 47 | My most used command is the formatting capability of SQLUtil. Please 48 | ensure the Align.vim plugin has already been installed see 49 | |sqlutil-dependencies|. 50 | 51 | Section 3 covers each command in detail, but to use these commands you can 52 | do the following. Assume you have a SQL statement you would like to 53 | be formatted. > 54 | SELECT t1.c1, t1.c2, t1.c3, t2.column1, t2.column2 55 | FROM t1 JOIN t2 WHERE t1.c1 = 'hello' 56 | AND t2.column2 = 'goodbye'; 57 | 58 | There are several ways to format this statement. 59 | 60 | 1. Start |visual-mode| using any of the modes (i.e. v, V or CTRL-V), 61 | highlight the 2 lines and (assuming the default ||) you can 62 | use the visual map: > 63 | \sf (sql - format). 64 | < 65 | 2. Start |visual-mode| using any of the modes (i.e. v, V or CTRL-V), 66 | highlight the 2 lines and run the SQLUFormatter command: > 67 | :'<,'>SQLUFormatter 68 | < 69 | 3. If using Vim in GUI mode, the plugin provides a menu to make accessing 70 | the commands easier. It also shows the mapping, to assist with 71 | remembering them. After visually selecting the lines you can 72 | use the (default) menu as: > 73 | Plugin->SQLUtil->Format Statement 74 | < 75 | 4. Specify the range of lines and run the SQLUFormatter command: > 76 | :1,2SQLUFormatter 77 | < 78 | The default settings produce a formatted statement as: > 79 | SELECT t1.c1, t1.c2, t1.c3, t2.column1, t2.column2 80 | FROM t1 81 | JOIN t2 82 | WHERE t1.c1 = 'hello' 83 | AND t2.column2 = 'goodbye'; 84 | < 85 | Using the menu Plugin -> SQLUtil -> Toggle Align Where and reformat the 86 | statement: > 87 | SELECT t1.c1, t1.c2, t1.c3, t2.column1, t2.column2 88 | FROM t1 89 | JOIN t2 90 | WHERE t1.c1 = 'hello' 91 | AND t2.column2 = 'goodbye'; 92 | < 93 | Using the menu Plugin -> SQLUtil -> Toggle Right Align Keywords and 94 | reformat the statement: > 95 | SELECT t1.c1, t1.c2, t1.c3, t2.column1, t2.column2 96 | FROM t1 97 | JOIN t2 98 | WHERE t1.c1 = 'hello' 99 | AND t2.column2 = 'goodbye'; 100 | < 101 | Using the menu Plugin -> SQLUtil -> Toggle Align Comma and retoggle 102 | Plugin -> SQLUtil -> Toggle Right Align Keywords and reformat the 103 | statement: > 104 | SELECT t1.c1 105 | , t1.c2 106 | , t1.c3 107 | , t2.column1 108 | , t2.column2 109 | FROM t1 110 | JOIN t2 111 | WHERE t1.c1 = 'hello' 112 | AND t2.column2 = 'goodbye'; 113 | < 114 | Using the menu Plugin -> SQLUtil -> Lowercase Keywords and reformat the 115 | statement: > 116 | select t1.c1, t1.c2, t1.c3, t2.column1, t2.column2 117 | from t1 118 | join t2 119 | where t1.c1 = 'hello' 120 | and t2.column2 = 'goodbye'; 121 | < 122 | Since there are many options to control how the statement is formatted, these 123 | can be set from the command line (though it is easier using the menus): > 124 | let g:sqlutil_align_where = 1 125 | let g:sqlutil_ to cycle through the various option names. 126 | < 127 | These features are much more easily set via the menu, which does a number of 128 | things for you: 129 | 1. Allows you to toggle the setting of the options. 130 | 2. Does not require you to remember the option names. 131 | 3. Shows the current setting of each of the options. 132 | 133 | The remaining commands all rely upon have the CREATE TABLE statements open 134 | in Vim (either in the same buffer or a different one) and will work 135 | over those statements: > 136 | SQLUCreateColumnList 137 | SQLUGetColumnDef 138 | SQLUGetColumnDataType 139 | SQLUCreateProcedure 140 | 141 | Each of these statements work on the current word the cursor is on. 142 | So if the cursor is on the "t1" word in the above SQL statement 143 | the you can either use the command: 144 | :SQLUCreateColumnList 145 | or 146 | \scl 147 | 148 | See below for more information in the mappings. 149 | 150 | 151 | If you do not have the CREATE TABLE statements handy in a SQL file, the 152 | dbext plugin (which I also author) can pull this information directly from 153 | within the database. So typically, I only use this plugin to format 154 | SQL statements and use the dbext plugin to execute statement against a 155 | database. See |sqlutil-complementary-plugins| for more details. 156 | 157 | 158 | ============================================================================== 159 | 3. Commands *sqlutil-commands* 160 | 161 | 3.1 SQLUFormatter *sqlutil-formatter* 162 | 163 | [range]SQLUFormatter(..list..) 164 | 165 | - Formats one statement at a time, this is not meant to be 166 | an indenter for SQL files. 167 | - Reformats the SQL statements over the specified range. 168 | - Statement will lined up given the existing indent of the first word. 169 | - Formats SQL statements into a easily readable form. 170 | - Breaks keywords onto new lines. 171 | - Forces column lists to be split over as many lines as 172 | necessary to fit the current textwidth of the buffer, 173 | so that lines do not wrap. 174 | - If parentheses are unbalanced (ie a subselect) it will 175 | indent everything within the unbalanced parenthesis. 176 | - Works for SELECT, INSERT, UPDATE, DELETE statements. 177 | 178 | 3.1.1 Formatting Examples: *sqlutil-examples* 179 | 180 | Original: > 181 | SELECT m.MSG_ID, m.PRIORITY_ID, CUST.CUST_NBR, CUST.CUST_NM, 182 | CUST.CUST_LEGAL_NM, CUST.STORE_ADDR_1, CUST.STORE_ADDR_2, 183 | CUST.CROSS_STREET, XMLELEMENT( 'Alerts', XMLELEMENT( 'Alert_alert_id', 184 | alert_id ), XMLELEMENT( 'Alert_agent_id', agent_id ), XMLELEMENT( 185 | 'Alert_alert_type_id', alert_type_desc), XMLELEMENT( 186 | 'Alert_alert_date', alert_date), XMLELEMENT( 187 | 'Alert_url_reference', url_reference), XMLELEMENT( 188 | 'Alert_read_status', read_status )) CUST.STORE_CITY, 189 | CUST.STORE_ST, CUST.POST_CODE, CUST.STORE_MGR_NM, FROM MESSAGES m JOIN 190 | PRIORITY_CD P WHERE m.to_person_id = ? AND p.NAME = 'PRI_EMERGENCY' AND 191 | p.JOB = 'Plumber' AND m.status_id < ( SELECT s.STATUS_ID FROM 192 | MSG_STATUS_CD s WHERE s.NAME = 'MSG_READ') ORDER BY m.msg_id desc 193 | < 194 | 195 | Formatted: > 196 | SELECT m.MSG_ID, m.PRIORITY_ID, CUST.CUST_NBR, CUST.CUST_NM, 197 | CUST.CUST_LEGAL_NM, CUST.STORE_ADDR_1, CUST.STORE_ADDR_2, 198 | CUST.CROSS_STREET, 199 | XMLELEMENT( 200 | 'Alerts', XMLELEMENT( 'Alert_alert_id', alert_id ), 201 | XMLELEMENT( 'Alert_agent_id', agent_id ), 202 | XMLELEMENT( 'Alert_alert_type_id', alert_type_desc), 203 | XMLELEMENT( 'Alert_alert_date', alert_date), 204 | XMLELEMENT( 205 | 'Alert_url_reference', url_reference 206 | ), XMLELEMENT( 'Alert_read_status', read_status ) 207 | ) CUST.STORE_CITY, CUST.STORE_ST, CUST.POST_CODE, 208 | CUST.STORE_MGR_NM 209 | FROM MESSAGES m 210 | JOIN PRIORITY_CD P 211 | WHERE m.to_person_id = ? 212 | AND p.NAME = 'PRI_EMERGENCY' 213 | AND p.JOB = 'Plumber' 214 | AND m.status_id < ( 215 | SELECT s.STATUS_ID 216 | FROM MSG_STATUS_CD s 217 | WHERE s.NAME = 'MSG_READ' 218 | ) 219 | ORDER BY m.msg_id desc 220 | < 221 | 222 | 223 | Original: > 224 | UPDATE "SERVICE_REQUEST" SET "BUILDING_ID" = ?, "UNIT_ID" = ?, 225 | "REASON_ID" = ?, "PERSON_ID" = ?, "PRIORITY_ID" = ?, "STATUS_ID" = ?, 226 | "CREATED" = ?, "REQUESTED" = ?, "ARRIVED" = ? WHERE "REQUEST_ID" = ? 227 | < 228 | 229 | Formatted: > 230 | UPDATE "SERVICE_REQUEST" 231 | SET "BUILDING_ID" = ?, 232 | "UNIT_ID" = ?, 233 | "REASON_ID" = ?, 234 | "PERSON_ID" = ?, 235 | "PRIORITY_ID" = ?, 236 | "STATUS_ID" = ?, 237 | "CREATED" = ?, 238 | "REQUESTED" = ?, 239 | "ARRIVED" = ?, 240 | WHERE "REQUEST_ID" = ? 241 | < 242 | 243 | 244 | Original: > 245 | INSERT INTO "MESSAGES" ( "MSG_ID", "TO_PERSON_ID", 246 | "FROM_PERSON_ID", "REQUEST_ID", "CREATED", "PRIORITY_ID", 247 | "MSG_TYPE_ID", "STATUS_ID", "READ_WHEN", "TIMEOUT", 248 | "MSG_TXT", "RESEND_COUNT" ) VALUES ( ?, ?, ?, 249 | ?, ?, ?, ?, ?, ?, ?, ?, ? ) 250 | < 251 | 252 | Formatted: > 253 | INSERT INTO "MESSAGES" ( "MSG_ID", "TO_PERSON_ID", 254 | "FROM_PERSON_ID", "REQUEST_ID", "CREATED", 255 | "PRIORITY_ID", "MSG_TYPE_ID", "STATUS_ID", 256 | "READ_WHEN", "TIMEOUT", "MSG_TXT", "RESEND_COUNT" ) 257 | VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 258 | < 259 | 260 | 261 | 3.1.2 Formatting Options *sqlutil-format-options* 262 | 263 | There are several options which can control how the SQL statements are 264 | formatted. 265 | 266 | 3.1.2.1 Align Where Clause *sqlutil-align-where* 267 | 268 | sqlutil_align_where is used to align operators. Valid operators are: 269 | =, =, >, <, >=, <=, !=, !<, !>, <> 270 | This option is "ON" by default. When formatting SQL statements with many 271 | nested statements, the results can shifted too much. You can disable it, 272 | format the statement and enable it again afterwards: > 273 | let g:sqlutil_align_where = 1 274 | 275 | SELECT CategoryID, CategoryName, CategorySystemName, ( 276 | SELECT B.CATEGORYID CATID 277 | FROM CATEGORY 278 | WHERE B.CATEGORYID = intCategoryID 279 | AND B.REVIDDFD = intRevID 280 | AND B.REVID > intRevID 281 | AND B.REVIDDFDSDSF < intRevID 282 | AND B.REVIDDFD >= intRevID 283 | AND B.REVIDD <= intRevID 284 | AND B.REVIDLLKKKK != intRevID 285 | AND B.REVIDK !< intRevID 286 | AND B.REVIDDD !> intRevID 287 | AND B.REV <> intRevID 288 | AND B.DEL = 0 289 | UNION ALL 290 | SELECT B.CATEGORYID 291 | FROM CATEGORYHDR B 292 | WHERE intCategoryID IS NULL 293 | ) tmp 294 | WHERE TMP.CATID = PCat.CategoryID 295 | AND PCat.RevID = intRevID 296 | AND P.RevID = PCat.RevID 297 | AND CATHDR.CATEGORYID = PCAT.CATEGORYID 298 | < 299 | 300 | To disable: > 301 | let g:sqlutil_align_where = 0 302 | 303 | SELECT CategoryID, CategoryName, CategorySystemName, ( 304 | SELECT B.CATEGORYID CATID 305 | FROM CATEGORY 306 | WHERE B.CATEGORYID = intCategoryID 307 | AND B.REVIDDFD = intRevID 308 | AND B.REVID > intRevID 309 | AND B.REVIDDFDSDSF < intRevID 310 | AND B.REVIDDFD >= intRevID 311 | AND B.REVIDD <= intRevID 312 | AND B.REVIDLLKKKK != intRevID 313 | AND B.REVIDK !< intRevID 314 | AND B.REVIDDD !> intRevID 315 | AND B.REV <> intRevID 316 | AND B.DEL = 0 317 | UNION ALL 318 | SELECT B.CATEGORYID 319 | FROM CATEGORYHDR B 320 | WHERE intCategoryID IS NULL 321 | ) tmp 322 | WHERE TMP.CATID = PCat.CategoryID 323 | AND PCat.RevID = intRevID 324 | AND P.RevID = PCat.RevID 325 | AND CATHDR.CATEGORYID = PCAT.CATEGORYID 326 | < 327 | 328 | 3.1.2.2 Align Comma *sqlutil-align-comma* 329 | 330 | sqlutil_align_comma is used to force each column in a column list to be 331 | placed on a new line. The SET statement in a UPDATE clause already 332 | does this by default. 333 | This option is "OFF" by default. > 334 | let g:sqlutil_align_comma = 0 335 | 336 | SELECT PK_BranchID, PK_ItemID, FK_VaultID, FK_ItemType, 337 | ItemBarCode, FK_CommodityType, FK_CommodityTypeCode, 338 | ItemQuantity, ItemSealNumber, FK_ItemDenominationType, 339 | ItemSaidToContain, ItemNotes, FK_PackageDeliveryLocationID, 340 | FK_PackagePickupLocationID, FK_ItemParentID 341 | FROM some_table 342 | < 343 | 344 | To enable: > 345 | let g:sqlutil_align_comma = 1 346 | 347 | SELECT PK_BranchID 348 | , PK_ItemID 349 | , FK_VaultID 350 | , FK_ItemType 351 | , ItemBarCode 352 | , FK_CommodityType 353 | , FK_CommodityTypeCode 354 | , ItemQuantity 355 | , ItemSealNumber 356 | , FK_ItemDenominationType 357 | , ItemSaidToContain 358 | , ItemNotes 359 | , FK_PackageDeliveryLocationID 360 | , FK_PackagePickupLocationID 361 | , FK_ItemParentID 362 | FROM some_table 363 | < 364 | 365 | 3.1.2.3 Align First Word *sqlutil-align-first-word* 366 | 367 | sqlutil_align_first_word is used to control how the keywords are 368 | aligned when formatting. The default behaviour is the keywords 369 | are RIGHT justified on the first word of the phrase. So for an 370 | ORDER BY statement the keywords are aligned between the ORDER and the 371 | BY words. 372 | This option is "ON" by default. > 373 | let g:sqlutil_align_first_word = 1 374 | 375 | SELECT CategoryID 376 | , CategoryName 377 | , CategorySystemName 378 | , ( 379 | SELECT B.CATEGORYID CATID 380 | FROM CATEGORY B 381 | START WITH B.CATEGORYID = intCategoryID 382 | AND B.REVID = intRevID 383 | AND B.DEL = 0 384 | CONNECT BY PRIOR B.CATEGORYID = B.PARENTCATEGORYID 385 | AND B.REVID = intRevID 386 | AND B.DEL = 0 387 | UNION ALL 388 | SELECT B.CATEGORYID 389 | FROM CATEGORYHDR B 390 | WHERE intCategoryID IS NULL 391 | ) tmp 392 | WHERE TMP.CATID = PCat.CategoryID 393 | AND PCat.RevID = intRevID 394 | AND P.RevID = PCat.RevID 395 | AND CATHDR.CATEGORYID = PCAT.CATEGORYID 396 | ORDER BY CategoryID 397 | < 398 | 399 | To disable: > 400 | let g:sqlutil_align_first_word = 0 401 | 402 | SELECT CategoryID 403 | , CategoryName 404 | , CategorySystemName 405 | , ( 406 | SELECT B.CATEGORYID CATID 407 | FROM CATEGORY B 408 | START WITH B.CATEGORYID = intCategoryID 409 | AND B.REVID = intRevID 410 | AND B.DEL = 0 411 | CONNECT BY PRIOR B.CATEGORYID = B.PARENTCATEGORYID 412 | AND B.REVID = intRevID 413 | AND B.DEL = 0 414 | UNION ALL 415 | SELECT B.CATEGORYID 416 | FROM CATEGORYHDR B 417 | WHERE intCategoryID IS NULL 418 | ) tmp 419 | WHERE TMP.CATID = PCat.CategoryID 420 | AND PCat.RevID = intRevID 421 | AND P.RevID = PCat.RevID 422 | AND CATHDR.CATEGORYID = PCAT.CATEGORYID 423 | ORDER BY CategoryID 424 | < 425 | 426 | 3.1.2.4 Align Keyword Right *sqlutil-align-keyword-right* 427 | 428 | sqlutil_align_keyword_right is used to control how the keywords are 429 | aligned when formatting. The default behaviour is the keywords 430 | are RIGHT justified on the first keyword. This option allows you to 431 | choose whether the keywords are left or right justified. 432 | This option is "1" by default. > 433 | let g:sqlutil_align_keyword_right = 1 434 | 435 | SELECT B.CATEGORYID CATID 436 | FROM CATEGORY B 437 | WHERE B.CATEGORYID = intCategoryID 438 | AND B.REVID = intRevID 439 | AND B.DEL = 0 440 | < 441 | 442 | To toggle: > 443 | let g:sqlutil_align_keyword_right = 0 444 | 445 | SELECT B.CATEGORYID CATID 446 | FROM CATEGORY B 447 | WHERE B.CATEGORYID = intCategoryID 448 | AND B.REVID = intRevID 449 | AND B.DEL = 0 450 | < 451 | 452 | 3.1.2.5 Change Keyword Case *sqlutil-change_keyword-case* 453 | 454 | sqlutil_keyword_case is used to control if the case of the keywords 455 | should be changed when formatting. This option uses Vim's standard 456 | regular expression syntax |/\l| to control its' behaviour. 457 | The default is to leave the cAsE aS Is. Assume the first query 458 | below is our original statement: > 459 | let g:sqlutil_keyword_case = '' 460 | 461 | select CategoryID, CategoryName, CategorySystemName 462 | WHERE TMP.CATID = PCat.CategoryID 463 | and PCat.RevID = intRevID 464 | aND P.RevID = PCat.RevID 465 | and CATHDR.CATEGORYID = PCAT.CATEGORYID 466 | 467 | 468 | let g:sqlutil_keyword_case = '\U' 469 | 470 | SELECT CategoryID, CategoryName, CategorySystemName 471 | WHERE TMP.CATID = PCat.CategoryID 472 | AND PCat.RevID = intRevID 473 | AND P.RevID = PCat.RevID 474 | AND CATHDR.CATEGORYID = PCAT.CATEGORYID 475 | 476 | 477 | let g:sqlutil_keyword_case = '\L' 478 | 479 | select CategoryID, CategoryName, CategorySystemName 480 | where TMP.CATID = PCat.CategoryID 481 | and PCat.RevID = intRevID 482 | and P.RevID = PCat.RevID 483 | and CATHDR.CATEGORYID = PCAT.CATEGORYID 484 | 485 | 486 | let g:sqlutil_keyword_case = '\u' 487 | 488 | Select CategoryID, CategoryName, CategorySystemName 489 | WHERE TMP.CATID = PCat.CategoryID 490 | And PCat.RevID = intRevID 491 | AND P.RevID = PCat.RevID 492 | And CATHDR.CATEGORYID = PCAT.CATEGORYID 493 | 494 | 495 | let g:sqlutil_keyword_case = '\l' 496 | 497 | select CategoryID, CategoryName, CategorySystemName 498 | wHERE TMP.CATID = PCat.CategoryID 499 | and PCat.RevID = intRevID 500 | aND P.RevID = PCat.RevID 501 | and CATHDR.CATEGORYID = PCAT.CATEGORYID 502 | 503 | 504 | 3.2 SQLUCreateColumnList *sqlutil-column-list* 505 | 506 | SQLUCreateColumnList( optional parameter(s) ) 507 | 508 | Creates a comma separated list of column names for the table name under the 509 | cursor, assuming the table definition exists in any open buffer. The column 510 | list is placed in the unnamed buffer. Be default, an alias is added to 511 | the column list (new to version 1.3.7). 512 | 513 | To determine where a statement ends the g:sqlutil_cmd_terminator is used. 514 | This is true for the CREATE TABLE statement, and the ALTER TABLE 515 | statements. 516 | 517 | Normally this command is run by placing your cursor anywhere on the 518 | table name and using the mapping scl (or \scl). The paste 519 | buffer contains the column list, and a message is displayed. 520 | 521 | You can also call this from the Vim command line, this function optionally 522 | takes 3 parameters: > 523 | SQLUCreateColumnList T1 524 | < Creates a column list for T1 525 | > 526 | SQLUCreateColumnList T1 1 527 | < Creates a column list for T1 but only for the primary keys for 528 | that table. 529 | > 530 | SQLUCreateColumnList T1 0 alias_name 531 | < Creates a column list for T1 add appends the supplied 532 | alias_name to each column. 533 | 534 | Assumes either the current file, or any other open buffer, has a CREATE 535 | TABLE statement in a format similar to this: > 536 | CREATE TABLE customer_list ( 537 | id INT DEFAULT AUTOINCREMENT, 538 | last_modified TIMESTAMP NULL, 539 | first_name VARCHAR(30) NOT NULL, 540 | last_name VARCHAR(60) NOT NULL, 541 | balance NUMERIC(10,2), 542 | PRIMARY KEY( id ) 543 | ); 544 | < 545 | If you place the cursor on the word customer, then the unnamed buffer (also 546 | displayed by an echo statement) will contain: > 547 | cl.id, cl.last_modified, cl.first_name, cl.last_name, cl.balance 548 | < 549 | The table alias has several options / features and is controlled by: > 550 | let g:sqlutil_use_tbl_alias = 'd|a|n' 551 | < 552 | Here are the meaning of each setting: > 553 | d - Use the default 554 | a - Calculate an alias, and prompt the user to override 555 | n - Do not use table aliases 556 | < 557 | An alias is determined following a few rules: 558 | 1. If the table name has an '_', then use it as a separator: > 559 | MY_TABLE_NAME --> MTN 560 | my_table_name --> mtn 561 | My_table_NAME --> MtN 562 | < 2. If the table name does NOT contain a '_', but DOES use 563 | mixed case then the case is used as a separator: > 564 | MyTableName --> MTN 565 | < 3. If the table name does NOT contain a '_', and does NOT use 566 | mixed case then the first letter of the table is used: > 567 | mytablename --> m 568 | MYTABLENAME --> M 569 | < 570 | This also uses the g:sqlutil_cmd_terminator to determine when the create 571 | table statement ends if none of the following terms (these are the defaults) 572 | are found before the final ");". > 573 | primary key,reference,unique,check,constraint, [not null] foreign 574 | < sqlutil_cmd_terminator defaults to ";" 575 | 576 | When building a column list from a script file (ie CREATE TABLE statements), 577 | you can customize the script to detect when the column list finishes by 578 | creating the following in your |vimrc|: > 579 | let g:sqlutil_col_list_terminators = 580 | \ 'primary,reference,unique,check,foreign' 581 | < 582 | This is necessary to determine where the list of columns finishes and 583 | when the list of table keywords begin in the following examples: > 584 | CREATE TABLE customer ( 585 | id INT DEFAULT AUTOINCREMENT, 586 | first_name VARCHAR(30) NOT NULL, 587 | last_name VARCHAR(60) NOT NULL, 588 | PRIMARY KEY( id ) 589 | ); 590 | 591 | CREATE TABLE contact ( 592 | id INT DEFAULT AUTOINCREMENT, 593 | cust_ INT NOT NULL, 594 | first_name VARCHAR(30) NOT NULL, 595 | last_name VARCHAR(60) NOT NULL, 596 | CHECK( id > 0 ) 597 | FOREIGN KEY fk_customer ( cust_id ) 598 | REFERENCES customer(id) 599 | PRIMARY KEY( id ) 600 | ); 601 | < 602 | 603 | 3.3 SQLUGetColumnDef *sqlutil-column-definition* 604 | SQLUGetColumnDataType *sqlutil-column-datatype* 605 | 606 | SQLUGetColumnDef( optional parameter ) 607 | SQLUGetColumnDataType( expand(""), 1 ) 608 | 609 | Assumes either the current file, or any other open buffer, has a CREATE TABLE 610 | statement in a format similar to this: > 611 | 612 | CREATE TABLE customer ( 613 | id INT DEFAULT AUTOINCREMENT, 614 | last_modified TIMESTAMP NULL, 615 | first_name VARCHAR(30) NOT NULL, 616 | last_name VARCHAR(60) NOT NULL, 617 | balance NUMERIC(10,2), 618 | PRIMARY KEY( id ) 619 | ); 620 | < 621 | |hidden| must be enabled for this plugin to cycle through other open 622 | buffers. If you place the cursor on the word first_name, then the column 623 | definition will be placed in the unnamed buffer (and also displayed by an 624 | echo statement). > 625 | VARCHAR(30) NOT NULL 626 | < 627 | If the command is called as SQLUGetColumnDef( expand(""), 1 ) or using 628 | the default mapping scdt, just the datatype (instead of the column 629 | definition) will be returned. A separate command SQLUGetColumnDataType has 630 | been created for this. > 631 | VARCHAR(30) 632 | < 633 | 634 | 635 | 3.4 SQLUCreateProcedure() *sqlutil-procedure* 636 | 637 | SQLUCreateProcedure() 638 | 639 | Creates a stored procedure that performs standard operations (SELECT, 640 | INSERT, UPDATE, DELETE) against the table that the cursor is currently under. 641 | Once the procedure has been pasted into the buffer, the unwanted statements 642 | can be removed. 643 | 644 | Assumes either the current file, or any other open buffer, has a CREATE TABLE 645 | statement in a format similar to this: > 646 | 647 | CREATE TABLE customer ( 648 | id INT DEFAULT AUTOINCREMENT, 649 | last_modified TIMESTAMP NULL, 650 | first_name VARCHAR(30) NOT NULL, 651 | last_name VARCHAR(60) NOT NULL, 652 | balance NUMERIC(10,2), 653 | PRIMARY KEY( id ) 654 | ); 655 | < 656 | |hidden| must be enabled for this plugin to cycle through other open 657 | buffers. 658 | 659 | 660 | ============================================================================== 661 | 4. Suggested Mappings: *sqlutil-mappings* 662 | 663 | vmap sf SQLU_Formatter 664 | nmap scl SQLU_CreateColumnList 665 | nmap scd SQLU_GetColumnDef 666 | nmap scdt SQLU_GetColumnDataType 667 | nmap scp SQLU_CreateProcedure 668 | 669 | mnemonic explanation 670 | s - sql 671 | f - format 672 | cl - column list 673 | cd - column definition 674 | cdt - column datatype 675 | cp - create procedure 676 | 677 | To prevent the default mappings from being created, place the following in 678 | your |vimrc|: 679 | let g:sqlutil_load_default_maps = 0 680 | 681 | 682 | ============================================================================== 683 | 5. Global Options *sqlutil-options* 684 | 685 | Many defaults for the SQLUtilities plugin can be enabled or disabled or 686 | customized via entries in your .vimrc. Here is a list of all options used 687 | by the plugin and a brief description of what it does. A more complete 688 | example of how to use this option can be found through the doc (if worthy) 689 | so just search for it. 690 | 691 | Many of these options can be controlled via the SQLUtil menu, which is often 692 | far more convienent that tweaking these variables. 693 | 694 | Global variables: > 695 | sqlutil_align_where 696 | < - See |sqlutil-align-where| 697 | - Default: 1 > 698 | let g:sqlutil_align_where = 1 699 | sqlutil_align_comma 700 | < - See |sqlutil-align-comma| 701 | - Default: 0 > 702 | let g:sqlutil_align_comma = 0 703 | sqlutil_align_first_word 704 | < - See |sqlutil-align-first-word| 705 | - Default: 0 > 706 | let g:sqlutil_align_first_word = 0 707 | sqlutil_align_keyword_right 708 | < - See |sqlutil-align-keyword-right| 709 | - Default: 1 > 710 | let g:sqlutil_align_keyword_right = 1 711 | sqlutil_wrap_expressions 712 | < - By default, when formatting a statement if a column is an expression 713 | or function call which is very long, break it apart and indent 714 | portions of it to make it clear. 715 | - Default: 0 > 716 | let g:sqlutil_wrap_expressions = 0 717 | sqlutil_cmd_terminator 718 | < - Certain SQL statements require cmd terminators. Different databases 719 | have different defaults. This is important when parsing SQL files. 720 | - Default: ';' > 721 | let g:sqlutil_cmd_terminator = ';' 722 | let g:sqlutil_cmd_terminator = "\ngo\n" 723 | sqlutil_stmt_keywords 724 | < - Used by the SQLUFormatter command to determine which SQL statements 725 | to format. 726 | - Default: 'select,insert,update,delete,with,merge' > 727 | let g:sqlutil_stmt_keywords = 'select,insert,update,delete,with,merge' 728 | sqlutil_keyword_case 729 | < - See |sqlutil-change_keyword-case| 730 | - Default: '' > 731 | let g:sqlutil_keyword_case = '' 732 | sqlutil_use_tbl_alias 733 | < - See |sqlutil-column-list| 734 | - Default: 'a' > 735 | let g:sqlutil_use_tbl_alias = 'a' 736 | g:sqlutil_use_syntax_support 737 | < - See |sqlutil-customization|| 738 | - Default: 1 > 739 | let g:g:sqlutil_use_syntax_support = 1 740 | sqlutil_syntax_elements 741 | < - See |sqlutil-column-list| 742 | - Default: 'Constant,sqlString' > 743 | let g:sqlutil_syntax_elements = 'Constant,sqlString' 744 | sqlutil_col_list_terminators 745 | < - See |sqlutil-change_keyword-case| > 746 | let g:sqlutil_col_list_terminators = 747 | \ 'primary\s\+key.*(' . 748 | \ ',references' . 749 | \ ',match' . 750 | \ ',unique' . 751 | \ ',check' . 752 | \ ',constraint' . 753 | \ ',\%(not\s\+null\s\+\)\?foreign' 754 | sqlutil_load_default_maps 755 | < - See |sqlutil-mappings| 756 | - Default: 1 > 757 | let g:sqlutil_load_default_maps = 1 758 | sqlutil_default_menu_mode 759 | < - See |sqlutil-customization| 760 | - Default: 3 > 761 | let g:sqlutil_default_menu_mode = 3 762 | 763 | ============================================================================== 764 | 6. Customization *sqlutil-customization* 765 | 766 | 6.1 Cmd Terminator 767 | 768 | By default this script assumes a command is terminated by a ; If you are 769 | using Microsoft SQL Server a command terminator would be "go", or perhaps 770 | "\ngo". 771 | 772 | To permanently override the terminator in your |vimrc| file you can add 773 | (note: using double quotes is necessary when using \n): > 774 | let g:sqlutil_cmd_terminator = "\ngo" 775 | < 776 | 6.2 Vim Menu 777 | 778 | By default a menu is created under the Plugin menu. Menus are useful for a 779 | number of reasons: 780 | - See a list of available commands 781 | - Remember what the shortcut maps are 782 | - Have a floating menu when using the plugin a lot 783 | - Allow you to quickly and easily toggle various formatting 784 | options on a per statement basis. Especially useful when 785 | used with the floating menu. 786 | - Quick reference guide 787 | 788 | You have several choices on where to place the menu. There are four 789 | settings that will control the placement of the menu: 790 | "0": Turns the menu off. 791 | "1": Turns the 'SQLUtil' menu on with no menu shortcut. 792 | "2": Turns the 'SQLUtil 'menu on with -d as the shortcut. 793 | "3": Turns the 'Plugin -> SQLUtil' menu on with -s as 794 | the shortcut. 795 | The option, g:sqlutil_default_menu_mode defaults to a value of 3 and can be 796 | changed by adding the following to your vimrc: > 797 | let g:sqlutil_default_menu_mode = 3 798 | < 799 | You can also control where (and the name of) the SQLUtil menu is created 800 | using the g:sqlutil_menu_root option. It can be used in conjuction with 801 | g:sqlutil_default_menu_mode = 3. To create the menu: 'MyPlugins -> SQLUtil' 802 | you can create the following variable: > 803 | let g:sqlutil_menu_root = 'MyPlugin.&SQLUtil' 804 | < 805 | Menus are created in a documented order by Vim (|menu-priority|). You can 806 | override this setting using sqlutil_menu_priority. This option allows you to 807 | override the setting and shift the SQLUtil menu item to the left between the 808 | Edit and Tools menu. > 809 | let g:sqlutil_menu_priority = 30 810 | 811 | 6.3 Vim's Syntax Support 812 | 813 | New to 5.0 of SQLUtilities, when reformatting a SQL statement Vim's syntax 814 | rules are used to determine if the keyword found (i.e. SELECT, FROM, WHERE, 815 | ...) is within a string. Consider the following statement: > 816 | SELECT 1, 'text with keywords IN FROM CASE WHERE AND OR ' FROM T1 WHERE c1 = 1 817 | < 818 | Formatting this statement with g:sqlutil_use_syntax_support = 0 results in: > 819 | SELECT 'text 820 | with keywords IN 821 | FROM CASE 822 | WHERE 823 | AND 824 | OR ' 825 | FROM T1 826 | WHERE c1 = 1 827 | < 828 | As you can see the keywords found within the string were aligned like all 829 | other keywords. To address this, when the keyword is found and Vim is 830 | highlighting the text (i.e. syntax on is enabled) then determine the 831 | syntax group. If the group is within the comma separated list of 832 | groups listed in g:sqlutil_syntax_elements, then it will be bypassed. 833 | The resulting query with g:sqlutil_use_syntax_support = 1 will be 834 | formatted as: > 835 | SELECT 1, 'some text with sql keywords IN FROM CASE WHERE AND OR ' 836 | FROM T1 837 | WHERE c1 = 1 838 | < 839 | To help you determine what the correct groups are, you can install: > 840 | SyntaxAttr.vim 841 | http://vim.sourceforge.net/script.php?script_id=383 842 | < 843 | Then create a mapping: > 844 | nnoremap -a :call SyntaxAttr() 845 | < 846 | Place your cursor on the word which is hightlighted in the colour you 847 | are interested in and hit -a. The output displayed looks something like 848 | this: > 849 | group: sqlString->Constant guifg=White(#ffffff) 850 | < 851 | With this information, you can override the default for SQLUtilities 852 | using the following line in my .vimrc: > 853 | let g:sqlutil_syntax_elements = 'Constant,sqlString' 854 | 855 | ============================================================================== 856 | 7. History *sqlutil-history* 857 | 858 | 6.0.0: October 10, 2012: 859 | NF: When formatting INSERT statements, the sqlutil_align_comma 860 | is also respected to place each column on a newline. 861 | NF: When formatting UPDATE statements and sqlutil_align_comma is set 862 | comments at the end of the line were removed (Rodrigo Laporte). 863 | 864 | 5.0.0: February 10, 2012: 865 | NF: Now an extra check is made for the Align plugin. If not 866 | found when attempting to format a SQL statement a friendly 867 | message is shown (Enrico Teotti). 868 | NF: Updated documentation added the Global Options section plus 869 | updated the Customization section. 870 | NF: Problem: Keywords within strings were being formatted 871 | (Olivier Laurent). 872 | Solution: Added an option, g:sqlutil_use_syntax_support, to 873 | determine whether or not to use Vim's syntax support 874 | to decide if the keyword is highlighted as a "string". 875 | If so, leave it and move on to the next keyword. 876 | Default value is 1 (enabled). 877 | See |sqlutil-customization| for details on usage. 878 | NF: Added an option, g:sqlutil_syntax_elements, to 879 | allow the user to decide which syntax elements 880 | should be considered a string. 881 | Default value is 'Constant,sqlString'. 882 | 883 | 4.1.0: August 18, 2010: 884 | NF: Store and reset the value of the |gdefault| option before 885 | formatting SQL statements (Sebastian Kusnier). 886 | BF: When g:sqlutil_align_keyword_right = 0 and 887 | g:sqlutil_align_comma = 1 commas where left aligned 888 | with the keywords instead of left aligned with the 889 | column list (Per Winkvist). 890 | 891 | 4.0.0: August 13, 2010: 892 | NF: Added a tutorial to take users through the common features 893 | of the plugin. 894 | NF: Added an option, g:sqlutil_align_keyword_right, to left or 895 | right (default) align the keywords (Per Winkvist). 896 | NF: Documented and added new global variables (g:sqlutil_menu_root, 897 | g:sqlutil_menu_priority) to customize the location of the 898 | SQLUtil menu. 899 | BF: SQLite used slightly different syntax specifying UNIQUE 900 | values and would not correctly generate a column list 901 | from the CREATE TABLE statement (Oliver Peters). 902 | BF: Ensured all normal commands used ! to ensure no mappings 903 | interfered with the commands (Benoit Mortgat). 904 | 905 | 3.0.0: January 15, 2009: 906 | NF: Added new menu links so that commonly used options can be 907 | quickly and easily toggled without having to remember the 908 | global variable names or values. For example, if you cut the 909 | menu so that it floats beside your buffer you can easily 910 | hit "Toggle Align Where" or "Uppercase Keywords". 911 | NF: Using the menu_mode option you can control if and where the 912 | SQLUtil menu is created. See the menu_mode option for more 913 | details. 914 | NF: Added the default maps to the menus. If you use a floating 915 | menu, or simply view the menu you can more easily memorize 916 | your most commonly used maps. 917 | BF: UPPER and lower case of keywords did not work for multi-word 918 | keywords (ORDER BY, LEFT OUTER JOIN, ...). 919 | 920 | 2.0.0: September 09, 2007: 921 | NF: Added support for Vim 7's autoload functionality 922 | 923 | 1.4.1: October 07, 2005: 924 | NF: Added additional statements to g:sqlutil_col_list_terminators 925 | BF: Forgot to increment g:loaded_sqlutilities 926 | 927 | 1.4.0: March 10, 2005: 928 | BF: If a statement has parenthesis inside of strings, the formatter 929 | was not ignoring them. This could result in the formatter 930 | reporting there were mismatched parenthesis. 931 | Example: select 'string' + '(' from dummy 932 | BF: If a keyword was not followed by a space, it was not placed on 933 | a newline. 934 | Example: SELECT * FROM(T1) 935 | BF: Nested function calls could potentially lead to an endless loop. 936 | 937 | 1.3.9: February 10, 2005: 938 | BF: When g:sqlutil_align_comma=1 and a select list spanned more than 1 939 | line (via functions calls and so on), it was possible the 940 | remaining comma separated list was not aligned properly. 941 | 942 | 1.3.8: December 2, 2004: 943 | NF: Enhanced the feature to change the case of keywords, to include 944 | the optional join words, left, right, full, inner, outer. These 945 | words were missed prior to this change and only the JOIN word was 946 | capitalized. 947 | C: Changed the default for g:sqlutil_use_tbl_alias = 'a' (ask) from 948 | being on at all times. This can be overridden in your vimrc. 949 | 950 | 1.3.7: July 21, 2004: 951 | NF: Added new option g:sqlutil_use_tbl_alias, which is on by default. 952 | When creating a column list for a table, it will add a table 953 | alias to each column. The table alias is calculated based on 954 | rules. This feature has 3 settings: 955 | n - no alias 956 | d - default calculated alias 957 | a - ask the user using default alias 958 | NF: Updated g:sqlutil_col_list_terminators to handle some additional 959 | cases. 960 | BF: In some cases -@- could be left in the query. This seems to be 961 | a bug in Vim, where the marks could move. Unsure why, but put 962 | a workaround in. 963 | BF: When g:sqlutil_align_comma=1, and the lines did not begin with 964 | commas, the formatting was incorrect. 965 | BF: When searching through buffers (SQLU_CreateColumnList), the 966 | alternate buffer could be changed. 967 | 968 | 1.3.6: June 21, 2004: 969 | NF: Added support for window functions (OVER, PARTITION BY, ROWS, 970 | RANGE), and additional Oracle SELECT keywords (DIMENSION, 971 | MEASURES, ITERATE, WITHIN GROUP, IGNORE, KEEP, RETURN, RULES) 972 | 973 | 1.3.5: Mar 05, 2004: 974 | NF: Added global variable sqlutil_align_where, sqlutil_align_comma, 975 | sqlutil_align_first_word for customization of alignment rules. 976 | 977 | 1.3.3: Sep 05, 2003: 978 | NF: Added global variable sqlutil_col_list_terminators for 979 | customization. 980 | 981 | 1.3.2: Aug 24, 2003: 982 | NF: Changed all functions to be prefixed by SQLU_ for consistency. 983 | BF: Fixed SQLU_GetColumnDataType and SQLU_GetColumnDef to handle tabs. 984 | 985 | 1.3.1: Aug 21, 2003: 986 | BF: -@- could be left after incorrect formatting. 987 | 988 | 1.3.0: Mar 30, 2003: 989 | NF: Support the formatting of FUNCTIONS or stored procedures used as 990 | derived tables. This will nest the function calls on new lines 991 | and correctly split the parenthesis on new lines if the function 992 | call is longer than one line. You would notice this mainly in the 993 | SELECT column list. 994 | NF: Support the formatting of nested CASE statements. 995 | NF: Added the SQLU_GetColumnDataType command. 996 | NF: Improved primary key determination, it no longer requires the 997 | PRIMARY KEY statement to be part of the CREATE TABLE statement, it 998 | can be part of an ALTER TABLE statement. 999 | NF: Improved formatting of SQL keywords. INSERT INTO statement, the 1000 | INTO will no longer be split onto a new line. 1001 | NF: Now correctly format the various JOIN keywords: NATURAL RIGHT 1002 | OUTER JOIN will be placed one online instead of just the JOIN 1003 | keyword as before. 1004 | BF: Did not properly handle the formatting of nested open parenthesis 1005 | in all cases. 1006 | BF: Using new technique to determine how to change the textwidth to 1007 | utilize more screen space when wrapping long lines. 1008 | 1009 | 1.2.0: Nov 30, 2002: 1010 | NF: Create procedure uses shiftwidth for indent. 1011 | BF: Save/restore previous search. 1012 | 1013 | 1.0.0: Nov 13, 2002: 1014 | NF: Initial version. 1015 | 1016 | 1017 | ============================================================================== 1018 | 8. Dependencies *sqlutil-dependencies* 1019 | 1020 | Align.vim - Version 15 (as a minimum) 1021 | - Author: Charles E. Campbell, Jr. 1022 | - http://www.vim.org/script.php?script_id=294 1023 | - SQLUtilities uses this to extensively 1024 | 1025 | 1026 | ============================================================================== 1027 | 9. Complementary Plugins *sqlutil-complementary-plugins* 1028 | 1029 | dbext.vim - Author: Peter Bagyinszki and David Fishburn 1030 | - http://www.vim.org/script.php?script_id=356 1031 | - Works with almost all databases 1032 | - Allows you to execute commands, browse through objects 1033 | and many more items. 1034 | 1035 | SrchRplcHiGrp.vim 1036 | - Author: David Fishburn 1037 | - http://www.vim.org/script.php?script_id=848 1038 | - Search and Replace based on a syntax highlight 1039 | group name. For example, you can visually select 1040 | a block of code and tell it to change all the 1041 | "yellow" words to UPPER case. 1042 | 1043 | Intellisense.vim 1044 | - Author: Ravi Shankar 1045 | - SQL plugin Author: David Fishburn 1046 | - http://www.vim.org/scripts/script.php?script_id=747 1047 | - Performs popup method completion for SQL development 1048 | this includes, keywords, functions, tables, columns, 1049 | procedures and more. 1050 | 1051 | 1052 | ============================================================================== 1053 | 10. TODO *sqlutil-todo* 1054 | 1055 | TODO: 1056 | 1. Suggestions welcome please email 1057 | 1058 | 1059 | ============================================================================== 1060 | 1061 | 1062 | vim: ts=4 ft=help 1063 | -------------------------------------------------------------------------------- /plugin/SQLUtilities.vim: -------------------------------------------------------------------------------- 1 | " SQLUtilities: Variety of tools for writing SQL 2 | " Author: David Fishburn 3 | " Date: Nov 23, 2002 4 | " Last Changed: 2012 Oct 09 5 | " Version: 6.0.0 6 | " Script: http://www.vim.org/script.php?script_id=492 7 | " License: GPL (http://www.gnu.org/licenses/gpl.html) 8 | " 9 | " Dependencies: 10 | " Align.vim - Version 15 (as a minimum) 11 | " - Author: Charles E. Campbell, Jr. 12 | " - http://www.vim.org/script.php?script_id=294 13 | " Documentation: 14 | " :h SQLUtilities.txt 15 | " 16 | 17 | " Prevent duplicate loading 18 | if exists("g:loaded_sqlutilities") 19 | finish 20 | endif 21 | let g:loaded_sqlutilities = 600 22 | 23 | " Turn on support for line continuations when creating the script 24 | let s:cpo_save = &cpo 25 | set cpo&vim 26 | 27 | if !exists('g:sqlutil_align_where') 28 | let g:sqlutil_align_where = 1 29 | endif 30 | 31 | if !exists('g:sqlutil_align_comma') 32 | let g:sqlutil_align_comma = 0 33 | endif 34 | 35 | if !exists('g:sqlutil_wrap_expressions') 36 | let g:sqlutil_wrap_expressions = 0 37 | endif 38 | 39 | if !exists('g:sqlutil_align_first_word') 40 | let g:sqlutil_align_first_word = 1 41 | endif 42 | 43 | if !exists('g:sqlutil_align_keyword_right') 44 | let g:sqlutil_align_keyword_right = 1 45 | endif 46 | 47 | if !exists('g:sqlutil_cmd_terminator') 48 | let g:sqlutil_cmd_terminator = ';' 49 | endif 50 | 51 | if !exists('g:sqlutil_stmt_keywords') 52 | let g:sqlutil_stmt_keywords = 'select,insert,update,delete,with,merge' 53 | endif 54 | 55 | if !exists('g:sqlutil_keyword_case') 56 | " This controls whether keywords should be made 57 | " upper or lower case. 58 | " The default is to leave them in current case. 59 | let g:sqlutil_keyword_case = '' 60 | endif 61 | 62 | if !exists('g:sqlutil_use_tbl_alias') 63 | " If this is set to 1, when you run SQLU_CreateColumnList 64 | " and you do not specify a 3rd parameter, you will be 65 | " prompted for the alias name to append to the column list. 66 | " 67 | " The default for the alias are the initials for the table: 68 | " some_thing_with_under_bars -> stwub 69 | " somethingwithout -> s 70 | " 71 | " The default is no asking 72 | " d - use by default 73 | " a - ask (prompt) 74 | " n - no 75 | let g:sqlutil_use_tbl_alias = 'a' 76 | endif 77 | 78 | if !exists('g:sqlutil_col_list_terminators') 79 | " You can override which keywords will determine 80 | " when a column list finishes: 81 | " CREATE TABLE customer ( 82 | " id INT DEFAULT AUTOINCREMENT, 83 | " last_modified TIMESTAMP NULL, 84 | " first_name VARCHAR(30) NOT NULL, 85 | " last_name VARCHAR(60) NOT NULL, 86 | " balance NUMERIC(10,2), 87 | " PRIMARY KEY( id ) 88 | " ); 89 | " So in the above example, when "primary" is reached, we 90 | " know the column list is complete. 91 | " PRIMARY KEY 92 | " foreign keys 93 | " indicies 94 | " check contraints 95 | " table contraints 96 | " foreign keys 97 | " 98 | let g:sqlutil_col_list_terminators = 99 | \ 'primary\s\+key.*(' . 100 | \ ',references' . 101 | \ ',match' . 102 | \ ',unique' . 103 | \ ',check' . 104 | \ ',constraint' . 105 | \ ',\%(not\s\+null\s\+\)\?foreign' 106 | endif 107 | 108 | if !exists('g:sqlutil_use_syntax_support') 109 | " This controls whether search and replace 110 | " of various keywords as part of the formatting 111 | " of sql statements should use Vim's built in 112 | " syntax support. 113 | " The default to use the syntax id to help 114 | " determine if keywords are within strings 115 | " and therefore not aligning them. 116 | let g:sqlutil_use_syntax_support = 1 117 | endif 118 | 119 | if !exists('g:sqlutil_syntax_elements') 120 | " This controls how SQLUtilities determines if 121 | " the keyword found is within a string or not. 122 | " This is a comma separated list of values. 123 | " The default is Constant,sqlString. 124 | let g:sqlutil_syntax_elements = 'Constant,sqlString' 125 | endif 126 | 127 | " Determines which menu items will be recreated 128 | let s:sqlutil_menus_created = 0 129 | 130 | " Public Interface: 131 | command! -range=% -nargs=* SQLUFormatStmts , 132 | \ call SQLUtilities#SQLU_FormatStmts() 133 | command! -range -nargs=* SQLUFormatter , 134 | \ call SQLUtilities#SQLU_Formatter() 135 | command! -nargs=* SQLUCreateColumnList 136 | \ call SQLU_CreateColumnList() 137 | command! -nargs=* SQLUGetColumnDef 138 | \ call SQLU_GetColumnDef() 139 | command! -nargs=* SQLUGetColumnDataType 140 | \ call SQLU_GetColumnDef(expand(""), 1) 141 | command! -nargs=* SQLUCreateProcedure 142 | \ call SQLU_CreateProcedure() 143 | command! -nargs=* SQLUToggleValue 144 | \ call SQLU_ToggleValue() 145 | 146 | if !exists("g:sqlutil_load_default_maps") 147 | let g:sqlutil_load_default_maps = 1 148 | endif 149 | 150 | if(g:sqlutil_load_default_maps == 1) 151 | if !hasmapto('SQLUFormatStmts') 152 | nmap sfr SQLUFormatStmts 153 | vmap sfr SQLUFormatStmts 154 | endif 155 | if !hasmapto('SQLUFormatter') 156 | nmap sfs SQLUFormatter 157 | vmap sfs SQLUFormatter 158 | nmap sf SQLUFormatter 159 | vmap sf SQLUFormatter 160 | endif 161 | if !hasmapto('SQLUCreateColumnList') 162 | nmap scl SQLUCreateColumnList 163 | endif 164 | if !hasmapto('SQLUGetColumnDef') 165 | nmap scd SQLUGetColumnDef 166 | endif 167 | if !hasmapto('SQLUGetColumnDataType') 168 | nmap scdt SQLUGetColumnDataType 169 | endif 170 | if !hasmapto('SQLUCreateProcedure') 171 | nmap scp SQLUCreateProcedure 172 | endif 173 | endif 174 | 175 | if exists("g:loaded_sqlutilities_global_maps") 176 | vunmap