ronin-sql 0.1.1 → 0.2.0

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.
Files changed (101) hide show
  1. data/History.txt +43 -0
  2. data/Manifest.txt +76 -23
  3. data/README.txt +31 -6
  4. data/Rakefile +2 -2
  5. data/lib/ronin/code/sql/{keyword.rb → add_column_clause.rb} +9 -13
  6. data/lib/ronin/code/sql/as.rb +47 -0
  7. data/lib/ronin/code/sql/asc.rb +38 -0
  8. data/lib/ronin/code/sql/between.rb +18 -12
  9. data/lib/ronin/code/sql/binary_expr.rb +12 -5
  10. data/lib/ronin/code/sql/clause.rb +37 -0
  11. data/lib/ronin/code/sql/code.rb +1 -1
  12. data/lib/ronin/code/sql/common_dialect.rb +16 -10
  13. data/lib/ronin/code/sql/create.rb +68 -0
  14. data/lib/ronin/code/sql/create_index.rb +9 -39
  15. data/lib/ronin/code/sql/create_table.rb +9 -56
  16. data/lib/ronin/code/sql/create_view.rb +7 -29
  17. data/lib/ronin/code/sql/default_values_clause.rb +38 -0
  18. data/lib/ronin/code/sql/delete.rb +10 -25
  19. data/lib/ronin/code/sql/desc.rb +38 -0
  20. data/lib/ronin/code/sql/dialect.rb +172 -52
  21. data/lib/ronin/code/sql/{builder.rb → drop.rb} +16 -20
  22. data/lib/ronin/code/sql/drop_index.rb +43 -0
  23. data/lib/ronin/code/sql/drop_table.rb +8 -16
  24. data/lib/ronin/code/sql/drop_view.rb +43 -0
  25. data/lib/ronin/code/sql/emittable.rb +102 -0
  26. data/lib/ronin/code/sql/exceptions/unknown_clause.rb +31 -0
  27. data/lib/ronin/code/sql/exceptions/unknown_dialect.rb +2 -2
  28. data/lib/ronin/code/sql/exceptions/unknown_statement.rb +31 -0
  29. data/lib/ronin/code/sql/exceptions.rb +3 -1
  30. data/lib/ronin/code/sql/expr.rb +7 -96
  31. data/lib/ronin/code/sql/field.rb +40 -23
  32. data/lib/ronin/code/sql/fields_clause.rb +48 -0
  33. data/lib/ronin/code/sql/from_clause.rb +44 -0
  34. data/lib/ronin/code/sql/function.rb +15 -12
  35. data/lib/ronin/code/sql/group_by_clause.rb +48 -0
  36. data/lib/ronin/code/sql/having_clause.rb +48 -0
  37. data/lib/ronin/code/sql/in.rb +9 -9
  38. data/lib/ronin/code/sql/injected_statement.rb +102 -0
  39. data/lib/ronin/code/sql/injection.rb +171 -5
  40. data/lib/ronin/code/sql/insert.rb +15 -45
  41. data/lib/ronin/code/sql/intersect_clause.rb +44 -0
  42. data/lib/ronin/code/sql/join_clause.rb +125 -0
  43. data/lib/ronin/code/sql/{like_expr.rb → like.rb} +19 -31
  44. data/lib/ronin/code/sql/limit_clause.rb +44 -0
  45. data/lib/ronin/code/sql/modifier.rb +50 -0
  46. data/lib/ronin/code/sql/offset_clause.rb +44 -0
  47. data/lib/ronin/code/sql/on_clause.rb +57 -0
  48. data/lib/ronin/code/sql/order_by_clause.rb +44 -0
  49. data/lib/ronin/code/sql/program.rb +170 -23
  50. data/lib/ronin/code/sql/rename_to_clause.rb +44 -0
  51. data/lib/ronin/code/sql/replace.rb +15 -17
  52. data/lib/ronin/code/sql/select.rb +46 -141
  53. data/lib/ronin/code/sql/set_clause.rb +44 -0
  54. data/lib/ronin/code/sql/statement.rb +117 -47
  55. data/lib/ronin/code/sql/token.rb +64 -0
  56. data/lib/ronin/code/sql/unary_expr.rb +9 -5
  57. data/lib/ronin/code/sql/union_all_clause.rb +44 -0
  58. data/lib/ronin/code/sql/union_clause.rb +44 -0
  59. data/lib/ronin/code/sql/update.rb +10 -31
  60. data/lib/ronin/code/sql/values_clause.rb +48 -0
  61. data/lib/ronin/code/sql/where_clause.rb +44 -0
  62. data/lib/ronin/code/sql.rb +1 -1
  63. data/lib/ronin/sql/error/error.rb +64 -0
  64. data/lib/ronin/sql/error/message.rb +64 -0
  65. data/lib/ronin/sql/error/pattern.rb +106 -0
  66. data/lib/ronin/sql/error/patterns.rb +100 -0
  67. data/lib/ronin/sql/error.rb +5 -30
  68. data/lib/ronin/sql/extensions/uri/http.rb +76 -21
  69. data/lib/ronin/sql/extensions/uri.rb +1 -1
  70. data/lib/ronin/sql/extensions.rb +2 -1
  71. data/lib/ronin/sql/injection.rb +213 -0
  72. data/lib/ronin/sql/version.rb +2 -2
  73. data/lib/ronin/sql.rb +7 -2
  74. data/spec/code/sql/create_examples.rb +19 -0
  75. data/spec/code/sql/create_index_spec.rb +25 -0
  76. data/spec/code/sql/create_table_spec.rb +27 -0
  77. data/spec/code/sql/create_view_spec.rb +16 -0
  78. data/spec/code/sql/delete_spec.rb +14 -0
  79. data/spec/code/sql/drop_examples.rb +10 -0
  80. data/spec/code/sql/drop_index_spec.rb +16 -0
  81. data/spec/code/sql/drop_table_spec.rb +16 -0
  82. data/spec/code/sql/drop_view_spec.rb +16 -0
  83. data/spec/code/sql/has_default_values_clause_examples.rb +10 -0
  84. data/spec/code/sql/has_fields_clause_examples.rb +15 -0
  85. data/spec/code/sql/has_from_clause_examples.rb +13 -0
  86. data/spec/code/sql/has_values_clause_examples.rb +15 -0
  87. data/spec/code/sql/has_where_clause_examples.rb +15 -0
  88. data/spec/code/sql/insert_spec.rb +21 -0
  89. data/spec/code/sql/replace_spec.rb +21 -0
  90. data/spec/code/sql/select_spec.rb +105 -0
  91. data/spec/code/sql/update_spec.rb +26 -0
  92. data/spec/helpers/code.rb +14 -0
  93. data/spec/sql/error_spec.rb +24 -0
  94. data/spec/sql/extensions/string_spec.rb +28 -0
  95. data/spec/sql_spec.rb +9 -0
  96. data/tasks/spec.rb +2 -0
  97. metadata +82 -29
  98. data/lib/ronin/code/sql/injection_builder.rb +0 -137
  99. data/lib/ronin/code/sql/injection_style.rb +0 -79
  100. data/lib/ronin/code/sql/style.rb +0 -170
  101. data/lib/ronin/sql/sql.rb +0 -83
@@ -3,7 +3,7 @@
3
3
  # Ronin SQL - A Ronin library providing support for SQL related security
4
4
  # tasks.
5
5
  #
6
- # Copyright (c) 2007-2008 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
7
  #
8
8
  # This program is free software; you can redistribute it and/or modify
9
9
  # it under the terms of the GNU General Public License as published by
@@ -21,55 +21,25 @@
21
21
  #++
22
22
  #
23
23
 
24
- require 'ronin/code/sql/statement'
24
+ require 'ronin/code/sql/create'
25
+ require 'ronin/code/sql/on_clause'
25
26
 
26
27
  module Ronin
27
28
  module Code
28
29
  module SQL
29
- class CreateIndex < Statement
30
+ class CreateIndex < Create
30
31
 
31
- option :unqiue, "UNIQUE"
32
- option :if_not_exists, "IF NOT EXISTS"
32
+ clause :on, OnClause
33
33
 
34
- def initialize(style,index=nil,table=nil,columns={},&block)
35
- @index = index
36
- @table = table
37
- @columns = columns
38
-
39
- super(style,&block)
40
- end
41
-
42
- def index(field)
43
- @index = field
44
- return self
45
- end
46
-
47
- def table(field)
48
- @table = field
49
- return self
34
+ def initialize(dialect,index=nil,options={},&block)
35
+ super(dialect,'INDEX',index,options,&block)
50
36
  end
51
37
 
52
- def column(name,type)
53
- @columns[name.to_s] = type.to_s
38
+ def index(name)
39
+ @name = name
54
40
  return self
55
41
  end
56
42
 
57
- def compile(dialect=nil,multiline=false)
58
- format_columns = lambda {
59
- @columns.map { |name,type|
60
- "#{name} #{type}"
61
- }
62
- }
63
-
64
- return compile_expr(keyword_create,unique?,keyword_index,if_not_exists?,@index,keyword_on,@table,compile_row(format_columns.call))
65
- end
66
-
67
- protected
68
-
69
- keyword :create
70
- keyword :index
71
- keyword :on
72
-
73
43
  end
74
44
  end
75
45
  end
@@ -3,7 +3,7 @@
3
3
  # Ronin SQL - A Ronin library providing support for SQL related security
4
4
  # tasks.
5
5
  #
6
- # Copyright (c) 2007-2008 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
7
  #
8
8
  # This program is free software; you can redistribute it and/or modify
9
9
  # it under the terms of the GNU General Public License as published by
@@ -21,72 +21,25 @@
21
21
  #++
22
22
  #
23
23
 
24
- require 'ronin/code/sql/statement'
25
- require 'ronin/code/sql/select'
24
+ require 'ronin/code/sql/create'
25
+ require 'ronin/code/sql/fields_clause'
26
26
 
27
27
  module Ronin
28
28
  module Code
29
29
  module SQL
30
- class CreateTable < Statement
30
+ class CreateTable < Create
31
31
 
32
- option :temp, "TEMP"
33
- option :if_not_exists, "IF NOT EXISTS"
32
+ clause :columns, FieldsClause
34
33
 
35
- def initialize(style,table=nil,opts={:columns => {}, :not_null => {}, :as => nil},&block)
36
- @table = table
37
- @columns = opts[:columns]
38
- @not_null = opts[:not_null]
39
- @as = opts[:as]
40
-
41
- super(style,&block)
34
+ def initialize(dialect,table=nil,options={},&block)
35
+ super(dialect,'TABLE',table,options,&block)
42
36
  end
43
37
 
44
- def table(field)
45
- @table = field
38
+ def table(name)
39
+ @name = name
46
40
  return self
47
41
  end
48
42
 
49
- def as(table=nil,opts={:fields => nil, :where => nil},&block)
50
- @as = Select.new(@style,table,opts,&block)
51
- return self
52
- end
53
-
54
- def column(name,type,null=false)
55
- name = name.to_s
56
- @columns[name] = type.to_s
57
- @not_null[name] = null
58
- return self
59
- end
60
-
61
- def primary_key(field)
62
- @primary_key = field
63
- return self
64
- end
65
-
66
- def compile
67
- format_columns = lambda {
68
- @columns.map { |name,type|
69
- if @not_null[name]
70
- "#{name} #{type} NOT NULL"
71
- else
72
- "#{name} #{type}"
73
- end
74
- }
75
- }
76
-
77
- return compile_expr(keyword_create,temp?,keyword_table,if_not_exists?,@table,compile_row(format_columns.call))
78
- end
79
-
80
- protected
81
-
82
- keyword :create
83
- keyword :table
84
- keyword :primary_key
85
-
86
- def primary_key?
87
- compile_expr(keyword_primary_key,@primary_key) if @primary_key
88
- end
89
-
90
43
  end
91
44
  end
92
45
  end
@@ -3,7 +3,7 @@
3
3
  # Ronin SQL - A Ronin library providing support for SQL related security
4
4
  # tasks.
5
5
  #
6
- # Copyright (c) 2007-2008 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
7
  #
8
8
  # This program is free software; you can redistribute it and/or modify
9
9
  # it under the terms of the GNU General Public License as published by
@@ -21,44 +21,22 @@
21
21
  #++
22
22
  #
23
23
 
24
- require 'ronin/code/sql/statement'
25
- require 'ronin/code/sql/select'
24
+ require 'ronin/code/sql/create'
26
25
 
27
26
  module Ronin
28
27
  module Code
29
28
  module SQL
30
- class CreateView < Statement
29
+ class CreateView < Create
31
30
 
32
- option :temp, "TEMP"
33
- option :if_not_exists, "IF NOT EXISTS"
34
-
35
- def initialize(style,view=nil,query=nil,&block)
36
- @view = view
37
- @query = query
38
-
39
- super(style,&block)
40
- end
41
-
42
- def view(field)
43
- @view = field
44
- return self
31
+ def initialize(dialect,view=nil,options={},&block)
32
+ super(dialect,'VIEW',view,options,&block)
45
33
  end
46
34
 
47
- def query(table=nil,opts={:fields => nil, :where => nil},&block)
48
- @query = Select.new(@style,table,opts,&block)
35
+ def view(name)
36
+ @name = name
49
37
  return self
50
38
  end
51
39
 
52
- def compile
53
- compile_expr(keyword_create,temp?,keyword_view,if_not_exists?,@view,keyword_as,@query)
54
- end
55
-
56
- protected
57
-
58
- keyword :create
59
- keyword :view
60
- keyword :as
61
-
62
40
  end
63
41
  end
64
42
  end
@@ -0,0 +1,38 @@
1
+ #
2
+ #--
3
+ # Ronin SQL - A Ronin library providing support for SQL related security
4
+ # tasks.
5
+ #
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation; either version 2 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ #++
22
+ #
23
+
24
+ require 'ronin/code/sql/default_values_clause'
25
+
26
+ module Ronin
27
+ module Code
28
+ module SQL
29
+ class DefaultValuesClause < Clause
30
+
31
+ def emit
32
+ emit_token('DEFAULT VALUES')
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+ end
@@ -3,7 +3,7 @@
3
3
  # Ronin SQL - A Ronin library providing support for SQL related security
4
4
  # tasks.
5
5
  #
6
- # Copyright (c) 2007-2008 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
7
  #
8
8
  # This program is free software; you can redistribute it and/or modify
9
9
  # it under the terms of the GNU General Public License as published by
@@ -22,40 +22,25 @@
22
22
  #
23
23
 
24
24
  require 'ronin/code/sql/statement'
25
+ require 'ronin/code/sql/from_clause'
26
+ require 'ronin/code/sql/where_clause'
25
27
 
26
28
  module Ronin
27
29
  module Code
28
30
  module SQL
29
31
  class Delete < Statement
30
32
 
31
- def initialize(style,table=nil,where_expr=nil,&block)
32
- @table = table || everything
33
- @where = where_expr
33
+ clause :from, FromClause
34
+ clause :where, WhereClause
34
35
 
35
- super(style,&block)
36
- end
37
-
38
- def from(table)
39
- @table = table
40
- return self
41
- end
36
+ def initialize(dialect,options={},&block)
37
+ @table = options[:table]
42
38
 
43
- def where(expr)
44
- @where = expr
45
- return self
39
+ super(dialect,options,&block)
46
40
  end
47
41
 
48
- def compile
49
- compile_expr(keyword_delete,@table,where?)
50
- end
51
-
52
- protected
53
-
54
- keyword :delete, 'DELETE FROM'
55
- keyword :where
56
-
57
- def where?
58
- compile_expr(keyword_where,@where) if @where
42
+ def emit
43
+ emit_token('DELETE FROM') + emit_value(@table)
59
44
  end
60
45
 
61
46
  end
@@ -0,0 +1,38 @@
1
+ #
2
+ #--
3
+ # Ronin SQL - A Ronin library providing support for SQL related security
4
+ # tasks.
5
+ #
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern.mod3 at gmail.com)
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation; either version 2 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ #++
22
+ #
23
+
24
+ require 'ronin/code/sql/modifier'
25
+
26
+ module Ronin
27
+ module Code
28
+ module SQL
29
+ class Asc < Modifier
30
+
31
+ def initialize(expr)
32
+ super(expr,'DESC')
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+ end
@@ -3,7 +3,7 @@
3
3
  # Ronin SQL - A Ronin library providing support for SQL related security
4
4
  # tasks.
5
5
  #
6
- # Copyright (c) 2007 Hal Brodigan (postmodern at users.sourceforge.net)
6
+ # Copyright (c) 2007-2009 Hal Brodigan (postmodern at users.sourceforge.net)
7
7
  #
8
8
  # This program is free software; you can redistribute it and/or modify
9
9
  # it under the terms of the GNU General Public License as published by
@@ -22,7 +22,10 @@
22
22
  #
23
23
 
24
24
  require 'ronin/code/sql/exceptions/unknown_dialect'
25
+ require 'ronin/code/sql/exceptions/unknown_statement'
26
+ require 'ronin/code/sql/exceptions/unknown_clause'
25
27
  require 'ronin/code/sql/function'
28
+ require 'ronin/code/symbol_table'
26
29
  require 'ronin/extensions/meta'
27
30
 
28
31
  module Ronin
@@ -30,130 +33,247 @@ module Ronin
30
33
  module SQL
31
34
  class Dialect
32
35
 
33
- # The style to use
34
- attr_reader :style
36
+ # Symbol Table for the dialect
37
+ attr_reader :symbols
35
38
 
36
- def initialize(style)
37
- @style = style
39
+ # Statements used within the dialect
40
+ attr_reader :statements
41
+
42
+ #
43
+ # Creates a new Dialect object connected to the specified
44
+ # _program_.
45
+ #
46
+ def initialize(symbols={})
47
+ @symbols = SymbolTable.new(symbols)
48
+ @statements = []
38
49
  end
39
50
 
51
+ #
52
+ # Returns the Hash of defined SQL dialects.
53
+ #
40
54
  def Dialect.dialects
41
55
  @@dialects ||= {}
42
56
  end
43
57
 
58
+ #
59
+ # Returns +true+ if there is a SQL Dialect defined with the
60
+ # specified _name_, returns +false+ otherwise.
61
+ #
44
62
  def Dialect.has_dialect?(name)
45
63
  Dialect.dialects.has_key?(name.to_sym)
46
64
  end
47
65
 
48
- def Dialect.get_dialect(name)
66
+ #
67
+ # Returns the SQL Dialect defined with the specified _name_. If no
68
+ # such SQL Dialect exists, an UnknownDialect exception will be
69
+ # raised.
70
+ #
71
+ def Dialect.get(name)
49
72
  name = name.to_sym
50
73
 
51
74
  unless Dialect.has_dialect?(name)
52
- raise(UnknownDialect,"unknown dialect #{name.dump}",caller)
75
+ raise(UnknownDialect,"unknown dialect #{name}",caller)
53
76
  end
54
77
 
55
78
  return Dialect.dialects[name]
56
79
  end
57
80
 
58
- def expresses?(name)
59
- public_methods.include?(name.to_s)
81
+ #
82
+ # Returns the Hash of defined Statements within the Dialect.
83
+ #
84
+ def self.statements
85
+ @@statements ||= {}
86
+ end
87
+
88
+ def self.has_statement?(name)
89
+ self.statements.has_key?(name.to_sym)
60
90
  end
61
91
 
62
- def express(name,*args,&block)
63
- unless expresses?(name)
64
- raise(NameError,"undefined method '#{name}' for #{self}",caller)
92
+ def self.clauses
93
+ all_clauses = {}
94
+
95
+ self.statements.each do |stmt|
96
+ all_clauses.merge!(stmt.clauses)
65
97
  end
66
98
 
67
- return send(name,*args,&block)
99
+ return all_clauses
68
100
  end
69
101
 
70
- def field(name)
71
- field_cache[name.to_sym]
102
+ def self.has_clause?(name)
103
+ self.statements.each_value do |stmt|
104
+ return true if stmt.has_clause?(name)
105
+ end
106
+
107
+ return false
72
108
  end
73
109
 
74
- protected
110
+ def has_statement?(name)
111
+ self.class.has_statement?(name)
112
+ end
75
113
 
76
- def self.dialect(name)
114
+ def statement(name,*arguments,&block)
115
+ name = name.to_sym
116
+
117
+ unless has_statement?(name)
118
+ raise(UnknownStatement,"unknown statement #{name} in #{dialect} dialect",caller)
119
+ end
120
+
121
+ return self.class.statements[name].new(self,*arguments,&block)
122
+ end
123
+
124
+ def enqueue_statement(name,*arguments,&block)
125
+ stmt = statement(name,*arguments,&block)
126
+
127
+ @statements << stmt
128
+ return stmt
129
+ end
130
+
131
+ def has_clause?(name)
132
+ self.class.has_clause?(name)
133
+ end
134
+
135
+ def clause(name,*arguments)
77
136
  name = name.to_sym
78
137
 
79
- class_def(:name) { name }
138
+ self.class.statements.each do |stmt|
139
+ if stmt.has_cluase?(name)
140
+ return stmt.clauses[name].new(*arguments)
141
+ end
142
+ end
143
+
144
+ raise(UnknownClause,"unknown clause #{name}",caller)
145
+ end
146
+
147
+ def symbol(name)
148
+ sym = @symbols.symbol(name)
149
+ sym.value ||= name
150
+
151
+ return sym
152
+ end
153
+
154
+ def field(name)
155
+ sym = @symbols.symbol(name)
156
+ sym.value ||= Field.new(@symbols,name)
157
+
158
+ return sym
159
+ end
160
+
161
+ def all
162
+ Token.new('*')
163
+ end
164
+
165
+ def id
166
+ field('id')
167
+ end
168
+
169
+ def each_token(&block)
170
+ @statements.each do |stmt|
171
+ stmt.emit.each(&block)
172
+
173
+ block.call(Token.separator)
174
+ end
80
175
 
81
- Dialect.dialects[name] = self
82
176
  return self
83
177
  end
84
178
 
85
- def self.keyword(name,value=name.to_s.upcase)
86
- name = name.to_s.downcase
179
+ protected
180
+
181
+ #
182
+ # Defines a SQL Dialect with the specified _name_.
183
+ #
184
+ def self.dialect(name)
185
+ name = name.to_sym
186
+
187
+ class_def(:dialect) { name }
87
188
 
88
- class_def("keyword_#{name}") { keyword(value) }
189
+ Dialect.dialects[name.to_sym] = self
89
190
  return self
90
191
  end
91
192
 
193
+ #
194
+ # Defines various SQL primitives with the specified _names_.
195
+ #
92
196
  def self.primitives(*names)
93
197
  names.each do |name|
94
198
  name = name.to_s.downcase
95
199
 
96
- class_def(name) { keyword(name) }
200
+ class_def(name) { Token.new(name) }
97
201
  end
98
202
 
99
203
  return self
100
204
  end
101
205
 
206
+ #
207
+ # Defines a SQL data-type with the specified _name_ and given
208
+ # _options_.
209
+ #
102
210
  def self.data_type(name,options={})
103
211
  name = name.to_s.downcase
104
- type_name = name.upcase.to_sym
105
-
106
- if options[:length]==true
107
- class_def(name) do |length|
108
- if length
109
- "#{type_name}(#{length})"
110
- else
111
- type_name
112
- end
212
+ type_name = name.upcase
213
+ supports_length = options[:length]
214
+
215
+ class_def(name) do |length|
216
+ if (supports_length && length)
217
+ Token.new("#{type_name}(#{length})")
218
+ else
219
+ Token.new(type_name)
113
220
  end
114
- else
115
- class_def(name) { type_name }
116
221
  end
117
222
 
118
223
  return self
119
224
  end
120
225
 
121
- def self.function(*names)
226
+ #
227
+ # Defines various SQL function with the specified _names_.
228
+ #
229
+ def self.functions(*names)
122
230
  names.each do |name|
123
- class_def(name) do |field|
124
- Function.new(@style,name,field)
231
+ class_def(name) do |*fields|
232
+ Function.new(name,*fields)
125
233
  end
126
234
  end
127
235
 
128
236
  return self
129
237
  end
130
238
 
239
+ #
240
+ # Defines various SQL aggregate functions with the specified
241
+ # _names_.
242
+ #
131
243
  def self.aggregators(*names)
132
- function(*names)
244
+ names.each do |name|
245
+ class_def(name) do |field|
246
+ Function.new(name,field)
247
+ end
248
+ end
249
+
250
+ return self
133
251
  end
134
252
 
135
- def self.command(name,base)
253
+ #
254
+ # Defines an SQL statement with the specified _name_ and _base_
255
+ # class.
256
+ #
257
+ def self.statement(name,base)
258
+ name = name.to_sym
259
+
260
+ self.statements[name] = base
261
+
136
262
  class_eval %{
137
- def #{name}(*args,&block)
138
- #{base}.new(@style,*args,&block)
263
+ def #{name}(*arguments,&block)
264
+ enqueue_statement(:#{name},*arguments,&block)
139
265
  end
140
266
  }
141
267
 
142
268
  return self
143
269
  end
144
270
 
145
- def keyword(value)
146
- keyword_cache[value.to_sym]
147
- end
148
-
149
- private
150
-
151
- def keyword_cache
152
- @keyword_cache ||= Hash.new { |hash,key| hash[key] = Keyword.new(@style,key) }
153
- end
271
+ def method_missing(name,*arguments,&block)
272
+ if (arguments.empty? && block.nil?)
273
+ return field(name)
274
+ end
154
275
 
155
- def field_cache
156
- @field_cache ||= Hash.new { |hash,key| hash[key] = Field.new(@style,key) }
276
+ raise(NoMethodError,name.id2name)
157
277
  end
158
278
 
159
279
  end