knjrbfw 0.0.110 → 0.0.111
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/Gemfile +1 -1
- data/Gemfile.lock +2 -2
- data/VERSION +1 -1
- data/knjrbfw.gemspec +8 -36
- data/lib/knj/autoload.rb +1 -2
- data/lib/knj/gtk2_window.rb +7 -7
- data/lib/knj/unix_proc.rb +35 -35
- metadata +33 -62
- data/lib/knj/db.rb +0 -1
- data/lib/knj/knjdb/dbtime.rb +0 -35
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql.rb +0 -604
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_columns.rb +0 -155
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_indexes.rb +0 -69
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_sqlspecs.rb +0 -5
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_tables.rb +0 -443
- data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3.rb +0 -184
- data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3_columns.rb +0 -177
- data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3_indexes.rb +0 -29
- data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3_sqlspecs.rb +0 -5
- data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3_tables.rb +0 -449
- data/lib/knj/knjdb/dump.rb +0 -122
- data/lib/knj/knjdb/idquery.rb +0 -109
- data/lib/knj/knjdb/libknjdb.rb +0 -797
- data/lib/knj/knjdb/libknjdb_java_sqlite3.rb +0 -83
- data/lib/knj/knjdb/libknjdb_row.rb +0 -153
- data/lib/knj/knjdb/libknjdb_sqlite3_ironruby.rb +0 -69
- data/lib/knj/knjdb/query_buffer.rb +0 -87
- data/lib/knj/knjdb/revision.rb +0 -342
- data/lib/knj/knjdb/sqlspecs.rb +0 -5
- data/lib/knj/objects.rb +0 -957
- data/lib/knj/process.rb +0 -480
- data/lib/knj/process_meta.rb +0 -569
- data/spec/db_spec.rb +0 -282
- data/spec/db_spec_encoding_test_file.txt +0 -1
- data/spec/objects_spec.rb +0 -394
- data/spec/process_meta_spec.rb +0 -172
- data/spec/process_spec.rb +0 -115
data/lib/knj/knjdb/dump.rb
DELETED
@@ -1,122 +0,0 @@
|
|
1
|
-
#This class can be used to make SQL-dumps of databases, tables or however you want it.
|
2
|
-
class Knj::Db::Dump
|
3
|
-
#Constructor.
|
4
|
-
#===Examples
|
5
|
-
# dump = Knj::Db::Dump.new(:db => db)
|
6
|
-
def initialize(args)
|
7
|
-
@args = args
|
8
|
-
@debug = @args[:debug]
|
9
|
-
end
|
10
|
-
|
11
|
-
#Method used to update the status.
|
12
|
-
def update_status
|
13
|
-
return nil if !@on_status
|
14
|
-
rows_count = Knj::Locales.number_out(@rows_count, 0)
|
15
|
-
rows_count_total = Knj::Locales.number_out(@rows_count_total, 0)
|
16
|
-
percent = (@rows_count.to_f / @rows_count_total.to_f) * 100
|
17
|
-
percent_text = Knj::Locales.number_out(percent, 1)
|
18
|
-
@on_status.call(:text => "Dumping table: '#{@table_obj.name}' (#{rows_count}/#{rows_count_total} - #{percent_text}%).")
|
19
|
-
end
|
20
|
-
|
21
|
-
#Dumps all tables into the given IO.
|
22
|
-
def dump(io)
|
23
|
-
print "Going through tables.\n" if @debug
|
24
|
-
@rows_count = 0
|
25
|
-
|
26
|
-
if @args[:tables]
|
27
|
-
tables = @args[:tables]
|
28
|
-
else
|
29
|
-
tables = @args[:db].tables.list.values
|
30
|
-
end
|
31
|
-
|
32
|
-
if @on_status
|
33
|
-
@on_status.call(:text => "Preparing.")
|
34
|
-
|
35
|
-
@rows_count_total = 0
|
36
|
-
tables.each do |table_obj|
|
37
|
-
@rows_count_total += table_obj.rows_count
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
tables.each do |table_obj|
|
42
|
-
table_obj = @args[:db].tables[table_obj] if table_obj.is_a?(String) or table_obj.is_a?(Symbol)
|
43
|
-
next if table_obj.native?
|
44
|
-
|
45
|
-
#Figure out keys.
|
46
|
-
@keys = []
|
47
|
-
table_obj.columns do |col|
|
48
|
-
@keys << col.name
|
49
|
-
end
|
50
|
-
|
51
|
-
@table_obj = table_obj
|
52
|
-
self.update_status
|
53
|
-
print "Dumping table: '#{table_obj.name}'.\n" if @debug
|
54
|
-
self.dump_table(io, table_obj)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
#A block can be executed when a new status occurs.
|
59
|
-
def on_status(&block)
|
60
|
-
@on_status = block
|
61
|
-
end
|
62
|
-
|
63
|
-
#Dumps the given table into the given IO.
|
64
|
-
def dump_table(io, table_obj)
|
65
|
-
#Get SQL for creating table and add it to IO.
|
66
|
-
sqls = @args[:db].tables.create(table_obj.name, table_obj.data, :return_sql => true)
|
67
|
-
sqls.each do |sql|
|
68
|
-
io.write("#{sql};\n")
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
#Try to find a primary column in the table.
|
73
|
-
prim_col = nil
|
74
|
-
table_obj.columns do |col|
|
75
|
-
if col.primarykey?
|
76
|
-
prim_col = col
|
77
|
-
break
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
|
82
|
-
#Set up rows and way to fill rows.
|
83
|
-
rows = []
|
84
|
-
block_data = proc do |row|
|
85
|
-
rows << row
|
86
|
-
@rows_count += 1
|
87
|
-
|
88
|
-
if rows.length >= 1000
|
89
|
-
self.update_status
|
90
|
-
self.dump_insert_multi(io, table_obj, rows)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
|
-
#If a primary column is found then use IDQuery. Otherwise use cloned unbuffered query.
|
96
|
-
args = {:idquery => prim_col.name.to_sym} if prim_col
|
97
|
-
|
98
|
-
|
99
|
-
#Clone the connecting with array-results and execute query.
|
100
|
-
@args[:db].clone_conn(:result => "array") do |db|
|
101
|
-
db.select(table_obj.name, nil, args, &block_data)
|
102
|
-
end
|
103
|
-
|
104
|
-
|
105
|
-
#Dump the last rows if any.
|
106
|
-
self.dump_insert_multi(io, table_obj, rows) if !rows.empty?
|
107
|
-
end
|
108
|
-
|
109
|
-
#Dumps the given rows from the given table into the given IO.
|
110
|
-
def dump_insert_multi(io, table_obj, rows)
|
111
|
-
print "Inserting #{rows.length} into #{table_obj.name}.\n" if @debug
|
112
|
-
sqls = @args[:db].insert_multi(table_obj.name, rows, :return_sql => true, :keys => @keys)
|
113
|
-
sqls.each do |sql|
|
114
|
-
io.write("#{sql};\n")
|
115
|
-
end
|
116
|
-
|
117
|
-
rows.clear
|
118
|
-
|
119
|
-
#Ensure garbage collection or we might start using A LOT of memory.
|
120
|
-
GC.start
|
121
|
-
end
|
122
|
-
end
|
data/lib/knj/knjdb/idquery.rb
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
#This class takes a lot of IDs and runs a query against them.
|
2
|
-
class Knj::Db::Idquery
|
3
|
-
#An array containing all the IDs that will be looked up.
|
4
|
-
attr_reader :ids
|
5
|
-
|
6
|
-
#Constructor.
|
7
|
-
#===Examples
|
8
|
-
# idq = Knj::Db::Idquery(:db => db, :table => :users)
|
9
|
-
# idq.ids + [1, 5, 9]
|
10
|
-
# idq.each do |user|
|
11
|
-
# print "Name: #{user[:name]}\n"
|
12
|
-
# end
|
13
|
-
def initialize(args, &block)
|
14
|
-
@args = args
|
15
|
-
@ids = []
|
16
|
-
@debug = @args[:debug]
|
17
|
-
|
18
|
-
if @args[:query]
|
19
|
-
@args[:db].q(@args[:query]) do |data|
|
20
|
-
@args[:col] = data.keys.first if !@args[:col]
|
21
|
-
|
22
|
-
if data.is_a?(Array)
|
23
|
-
@ids << data.first
|
24
|
-
else
|
25
|
-
@ids << data[@args[:col]]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
@args[:col] = :id if !@args[:col]
|
31
|
-
@args[:size] = 200 if !@args[:size]
|
32
|
-
|
33
|
-
if block
|
34
|
-
raise "No query was given but a block was." if !@args[:query]
|
35
|
-
self.each(&block)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
#Fetches results.
|
40
|
-
#===Examples
|
41
|
-
# data = idq.fetch #=> Hash
|
42
|
-
def fetch
|
43
|
-
return nil if !@args
|
44
|
-
|
45
|
-
if @res
|
46
|
-
data = @res.fetch if @res
|
47
|
-
@res = nil if !data
|
48
|
-
return data if data
|
49
|
-
end
|
50
|
-
|
51
|
-
@res = new_res if !@res
|
52
|
-
if !@res
|
53
|
-
destroy
|
54
|
-
return nil
|
55
|
-
end
|
56
|
-
|
57
|
-
data = @res.fetch
|
58
|
-
if !data
|
59
|
-
destroy
|
60
|
-
return nil
|
61
|
-
end
|
62
|
-
|
63
|
-
return data
|
64
|
-
end
|
65
|
-
|
66
|
-
#Yields a block for every result.
|
67
|
-
#===Examples
|
68
|
-
# idq.each do |data|
|
69
|
-
# print "Name: #{data[:name]}\n"
|
70
|
-
# end
|
71
|
-
def each
|
72
|
-
while data = self.fetch
|
73
|
-
yield(data)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
|
-
#Spawns a new database-result to read from.
|
80
|
-
def new_res
|
81
|
-
table_esc = "`#{@args[:db].esc_table(@args[:table])}`"
|
82
|
-
col_esc = "`#{@args[:db].esc_col(@args[:col])}`"
|
83
|
-
ids = @ids.shift(@args[:size])
|
84
|
-
|
85
|
-
if ids.empty?
|
86
|
-
destroy
|
87
|
-
return nil
|
88
|
-
end
|
89
|
-
|
90
|
-
ids_sql = Knj::ArrayExt.join(
|
91
|
-
:arr => ids,
|
92
|
-
:callback => proc{|val| @args[:db].esc(val)},
|
93
|
-
:sep => ",",
|
94
|
-
:surr => "'"
|
95
|
-
)
|
96
|
-
|
97
|
-
query_str = "SELECT * FROM #{table_esc} WHERE #{table_esc}.#{col_esc} IN (#{ids_sql})"
|
98
|
-
print "Query: #{query_str}\n" if @debug
|
99
|
-
|
100
|
-
return @args[:db].q(query_str)
|
101
|
-
end
|
102
|
-
|
103
|
-
#Removes all variables on the object. This is done when no more results are available.
|
104
|
-
def destroy
|
105
|
-
@args = nil
|
106
|
-
@ids = nil
|
107
|
-
@debug = nil
|
108
|
-
end
|
109
|
-
end
|
data/lib/knj/knjdb/libknjdb.rb
DELETED
@@ -1,797 +0,0 @@
|
|
1
|
-
Knj.gem_require([:wref, :datet])
|
2
|
-
|
3
|
-
#A wrapper of several possible database-types.
|
4
|
-
#
|
5
|
-
#===Examples
|
6
|
-
# db = Knj::Db.new(:type => "mysql", :subtype => "mysql2", :db => "mysql", :user => "user", :pass => "password")
|
7
|
-
# mysql_table = db.tables['mysql']
|
8
|
-
# name = mysql_table.name
|
9
|
-
# cols = mysql_table.columns
|
10
|
-
#
|
11
|
-
# db = Knj::Db.new(:type => "sqlite3", :path => "some_db.sqlite3")
|
12
|
-
#
|
13
|
-
# db.q("SELECT * FROM users") do |data|
|
14
|
-
# print data[:name]
|
15
|
-
# end
|
16
|
-
class Knj::Db
|
17
|
-
#Autoloader for subclasses..
|
18
|
-
def self.const_missing(name)
|
19
|
-
require "#{$knjpath}knjdb/#{name.to_s.downcase}.rb"
|
20
|
-
raise "Still not defined: '#{name}'." if !Knj::Db.const_defined?(name)
|
21
|
-
return Knj::Db.const_get(name)
|
22
|
-
end
|
23
|
-
|
24
|
-
attr_reader :sep_col, :sep_table, :sep_val, :opts, :conn, :conns, :int_types
|
25
|
-
|
26
|
-
def initialize(opts)
|
27
|
-
require "#{$knjpath}threadhandler"
|
28
|
-
|
29
|
-
self.setOpts(opts) if opts != nil
|
30
|
-
|
31
|
-
@int_types = ["int", "bigint", "tinyint", "smallint", "mediumint"]
|
32
|
-
|
33
|
-
if !@opts[:threadsafe]
|
34
|
-
require "monitor"
|
35
|
-
@mutex = Monitor.new
|
36
|
-
end
|
37
|
-
|
38
|
-
@debug = @opts[:debug]
|
39
|
-
|
40
|
-
self.conn_exec do |driver|
|
41
|
-
@sep_table = driver.sep_table
|
42
|
-
@sep_col = driver.sep_col
|
43
|
-
@sep_val = driver.sep_val
|
44
|
-
@esc_driver = driver
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def args
|
49
|
-
return @opts
|
50
|
-
end
|
51
|
-
|
52
|
-
def setOpts(arr_opts)
|
53
|
-
@opts = {}
|
54
|
-
arr_opts.each do |key, val|
|
55
|
-
@opts[key.to_sym] = val
|
56
|
-
end
|
57
|
-
|
58
|
-
if RUBY_PLATFORM == "java"
|
59
|
-
@opts[:subtype] = "java"
|
60
|
-
elsif @opts[:type] == "sqlite3" and RUBY_PLATFORM.index("mswin32") != nil
|
61
|
-
@opts[:subtype] = "ironruby"
|
62
|
-
end
|
63
|
-
|
64
|
-
self.connect
|
65
|
-
end
|
66
|
-
|
67
|
-
#Actually connects to the database. This is useually done automatically.
|
68
|
-
def connect
|
69
|
-
if @opts[:threadsafe]
|
70
|
-
@conns = Knj::Threadhandler.new
|
71
|
-
|
72
|
-
@conns.on_spawn_new do
|
73
|
-
self.spawn
|
74
|
-
end
|
75
|
-
|
76
|
-
@conns.on_inactive do |data|
|
77
|
-
data[:obj].close
|
78
|
-
end
|
79
|
-
|
80
|
-
@conns.on_activate do |data|
|
81
|
-
data[:obj].reconnect
|
82
|
-
end
|
83
|
-
else
|
84
|
-
@conn = self.spawn
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
#Spawns a new driver (useally done automatically).
|
89
|
-
#===Examples
|
90
|
-
# driver_instance = db.spawn
|
91
|
-
def spawn
|
92
|
-
raise "No type given (#{@opts.keys.join(",")})." if !@opts[:type]
|
93
|
-
|
94
|
-
fpaths = [
|
95
|
-
"drivers/#{@opts[:type]}/knjdb_#{@opts[:type]}.rb",
|
96
|
-
"libknjdb_#{@opts[:type]}.rb"
|
97
|
-
]
|
98
|
-
fpaths.each do |fpath|
|
99
|
-
rpath = "#{File.dirname(__FILE__)}/#{fpath}"
|
100
|
-
|
101
|
-
if (!@opts.key?(:require) or @opts[:require]) and File.exists?(rpath)
|
102
|
-
require rpath
|
103
|
-
break
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
return Kernel.const_get("KnjDB_#{@opts[:type]}").new(self)
|
108
|
-
end
|
109
|
-
|
110
|
-
#Registers a driver to the current thread.
|
111
|
-
def get_and_register_thread
|
112
|
-
raise "KnjDB-object is not in threadding mode." if !@conns
|
113
|
-
|
114
|
-
thread_cur = Thread.current
|
115
|
-
tid = self.__id__
|
116
|
-
thread_cur[:knjdb] = {} if !thread_cur[:knjdb]
|
117
|
-
|
118
|
-
if thread_cur[:knjdb][tid]
|
119
|
-
#An object has already been spawned - free that first to avoid endless "used" objects.
|
120
|
-
self.free_thread
|
121
|
-
end
|
122
|
-
|
123
|
-
thread_cur[:knjdb][tid] = @conns.get_and_lock if !thread_cur[:knjdb][tid]
|
124
|
-
|
125
|
-
#If block given then be ensure to free thread after yielding.
|
126
|
-
if block_given?
|
127
|
-
begin
|
128
|
-
yield
|
129
|
-
ensure
|
130
|
-
self.free_thread
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
#Frees the current driver from the current thread.
|
136
|
-
def free_thread
|
137
|
-
thread_cur = Thread.current
|
138
|
-
tid = self.__id__
|
139
|
-
|
140
|
-
if thread_cur[:knjdb] and thread_cur[:knjdb].key?(tid)
|
141
|
-
db = thread_cur[:knjdb][tid]
|
142
|
-
thread_cur[:knjdb].delete(tid)
|
143
|
-
@conns.free(db) if @conns
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
#Clean up various memory-stuff if possible.
|
148
|
-
def clean
|
149
|
-
if @conns
|
150
|
-
@conns.objects.each do |data|
|
151
|
-
data[:object].clean if data[:object].respond_to?("clean")
|
152
|
-
end
|
153
|
-
elsif @conn
|
154
|
-
@conn.clean if @conn.respond_to?("clean")
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
#The all driver-database-connections.
|
159
|
-
def close
|
160
|
-
@conn.close if @conn
|
161
|
-
@conns.destroy if @conns
|
162
|
-
|
163
|
-
@conn = nil
|
164
|
-
@conns = nil
|
165
|
-
end
|
166
|
-
|
167
|
-
#Clones the current database-connection with possible extra arguments.
|
168
|
-
def clone_conn(args = {})
|
169
|
-
conn = Knj::Db.new(@opts.clone.merge(args))
|
170
|
-
|
171
|
-
if block_given?
|
172
|
-
begin
|
173
|
-
yield(conn)
|
174
|
-
ensure
|
175
|
-
conn.close
|
176
|
-
end
|
177
|
-
|
178
|
-
return nil
|
179
|
-
else
|
180
|
-
return conn
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
#Copies the content of the current database to another instance of Knj::Db.
|
185
|
-
def copy_to(db, args = {})
|
186
|
-
data["tables"].each do |table|
|
187
|
-
table_args = nil
|
188
|
-
table_args = args["tables"][table["name"].to_s] if args and args["tables"] and args["tables"][table["name"].to_s]
|
189
|
-
next if table_args and table_args["skip"]
|
190
|
-
table.delete("indexes") if table.key?("indexes") and args["skip_indexes"]
|
191
|
-
db.tables.create(table["name"], table)
|
192
|
-
|
193
|
-
limit_from = 0
|
194
|
-
limit_incr = 1000
|
195
|
-
|
196
|
-
loop do
|
197
|
-
ins_arr = []
|
198
|
-
q_rows = self.select(table["name"], {}, {"limit_from" => limit_from, "limit_to" => limit_incr})
|
199
|
-
while d_rows = q_rows.fetch
|
200
|
-
col_args = nil
|
201
|
-
|
202
|
-
if table_args and table_args["columns"]
|
203
|
-
d_rows.each do |col_name, col_data|
|
204
|
-
col_args = table_args["columns"][col_name.to_s] if table_args and table_args["columns"]
|
205
|
-
d_rows[col_name] = "" if col_args and col_args["empty"]
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
ins_arr << d_rows
|
210
|
-
end
|
211
|
-
|
212
|
-
break if ins_arr.empty?
|
213
|
-
|
214
|
-
db.insert_multi(table["name"], ins_arr)
|
215
|
-
limit_from += limit_incr
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
#Returns the data of this database in a hash.
|
221
|
-
#===Examples
|
222
|
-
# data = db.data
|
223
|
-
# tables_hash = data['tables']
|
224
|
-
def data
|
225
|
-
tables_ret = []
|
226
|
-
tables.list.each do |name, table|
|
227
|
-
tables_ret << table.data
|
228
|
-
end
|
229
|
-
|
230
|
-
return {
|
231
|
-
"tables" => tables_ret
|
232
|
-
}
|
233
|
-
end
|
234
|
-
|
235
|
-
#Simply inserts data into a table.
|
236
|
-
#
|
237
|
-
#===Examples
|
238
|
-
# db.insert(:users, {:name => "John", :lastname => "Doe"})
|
239
|
-
# id = db.insert(:users, {:name => "John", :lastname => "Doe"}, :return_id => true)
|
240
|
-
# sql = db.insert(:users, {:name => "John", :lastname => "Doe"}, :return_sql => true) #=> "INSERT INTO `users` (`name`, `lastname`) VALUES ('John', 'Doe')"
|
241
|
-
def insert(tablename, arr_insert, args = nil)
|
242
|
-
sql = "INSERT INTO #{@sep_table}#{tablename}#{@sep_table}"
|
243
|
-
|
244
|
-
if !arr_insert or arr_insert.empty?
|
245
|
-
#This is the correct syntax for inserting a blank row in MySQL.
|
246
|
-
if @opts[:type].to_s == "mysql"
|
247
|
-
sql << " VALUES ()"
|
248
|
-
elsif @opts[:type].to_s == "sqlite3"
|
249
|
-
sql << " DEFAULT VALUES"
|
250
|
-
else
|
251
|
-
raise "Unknown database-type: '#{@opts[:type]}'."
|
252
|
-
end
|
253
|
-
else
|
254
|
-
sql << " ("
|
255
|
-
|
256
|
-
first = true
|
257
|
-
arr_insert.each do |key, value|
|
258
|
-
if first
|
259
|
-
first = false
|
260
|
-
else
|
261
|
-
sql << ", "
|
262
|
-
end
|
263
|
-
|
264
|
-
sql << "#{@sep_col}#{key}#{@sep_col}"
|
265
|
-
end
|
266
|
-
|
267
|
-
sql << ") VALUES ("
|
268
|
-
|
269
|
-
first = true
|
270
|
-
arr_insert.each do |key, value|
|
271
|
-
if first
|
272
|
-
first = false
|
273
|
-
else
|
274
|
-
sql << ", "
|
275
|
-
end
|
276
|
-
|
277
|
-
sql << self.sqlval(value)
|
278
|
-
end
|
279
|
-
|
280
|
-
sql << ")"
|
281
|
-
end
|
282
|
-
|
283
|
-
return sql if args and args[:return_sql]
|
284
|
-
|
285
|
-
self.conn_exec do |driver|
|
286
|
-
driver.query(sql)
|
287
|
-
return driver.lastID if args and args[:return_id]
|
288
|
-
return nil
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
#Returns the correct SQL-value for the given value. If it is a number, then just the raw number as a string will be returned. nil's will be NULL and strings will have quotes and will be escaped.
|
293
|
-
def sqlval(val)
|
294
|
-
return @conn.sqlval(val) if @conn.respond_to?(:sqlval)
|
295
|
-
|
296
|
-
if val.is_a?(Fixnum) or val.is_a?(Integer)
|
297
|
-
return val.to_s
|
298
|
-
elsif val == nil
|
299
|
-
return "NULL"
|
300
|
-
elsif val.is_a?(Date)
|
301
|
-
return "#{@sep_val}#{Datet.in(val).dbstr(:time => false)}#{@sep_val}"
|
302
|
-
elsif val.is_a?(Time) or val.is_a?(DateTime)
|
303
|
-
return "#{@sep_val}#{Datet.in(val).dbstr}#{@sep_val}"
|
304
|
-
else
|
305
|
-
return "#{@sep_val}#{self.escape(val)}#{@sep_val}"
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
#Simply and optimal insert multiple rows into a table in a single query. Uses the drivers functionality if supported or inserts each row manually.
|
310
|
-
#
|
311
|
-
#===Examples
|
312
|
-
# db.insert_multi(:users, [
|
313
|
-
# {:name => "John", :lastname => "Doe"},
|
314
|
-
# {:name => "Kasper", :lastname => "Johansen"}
|
315
|
-
# ])
|
316
|
-
def insert_multi(tablename, arr_hashes, args = nil)
|
317
|
-
return false if arr_hashes.empty?
|
318
|
-
|
319
|
-
if @esc_driver.respond_to?(:insert_multi)
|
320
|
-
if args and args[:return_sql]
|
321
|
-
return [@esc_driver.insert_multi(tablename, arr_hashes, args)]
|
322
|
-
end
|
323
|
-
|
324
|
-
self.conn_exec do |driver|
|
325
|
-
return driver.insert_multi(tablename, arr_hashes, args)
|
326
|
-
end
|
327
|
-
else
|
328
|
-
ret = [] if args and (args[:return_id] or args[:return_sql])
|
329
|
-
arr_hashes.each do |hash|
|
330
|
-
if ret
|
331
|
-
ret << self.insert(tablename, hash, args)
|
332
|
-
else
|
333
|
-
self.insert(tablename, hash, args)
|
334
|
-
end
|
335
|
-
end
|
336
|
-
|
337
|
-
if ret
|
338
|
-
return ret
|
339
|
-
else
|
340
|
-
return nil
|
341
|
-
end
|
342
|
-
end
|
343
|
-
end
|
344
|
-
|
345
|
-
#Simple updates rows.
|
346
|
-
#
|
347
|
-
#===Examples
|
348
|
-
# db.update(:users, {:name => "John"}, {:lastname => "Doe"})
|
349
|
-
def update(tablename, arr_update, arr_terms = {}, args = nil)
|
350
|
-
raise "'arr_update' was not a hash." if !arr_update.is_a?(Hash)
|
351
|
-
return false if arr_update.empty?
|
352
|
-
|
353
|
-
sql = ""
|
354
|
-
sql << "UPDATE #{@sep_col}#{tablename}#{@sep_col} SET "
|
355
|
-
|
356
|
-
first = true
|
357
|
-
arr_update.each do |key, value|
|
358
|
-
if first
|
359
|
-
first = false
|
360
|
-
else
|
361
|
-
sql << ", "
|
362
|
-
end
|
363
|
-
|
364
|
-
#Convert dates to valid dbstr.
|
365
|
-
value = self.date_out(value) if value.is_a?(Datet) or value.is_a?(Time)
|
366
|
-
|
367
|
-
sql << "#{@sep_col}#{key}#{@sep_col} = "
|
368
|
-
sql << "#{@sep_val}#{@esc_driver.escape(value)}#{@sep_val}"
|
369
|
-
end
|
370
|
-
|
371
|
-
if arr_terms and arr_terms.length > 0
|
372
|
-
sql << " WHERE #{self.makeWhere(arr_terms)}"
|
373
|
-
end
|
374
|
-
|
375
|
-
return sql if args and args[:return_sql]
|
376
|
-
|
377
|
-
self.conn_exec do |driver|
|
378
|
-
driver.query(sql)
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|
382
|
-
#Checks if a given selector exists. If it does, updates it to match data. If not inserts the row.
|
383
|
-
def upsert(table, selector, data)
|
384
|
-
row = self.select(table, selector, "limit" => 1).fetch
|
385
|
-
|
386
|
-
if row
|
387
|
-
self.update(table, data, row)
|
388
|
-
else
|
389
|
-
self.insert(table, selector.merge(data))
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
#Makes a select from the given arguments: table-name, where-terms and other arguments as limits and orders. Also takes a block to avoid raping of memory.
|
394
|
-
def select(tablename, arr_terms = nil, args = nil, &block)
|
395
|
-
#Set up vars.
|
396
|
-
sql = ""
|
397
|
-
args_q = nil
|
398
|
-
select_sql = "*"
|
399
|
-
|
400
|
-
#Give 'cloned_ubuf' argument to 'q'-method.
|
401
|
-
if args and args[:cloned_ubuf]
|
402
|
-
args_q = {:cloned_ubuf => true}
|
403
|
-
end
|
404
|
-
|
405
|
-
#Set up IDQuery-stuff if that is given in arguments.
|
406
|
-
if args and args[:idquery]
|
407
|
-
if args[:idquery] == true
|
408
|
-
select_sql = "`id`"
|
409
|
-
col = :id
|
410
|
-
else
|
411
|
-
select_sql = "`#{self.esc_col(args[:idquery])}`"
|
412
|
-
col = args[:idquery]
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
sql = "SELECT #{select_sql} FROM #{@sep_table}#{tablename}#{@sep_table}"
|
417
|
-
|
418
|
-
if arr_terms != nil and !arr_terms.empty?
|
419
|
-
sql << " WHERE #{self.makeWhere(arr_terms)}"
|
420
|
-
end
|
421
|
-
|
422
|
-
if args != nil
|
423
|
-
if args["orderby"]
|
424
|
-
sql << " ORDER BY #{args["orderby"]}"
|
425
|
-
end
|
426
|
-
|
427
|
-
if args["limit"]
|
428
|
-
sql << " LIMIT #{args["limit"]}"
|
429
|
-
end
|
430
|
-
|
431
|
-
if args["limit_from"] and args["limit_to"]
|
432
|
-
raise "'limit_from' was not numeric: '#{args["limit_from"]}'." if !(Float(args["limit_from"]) rescue false)
|
433
|
-
raise "'limit_to' was not numeric: '#{args["limit_to"]}'." if !(Float(args["limit_to"]) rescue false)
|
434
|
-
sql << " LIMIT #{args["limit_from"]}, #{args["limit_to"]}"
|
435
|
-
end
|
436
|
-
end
|
437
|
-
|
438
|
-
#Do IDQuery if given in arguments.
|
439
|
-
if args and args[:idquery]
|
440
|
-
res = Knj::Db::Idquery.new(:db => self, :table => tablename, :query => sql, :col => col, &block)
|
441
|
-
else
|
442
|
-
res = self.q(sql, args_q, &block)
|
443
|
-
end
|
444
|
-
|
445
|
-
#Return result if a block wasnt given.
|
446
|
-
if block
|
447
|
-
return nil
|
448
|
-
else
|
449
|
-
return res
|
450
|
-
end
|
451
|
-
end
|
452
|
-
|
453
|
-
#Returns a single row from a database.
|
454
|
-
#
|
455
|
-
#===Examples
|
456
|
-
# row = db.single(:users, {:lastname => "Doe"})
|
457
|
-
def single(tablename, arr_terms = nil, args = {})
|
458
|
-
args["limit"] = 1
|
459
|
-
|
460
|
-
#Experienced very weird memory leak if this was not done by block. Maybe bug in Ruby 1.9.2? - knj
|
461
|
-
self.select(tablename, arr_terms, args) do |data|
|
462
|
-
return data
|
463
|
-
end
|
464
|
-
|
465
|
-
return false
|
466
|
-
end
|
467
|
-
|
468
|
-
alias :selectsingle :single
|
469
|
-
|
470
|
-
#Deletes rows from the database.
|
471
|
-
#
|
472
|
-
#===Examples
|
473
|
-
# db.delete(:users, {:lastname => "Doe"})
|
474
|
-
def delete(tablename, arr_terms, args = nil)
|
475
|
-
sql = "DELETE FROM #{@sep_table}#{tablename}#{@sep_table}"
|
476
|
-
|
477
|
-
if arr_terms != nil and !arr_terms.empty?
|
478
|
-
sql << " WHERE #{self.makeWhere(arr_terms)}"
|
479
|
-
end
|
480
|
-
|
481
|
-
return sql if args and args[:return_sql]
|
482
|
-
|
483
|
-
self.conn_exec do |driver|
|
484
|
-
driver.query(sql)
|
485
|
-
end
|
486
|
-
|
487
|
-
return nil
|
488
|
-
end
|
489
|
-
|
490
|
-
#Internally used to generate SQL.
|
491
|
-
#
|
492
|
-
#===Examples
|
493
|
-
# sql = db.makeWhere({:lastname => "Doe"}, driver_obj)
|
494
|
-
def makeWhere(arr_terms, driver = nil)
|
495
|
-
sql = ""
|
496
|
-
|
497
|
-
first = true
|
498
|
-
arr_terms.each do |key, value|
|
499
|
-
if first
|
500
|
-
first = false
|
501
|
-
else
|
502
|
-
sql << " AND "
|
503
|
-
end
|
504
|
-
|
505
|
-
if value.is_a?(Array)
|
506
|
-
raise "Array for column '#{key}' was empty." if value.empty?
|
507
|
-
sql << "#{@sep_col}#{key}#{@sep_col} IN (#{Knj::ArrayExt.join(:arr => value, :sep => ",", :surr => "'", :callback => proc{|ele| self.esc(ele)})})"
|
508
|
-
elsif value.is_a?(Hash)
|
509
|
-
raise "Dont know how to handle hash."
|
510
|
-
else
|
511
|
-
sql << "#{@sep_col}#{key}#{@sep_col} = #{@sep_val}#{@esc_driver.escape(value)}#{@sep_val}"
|
512
|
-
end
|
513
|
-
end
|
514
|
-
|
515
|
-
return sql
|
516
|
-
end
|
517
|
-
|
518
|
-
#Returns a driver-object based on the current thread and free driver-objects.
|
519
|
-
#
|
520
|
-
#===Examples
|
521
|
-
# db.conn_exec do |driver|
|
522
|
-
# str = driver.escape('something̈́')
|
523
|
-
# end
|
524
|
-
def conn_exec
|
525
|
-
if tcur = Thread.current and tcur[:knjdb]
|
526
|
-
tid = self.__id__
|
527
|
-
|
528
|
-
if tcur[:knjdb].key?(tid)
|
529
|
-
yield(tcur[:knjdb][tid])
|
530
|
-
return nil
|
531
|
-
end
|
532
|
-
end
|
533
|
-
|
534
|
-
if @conns
|
535
|
-
conn = @conns.get_and_lock
|
536
|
-
|
537
|
-
begin
|
538
|
-
yield(conn)
|
539
|
-
return nil
|
540
|
-
ensure
|
541
|
-
@conns.free(conn)
|
542
|
-
end
|
543
|
-
elsif @conn
|
544
|
-
@mutex.synchronize do
|
545
|
-
yield(@conn)
|
546
|
-
return nil
|
547
|
-
end
|
548
|
-
end
|
549
|
-
|
550
|
-
raise "Could not figure out how to find a driver to use?"
|
551
|
-
end
|
552
|
-
|
553
|
-
#Executes a query and returns the result.
|
554
|
-
#
|
555
|
-
#===Examples
|
556
|
-
# res = db.query('SELECT * FROM users')
|
557
|
-
# while data = res.fetch
|
558
|
-
# print data[:name]
|
559
|
-
# end
|
560
|
-
def query(string)
|
561
|
-
if @debug
|
562
|
-
print "SQL: #{string}\n"
|
563
|
-
|
564
|
-
if @debug.is_a?(Fixnum) and @debug >= 2
|
565
|
-
print caller.join("\n")
|
566
|
-
print "\n"
|
567
|
-
end
|
568
|
-
end
|
569
|
-
|
570
|
-
self.conn_exec do |driver|
|
571
|
-
return driver.query(string)
|
572
|
-
end
|
573
|
-
end
|
574
|
-
|
575
|
-
#Execute an ubuffered query and returns the result.
|
576
|
-
#
|
577
|
-
#===Examples
|
578
|
-
# db.query_ubuf('SELECT * FROM users') do |data|
|
579
|
-
# print data[:name]
|
580
|
-
# end
|
581
|
-
def query_ubuf(string, &block)
|
582
|
-
ret = nil
|
583
|
-
|
584
|
-
self.conn_exec do |driver|
|
585
|
-
ret = driver.query_ubuf(string, &block)
|
586
|
-
end
|
587
|
-
|
588
|
-
if block
|
589
|
-
ret.each(&block)
|
590
|
-
return nil
|
591
|
-
end
|
592
|
-
|
593
|
-
return ret
|
594
|
-
end
|
595
|
-
|
596
|
-
#Clones the connection, executes the given block and closes the connection again.
|
597
|
-
#
|
598
|
-
#===Examples
|
599
|
-
# db.cloned_conn do |conn|
|
600
|
-
# conn.q('SELCET * FROM users') do |data|
|
601
|
-
# print data[:name]
|
602
|
-
# end
|
603
|
-
# end
|
604
|
-
def cloned_conn(args = nil, &block)
|
605
|
-
clone_conn_args = {
|
606
|
-
:threadsafe => false
|
607
|
-
}
|
608
|
-
|
609
|
-
clone_conn_args.merge!(args[:clone_args]) if args and args[:clone_args]
|
610
|
-
dbconn = self.clone_conn(clone_conn_args)
|
611
|
-
|
612
|
-
begin
|
613
|
-
yield(dbconn)
|
614
|
-
ensure
|
615
|
-
dbconn.close
|
616
|
-
end
|
617
|
-
end
|
618
|
-
|
619
|
-
#Executes a query and returns the result. If a block is given the result is iterated over that block instead and it returns nil.
|
620
|
-
#
|
621
|
-
#===Examples
|
622
|
-
# db.q('SELECT * FROM users') do |data|
|
623
|
-
# print data[:name]
|
624
|
-
# end
|
625
|
-
def q(str, args = nil, &block)
|
626
|
-
#If the query should be executed in a new connection unbuffered.
|
627
|
-
if args
|
628
|
-
if args[:cloned_ubuf]
|
629
|
-
raise "No block given." if !block
|
630
|
-
|
631
|
-
self.cloned_conn(:clone_args => args[:clone_args]) do |cloned_conn|
|
632
|
-
ret = cloned_conn.query_ubuf(str)
|
633
|
-
ret.each(&block)
|
634
|
-
end
|
635
|
-
|
636
|
-
return nil
|
637
|
-
else
|
638
|
-
raise "Invalid arguments given: '#{args}'."
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
ret = self.query(str)
|
643
|
-
|
644
|
-
if block
|
645
|
-
ret.each(&block)
|
646
|
-
return nil
|
647
|
-
end
|
648
|
-
|
649
|
-
return ret
|
650
|
-
end
|
651
|
-
|
652
|
-
#Yields a query-buffer and flushes at the end of the block given.
|
653
|
-
def q_buffer(&block)
|
654
|
-
Knj::Db::Query_buffer.new(:db => self, &block)
|
655
|
-
return nil
|
656
|
-
end
|
657
|
-
|
658
|
-
#Returns the last inserted ID.
|
659
|
-
#
|
660
|
-
#===Examples
|
661
|
-
# id = db.last_id
|
662
|
-
def lastID
|
663
|
-
self.conn_exec do |driver|
|
664
|
-
return driver.lastID
|
665
|
-
end
|
666
|
-
end
|
667
|
-
|
668
|
-
alias :last_id :lastID
|
669
|
-
|
670
|
-
#Escapes a string to be safe-to-use in a query-string.
|
671
|
-
#
|
672
|
-
#===Examples
|
673
|
-
# db.q("INSERT INTO users (name) VALUES ('#{db.esc('John')}')")
|
674
|
-
def escape(string)
|
675
|
-
return @esc_driver.escape(string)
|
676
|
-
end
|
677
|
-
|
678
|
-
alias :esc :escape
|
679
|
-
|
680
|
-
#Escapes the given string to be used as a column.
|
681
|
-
def esc_col(str)
|
682
|
-
return @esc_driver.esc_col(str)
|
683
|
-
end
|
684
|
-
|
685
|
-
#Escapes the given string to be used as a table.
|
686
|
-
def esc_table(str)
|
687
|
-
return @esc_driver.esc_table(str)
|
688
|
-
end
|
689
|
-
|
690
|
-
#Returns a string which can be used in SQL with the current driver.
|
691
|
-
#===Examples
|
692
|
-
# str = db.date_out(Time.now) #=> "2012-05-20 22:06:09"
|
693
|
-
def date_out(date_obj = Datet.new, args = {})
|
694
|
-
if @esc_driver.respond_to?(:date_out)
|
695
|
-
return @esc_driver.date_out(date_obj, args)
|
696
|
-
end
|
697
|
-
|
698
|
-
return Datet.in(date_obj).dbstr(args)
|
699
|
-
end
|
700
|
-
|
701
|
-
#Takes a valid date-db-string and converts it into a Datet.
|
702
|
-
#===Examples
|
703
|
-
# db.date_in('2012-05-20 22:06:09') #=> 2012-05-20 22:06:09 +0200
|
704
|
-
def date_in(date_obj)
|
705
|
-
if @esc_driver.respond_to?(:date_in)
|
706
|
-
return @esc_driver.date_in(date_obj)
|
707
|
-
end
|
708
|
-
|
709
|
-
return Datet.in(date_obj)
|
710
|
-
end
|
711
|
-
|
712
|
-
#Returns the table-module and spawns it if it isnt already spawned.
|
713
|
-
def tables
|
714
|
-
if !@tables
|
715
|
-
require "#{File.dirname(__FILE__)}/drivers/#{@opts[:type]}/knjdb_#{@opts[:type]}_tables" if (!@opts.key?(:require) or @opts[:require])
|
716
|
-
@tables = Kernel.const_get("KnjDB_#{@opts[:type]}".to_sym).const_get(:Tables).new(
|
717
|
-
:db => self
|
718
|
-
)
|
719
|
-
end
|
720
|
-
|
721
|
-
return @tables
|
722
|
-
end
|
723
|
-
|
724
|
-
#Returns the columns-module and spawns it if it isnt already spawned.
|
725
|
-
def cols
|
726
|
-
if !@cols
|
727
|
-
require "#{File.dirname(__FILE__)}/drivers/#{@opts[:type]}/knjdb_#{@opts[:type]}_columns" if (!@opts.key?(:require) or @opts[:require])
|
728
|
-
@cols = Kernel.const_get("KnjDB_#{@opts[:type]}".to_sym).const_get(:Columns).new(
|
729
|
-
:db => self
|
730
|
-
)
|
731
|
-
end
|
732
|
-
|
733
|
-
return @cols
|
734
|
-
end
|
735
|
-
|
736
|
-
#Returns the index-module and spawns it if it isnt already spawned.
|
737
|
-
def indexes
|
738
|
-
if !@indexes
|
739
|
-
require "#{File.dirname(__FILE__)}/drivers/#{@opts[:type]}/knjdb_#{@opts[:type]}_indexes" if (!@opts.key?(:require) or @opts[:require])
|
740
|
-
@indexes = Kernel.const_get("KnjDB_#{@opts[:type]}".to_sym).const_get(:Indexes).new(
|
741
|
-
:db => self
|
742
|
-
)
|
743
|
-
end
|
744
|
-
|
745
|
-
return @indexes
|
746
|
-
end
|
747
|
-
|
748
|
-
#Returns the SQLSpec-module and spawns it if it isnt already spawned.
|
749
|
-
def sqlspecs
|
750
|
-
if !@sqlspecs
|
751
|
-
require "#{File.dirname(__FILE__)}/drivers/#{@opts[:type]}/knjdb_#{@opts[:type]}_sqlspecs" if (!@opts.key?(:require) or @opts[:require])
|
752
|
-
@sqlspecs = Kernel.const_get("KnjDB_#{@opts[:type]}".to_sym).const_get(:Sqlspecs).new(
|
753
|
-
:db => self
|
754
|
-
)
|
755
|
-
end
|
756
|
-
|
757
|
-
return @sqlspecs
|
758
|
-
end
|
759
|
-
|
760
|
-
#Beings a transaction and commits when the block ends.
|
761
|
-
#
|
762
|
-
#===Examples
|
763
|
-
# db.transaction do |db|
|
764
|
-
# db.insert(:users, {:name => "John"})
|
765
|
-
# db.insert(:users, {:name => "Kasper"})
|
766
|
-
# end
|
767
|
-
def transaction(&block)
|
768
|
-
self.conn_exec do |driver|
|
769
|
-
driver.transaction(&block)
|
770
|
-
end
|
771
|
-
end
|
772
|
-
|
773
|
-
#Optimizes all tables in the database.
|
774
|
-
def optimize(args = nil)
|
775
|
-
STDOUT.puts "Beginning optimization of database." if @debug or (args and args[:debug])
|
776
|
-
self.tables.list do |table|
|
777
|
-
STDOUT.puts "Optimizing table: '#{table.name}'." if @debug or (args and args[:debug])
|
778
|
-
table.optimize
|
779
|
-
end
|
780
|
-
|
781
|
-
return nil
|
782
|
-
end
|
783
|
-
|
784
|
-
#Proxies the method to the driver.
|
785
|
-
#
|
786
|
-
#===Examples
|
787
|
-
# db.method_on_driver
|
788
|
-
def method_missing(method_name, *args)
|
789
|
-
self.conn_exec do |driver|
|
790
|
-
if driver.respond_to?(method_name.to_sym)
|
791
|
-
return driver.send(method_name, *args)
|
792
|
-
end
|
793
|
-
end
|
794
|
-
|
795
|
-
raise "Method not found: #{method_name}"
|
796
|
-
end
|
797
|
-
end
|