pg_query 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -0
- data/ext/pg_query/extconf.rb +1 -1
- data/lib/pg_query/deparse.rb +393 -31
- data/lib/pg_query/deparse/keywords.rb +760 -0
- data/lib/pg_query/deparse/rename.rb +41 -0
- data/lib/pg_query/node_types.rb +9 -0
- data/lib/pg_query/version.rb +1 -1
- metadata +5 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 9cb01b49c6ea65d1ff126562ce68adaa5635d37093ff726b1bc70d65c341ae9e
         | 
| 4 | 
            +
              data.tar.gz: 4dc7fa1bf00d7ff6036a79d8a38fd9f3e383f449b21f0d53f0168be7d32df89a
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: ad48c885044147fcc9fa406543fc8a805c789fa227d71000bd1d25be0846aa1f7e183420e7ee86df262ff0d7ae668f2c4b1cd4ef15f5d305d5deeb5d86d6e8ad
         | 
| 7 | 
            +
              data.tar.gz: 860aa2345238226eaf5594d20d34af5a6aed39177a0900e0b72e79771586f96bf2917ac73722d3672cf730e18c2977cd275617fe411e79b4af8266ac4e499124
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,40 @@ | |
| 1 1 | 
             
            # Changelog
         | 
| 2 2 |  | 
| 3 | 
            +
            ## 1.1.1     2019-11-10
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            * Deparsing improvements by [@emin100](https://github.com/emin100)
         | 
| 6 | 
            +
              * Deparse ILIKE, COLLATE and DISCARD (#133)
         | 
| 7 | 
            +
              * CREATE CAST (#136)
         | 
| 8 | 
            +
              * CREATE SCHEMA (#136)
         | 
| 9 | 
            +
              * UNION, UNION ALL and EXCEPT in SELECT queries (#136)
         | 
| 10 | 
            +
              * CREATE DOMAIN (#145)
         | 
| 11 | 
            +
              * Subquery indirection (#157)
         | 
| 12 | 
            +
              * Fix Type Cast Parentheses Problem (#152)
         | 
| 13 | 
            +
              * SELECT INTO (#151)
         | 
| 14 | 
            +
              * SET DEFAULT in INSERT INTO (#154)
         | 
| 15 | 
            +
              * REVOKE (#155)
         | 
| 16 | 
            +
              * PREPARE and EXECUTE (#148)
         | 
| 17 | 
            +
              * INSERT INTO ... RETURNING (#153)
         | 
| 18 | 
            +
              * Fix Alter .. RENAME SQL (#146)
         | 
| 19 | 
            +
            * Deparsing improvements by [@herwinw](https://github.com/herwinw)
         | 
| 20 | 
            +
              * Fix subquery in COPY in deparse (#112)
         | 
| 21 | 
            +
              * Function call indirection (#116)
         | 
| 22 | 
            +
              * Function without parameters (#117)
         | 
| 23 | 
            +
              * CREATE AGGREGATE
         | 
| 24 | 
            +
              * CREATE OPERATOR
         | 
| 25 | 
            +
              * CREATE TYPE
         | 
| 26 | 
            +
              * GRANT statements
         | 
| 27 | 
            +
              * DROP SCHEMA
         | 
| 28 | 
            +
            * Deparsing improvements by [@akiellor](https://github.com/akiellor)
         | 
| 29 | 
            +
              * Named window functions (#150)
         | 
| 30 | 
            +
            * Deparsing improvements by [@himanshu](https://github.com/himanshu)
         | 
| 31 | 
            +
              * Arguments in custom types (#143)
         | 
| 32 | 
            +
              * Use "double precision" instead of "double" type name (#139)
         | 
| 33 | 
            +
            * Use explicit -z flag to support OpenBSD tar (#134) [@sirn](https://github.com/sirn)
         | 
| 34 | 
            +
            * Add Ruby 2.6 to Travis tests
         | 
| 35 | 
            +
            * Escape identifiers in more cases, if necessary
         | 
| 36 | 
            +
             | 
| 37 | 
            +
             | 
| 3 38 | 
             
            ## 1.1.0     2018-10-04
         | 
| 4 39 |  | 
| 5 40 | 
             
            * Deparsing improvements by [@herwinw](https://github.com/herwinw)
         | 
    
        data/ext/pg_query/extconf.rb
    CHANGED
    
    | @@ -19,7 +19,7 @@ unless File.exist?("#{workdir}/libpg_query.tar.gz") | |
| 19 19 | 
             
            end
         | 
| 20 20 |  | 
| 21 21 | 
             
            unless Dir.exist?(libdir)
         | 
| 22 | 
            -
              system("tar - | 
| 22 | 
            +
              system("tar -xzf #{workdir}/libpg_query.tar.gz") || raise('ERROR')
         | 
| 23 23 | 
             
            end
         | 
| 24 24 |  | 
| 25 25 | 
             
            unless Dir.exist?(libfile)
         | 
    
        data/lib/pg_query/deparse.rb
    CHANGED
    
    | @@ -1,5 +1,8 @@ | |
| 1 | 
            -
            require_relative 'deparse/interval'
         | 
| 2 1 | 
             
            require_relative 'deparse/alter_table'
         | 
| 2 | 
            +
            require_relative 'deparse/rename'
         | 
| 3 | 
            +
            require_relative 'deparse/interval'
         | 
| 4 | 
            +
            require_relative 'deparse/keywords'
         | 
| 5 | 
            +
             | 
| 3 6 | 
             
            class PgQuery
         | 
| 4 7 | 
             
              # Reconstruct all of the parsed queries into their original form
         | 
| 5 8 | 
             
              def deparse(tree = @tree)
         | 
| @@ -32,10 +35,14 @@ class PgQuery | |
| 32 35 | 
             
                    case node['kind']
         | 
| 33 36 | 
             
                    when AEXPR_OP
         | 
| 34 37 | 
             
                      deparse_aexpr(node, context)
         | 
| 38 | 
            +
                    when AEXPR_OP_ALL
         | 
| 39 | 
            +
                      deparse_aexpr_all(node)
         | 
| 35 40 | 
             
                    when AEXPR_OP_ANY
         | 
| 36 41 | 
             
                      deparse_aexpr_any(node)
         | 
| 37 42 | 
             
                    when AEXPR_IN
         | 
| 38 43 | 
             
                      deparse_aexpr_in(node)
         | 
| 44 | 
            +
                    when AEXPR_ILIKE
         | 
| 45 | 
            +
                      deparse_aexpr_ilike(node)
         | 
| 39 46 | 
             
                    when CONSTR_TYPE_FOREIGN
         | 
| 40 47 | 
             
                      deparse_aexpr_like(node)
         | 
| 41 48 | 
             
                    when AEXPR_BETWEEN, AEXPR_NOT_BETWEEN, AEXPR_BETWEEN_SYM, AEXPR_NOT_BETWEEN_SYM
         | 
| @@ -45,6 +52,8 @@ class PgQuery | |
| 45 52 | 
             
                    else
         | 
| 46 53 | 
             
                      raise format("Can't deparse: %s: %s", type, node.inspect)
         | 
| 47 54 | 
             
                    end
         | 
| 55 | 
            +
                  when ACCESS_PRIV
         | 
| 56 | 
            +
                    deparse_access_priv(node)
         | 
| 48 57 | 
             
                  when ALIAS
         | 
| 49 58 | 
             
                    deparse_alias(node)
         | 
| 50 59 | 
             
                  when ALTER_TABLE_STMT
         | 
| @@ -78,18 +87,32 @@ class PgQuery | |
| 78 87 | 
             
                    deparse_case(node)
         | 
| 79 88 | 
             
                  when COALESCE_EXPR
         | 
| 80 89 | 
             
                    deparse_coalesce(node)
         | 
| 90 | 
            +
                  when COLLATE_CLAUSE
         | 
| 91 | 
            +
                    deparse_collate(node)
         | 
| 81 92 | 
             
                  when COLUMN_DEF
         | 
| 82 93 | 
             
                    deparse_columndef(node)
         | 
| 83 94 | 
             
                  when COLUMN_REF
         | 
| 84 95 | 
             
                    deparse_columnref(node)
         | 
| 85 96 | 
             
                  when COMMON_TABLE_EXPR
         | 
| 86 97 | 
             
                    deparse_cte(node)
         | 
| 98 | 
            +
                  when COMPOSITE_TYPE_STMT
         | 
| 99 | 
            +
                    deparse_composite_type(node)
         | 
| 87 100 | 
             
                  when CONSTRAINT
         | 
| 88 101 | 
             
                    deparse_constraint(node)
         | 
| 89 102 | 
             
                  when COPY_STMT
         | 
| 90 103 | 
             
                    deparse_copy(node)
         | 
| 104 | 
            +
                  when CREATE_CAST_STMT
         | 
| 105 | 
            +
                    deparse_create_cast(node)
         | 
| 106 | 
            +
                  when CREATE_DOMAIN_STMT
         | 
| 107 | 
            +
                    deparse_create_domain(node)
         | 
| 108 | 
            +
                  when CREATE_ENUM_STMT
         | 
| 109 | 
            +
                    deparse_create_enum(node)
         | 
| 91 110 | 
             
                  when CREATE_FUNCTION_STMT
         | 
| 92 111 | 
             
                    deparse_create_function(node)
         | 
| 112 | 
            +
                  when CREATE_RANGE_STMT
         | 
| 113 | 
            +
                    deparse_create_range(node)
         | 
| 114 | 
            +
                  when CREATE_SCHEMA_STMT
         | 
| 115 | 
            +
                    deparse_create_schema(node)
         | 
| 93 116 | 
             
                  when CREATE_STMT
         | 
| 94 117 | 
             
                    deparse_create_table(node)
         | 
| 95 118 | 
             
                  when CREATE_TABLE_AS_STMT
         | 
| @@ -98,16 +121,26 @@ class PgQuery | |
| 98 121 | 
             
                    deparse_into_clause(node)
         | 
| 99 122 | 
             
                  when DEF_ELEM
         | 
| 100 123 | 
             
                    deparse_defelem(node)
         | 
| 124 | 
            +
                  when DEFINE_STMT
         | 
| 125 | 
            +
                    deparse_define_stmt(node)
         | 
| 101 126 | 
             
                  when DELETE_STMT
         | 
| 102 127 | 
             
                    deparse_delete_from(node)
         | 
| 128 | 
            +
                  when DISCARD_STMT
         | 
| 129 | 
            +
                    deparse_discard(node)
         | 
| 103 130 | 
             
                  when DROP_STMT
         | 
| 104 131 | 
             
                    deparse_drop(node)
         | 
| 105 132 | 
             
                  when EXPLAIN_STMT
         | 
| 106 133 | 
             
                    deparse_explain(node)
         | 
| 134 | 
            +
                  when EXECUTE_STMT
         | 
| 135 | 
            +
                    deparse_execute(node)
         | 
| 107 136 | 
             
                  when FUNC_CALL
         | 
| 108 137 | 
             
                    deparse_funccall(node)
         | 
| 109 138 | 
             
                  when FUNCTION_PARAMETER
         | 
| 110 139 | 
             
                    deparse_functionparameter(node)
         | 
| 140 | 
            +
                  when GRANT_ROLE_STMT
         | 
| 141 | 
            +
                    deparse_grant_role(node)
         | 
| 142 | 
            +
                  when GRANT_STMT
         | 
| 143 | 
            +
                    deparse_grant(node)
         | 
| 111 144 | 
             
                  when INSERT_STMT
         | 
| 112 145 | 
             
                    deparse_insert_into(node)
         | 
| 113 146 | 
             
                  when JOIN_EXPR
         | 
| @@ -118,8 +151,12 @@ class PgQuery | |
| 118 151 | 
             
                    deparse_lockingclause(node)
         | 
| 119 152 | 
             
                  when NULL_TEST
         | 
| 120 153 | 
             
                    deparse_nulltest(node)
         | 
| 154 | 
            +
                  when OBJECT_WITH_ARGS
         | 
| 155 | 
            +
                    deparse_object_with_args(node)
         | 
| 121 156 | 
             
                  when PARAM_REF
         | 
| 122 157 | 
             
                    deparse_paramref(node)
         | 
| 158 | 
            +
                  when PREPARE_STMT
         | 
| 159 | 
            +
                    deparse_prepare(node)
         | 
| 123 160 | 
             
                  when RANGE_FUNCTION
         | 
| 124 161 | 
             
                    deparse_range_function(node)
         | 
| 125 162 | 
             
                  when RANGE_SUBSELECT
         | 
| @@ -132,6 +169,8 @@ class PgQuery | |
| 132 169 | 
             
                    deparse_renamestmt(node)
         | 
| 133 170 | 
             
                  when RES_TARGET
         | 
| 134 171 | 
             
                    deparse_restarget(node, context)
         | 
| 172 | 
            +
                  when ROLE_SPEC
         | 
| 173 | 
            +
                    deparse_role_spec(node)
         | 
| 135 174 | 
             
                  when ROW_EXPR
         | 
| 136 175 | 
             
                    deparse_row(node)
         | 
| 137 176 | 
             
                  when SELECT_STMT
         | 
| @@ -164,13 +203,15 @@ class PgQuery | |
| 164 203 | 
             
                    deparse_vacuum_stmt(node)
         | 
| 165 204 | 
             
                  when DO_STMT
         | 
| 166 205 | 
             
                    deparse_do_stmt(node)
         | 
| 206 | 
            +
                  when SET_TO_DEFAULT
         | 
| 207 | 
            +
                    'DEFAULT'
         | 
| 167 208 | 
             
                  when STRING
         | 
| 168 209 | 
             
                    if context == A_CONST
         | 
| 169 210 | 
             
                      format("'%s'", node['str'].gsub("'", "''"))
         | 
| 170 211 | 
             
                    elsif [FUNC_CALL, TYPE_NAME, :operator, :defname_as].include?(context)
         | 
| 171 212 | 
             
                      node['str']
         | 
| 172 213 | 
             
                    else
         | 
| 173 | 
            -
                       | 
| 214 | 
            +
                      deparse_identifier(node['str'], escape_always: true)
         | 
| 174 215 | 
             
                    end
         | 
| 175 216 | 
             
                  when INTEGER
         | 
| 176 217 | 
             
                    node['ival'].to_s
         | 
| @@ -187,6 +228,15 @@ class PgQuery | |
| 187 228 | 
             
                  nodes.map { |n| deparse_item(n, context) }
         | 
| 188 229 | 
             
                end
         | 
| 189 230 |  | 
| 231 | 
            +
                def deparse_identifier(ident, escape_always: false)
         | 
| 232 | 
            +
                  return if ident.nil?
         | 
| 233 | 
            +
                  if escape_always || !ident[/^\w+$/] || KEYWORDS.include?(ident.upcase)
         | 
| 234 | 
            +
                    format('"%s"', ident.gsub('"', '""'))
         | 
| 235 | 
            +
                  else
         | 
| 236 | 
            +
                    ident
         | 
| 237 | 
            +
                  end
         | 
| 238 | 
            +
                end
         | 
| 239 | 
            +
             | 
| 190 240 | 
             
                def deparse_rangevar(node)
         | 
| 191 241 | 
             
                  output = []
         | 
| 192 242 | 
             
                  output << 'ONLY' unless node['inh']
         | 
| @@ -200,19 +250,32 @@ class PgQuery | |
| 200 250 | 
             
                  deparse_item(node[STMT_FIELD])
         | 
| 201 251 | 
             
                end
         | 
| 202 252 |  | 
| 203 | 
            -
                def  | 
| 204 | 
            -
                   | 
| 205 | 
            -
             | 
| 206 | 
            -
             | 
| 207 | 
            -
             | 
| 208 | 
            -
             | 
| 209 | 
            -
                     | 
| 210 | 
            -
             | 
| 211 | 
            -
                     | 
| 253 | 
            +
                def deparse_renamestmt_decision(node, type)
         | 
| 254 | 
            +
                  if node[type]
         | 
| 255 | 
            +
                    if node[type].is_a?(String)
         | 
| 256 | 
            +
                      deparse_identifier(node[type])
         | 
| 257 | 
            +
                    elsif node[type].is_a?(Array)
         | 
| 258 | 
            +
                      deparse_item_list(node[type])
         | 
| 259 | 
            +
                    elsif node[type].is_a?(Object)
         | 
| 260 | 
            +
                      deparse_item(node[type])
         | 
| 261 | 
            +
                    end
         | 
| 212 262 | 
             
                  else
         | 
| 213 | 
            -
                     | 
| 263 | 
            +
                    type
         | 
| 214 264 | 
             
                  end
         | 
| 265 | 
            +
                end
         | 
| 215 266 |  | 
| 267 | 
            +
                def deparse_renamestmt(node)
         | 
| 268 | 
            +
                  output = []
         | 
| 269 | 
            +
                  output << 'ALTER'
         | 
| 270 | 
            +
                  command, type, options, type2, options2 = Rename.commands(node)
         | 
| 271 | 
            +
             | 
| 272 | 
            +
                  output << command if command
         | 
| 273 | 
            +
                  output << deparse_renamestmt_decision(node, type)
         | 
| 274 | 
            +
                  output << options if options
         | 
| 275 | 
            +
                  output << deparse_renamestmt_decision(node, type2) if type2
         | 
| 276 | 
            +
                  output << deparse_renamestmt_decision(node, options2) if options2
         | 
| 277 | 
            +
                  output << 'TO'
         | 
| 278 | 
            +
                  output << deparse_identifier(node['newname'], escape_always: true)
         | 
| 216 279 | 
             
                  output.join(' ')
         | 
| 217 280 | 
             
                end
         | 
| 218 281 |  | 
| @@ -223,7 +286,7 @@ class PgQuery | |
| 223 286 | 
             
                end
         | 
| 224 287 |  | 
| 225 288 | 
             
                def deparse_a_arrayexp(node)
         | 
| 226 | 
            -
                  'ARRAY[' + node['elements'].map do |element|
         | 
| 289 | 
            +
                  'ARRAY[' + (node['elements'] || []).map do |element|
         | 
| 227 290 | 
             
                    deparse_item(element)
         | 
| 228 291 | 
             
                  end.join(', ') + ']'
         | 
| 229 292 | 
             
                end
         | 
| @@ -237,7 +300,13 @@ class PgQuery | |
| 237 300 | 
             
                end
         | 
| 238 301 |  | 
| 239 302 | 
             
                def deparse_a_indirection(node)
         | 
| 240 | 
            -
                  output = [ | 
| 303 | 
            +
                  output = []
         | 
| 304 | 
            +
                  arg = deparse_item(node['arg'])
         | 
| 305 | 
            +
                  output << if node['arg'].key?(FUNC_CALL) || node['arg'].key?(SUB_LINK)
         | 
| 306 | 
            +
                              "(#{arg})."
         | 
| 307 | 
            +
                            else
         | 
| 308 | 
            +
                              arg
         | 
| 309 | 
            +
                            end
         | 
| 241 310 | 
             
                  node['indirection'].each do |subnode|
         | 
| 242 311 | 
             
                    output << deparse_item(subnode)
         | 
| 243 312 | 
             
                  end
         | 
| @@ -253,13 +322,16 @@ class PgQuery | |
| 253 322 | 
             
                  if node['colnames']
         | 
| 254 323 | 
             
                    name + '(' + deparse_item_list(node['colnames']).join(', ') + ')'
         | 
| 255 324 | 
             
                  else
         | 
| 256 | 
            -
                    name
         | 
| 325 | 
            +
                    deparse_identifier(name)
         | 
| 257 326 | 
             
                  end
         | 
| 258 327 | 
             
                end
         | 
| 259 328 |  | 
| 260 329 | 
             
                def deparse_alter_table(node)
         | 
| 261 330 | 
             
                  output = []
         | 
| 262 | 
            -
                  output << 'ALTER | 
| 331 | 
            +
                  output << 'ALTER'
         | 
| 332 | 
            +
             | 
| 333 | 
            +
                  output << 'TABLE' if node['relkind'] == OBJECT_TYPE_TABLE
         | 
| 334 | 
            +
                  output << 'VIEW' if node['relkind'] == OBJECT_TYPE_VIEW
         | 
| 263 335 |  | 
| 264 336 | 
             
                  output << deparse_item(node['relation'])
         | 
| 265 337 |  | 
| @@ -284,6 +356,16 @@ class PgQuery | |
| 284 356 | 
             
                  output.compact.join(' ')
         | 
| 285 357 | 
             
                end
         | 
| 286 358 |  | 
| 359 | 
            +
                def deparse_object_with_args(node)
         | 
| 360 | 
            +
                  output = []
         | 
| 361 | 
            +
                  output += node['objname'].map(&method(:deparse_item))
         | 
| 362 | 
            +
                  unless node['args_unspecified']
         | 
| 363 | 
            +
                    args = node.fetch('objargs', []).map(&method(:deparse_item)).join(', ')
         | 
| 364 | 
            +
                    output << "(#{args})"
         | 
| 365 | 
            +
                  end
         | 
| 366 | 
            +
                  output.join('')
         | 
| 367 | 
            +
                end
         | 
| 368 | 
            +
             | 
| 287 369 | 
             
                def deparse_paramref(node)
         | 
| 288 370 | 
             
                  if node['number'].nil?
         | 
| 289 371 | 
             
                    '?'
         | 
| @@ -292,9 +374,18 @@ class PgQuery | |
| 292 374 | 
             
                  end
         | 
| 293 375 | 
             
                end
         | 
| 294 376 |  | 
| 377 | 
            +
                def deparse_prepare(node)
         | 
| 378 | 
            +
                  output = ['PREPARE']
         | 
| 379 | 
            +
                  output << deparse_identifier(node['name'])
         | 
| 380 | 
            +
                  output << "(#{deparse_item_list(node['argtypes']).join(', ')})" if node['argtypes']
         | 
| 381 | 
            +
                  output << 'AS'
         | 
| 382 | 
            +
                  output << deparse_item(node['query'])
         | 
| 383 | 
            +
                  output.join(' ')
         | 
| 384 | 
            +
                end
         | 
| 385 | 
            +
             | 
| 295 386 | 
             
                def deparse_restarget(node, context)
         | 
| 296 387 | 
             
                  if context == :select
         | 
| 297 | 
            -
                    [deparse_item(node['val']), node['name']].compact.join(' AS ')
         | 
| 388 | 
            +
                    [deparse_item(node['val']), deparse_identifier(node['name'])].compact.join(' AS ')
         | 
| 298 389 | 
             
                  elsif context == :update
         | 
| 299 390 | 
             
                    [node['name'], deparse_item(node['val'])].compact.join(' = ')
         | 
| 300 391 | 
             
                  elsif node['val'].nil?
         | 
| @@ -315,12 +406,14 @@ class PgQuery | |
| 315 406 | 
             
                  name = (node['funcname'].map { |n| deparse_item(n, FUNC_CALL) } - ['pg_catalog']).join('.')
         | 
| 316 407 | 
             
                  distinct = node['agg_distinct'] ? 'DISTINCT ' : ''
         | 
| 317 408 | 
             
                  output << format('%s(%s%s)', name, distinct, args.join(', '))
         | 
| 318 | 
            -
                  output << format('OVER  | 
| 409 | 
            +
                  output << format('OVER %s', deparse_item(node['over'])) if node['over']
         | 
| 319 410 |  | 
| 320 411 | 
             
                  output.join(' ')
         | 
| 321 412 | 
             
                end
         | 
| 322 413 |  | 
| 323 414 | 
             
                def deparse_windowdef(node)
         | 
| 415 | 
            +
                  return deparse_identifier(node['name']) if node['name']
         | 
| 416 | 
            +
             | 
| 324 417 | 
             
                  output = []
         | 
| 325 418 |  | 
| 326 419 | 
             
                  if node['partitionClause']
         | 
| @@ -337,13 +430,84 @@ class PgQuery | |
| 337 430 | 
             
                    end.join(', ')
         | 
| 338 431 | 
             
                  end
         | 
| 339 432 |  | 
| 340 | 
            -
                  output.join(' ')
         | 
| 433 | 
            +
                  format('(%s)', output.join(' '))
         | 
| 341 434 | 
             
                end
         | 
| 342 435 |  | 
| 343 436 | 
             
                def deparse_functionparameter(node)
         | 
| 344 437 | 
             
                  deparse_item(node['argType'])
         | 
| 345 438 | 
             
                end
         | 
| 346 439 |  | 
| 440 | 
            +
                def deparse_grant_role(node)
         | 
| 441 | 
            +
                  output = []
         | 
| 442 | 
            +
                  output << ['GRANT'] if node['is_grant']
         | 
| 443 | 
            +
                  output << ['REVOKE'] unless node['is_grant']
         | 
| 444 | 
            +
                  output << node['granted_roles'].map(&method(:deparse_item)).join(', ')
         | 
| 445 | 
            +
                  output << ['TO'] if node['is_grant']
         | 
| 446 | 
            +
                  output << ['FROM'] unless node['is_grant']
         | 
| 447 | 
            +
                  output << node['grantee_roles'].map(&method(:deparse_item)).join(', ')
         | 
| 448 | 
            +
                  output << 'WITH ADMIN OPTION' if node['admin_opt']
         | 
| 449 | 
            +
                  output.join(' ')
         | 
| 450 | 
            +
                end
         | 
| 451 | 
            +
             | 
| 452 | 
            +
                def deparse_grant(node) # rubocop:disable Metrics/CyclomaticComplexity
         | 
| 453 | 
            +
                  objtype, allow_all = deparse_grant_objtype(node)
         | 
| 454 | 
            +
                  output = []
         | 
| 455 | 
            +
                  output << ['GRANT'] if node['is_grant']
         | 
| 456 | 
            +
                  output << ['REVOKE'] unless node['is_grant']
         | 
| 457 | 
            +
                  output << if node.key?('privileges')
         | 
| 458 | 
            +
                              node['privileges'].map(&method(:deparse_item)).join(', ')
         | 
| 459 | 
            +
                            else
         | 
| 460 | 
            +
                              'ALL'
         | 
| 461 | 
            +
                            end
         | 
| 462 | 
            +
                  output << 'ON'
         | 
| 463 | 
            +
                  objects = node['objects']
         | 
| 464 | 
            +
                  objects = objects[0] if %w[DOMAIN TYPE].include?(objtype)
         | 
| 465 | 
            +
                  objects = objects.map do |object|
         | 
| 466 | 
            +
                    deparsed = deparse_item(object)
         | 
| 467 | 
            +
                    if object.key?(RANGE_VAR) || object.key?(OBJECT_WITH_ARGS) || !allow_all
         | 
| 468 | 
            +
                      objtype == 'TABLE' ? deparsed : "#{objtype} #{deparsed}"
         | 
| 469 | 
            +
                    else
         | 
| 470 | 
            +
                      "ALL #{objtype}S IN SCHEMA #{deparsed}"
         | 
| 471 | 
            +
                    end
         | 
| 472 | 
            +
                  end
         | 
| 473 | 
            +
                  output << objects.join(', ')
         | 
| 474 | 
            +
                  output << ['TO'] if node['is_grant']
         | 
| 475 | 
            +
                  output << ['FROM'] unless node['is_grant']
         | 
| 476 | 
            +
                  output << node['grantees'].map(&method(:deparse_item)).join(', ')
         | 
| 477 | 
            +
                  output << 'WITH GRANT OPTION' if node['grant_option']
         | 
| 478 | 
            +
                  output.join(' ')
         | 
| 479 | 
            +
                end
         | 
| 480 | 
            +
             | 
| 481 | 
            +
                def deparse_grant_objtype(node)
         | 
| 482 | 
            +
                  {
         | 
| 483 | 
            +
                    1 => ['TABLE', true],
         | 
| 484 | 
            +
                    2 => ['SEQUENCE', true],
         | 
| 485 | 
            +
                    3 => ['DATABASE', false],
         | 
| 486 | 
            +
                    4 => ['DOMAIN', false],
         | 
| 487 | 
            +
                    5 => ['FOREIGN DATA WRAPPER', false],
         | 
| 488 | 
            +
                    6 => ['FOREIGN SERVER', false],
         | 
| 489 | 
            +
                    7 => ['FUNCTION', true],
         | 
| 490 | 
            +
                    8 => ['LANGUAGE', false],
         | 
| 491 | 
            +
                    9 => ['LARGE OBJECT', false],
         | 
| 492 | 
            +
                    10 => ['SCHEMA', false],
         | 
| 493 | 
            +
                    11 => ['TABLESPACE', false],
         | 
| 494 | 
            +
                    12 => ['TYPE', false]
         | 
| 495 | 
            +
                  }.fetch(node['objtype'])
         | 
| 496 | 
            +
                end
         | 
| 497 | 
            +
             | 
| 498 | 
            +
                def deparse_access_priv(node)
         | 
| 499 | 
            +
                  output = [node['priv_name']]
         | 
| 500 | 
            +
                  output << "(#{node['cols'].map(&method(:deparse_item)).join(', ')})" if node.key?('cols')
         | 
| 501 | 
            +
                  output.join(' ')
         | 
| 502 | 
            +
                end
         | 
| 503 | 
            +
             | 
| 504 | 
            +
                def deparse_role_spec(node)
         | 
| 505 | 
            +
                  return 'CURRENT_USER' if node['roletype'] == 1
         | 
| 506 | 
            +
                  return 'SESSION_USER' if node['roletype'] == 2
         | 
| 507 | 
            +
                  return 'PUBLIC' if node['roletype'] == 3
         | 
| 508 | 
            +
                  deparse_identifier(node['rolename'], escape_always: true)
         | 
| 509 | 
            +
                end
         | 
| 510 | 
            +
             | 
| 347 511 | 
             
                def deparse_aexpr_in(node)
         | 
| 348 512 | 
             
                  rexpr = Array(node['rexpr']).map { |arg| deparse_item(arg) }
         | 
| 349 513 | 
             
                  operator = node['name'].map { |n| deparse_item(n, :operator) } == ['='] ? 'IN' : 'NOT IN'
         | 
| @@ -356,6 +520,12 @@ class PgQuery | |
| 356 520 | 
             
                  format('%s %s %s', deparse_item(node['lexpr']), operator, value)
         | 
| 357 521 | 
             
                end
         | 
| 358 522 |  | 
| 523 | 
            +
                def deparse_aexpr_ilike(node)
         | 
| 524 | 
            +
                  value = deparse_item(node['rexpr'])
         | 
| 525 | 
            +
                  operator = node['name'][0]['String']['str'] == '~~*' ? 'ILIKE' : 'NOT ILIKE'
         | 
| 526 | 
            +
                  format('%s %s %s', deparse_item(node['lexpr']), operator, value)
         | 
| 527 | 
            +
                end
         | 
| 528 | 
            +
             | 
| 359 529 | 
             
                def deparse_bool_expr_not(node)
         | 
| 360 530 | 
             
                  format('NOT %s', deparse_item(node['args'][0]))
         | 
| 361 531 | 
             
                end
         | 
| @@ -422,6 +592,13 @@ class PgQuery | |
| 422 592 | 
             
                  output.join(' ' + deparse_item(node['name'][0], :operator) + ' ')
         | 
| 423 593 | 
             
                end
         | 
| 424 594 |  | 
| 595 | 
            +
                def deparse_aexpr_all(node)
         | 
| 596 | 
            +
                  output = []
         | 
| 597 | 
            +
                  output << deparse_item(node['lexpr'])
         | 
| 598 | 
            +
                  output << format('ALL(%s)', deparse_item(node['rexpr']))
         | 
| 599 | 
            +
                  output.join(' ' + deparse_item(node['name'][0], :operator) + ' ')
         | 
| 600 | 
            +
                end
         | 
| 601 | 
            +
             | 
| 425 602 | 
             
                def deparse_aexpr_between(node)
         | 
| 426 603 | 
             
                  between = case node['kind']
         | 
| 427 604 | 
             
                            when AEXPR_BETWEEN
         | 
| @@ -510,6 +687,14 @@ class PgQuery | |
| 510 687 | 
             
                  output.join(' ')
         | 
| 511 688 | 
             
                end
         | 
| 512 689 |  | 
| 690 | 
            +
                def deparse_collate(node)
         | 
| 691 | 
            +
                  output = []
         | 
| 692 | 
            +
                  output << deparse_item(node['arg'])
         | 
| 693 | 
            +
                  output << 'COLLATE'
         | 
| 694 | 
            +
                  output << deparse_item_list(node['collname'])
         | 
| 695 | 
            +
                  output.join(' ')
         | 
| 696 | 
            +
                end
         | 
| 697 | 
            +
             | 
| 513 698 | 
             
                def deparse_with_clause(node)
         | 
| 514 699 | 
             
                  output = ['WITH']
         | 
| 515 700 | 
             
                  output << 'RECURSIVE' if node['recursive']
         | 
| @@ -614,9 +799,22 @@ class PgQuery | |
| 614 799 | 
             
                      deparse_item(item)
         | 
| 615 800 | 
             
                    end
         | 
| 616 801 | 
             
                  end
         | 
| 802 | 
            +
                  if node['collClause']
         | 
| 803 | 
            +
                    output << 'COLLATE'
         | 
| 804 | 
            +
                    output += node['collClause']['CollateClause']['collname'].map(&method(:deparse_item))
         | 
| 805 | 
            +
                  end
         | 
| 617 806 | 
             
                  output.compact.join(' ')
         | 
| 618 807 | 
             
                end
         | 
| 619 808 |  | 
| 809 | 
            +
                def deparse_composite_type(node)
         | 
| 810 | 
            +
                  output = ['CREATE TYPE']
         | 
| 811 | 
            +
                  output << deparse_rangevar(node['typevar'][RANGE_VAR].merge('inh' => true))
         | 
| 812 | 
            +
                  output << 'AS'
         | 
| 813 | 
            +
                  coldeflist = node['coldeflist'].map(&method(:deparse_item))
         | 
| 814 | 
            +
                  output << "(#{coldeflist.join(', ')})"
         | 
| 815 | 
            +
                  output.join(' ')
         | 
| 816 | 
            +
                end
         | 
| 817 | 
            +
             | 
| 620 818 | 
             
                def deparse_constraint(node) # rubocop:disable Metrics/CyclomaticComplexity
         | 
| 621 819 | 
             
                  output = []
         | 
| 622 820 | 
             
                  if node['conname']
         | 
| @@ -645,6 +843,7 @@ class PgQuery | |
| 645 843 | 
             
                  if node['raw_expr']
         | 
| 646 844 | 
             
                    expression = deparse_item(node['raw_expr'])
         | 
| 647 845 | 
             
                    # Unless it's simple, put parentheses around it
         | 
| 846 | 
            +
                    expression = '(' + expression + ')' if node['raw_expr'][BOOL_EXPR]
         | 
| 648 847 | 
             
                    expression = '(' + expression + ')' if node['raw_expr'][A_EXPR] && node['raw_expr'][A_EXPR]['kind'] == AEXPR_OP
         | 
| 649 848 | 
             
                    output << expression
         | 
| 650 849 | 
             
                  end
         | 
| @@ -658,16 +857,63 @@ class PgQuery | |
| 658 857 |  | 
| 659 858 | 
             
                def deparse_copy(node)
         | 
| 660 859 | 
             
                  output = ['COPY']
         | 
| 661 | 
            -
                   | 
| 860 | 
            +
                  if node.key?('relation')
         | 
| 861 | 
            +
                    output << deparse_item(node['relation'])
         | 
| 862 | 
            +
                  elsif node.key?('query')
         | 
| 863 | 
            +
                    output << "(#{deparse_item(node['query'])})"
         | 
| 864 | 
            +
                  end
         | 
| 662 865 | 
             
                  columns = node.fetch('attlist', []).map { |column| deparse_item(column) }
         | 
| 663 866 | 
             
                  output << "(#{columns.join(', ')})" unless columns.empty?
         | 
| 664 867 | 
             
                  output << (node['is_from'] ? 'FROM' : 'TO')
         | 
| 665 868 | 
             
                  output << 'PROGRAM' if node['is_program']
         | 
| 666 | 
            -
                  output <<  | 
| 667 | 
            -
             | 
| 869 | 
            +
                  output << deparse_copy_output(node)
         | 
| 870 | 
            +
                  output.join(' ')
         | 
| 871 | 
            +
                end
         | 
| 872 | 
            +
             | 
| 873 | 
            +
                def deparse_copy_output(node)
         | 
| 874 | 
            +
                  return "'#{node['filename']}'" if node.key?('filename')
         | 
| 875 | 
            +
                  return 'STDIN' if node['is_from']
         | 
| 876 | 
            +
                  'STDOUT'
         | 
| 877 | 
            +
                end
         | 
| 878 | 
            +
             | 
| 879 | 
            +
                def deparse_create_enum(node)
         | 
| 880 | 
            +
                  output = ['CREATE TYPE']
         | 
| 881 | 
            +
                  output << deparse_item(node['typeName'][0])
         | 
| 882 | 
            +
                  output << 'AS ENUM'
         | 
| 883 | 
            +
                  vals = node['vals'].map { |val| deparse_item(val, A_CONST) }
         | 
| 884 | 
            +
                  output << "(#{vals.join(', ')})"
         | 
| 885 | 
            +
                  output.join(' ')
         | 
| 886 | 
            +
                end
         | 
| 887 | 
            +
             | 
| 888 | 
            +
                def deparse_create_cast(node)
         | 
| 889 | 
            +
                  output = []
         | 
| 890 | 
            +
                  output << 'CREATE'
         | 
| 891 | 
            +
                  output << 'CAST'
         | 
| 892 | 
            +
                  output << format('(%s AS %s)', deparse_item(node['sourcetype']), deparse_item(node['targettype']))
         | 
| 893 | 
            +
                  output << if node['func']
         | 
| 894 | 
            +
                              function = node['func']['ObjectWithArgs']
         | 
| 895 | 
            +
                              name = deparse_item_list(function['objname']).join('.')
         | 
| 896 | 
            +
                              arguments = deparse_item_list(function['objargs']).join(', ')
         | 
| 897 | 
            +
                              format('WITH FUNCTION %s(%s)', name, arguments)
         | 
| 898 | 
            +
                            elsif node['inout']
         | 
| 899 | 
            +
                              'WITH INOUT'
         | 
| 668 900 | 
             
                            else
         | 
| 669 | 
            -
                               | 
| 901 | 
            +
                              'WITHOUT FUNCTION'
         | 
| 670 902 | 
             
                            end
         | 
| 903 | 
            +
                  output << 'AS IMPLICIT' if (node['context']).zero?
         | 
| 904 | 
            +
                  output << 'AS ASSIGNMENT' if node['context'] == 1
         | 
| 905 | 
            +
                  output.join(' ')
         | 
| 906 | 
            +
                end
         | 
| 907 | 
            +
             | 
| 908 | 
            +
                def deparse_create_domain(node)
         | 
| 909 | 
            +
                  output = []
         | 
| 910 | 
            +
                  output << 'CREATE'
         | 
| 911 | 
            +
                  output << 'DOMAIN'
         | 
| 912 | 
            +
                  output << deparse_item_list(node['domainname']).join('.')
         | 
| 913 | 
            +
                  output << 'AS'
         | 
| 914 | 
            +
                  output << deparse_item(node['typeName']) if node['typeName']
         | 
| 915 | 
            +
                  output << deparse_item(node['collClause']) if node['collClause']
         | 
| 916 | 
            +
                  output << deparse_item_list(node['constraints'])
         | 
| 671 917 | 
             
                  output.join(' ')
         | 
| 672 918 | 
             
                end
         | 
| 673 919 |  | 
| @@ -677,7 +923,7 @@ class PgQuery | |
| 677 923 | 
             
                  output << 'OR REPLACE' if node['replace']
         | 
| 678 924 | 
             
                  output << 'FUNCTION'
         | 
| 679 925 |  | 
| 680 | 
            -
                  arguments = deparse_item_list(node | 
| 926 | 
            +
                  arguments = deparse_item_list(node.fetch('parameters', [])).join(', ')
         | 
| 681 927 |  | 
| 682 928 | 
             
                  output << deparse_item_list(node['funcname']).join('.') + '(' + arguments + ')'
         | 
| 683 929 |  | 
| @@ -688,6 +934,30 @@ class PgQuery | |
| 688 934 | 
             
                  output.join(' ')
         | 
| 689 935 | 
             
                end
         | 
| 690 936 |  | 
| 937 | 
            +
                def deparse_create_range(node)
         | 
| 938 | 
            +
                  output = ['CREATE TYPE']
         | 
| 939 | 
            +
                  output << deparse_item(node['typeName'][0])
         | 
| 940 | 
            +
                  output << 'AS RANGE'
         | 
| 941 | 
            +
                  params = node['params'].map do |param|
         | 
| 942 | 
            +
                    param_out = [param['DefElem']['defname']]
         | 
| 943 | 
            +
                    if param['DefElem'].key?('arg')
         | 
| 944 | 
            +
                      param_out << deparse_item(param['DefElem']['arg'])
         | 
| 945 | 
            +
                    end
         | 
| 946 | 
            +
                    param_out.join('=')
         | 
| 947 | 
            +
                  end
         | 
| 948 | 
            +
                  output << "(#{params.join(', ')})"
         | 
| 949 | 
            +
                  output.join(' ')
         | 
| 950 | 
            +
                end
         | 
| 951 | 
            +
             | 
| 952 | 
            +
                def deparse_create_schema(node)
         | 
| 953 | 
            +
                  output = ['CREATE SCHEMA']
         | 
| 954 | 
            +
                  output << 'IF NOT EXISTS' if node['if_not_exists']
         | 
| 955 | 
            +
                  output << deparse_identifier(node['schemaname']) if node.key?('schemaname')
         | 
| 956 | 
            +
                  output << format('AUTHORIZATION %s', deparse_item(node['authrole'])) if node.key?('authrole')
         | 
| 957 | 
            +
                  output << deparse_item_list(node['schemaElts']) if node.key?('schemaElts')
         | 
| 958 | 
            +
                  output.join(' ')
         | 
| 959 | 
            +
                end
         | 
| 960 | 
            +
             | 
| 691 961 | 
             
                def deparse_create_table(node)
         | 
| 692 962 | 
             
                  output = []
         | 
| 693 963 | 
             
                  output << 'CREATE'
         | 
| @@ -724,6 +994,13 @@ class PgQuery | |
| 724 994 | 
             
                  output.join(' ')
         | 
| 725 995 | 
             
                end
         | 
| 726 996 |  | 
| 997 | 
            +
                def deparse_execute(node)
         | 
| 998 | 
            +
                  output = ['EXECUTE']
         | 
| 999 | 
            +
                  output << deparse_identifier(node['name'])
         | 
| 1000 | 
            +
                  output << "(#{deparse_item_list(node['params']).join(', ')})" if node['params']
         | 
| 1001 | 
            +
                  output.join(' ')
         | 
| 1002 | 
            +
                end
         | 
| 1003 | 
            +
             | 
| 727 1004 | 
             
                def deparse_into_clause(node)
         | 
| 728 1005 | 
             
                  deparse_item(node['rel'])
         | 
| 729 1006 | 
             
                end
         | 
| @@ -739,6 +1016,8 @@ class PgQuery | |
| 739 1016 | 
             
                def deparse_sublink(node)
         | 
| 740 1017 | 
             
                  if node['subLinkType'] == SUBLINK_TYPE_ANY
         | 
| 741 1018 | 
             
                    format('%s IN (%s)', deparse_item(node['testexpr']), deparse_item(node['subselect']))
         | 
| 1019 | 
            +
                  elsif node['subLinkType'] == SUBLINK_TYPE_ALL
         | 
| 1020 | 
            +
                    format('%s %s ALL (%s)', deparse_item(node['testexpr']), deparse_item(node['operName'][0], :operator), deparse_item(node['subselect']))
         | 
| 742 1021 | 
             
                  elsif node['subLinkType'] == SUBLINK_TYPE_EXISTS
         | 
| 743 1022 | 
             
                    format('EXISTS(%s)', deparse_item(node['subselect']))
         | 
| 744 1023 | 
             
                  else
         | 
| @@ -762,15 +1041,22 @@ class PgQuery | |
| 762 1041 | 
             
                def deparse_select(node) # rubocop:disable Metrics/CyclomaticComplexity
         | 
| 763 1042 | 
             
                  output = []
         | 
| 764 1043 |  | 
| 1044 | 
            +
                  output << deparse_item(node['withClause']) if node['withClause']
         | 
| 1045 | 
            +
             | 
| 765 1046 | 
             
                  if node['op'] == 1
         | 
| 766 1047 | 
             
                    output << deparse_item(node['larg'])
         | 
| 767 1048 | 
             
                    output << 'UNION'
         | 
| 768 1049 | 
             
                    output << 'ALL' if node['all']
         | 
| 769 1050 | 
             
                    output << deparse_item(node['rarg'])
         | 
| 770 | 
            -
                     | 
| 1051 | 
            +
                    output.join(' ')
         | 
| 771 1052 | 
             
                  end
         | 
| 772 1053 |  | 
| 773 | 
            -
                   | 
| 1054 | 
            +
                  if node['op'] == 3
         | 
| 1055 | 
            +
                    output << deparse_item(node['larg'])
         | 
| 1056 | 
            +
                    output << 'EXCEPT'
         | 
| 1057 | 
            +
                    output << deparse_item(node['rarg'])
         | 
| 1058 | 
            +
                    output.join(' ')
         | 
| 1059 | 
            +
                  end
         | 
| 774 1060 |  | 
| 775 1061 | 
             
                  if node[TARGET_LIST_FIELD]
         | 
| 776 1062 | 
             
                    output << 'SELECT'
         | 
| @@ -784,6 +1070,11 @@ class PgQuery | |
| 784 1070 | 
             
                    output << node[TARGET_LIST_FIELD].map do |item|
         | 
| 785 1071 | 
             
                      deparse_item(item, :select)
         | 
| 786 1072 | 
             
                    end.join(', ')
         | 
| 1073 | 
            +
             | 
| 1074 | 
            +
                    if node['intoClause']
         | 
| 1075 | 
            +
                      output << 'INTO'
         | 
| 1076 | 
            +
                      output << deparse_item(node['intoClause'])
         | 
| 1077 | 
            +
                    end
         | 
| 787 1078 | 
             
                  end
         | 
| 788 1079 |  | 
| 789 1080 | 
             
                  if node[FROM_CLAUSE_FIELD]
         | 
| @@ -882,6 +1173,13 @@ class PgQuery | |
| 882 1173 |  | 
| 883 1174 | 
             
                  output << deparse_item(node['selectStmt'])
         | 
| 884 1175 |  | 
| 1176 | 
            +
                  if node['returningList']
         | 
| 1177 | 
            +
                    output << 'RETURNING'
         | 
| 1178 | 
            +
                    output << node['returningList'].map do |column|
         | 
| 1179 | 
            +
                      deparse_item(column, :select)
         | 
| 1180 | 
            +
                    end.join(', ')
         | 
| 1181 | 
            +
                  end
         | 
| 1182 | 
            +
             | 
| 885 1183 | 
             
                  output.join(' ')
         | 
| 886 1184 | 
             
                end
         | 
| 887 1185 |  | 
| @@ -920,7 +1218,8 @@ class PgQuery | |
| 920 1218 | 
             
                  if deparse_item(node['typeName']) == 'boolean'
         | 
| 921 1219 | 
             
                    deparse_item(node['arg']) == "'t'" ? 'true' : 'false'
         | 
| 922 1220 | 
             
                  else
         | 
| 923 | 
            -
                     | 
| 1221 | 
            +
                    context = true if node['arg']['A_Expr']
         | 
| 1222 | 
            +
                    deparse_item(node['arg'], context) + '::' + deparse_typename(node['typeName'][TYPE_NAME])
         | 
| 924 1223 | 
             
                  end
         | 
| 925 1224 | 
             
                end
         | 
| 926 1225 |  | 
| @@ -950,7 +1249,7 @@ class PgQuery | |
| 950 1249 | 
             
                  # Just pass along any custom types.
         | 
| 951 1250 | 
             
                  # (The pg_catalog types are built-in Postgres system types and are
         | 
| 952 1251 | 
             
                  #  handled in the case statement below)
         | 
| 953 | 
            -
                  return names.join('.') if catalog != 'pg_catalog'
         | 
| 1252 | 
            +
                  return names.join('.') + (arguments.nil? ? '' : "(#{arguments})") if catalog != 'pg_catalog'
         | 
| 954 1253 |  | 
| 955 1254 | 
             
                  case type
         | 
| 956 1255 | 
             
                  when 'bpchar'
         | 
| @@ -972,7 +1271,7 @@ class PgQuery | |
| 972 1271 | 
             
                  when 'real', 'float4'
         | 
| 973 1272 | 
             
                    'real'
         | 
| 974 1273 | 
             
                  when 'float8'
         | 
| 975 | 
            -
                    'double'
         | 
| 1274 | 
            +
                    'double precision'
         | 
| 976 1275 | 
             
                  when 'time'
         | 
| 977 1276 | 
             
                    'time'
         | 
| 978 1277 | 
             
                  when 'timetz'
         | 
| @@ -1055,6 +1354,57 @@ class PgQuery | |
| 1055 1354 | 
             
                  end
         | 
| 1056 1355 | 
             
                end
         | 
| 1057 1356 |  | 
| 1357 | 
            +
                def deparse_define_stmt(node)
         | 
| 1358 | 
            +
                  dispatch = {
         | 
| 1359 | 
            +
                    1 => :deparse_create_aggregate,
         | 
| 1360 | 
            +
                    25 => :deparse_create_operator,
         | 
| 1361 | 
            +
                    45 => :deparse_create_type
         | 
| 1362 | 
            +
                  }
         | 
| 1363 | 
            +
                  method(dispatch.fetch(node['kind'])).call(node)
         | 
| 1364 | 
            +
                end
         | 
| 1365 | 
            +
             | 
| 1366 | 
            +
                def deparse_create_aggregate(node)
         | 
| 1367 | 
            +
                  output = ['CREATE AGGREGATE']
         | 
| 1368 | 
            +
                  output << node['defnames'].map(&method(:deparse_item))
         | 
| 1369 | 
            +
                  args = node['args'][0] || [{ A_STAR => nil }]
         | 
| 1370 | 
            +
                  output << "(#{args.map(&method(:deparse_item)).join(', ')})"
         | 
| 1371 | 
            +
                  definitions = node['definition'].map do |definition|
         | 
| 1372 | 
            +
                    definition_output = [definition['DefElem']['defname']]
         | 
| 1373 | 
            +
                    definition_output << definition['DefElem']['arg']['TypeName']['names'].map(&method(:deparse_item)).join(', ') if definition['DefElem'].key?('arg')
         | 
| 1374 | 
            +
                    definition_output.join('=')
         | 
| 1375 | 
            +
                  end
         | 
| 1376 | 
            +
                  output << "(#{definitions.join(', ')})"
         | 
| 1377 | 
            +
                  output.join(' ')
         | 
| 1378 | 
            +
                end
         | 
| 1379 | 
            +
             | 
| 1380 | 
            +
                def deparse_create_operator(node)
         | 
| 1381 | 
            +
                  output = ['CREATE OPERATOR']
         | 
| 1382 | 
            +
                  output << node['defnames'][0]['String']['str']
         | 
| 1383 | 
            +
                  definitions = node['definition'].map do |definition|
         | 
| 1384 | 
            +
                    definition_output = [definition['DefElem']['defname']]
         | 
| 1385 | 
            +
                    definition_output << definition['DefElem']['arg']['TypeName']['names'].map(&method(:deparse_item)).join(', ') if definition['DefElem'].key?('arg')
         | 
| 1386 | 
            +
                    definition_output.join('=')
         | 
| 1387 | 
            +
                  end
         | 
| 1388 | 
            +
                  output << "(#{definitions.join(', ')})"
         | 
| 1389 | 
            +
                  output.join(' ')
         | 
| 1390 | 
            +
                end
         | 
| 1391 | 
            +
             | 
| 1392 | 
            +
                def deparse_create_type(node)
         | 
| 1393 | 
            +
                  output = ['CREATE TYPE']
         | 
| 1394 | 
            +
                  output << node['defnames'].map(&method(:deparse_item))
         | 
| 1395 | 
            +
                  if node.key?('definition')
         | 
| 1396 | 
            +
                    definitions = node['definition'].map do |definition|
         | 
| 1397 | 
            +
                      definition_output = [definition['DefElem']['defname']]
         | 
| 1398 | 
            +
                      if definition['DefElem'].key?('arg')
         | 
| 1399 | 
            +
                        definition_output += definition['DefElem']['arg']['TypeName']['names'].map(&method(:deparse_item))
         | 
| 1400 | 
            +
                      end
         | 
| 1401 | 
            +
                      definition_output.join('=')
         | 
| 1402 | 
            +
                    end
         | 
| 1403 | 
            +
                    output << "(#{definitions.join(', ')})"
         | 
| 1404 | 
            +
                  end
         | 
| 1405 | 
            +
                  output.join(' ')
         | 
| 1406 | 
            +
                end
         | 
| 1407 | 
            +
             | 
| 1058 1408 | 
             
                def deparse_delete_from(node)
         | 
| 1059 1409 | 
             
                  output = []
         | 
| 1060 1410 | 
             
                  output << deparse_item(node['withClause']) if node['withClause']
         | 
| @@ -1085,13 +1435,25 @@ class PgQuery | |
| 1085 1435 | 
             
                  output.join(' ')
         | 
| 1086 1436 | 
             
                end
         | 
| 1087 1437 |  | 
| 1088 | 
            -
                def  | 
| 1438 | 
            +
                def deparse_discard(node)
         | 
| 1439 | 
            +
                  output = ['DISCARD']
         | 
| 1440 | 
            +
                  output << 'ALL' if (node['target']).zero?
         | 
| 1441 | 
            +
                  output << 'PLANS' if node['target'] == 1
         | 
| 1442 | 
            +
                  output << 'SEQUENCES' if node['target'] == 2
         | 
| 1443 | 
            +
                  output << 'TEMP' if node['target'] == 3
         | 
| 1444 | 
            +
                  output.join(' ')
         | 
| 1445 | 
            +
                end
         | 
| 1446 | 
            +
             | 
| 1447 | 
            +
                def deparse_drop(node) # rubocop:disable Metrics/CyclomaticComplexity
         | 
| 1089 1448 | 
             
                  output = ['DROP']
         | 
| 1090 1449 | 
             
                  output << 'TABLE' if node['removeType'] == OBJECT_TYPE_TABLE
         | 
| 1450 | 
            +
                  output << 'SCHEMA' if node['removeType'] == OBJECT_TYPE_SCHEMA
         | 
| 1091 1451 | 
             
                  output << 'CONCURRENTLY' if node['concurrent']
         | 
| 1092 1452 | 
             
                  output << 'IF EXISTS' if node['missing_ok']
         | 
| 1093 1453 |  | 
| 1094 | 
            -
                   | 
| 1454 | 
            +
                  objects = node['objects']
         | 
| 1455 | 
            +
                  objects = [objects] unless objects[0].is_a?(Array)
         | 
| 1456 | 
            +
                  output << objects.map { |list| list.map { |object| deparse_item(object) } }.join(', ')
         | 
| 1095 1457 |  | 
| 1096 1458 | 
             
                  output << 'CASCADE' if node['behavior'] == 1
         | 
| 1097 1459 |  |