knjrbfw 0.0.39 → 0.0.40
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.
- data/VERSION +1 -1
- data/knjrbfw.gemspec +5 -2
- data/lib/knj/datarow.rb +18 -15
- data/lib/knj/errors.rb +3 -0
- data/lib/knj/http2.rb +104 -38
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql.rb +62 -11
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_columns.rb +29 -11
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_tables.rb +10 -3
- data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3.rb +24 -0
- data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3_columns.rb +30 -16
- data/lib/knj/knjdb/drivers/sqlite3/knjdb_sqlite3_tables.rb +51 -8
- data/lib/knj/knjdb/dump.rb +121 -0
- data/lib/knj/knjdb/idquery.rb +109 -0
- data/lib/knj/knjdb/libknjdb.rb +97 -36
- data/lib/knj/knjdb/query_buffer.rb +43 -0
- data/lib/knj/locales.rb +4 -8
- data/lib/knj/objects/objects_sqlhelper.rb +2 -2
- data/lib/knj/process.rb +6 -0
- data/lib/knj/process_meta.rb +4 -2
- data/lib/knj/threadpool.rb +84 -40
- data/lib/knj/web.rb +1 -1
- data/spec/db_spec.rb +72 -10
- data/spec/http2_spec.rb +51 -14
- data/spec/process_meta_spec.rb +17 -1
- metadata +6 -3
@@ -1,6 +1,8 @@
|
|
1
|
+
#This class handels various MySQL-table-specific behaviour.
|
1
2
|
class KnjDB_mysql::Tables
|
2
3
|
attr_reader :db, :list
|
3
4
|
|
5
|
+
#Constructor. This should not be called manually.
|
4
6
|
def initialize(args)
|
5
7
|
@args = args
|
6
8
|
@db = @args[:db]
|
@@ -10,6 +12,7 @@ class KnjDB_mysql::Tables
|
|
10
12
|
@list_should_be_reloaded = true
|
11
13
|
end
|
12
14
|
|
15
|
+
#Cleans the wref-map.
|
13
16
|
def clean
|
14
17
|
@list.clean
|
15
18
|
end
|
@@ -31,6 +34,7 @@ class KnjDB_mysql::Tables
|
|
31
34
|
raise Knj::Errors::NotFound.new("Table was not found: #{table_name}.")
|
32
35
|
end
|
33
36
|
|
37
|
+
#Yields the tables of the current database.
|
34
38
|
def list(args = {})
|
35
39
|
ret = {} unless block_given?
|
36
40
|
|
@@ -66,7 +70,8 @@ class KnjDB_mysql::Tables
|
|
66
70
|
end
|
67
71
|
end
|
68
72
|
|
69
|
-
|
73
|
+
#Creates a new table by the given name and data.
|
74
|
+
def create(name, data, args = nil)
|
70
75
|
raise "No columns was given for '#{name}'." if !data["columns"] or data["columns"].empty?
|
71
76
|
|
72
77
|
sql = "CREATE TABLE `#{name}` ("
|
@@ -91,6 +96,8 @@ class KnjDB_mysql::Tables
|
|
91
96
|
end
|
92
97
|
|
93
98
|
sql << ")"
|
99
|
+
|
100
|
+
return [sql] if args and args[:return_sql]
|
94
101
|
@db.query(sql)
|
95
102
|
end
|
96
103
|
end
|
@@ -106,7 +113,7 @@ class KnjDB_mysql::Tables::Table
|
|
106
113
|
@list = Wref_map.new
|
107
114
|
@indexes_list = Wref_map.new
|
108
115
|
|
109
|
-
raise "Could not figure out name from: '#{@data}'." if
|
116
|
+
raise "Could not figure out name from: '#{@data}'." if @data[:Name].to_s.strip.length <= 0
|
110
117
|
end
|
111
118
|
|
112
119
|
def reload
|
@@ -321,7 +328,7 @@ class KnjDB_mysql::Tables::Table
|
|
321
328
|
|
322
329
|
def data
|
323
330
|
ret = {
|
324
|
-
"name" => name,
|
331
|
+
"name" => self.name,
|
325
332
|
"columns" => [],
|
326
333
|
"indexes" => []
|
327
334
|
}
|
@@ -1,7 +1,9 @@
|
|
1
|
+
#This class handels SQLite3-specific behaviour.
|
1
2
|
class KnjDB_sqlite3
|
2
3
|
attr_reader :knjdb, :conn, :escape_table, :escape_col, :escape_val, :esc_table, :esc_col, :symbolize
|
3
4
|
attr_accessor :tables, :cols, :indexes
|
4
5
|
|
6
|
+
#Constructor. This should not be called manually.
|
5
7
|
def initialize(knjdb_ob)
|
6
8
|
@escape_table = "`"
|
7
9
|
@escape_col = "`"
|
@@ -37,6 +39,7 @@ class KnjDB_sqlite3
|
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
42
|
+
#Executes a query against the driver.
|
40
43
|
def query(string)
|
41
44
|
begin
|
42
45
|
if @knjdb.opts[:subtype] == "rhodes"
|
@@ -60,12 +63,17 @@ class KnjDB_sqlite3
|
|
60
63
|
end
|
61
64
|
end
|
62
65
|
|
66
|
+
#SQLite3 driver doesnt support unbuffered queries??
|
67
|
+
alias query_ubuf query
|
68
|
+
|
69
|
+
#Escapes a string to be safe to used in a query.
|
63
70
|
def escape(string)
|
64
71
|
#This code is taken directly from the documentation so we dont have to rely on the SQLite3::Database class. This way it can also be used with JRuby and IronRuby...
|
65
72
|
#http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html
|
66
73
|
return string.to_s.gsub(/'/, "''")
|
67
74
|
end
|
68
75
|
|
76
|
+
#Escapes a string to be used as a column.
|
69
77
|
def esc_col(string)
|
70
78
|
string = string.to_s
|
71
79
|
raise "Invalid column-string: #{string}" if string.index(@escape_col) != nil
|
@@ -75,16 +83,26 @@ class KnjDB_sqlite3
|
|
75
83
|
alias :esc_table :esc_col
|
76
84
|
alias :esc :escape
|
77
85
|
|
86
|
+
#Returns the last inserted ID.
|
78
87
|
def lastID
|
79
88
|
return @conn.last_insert_row_id if @conn.respond_to?(:last_insert_row_id)
|
80
89
|
return self.query("SELECT last_insert_rowid() AS id").fetch[:id].to_i
|
81
90
|
end
|
82
91
|
|
92
|
+
#Closes the connection to the database.
|
83
93
|
def close
|
84
94
|
@conn.close
|
85
95
|
end
|
96
|
+
|
97
|
+
#Starts a transaction, yields the database and commits.
|
98
|
+
def transaction
|
99
|
+
@conn.transaction do
|
100
|
+
yield(@knjdb)
|
101
|
+
end
|
102
|
+
end
|
86
103
|
end
|
87
104
|
|
105
|
+
#This class handels results when running in JRuby.
|
88
106
|
class KnjDB_sqlite3_result_java
|
89
107
|
def initialize(driver, rs)
|
90
108
|
@index = 0
|
@@ -108,6 +126,7 @@ class KnjDB_sqlite3_result_java
|
|
108
126
|
end
|
109
127
|
end
|
110
128
|
|
129
|
+
#Returns a single result.
|
111
130
|
def fetch
|
112
131
|
return false if !@rows
|
113
132
|
ret = @rows[@index]
|
@@ -116,6 +135,7 @@ class KnjDB_sqlite3_result_java
|
|
116
135
|
return ret
|
117
136
|
end
|
118
137
|
|
138
|
+
#Loops over every result and yields them.
|
119
139
|
def each
|
120
140
|
while data = self.fetch
|
121
141
|
yield(data)
|
@@ -123,7 +143,9 @@ class KnjDB_sqlite3_result_java
|
|
123
143
|
end
|
124
144
|
end
|
125
145
|
|
146
|
+
#This class handels the result when running MRI (or others).
|
126
147
|
class KnjDB_sqlite3_result
|
148
|
+
#Constructor. This should not be called manually.
|
127
149
|
def initialize(driver, result_array)
|
128
150
|
@result_array = result_array
|
129
151
|
@index = 0
|
@@ -135,6 +157,7 @@ class KnjDB_sqlite3_result
|
|
135
157
|
end
|
136
158
|
end
|
137
159
|
|
160
|
+
#Returns a single result.
|
138
161
|
def fetch
|
139
162
|
result_hash = @result_array[@index]
|
140
163
|
return false if !result_hash
|
@@ -154,6 +177,7 @@ class KnjDB_sqlite3_result
|
|
154
177
|
return ret
|
155
178
|
end
|
156
179
|
|
180
|
+
#Loops over every result yielding them.
|
157
181
|
def each
|
158
182
|
while data = self.fetch
|
159
183
|
yield(data)
|
@@ -1,12 +1,13 @@
|
|
1
|
+
#This class handels the SQLite3-specific behaviour for columns.
|
1
2
|
class KnjDB_sqlite3::Columns
|
2
|
-
attr_reader :db
|
3
|
+
attr_reader :db
|
3
4
|
|
5
|
+
#Constructor. This should not be called manually.
|
4
6
|
def initialize(args)
|
5
7
|
@args = args
|
6
|
-
@db = @args[:db]
|
7
|
-
@driver = @args[:driver]
|
8
8
|
end
|
9
9
|
|
10
|
+
#Returns SQL for a knjdb-compatible hash.
|
10
11
|
def data_sql(data)
|
11
12
|
raise "No type given." if !data["type"]
|
12
13
|
type = data["type"]
|
@@ -17,7 +18,7 @@ class KnjDB_sqlite3::Columns
|
|
17
18
|
end
|
18
19
|
|
19
20
|
data["maxlength"] = 255 if type == "varchar" and !data.key?("maxlength")
|
20
|
-
type = "integer" if @db.int_types.index(type) and (data["autoincr"] or data["primarykey"])
|
21
|
+
type = "integer" if @args[:db].int_types.index(type) and (data["autoincr"] or data["primarykey"])
|
21
22
|
|
22
23
|
sql = "`#{data["name"]}` #{type}"
|
23
24
|
sql << "(#{data["maxlength"]})" if data["maxlength"] and !data["autoincr"]
|
@@ -28,29 +29,34 @@ class KnjDB_sqlite3::Columns
|
|
28
29
|
if data.key?("default_func")
|
29
30
|
sql << " DEFAULT #{data["default_func"]}"
|
30
31
|
elsif data.key?("default") and data["default"] != false
|
31
|
-
sql << " DEFAULT '#{@db.escape(data["default"])}'"
|
32
|
+
sql << " DEFAULT '#{@args[:db].escape(data["default"])}'"
|
32
33
|
end
|
33
34
|
|
34
35
|
return sql
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
39
|
+
#This class handels all the SQLite3-columns.
|
38
40
|
class KnjDB_sqlite3::Columns::Column
|
39
41
|
attr_reader :args
|
40
42
|
|
43
|
+
#Constructor. This should not be called manually.
|
41
44
|
def initialize(args)
|
42
45
|
@args = args
|
43
46
|
@db = @args[:db]
|
44
47
|
end
|
45
48
|
|
49
|
+
#Returns the name of the column.
|
46
50
|
def name
|
47
51
|
return @args[:data][:name]
|
48
52
|
end
|
49
53
|
|
54
|
+
#Returns the columns table-object.
|
50
55
|
def table
|
51
56
|
return @db.tables[@args[:table_name]]
|
52
57
|
end
|
53
58
|
|
59
|
+
#Returns the data of the column as a hash in knjdb-format.
|
54
60
|
def data
|
55
61
|
return {
|
56
62
|
"type" => self.type,
|
@@ -63,6 +69,7 @@ class KnjDB_sqlite3::Columns::Column
|
|
63
69
|
}
|
64
70
|
end
|
65
71
|
|
72
|
+
#Returns the type of the column.
|
66
73
|
def type
|
67
74
|
if !@type
|
68
75
|
if match = @args[:data][:type].match(/^([A-z]+)$/)
|
@@ -70,36 +77,41 @@ class KnjDB_sqlite3::Columns::Column
|
|
70
77
|
type = match[0]
|
71
78
|
elsif match = @args[:data][:type].match(/^decimal\((\d+),(\d+)\)$/)
|
72
79
|
@maxlength = "#{match[1]},#{match[2]}"
|
73
|
-
type =
|
80
|
+
type = :decimal
|
74
81
|
elsif match = @args[:data][:type].match(/^enum\((.+)\)$/)
|
75
82
|
@maxlength = match[1]
|
76
|
-
type =
|
83
|
+
type = :enum
|
77
84
|
elsif match = @args[:data][:type].match(/^(.+)\((\d+)\)$/)
|
78
85
|
@maxlength = match[2]
|
79
|
-
type = match[1]
|
86
|
+
type = match[1].to_sym
|
80
87
|
end
|
81
88
|
|
82
|
-
if type ==
|
83
|
-
@type =
|
89
|
+
if type == :integer
|
90
|
+
@type = :int
|
84
91
|
else
|
85
92
|
@type = type
|
86
93
|
end
|
94
|
+
|
95
|
+
raise "Still not type?" if @type.to_s.strip.length <= 0
|
87
96
|
end
|
88
97
|
|
89
98
|
return @type
|
90
99
|
end
|
91
100
|
|
101
|
+
#Returns true if the column allows null. Otherwise false.
|
92
102
|
def null?
|
93
103
|
return false if @args[:data][:notnull].to_i == 1
|
94
104
|
return true
|
95
105
|
end
|
96
106
|
|
107
|
+
#Returns the maxlength of the column.
|
97
108
|
def maxlength
|
98
|
-
self.type
|
109
|
+
self.type if !@maxlength
|
99
110
|
return @maxlength if @maxlength
|
100
111
|
return false
|
101
112
|
end
|
102
113
|
|
114
|
+
#Returns the default value of the column.
|
103
115
|
def default
|
104
116
|
def_val = @args[:data][:dflt_value]
|
105
117
|
if def_val.to_s.slice(0..0) == "'"
|
@@ -114,24 +126,26 @@ class KnjDB_sqlite3::Columns::Column
|
|
114
126
|
return def_val
|
115
127
|
end
|
116
128
|
|
129
|
+
#Returns true if the column is the primary key.
|
117
130
|
def primarykey?
|
118
|
-
return true if
|
131
|
+
return true if self.name.to_s == "id"
|
119
132
|
return false if @args[:data][:pk].to_i == 0
|
120
133
|
return true
|
121
134
|
end
|
122
135
|
|
136
|
+
#Returns true if the column is auto-increasing.
|
123
137
|
def autoincr?
|
124
|
-
return true if
|
138
|
+
return true if self.name.to_s == "id"
|
125
139
|
return true if @args[:data][:pk].to_i >= 1
|
126
140
|
return false
|
127
141
|
end
|
128
142
|
|
143
|
+
#Drops the column from the table.
|
129
144
|
def drop
|
130
|
-
|
131
|
-
"drops" => self.name
|
132
|
-
)
|
145
|
+
self.table.copy("drops" => self.name)
|
133
146
|
end
|
134
147
|
|
148
|
+
#Changes data on the column. Like the name, type, maxlength or whatever.
|
135
149
|
def change(data)
|
136
150
|
newdata = data.clone
|
137
151
|
|
@@ -13,16 +13,17 @@ class KnjDB_sqlite3::Tables
|
|
13
13
|
table_name = table_name.to_s
|
14
14
|
|
15
15
|
begin
|
16
|
-
|
16
|
+
ret = @list[table_name]
|
17
|
+
return ret
|
17
18
|
rescue Wref::Recycled
|
18
19
|
#ignore.
|
19
20
|
end
|
20
21
|
|
21
22
|
self.list do |table_obj|
|
22
|
-
return table_obj if table_obj.name.to_s == table_name
|
23
|
+
return table_obj if table_obj.name.to_s == table_name.to_s
|
23
24
|
end
|
24
25
|
|
25
|
-
raise Knj::Errors::NotFound
|
26
|
+
raise Knj::Errors::NotFound, "Table was not found: #{table_name}."
|
26
27
|
end
|
27
28
|
|
28
29
|
def list
|
@@ -55,7 +56,7 @@ class KnjDB_sqlite3::Tables
|
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
58
|
-
def create(name, data)
|
59
|
+
def create(name, data, args = nil)
|
59
60
|
sql = "CREATE TABLE `#{name}` ("
|
60
61
|
|
61
62
|
first = true
|
@@ -67,11 +68,26 @@ class KnjDB_sqlite3::Tables
|
|
67
68
|
|
68
69
|
sql << ")"
|
69
70
|
|
70
|
-
|
71
|
+
if args and args[:return_sql]
|
72
|
+
ret = [sql]
|
73
|
+
else
|
74
|
+
@db.query(sql)
|
75
|
+
end
|
71
76
|
|
72
77
|
if data.key?("indexes") and data["indexes"]
|
73
78
|
table_obj = self[name]
|
74
|
-
|
79
|
+
|
80
|
+
if args and args[:return_sql]
|
81
|
+
ret += table_obj.create_indexes(data["indexes"], :return_sql => true)
|
82
|
+
else
|
83
|
+
table_obj.create_indexes(data["indexes"])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
if args and args[:return_sql]
|
88
|
+
return ret
|
89
|
+
else
|
90
|
+
return nil
|
75
91
|
end
|
76
92
|
end
|
77
93
|
end
|
@@ -89,6 +105,14 @@ class KnjDB_sqlite3::Tables::Table
|
|
89
105
|
return @data[:name]
|
90
106
|
end
|
91
107
|
|
108
|
+
def type
|
109
|
+
return @data[:type]
|
110
|
+
end
|
111
|
+
|
112
|
+
def maxlength
|
113
|
+
return @data[:maxlength]
|
114
|
+
end
|
115
|
+
|
92
116
|
def drop
|
93
117
|
sql = "DROP TABLE `#{self.name}`"
|
94
118
|
@db.query(sql)
|
@@ -98,6 +122,11 @@ class KnjDB_sqlite3::Tables::Table
|
|
98
122
|
raise "stub!"
|
99
123
|
end
|
100
124
|
|
125
|
+
def truncate
|
126
|
+
@db.query("DELETE FROM `#{self.name}` WHERE 1=1")
|
127
|
+
return nil
|
128
|
+
end
|
129
|
+
|
101
130
|
def table
|
102
131
|
return @db.tables[@table_name]
|
103
132
|
end
|
@@ -331,7 +360,11 @@ class KnjDB_sqlite3::Tables::Table
|
|
331
360
|
end
|
332
361
|
end
|
333
362
|
|
334
|
-
def create_indexes(index_arr)
|
363
|
+
def create_indexes(index_arr, args = nil)
|
364
|
+
if args and args[:return_sql]
|
365
|
+
ret = []
|
366
|
+
end
|
367
|
+
|
335
368
|
index_arr.each do |index_data|
|
336
369
|
if index_data.is_a?(String)
|
337
370
|
index_data = {"name" => index_data, "columns" => [index_data]}
|
@@ -355,7 +388,17 @@ class KnjDB_sqlite3::Tables::Table
|
|
355
388
|
|
356
389
|
sql << ")"
|
357
390
|
|
358
|
-
|
391
|
+
if args and args[:return_sql]
|
392
|
+
ret << sql
|
393
|
+
else
|
394
|
+
@db.query(sql)
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
if args and args[:return_sql]
|
399
|
+
return ret
|
400
|
+
else
|
401
|
+
return nil
|
359
402
|
end
|
360
403
|
end
|
361
404
|
|
@@ -0,0 +1,121 @@
|
|
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
|
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_name, table_obj|
|
42
|
+
table_obj = @args[:db].tables[table_obj] if table_obj.is_a?(String) or table_obj.is_a?(Symbol)
|
43
|
+
|
44
|
+
#Figure out keys.
|
45
|
+
@keys = []
|
46
|
+
table_obj.columns do |col|
|
47
|
+
@keys << col.name
|
48
|
+
end
|
49
|
+
|
50
|
+
@table_obj = table_obj
|
51
|
+
self.update_status
|
52
|
+
print "Dumping table: '#{table_obj.name}'.\n" if @debug
|
53
|
+
self.dump_table(io, table_obj)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#A block can be executed when a new status occurs.
|
58
|
+
def on_status(&block)
|
59
|
+
@on_status = block
|
60
|
+
end
|
61
|
+
|
62
|
+
#Dumps the given table into the given IO.
|
63
|
+
def dump_table(io, table_obj)
|
64
|
+
#Get SQL for creating table and add it to IO.
|
65
|
+
sqls = @args[:db].tables.create(table_obj.name, table_obj.data, :return_sql => true)
|
66
|
+
sqls.each do |sql|
|
67
|
+
io.write("#{sql};\n")
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
#Try to find a primary column in the table.
|
72
|
+
prim_col = nil
|
73
|
+
table_obj.columns do |col|
|
74
|
+
if col.primarykey?
|
75
|
+
prim_col = col
|
76
|
+
break
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
#Set up rows and way to fill rows.
|
82
|
+
rows = []
|
83
|
+
block_data = proc do |row|
|
84
|
+
rows << row
|
85
|
+
@rows_count += 1
|
86
|
+
|
87
|
+
if rows.length >= 1000
|
88
|
+
self.update_status
|
89
|
+
self.dump_insert_multi(io, table_obj, rows)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
#If a primary column is found then use IDQuery. Otherwise use cloned unbuffered query.
|
95
|
+
args = {:idquery => prim_col.name.to_sym} if prim_col
|
96
|
+
|
97
|
+
|
98
|
+
#Clone the connecting with array-results and execute query.
|
99
|
+
@args[:db].clone_conn(:result => "array") do |db|
|
100
|
+
db.select(table_obj.name, nil, args, &block_data)
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
#Dump the last rows if any.
|
105
|
+
self.dump_insert_multi(io, table_obj, rows) if !rows.empty?
|
106
|
+
end
|
107
|
+
|
108
|
+
#Dumps the given rows from the given table into the given IO.
|
109
|
+
def dump_insert_multi(io, table_obj, rows)
|
110
|
+
print "Inserting #{rows.length} into #{table_obj.name}.\n" if @debug
|
111
|
+
sqls = @args[:db].insert_multi(table_obj.name, rows, :return_sql => true, :keys => @keys)
|
112
|
+
sqls.each do |sql|
|
113
|
+
io.write("#{sql};\n")
|
114
|
+
end
|
115
|
+
|
116
|
+
rows.clear
|
117
|
+
|
118
|
+
#Ensure garbage collection or we might start using A LOT of memory.
|
119
|
+
GC.start
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,109 @@
|
|
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
|