manqod-server 1.257.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.
@@ -0,0 +1,671 @@
1
+ #this file is part of manqod
2
+ #manqod is distributed under the CDDL licence
3
+ #the owner of manqod is Dobai-Pataky Balint(dpblnt@gmail.com)
4
+
5
+
6
+ class DrbListModel
7
+ include Eprint
8
+ include DRbUndumped
9
+ def initialize(drbdb,my_id)
10
+ @my_id=my_id.to_i
11
+ @drbdb=drbdb
12
+ @data=nil
13
+ @rowcount=0
14
+ @tree_key=nil
15
+ @tree_parent_key=nil
16
+ @fetch_filter_key=nil
17
+ @fetch_filter_value=nil
18
+ @fetch_filter_negate=false
19
+ @archive_key=nil
20
+ @clients=Array.new
21
+ @base=nil
22
+ @last_seq=Hash.new
23
+ @buttons=Array.new
24
+ @childs=Array.new
25
+ end
26
+ attr_reader :data, :rowcount, :headers, :headertypes, :my_id, :moditem, :clients, :querysql
27
+
28
+ attr_reader :column_of_visible, :column_of_id, :column_of_sensitive, :column_of_background, :column_of_foreground
29
+ attr_reader :tree_key, :tree_parent_key, :fetch_filter_key, :fetch_filter_value, :fetch_filter_negate, :archive_key
30
+ attr_reader :column_of_tree, :column_of_tree_parent, :column_of_iter_depth, :column_of_archive
31
+ attr_reader :base
32
+
33
+ def to_s
34
+ "Drbmodel{#{@drbdb.name}:#{moditem['display']}(#{my_id})}"
35
+ end
36
+ def get_id
37
+ @my_id
38
+ end
39
+ def mod_type
40
+ "list"
41
+ end
42
+ def gtk_attribute(gattr)
43
+ @drbdb.gtk_attribute(gattr,self)
44
+ end
45
+
46
+ def lock_iter(locked_id)
47
+ edebug("lock for #{locked_id}") unless @clients.size==0
48
+ if @data.has_key?(locked_id) && @data[locked_id][@column_of_sensitive]
49
+ @data[locked_id][@column_of_sensitive]=false
50
+ begin
51
+ cache.set("#{@my_id}[#{locked_id}]",@data[locked_id])
52
+ rescue => err
53
+ eerror("Locking: #{err}")
54
+ end
55
+ notify_clients(locked_id)
56
+ end
57
+ end
58
+
59
+ def unlock_iter(unlocked_id)
60
+ if @data.has_key?(unlocked_id) && !@data[unlocked_id][@column_of_sensitive]
61
+ edebug("unlock for #{unlocked_id}") unless @clients.size==0
62
+ @data[unlocked_id][@column_of_sensitive]=true
63
+ begin
64
+ cache.set("#{@my_id}[#{unlocked_id}]",@data[unlocked_id])
65
+ rescue => err
66
+ eerror("Unlocking: #{err}")
67
+ end
68
+ notify_clients(unlocked_id)
69
+ #else the row was locked and removed. we do not unlock it
70
+ end
71
+ end
72
+
73
+ #finds iter by col_num, col_num=colnum number to search for, col_num_data=the data we're looking for
74
+ def data_iter_of_col_num(col_num,col_num_data)
75
+ found_iter=nil
76
+ @data.each{|row_id,iter|
77
+ if iter[col_num]==col_num_data
78
+ found_iter=iter
79
+ break
80
+ end
81
+ }
82
+ found_iter
83
+ end
84
+
85
+ def set_iter_depth(row,depth_check=nil)
86
+ depth_check=Array.new if depth_check.nil?
87
+ if @tree_key
88
+ if piter=data_iter_of_col_num(@column_of_tree_parent,row[@column_of_tree])
89
+ unless depth_check.include?(piter[@column_of_id])
90
+ depth_check.push(piter[@column_of_id])
91
+ set_iter_depth(piter,depth_check)
92
+ # else
93
+ # print "circular child=>parent relation: ",depth_check.join("->"),"-/>",piter[@column_of_id],"\n"
94
+ end
95
+ row[@column_of_iter_depth]=piter[@column_of_iter_depth]+1
96
+ end
97
+ end
98
+ end
99
+
100
+ def child_iter_ids(iter_id)
101
+ chs=Array.new
102
+ @data.each{|chid,chrow|
103
+ chs.push(chid) if iter_id==chrow[@column_of_tree]
104
+ }
105
+ chs
106
+ end
107
+
108
+ def set_children_depth(ids)
109
+ ids.each{|iid|
110
+ if @data.has_key?(iid)
111
+ edebug("setting depth for: #{iid}")
112
+ set_iter_depth(@data[iid])
113
+ set_children_depth(child_iter_ids(iid))
114
+ end
115
+ }
116
+ end
117
+
118
+ def data_of_column(colname,lid)
119
+ ret=nil
120
+ if di=@data[lid] and col=headers[colname]
121
+ ret=di[col["model_col"]]
122
+ end
123
+ end
124
+
125
+ def create_skeleton
126
+ @moditem=@drbdb.admin.qrow("select moditems.*,`queries`.`sql`,tables.name as base_table from moditems left join `queries` on `queries`.`id` = `moditems`.`query_sql_id` left join tables on queries.base = tables.id where moditems.id='#{my_id}'")
127
+
128
+ #querysql
129
+ @querysql=@moditem['sql'] if !@moditem["sql"].nil? and @moditem["sql"].length>5
130
+ @querysql=@moditem['querysql'] if @moditem["querysql"].length>5
131
+
132
+ #base
133
+ @base=@moditem["base_table"]
134
+ @base=@drbdb.guess_table(querysql,"id") if @base.nil?
135
+
136
+ #id/list_key
137
+ @list_key=gtk_attribute("list_key") || "#{@base}.id"
138
+
139
+ @key_child=gtk_attribute("child_key")
140
+ @key_parent=gtk_attribute("parent_key")
141
+ @key_child2=gtk_attribute("second_child_key")
142
+ @key_parent2=gtk_attribute("second_parent_key")
143
+
144
+ if @tree_key=gtk_attribute("tree_key")
145
+ @tree_parent_key=gtk_attribute("tree_parent_key") || @list_key
146
+ end
147
+
148
+ @fetch_filter_key=gtk_attribute("fetch_filter_key")
149
+ @fetch_filter_value=gtk_attribute("fetch_filter_value")
150
+ @fetch_filter_negate=gtk_attribute("fetch_filter_negate") == 'true'
151
+ @background_key=gtk_attribute("background_key")
152
+ @foreground_key=gtk_attribute("foreground_key")
153
+ @archive_key=gtk_attribute("archive_key")
154
+
155
+ einfo("base:#{@base}, list_key:#{@list_key}, tree_key:#{@tree_key}, child_key: #{@key_child}, parent_key: #{@key_parent}, child_key2: #{@key_child2}, parent_key2: #{@key_parent2}") unless @drbdb.main_server.starting_up
156
+
157
+ @headers=Hash.new
158
+ headers[@list_key]= { "type" => "Bignum", "visible" => false, "data" => @list_key } #id
159
+ headers["visible_for_filter"]= { "type" => "TrueClass", "visible" => false, "data" => "visible_for_filter" } #visible_for_filter
160
+ headers["sensitive"]= { "type" => "TrueClass", "visible" => false, "data" => "sensitive" } #sensitive
161
+ headers[@background_key]= { "type" => "String", "visible" => false, "data" => @background_key } if @background_key
162
+ headers[@foreground_key]= { "type" => "String", "visible" => false, "data" => @foreground_key } if @foreground_key
163
+ headers[@tree_key]= { "type" => "Bignum", "visible" => false, "data" => @tree_key } if @tree_key
164
+ headers[@tree_parent_key]= { "type" => "Bignum", "visible" => false, "data" => @tree_parent_key } if (!@tree_parent_key.nil?)
165
+ headers["iter_depth"]= { "type" => "Bignum", "visible" => false, "data" => "iter_depth" } if @tree_key
166
+ headers[@key_child]= { "type" => "Bignum", "visible" => false, "data" => @key_child } if @key_child
167
+ headers[@key_child2]= { "type" => "Bignum", "visible" => false, "data" => @key_child2 } if @key_child2
168
+ headers[@fetch_filter_key]= { "type" => "String", "visible" => false, "data" => @fetch_filter_key } if @fetch_filter_key
169
+ headers[@archive_key]= { "type" => "TrueClass", "visible" => false, "data" => @archive_key } if @archive_key
170
+
171
+ hdebug="\nheaders from query:"
172
+ @drbdb.admin.rows("select * from gtkheaders where listing='#{my_id}' order by oid asc").each{|row|
173
+ headers[row["data"]]= row
174
+ headers[row["data"]]["visible"] = !(['gtk_invisible_int','gtk_invisible_string'].include?(row['type']))
175
+ hdebug="#{hdebug}\n #{row['data']} #{row['type']}"
176
+ }
177
+
178
+ @headertypes=Array.new
179
+ header_n=0
180
+ headers.each_value{|header|
181
+ header["model_col"]=header_n
182
+ case header['type']
183
+ when 'gtk_int','Integer','gtk_invisible_int','Bignum','gtk_duration','gtk_timestamp' then headertypes.push(Bignum)
184
+ when 'gtk_float','gtk_progress' then headertypes.push(Float)
185
+ when 'gtk_toggle','TrueClass' then headertypes.push(TrueClass)
186
+ # when 'gtk_pixbuf' then headertypes.push(Gdk::Pixbuf)
187
+ when 'gtk_pixbuf' then headertypes.push(Fixnum)
188
+ else
189
+ headertypes.push(String)
190
+ end
191
+ header_n+=1
192
+ }
193
+
194
+ @data=Hash.new
195
+
196
+ @column_of_id=headers[@list_key]["model_col"]
197
+ @column_of_visible=headers["visible_for_filter"]["model_col"]
198
+ @column_of_background=headers[@background_key]["model_col"] unless headers[@background_key].nil?
199
+ @column_of_foreground=headers[@foreground_key]["model_col"] unless headers[@foreground_key].nil?
200
+ @column_of_sensitive=headers["sensitive"]["model_col"]
201
+ @column_of_fetch_filter=if @fetch_filter_key then headers[@fetch_filter_key]["model_col"] else nil end
202
+ @column_of_archive=if @archive_key then headers[@archive_key]["model_col"] else nil end
203
+ hdebug="#{hdebug}\nheadertypes: #{@headertypes.inspect}\nheaders:\n"
204
+
205
+ @headers.each_value{|val| hdebug="#{hdebug} #{val['data']} #{val['model_col']}\n"}
206
+ # print "#{self} #{hdebug}\n"
207
+ @column_of_tree=nil
208
+ @column_of_tree_parent=nil
209
+ if @tree_key
210
+ @column_of_tree=if tree_header=headers[@tree_key] then tree_header["model_col"]; else nil;end
211
+ @column_of_tree_parent=if tree_parent_header=headers[@tree_parent_key] then tree_parent_header["model_col"] else nil end
212
+ @column_of_iter_depth=headers["iter_depth"]["model_col"]
213
+ end
214
+
215
+
216
+
217
+ @relations=Array.new
218
+ @drbdb.admin.rows("select * from relations where src_table='#{base}' or dst_table='#{base}'").each{|relation|
219
+ @relations.push(relation)
220
+ }
221
+
222
+ cache.set("#{@my_id}moditem",@moditem)
223
+ cache.set("#{@my_id}headers",@headers)
224
+ cache.set("#{@my_id}headertypes",@headertypes)
225
+ cache.set("#{@my_id}attributes",{
226
+ :querySQL=>@querysql,
227
+ :base=>@base,
228
+ :list_key=>@list_key,
229
+ :child_key=>@key_child,
230
+ :parent_key=>@key_parent,
231
+ :child_key2=>@key_child2,
232
+ :parent_key2=>@key_parent2,
233
+ :tree_key=>@tree_key,
234
+ :column_of_id=>@column_of_id,
235
+ :column_of_visible=>@column_of_visible,
236
+ :column_of_sensitive=>@column_of_sensitive,
237
+ :column_of_background=>@column_of_background,
238
+ :column_of_foreground=>@column_of_foreground,
239
+ :column_of_archive=>@column_of_archive,
240
+ :column_of_tree_parent=>@column_of_tree_parent,
241
+ :column_of_tree=>@column_of_tree,
242
+ :fetch_filter_key=>@fetch_filter_key,
243
+ :column_of_fetch_filter=>@column_of_fetch_filter,
244
+ :fetch_filter_value=>@fetch_filter_value,
245
+ :archive_key=>@archive_key
246
+ })
247
+
248
+ reset_buttons
249
+ reset_childs
250
+ self
251
+ end
252
+
253
+ def reset_childs
254
+ #loading childs
255
+ einfo("resetting childs") unless @drbdb.main_server.starting_up
256
+ @childs.clear
257
+ @drbdb.admin.rows("select moditems.id,moditems.display,moditems.oid,modules.modname from moditems left join modules on modid = modules.id where parent='#{my_id}' order by oid").each{|moditem|
258
+ @childs.push(moditem)
259
+ }
260
+ end
261
+
262
+ def reset_buttons
263
+ #loading buttons
264
+ einfo("resetting buttons") unless @drbdb.main_server.starting_up
265
+ @buttons.clear
266
+ @drbdb.admin.rows("select * from buttons where moditemid='#{my_id}' order by oid").each{|button|
267
+ @buttons.push(button)
268
+ }
269
+ notify_clients(nil,"buttons")
270
+ end
271
+
272
+ def update(notifier,ids=nil,rnick=nil)
273
+ before_update=Time.now
274
+ before=Time.now
275
+ if ids
276
+ if ids=='last' || ids == ["last"]
277
+ begin
278
+ sql=@drbdb.select_last(eval("\"#{querysql}\""),@list_key)
279
+ edebug(sql)
280
+ rescue =>err
281
+ eerror("update last: #{err}\n#{querysql}")
282
+ @drbdb.report_mail("update last: #{err}",{'self'=>self.inspect,'error'=>err.inspect,'query'=>querysql.inspect,'backtrace'=>err.backtrace.join("\n")})
283
+ end
284
+ else
285
+ ids=[ids] if ids.class != Array
286
+ begin
287
+ # sql=eval("\"select * from (#{querysql}) as the_query where #{@list_key} in (#{ids.join(',')})\"")
288
+ s=@drbdb.add_where("#{querysql}","#{@list_key} in (#{ids.join(',')})")
289
+ # edebug("query:#{s}")
290
+ sql=eeval("\"#{@drbdb.escape_string(s)}\"")
291
+ # edebug("query:#{sql}")
292
+ rescue =>err
293
+ eerror("update #{ids.inspect}: #{err}\n#{querysql}")
294
+ @drbdb.report_mail("update ids:#{ids.inspect}",{'self'=>self.inspect,'error'=>err.inspect,'query'=>querysql.inspect,'backtrace'=>err.backtrace.join("\n")})
295
+ end
296
+ end
297
+ else
298
+ begin
299
+ sql=eeval("\"#{@drbdb.escape_string(querysql)}\"") #'
300
+ rescue =>err
301
+ @drbdb.report_mail("update full: #{err}",{'self'=>self.inspect,'error'=>err.inspect,'query'=>querysql.inspect,'backtrace'=>err.backtrace.join("\n")})
302
+ end
303
+ end
304
+ begin
305
+ qres=@drbdb.rows(sql,true) if sql
306
+ rescue =>err
307
+ eerror("update: #{err}\n#{sql}")
308
+ @drbdb.report_mail("update: #{err}",{'self'=>self.inspect,'error'=>err.inspect,'query'=>querysql.inspect,'backtrace'=>err.backtrace.join("\n")})
309
+ end
310
+
311
+ sql_time_diff=Time.now.to_f-before.to_f
312
+
313
+ if qres then
314
+ unless ids
315
+ @data.clear
316
+ @rowcount=0
317
+ end
318
+ last_ids=nil
319
+ before=Time.now
320
+ qres.each{|row|
321
+ last_ids=[row[@list_key].to_i] if ids == "last" || ids == ["last"]
322
+ #warning about wrongly implemented queries, which force us to overwrite rows
323
+ ewarn("overwriting row ##{row[@list_key].to_i}:#{@data[row[@list_key].to_i].inspect}") if @data.has_key?(row[@list_key].to_i) and ids.class.name != "Array"
324
+ #history
325
+ row_backup=if !rnick.nil? && @data.has_key?(row[@list_key].to_i) then @data[row[@list_key].to_i].clone else nil end
326
+ #preserve row insensitivity(lock state)
327
+ row_insens=@data.has_key?(row[@list_key].to_i) ? @data[row[@list_key].to_i][@column_of_sensitive] : true
328
+ @data[row[@list_key].to_i]=Hash.new
329
+ iter=@data[row[@list_key].to_i]
330
+ headers.each_value{|header|
331
+ if row.has_key?(header['data'])
332
+ iter[header['model_col']]=
333
+ case header['type']
334
+ when 'gtk_toggle','TrueClass' then row[header['data']]=='true'
335
+ when 'gtk_int','Integer','gtk_invisible_int','Bignum','gtk_duration','gtk_timestamp' then row[header['data']].to_i
336
+ when 'gtk_float','gtk_progress' then row[header['data']].to_f
337
+ when 'gtk_pixbuf' then row[header['data']].to_i #we hold only ids here
338
+ else
339
+ row[header['data']]
340
+ end
341
+ #history
342
+ unless row_backup.nil?
343
+ if header.has_key?("id") && row_backup[header['model_col']] != iter[header['model_col']]
344
+ store_history(rnick,row[@list_key],"u",header['id'],row_backup[header['model_col']])
345
+ end
346
+ end
347
+ end
348
+ }
349
+ #history
350
+ store_history(rnick,row[@list_key],"i") if row_backup.nil? and !rnick.nil?
351
+ #defaults
352
+ iter[@column_of_sensitive]=row_insens
353
+ iter[@column_of_visible]=false
354
+ iter[@column_of_iter_depth]=0 if @tree_key
355
+ @rowcount+=1 unless ids
356
+ }
357
+
358
+ if ids and qres.size == 0
359
+ edebug("removed #{ids.inspect}")
360
+ #we were called to load_data of a non existing id, which means it was deleted
361
+ ids.each{|id_to_remove|
362
+ @data.delete(id_to_remove.to_i);
363
+ einfo("removing from cache: #{id_to_remove.inspect}")
364
+ begin
365
+ cache.delete("#{@my_id}[#{id_to_remove}]")
366
+ rescue Memcached::NotFound
367
+ end
368
+ @rowcount-=1;
369
+ store_history(rnick,id_to_remove,"d") unless rnick.nil?
370
+ }
371
+ end
372
+ end
373
+ download_time_diff=Time.now.to_f-before.to_f
374
+ before=Time.now
375
+ if @tree_key
376
+ #set up the iter depth, for tree building
377
+ if ids.nil?
378
+ #full reload
379
+ @data.each_value{|row| set_iter_depth(row)}
380
+ else
381
+ #set iter_depth for all recursive children
382
+ set_children_depth(ids)
383
+ end
384
+ end
385
+ tree_prep_time_diff=Time.now.to_f-before.to_f
386
+ before=Time.now
387
+ if @tree_key
388
+ keys=Array.new
389
+ tree_sorted.each{|row| keys.push(row[@column_of_id])}
390
+ else
391
+ keys=@data.keys
392
+ end
393
+
394
+ if ids.nil?
395
+ @data.each{|key,row|
396
+ cache.set("#{@my_id}[#{key}]",row)
397
+ }
398
+ else
399
+ ids.each{|iid|
400
+ cache.set("#{@my_id}[#{iid}]",@data[iid])
401
+ }
402
+ end
403
+ cache.set("#{@my_id}[ids]",keys)
404
+
405
+ cache_time_diff=Time.now.to_f-before.to_f
406
+
407
+ ids=last_ids unless last_ids.nil?
408
+ update_time_diff=Time.now.to_f-before_update.to_f
409
+ einfo("loaded #{if ids then ids.inspect else @rowcount end}/#{@data.size} in q:"+sprintf("%.1fs",sql_time_diff)+",d:"+sprintf("%.1fs",download_time_diff)+",t:"+sprintf("%.1fs",tree_prep_time_diff)+",c:"+sprintf("%.1fs",cache_time_diff)+"/"+sprintf("%.1fs",update_time_diff)) unless @drbdb.main_server.starting_up
410
+ notify_clients(ids)
411
+ ids
412
+ end
413
+
414
+ def tree_sorted
415
+ if @tree_key
416
+ @data.values.sort{|a,b|
417
+ a[@column_of_iter_depth]<=>b[@column_of_iter_depth]
418
+ }
419
+ else
420
+ @data.values
421
+ end
422
+ end
423
+
424
+ def filtered_fetch(ff_value=nil)
425
+ t=Thread.new{
426
+ einfo("serving")
427
+ before=Time.now
428
+ served_rows=0
429
+ tree_sorted.each{|row_id,row|
430
+ if @column_of_fetch_filter.nil? or ff_value.nil? or (not @fetch_filter_negate and row[@column_of_fetch_filter].to_s == ff_value.to_s) or (@fetch_filter_negate and row[@column_of_fetch_filter].to_s != ff_value.to_s)
431
+ yield row
432
+ served_rows+=1
433
+ end
434
+ }
435
+ yield served_rows
436
+ serve_time=Time.now.to_f-before.to_f
437
+ einfo("served #{served_rows}(of #{@rowcount}) in "+sprintf("%.2fs",serve_time))
438
+ }
439
+ end
440
+
441
+ def filtered_fetch2(ff_value=nil,archive=false)
442
+ # t=Thread.new{
443
+ before=Time.now.to_f
444
+ tree=tree_sorted
445
+ sort_time=Time.now.to_f
446
+ ret=Array.new
447
+ tree.each{|row|
448
+ ret.push(row) if (@column_of_fetch_filter.nil? || ff_value.nil? || (!@fetch_filter_negate && row[@column_of_fetch_filter].to_s == ff_value.to_s) || (@fetch_filter_negate && row[@column_of_fetch_filter].to_s != ff_value.to_s) ) && (@column_of_archive.nil? || (archive || !row[@column_of_archive]))
449
+ }
450
+ end_time=Time.now.to_f
451
+ einfo("serving #{ret.size}(of #{@rowcount}) (sort:"+sprintf("%.2fs",sort_time-before)+" filter:"+sprintf("%.2fs",end_time-sort_time)+") "+sprintf("%.2fs",end_time-before))
452
+ # }
453
+ ret
454
+ end
455
+
456
+ def rows_changed(chids,nick=nil,chseq=0)
457
+ ids=if chids.class.name == "Array" then chids.clone else [chids] end
458
+ #prevent circular calling of rows_changed
459
+ chseq=Time.new.to_f-@my_id if chseq == 0 #FIXME: not unique
460
+
461
+ # edebug("rows_changed:@#{chseq}:#{nick}:#{ids.inspect}")
462
+ ids_to_remove=Array.new
463
+ ids.each{|ch_id|
464
+ if @last_seq[ch_id] == chseq
465
+ ids_to_remove.push(ch_id)
466
+ else
467
+ @last_seq[ch_id]=chseq
468
+ end
469
+ }
470
+ ids_to_remove.each{|to_rem| ids.delete(to_rem)}
471
+
472
+ return unless ids.size > 0
473
+
474
+ #precaching related ids, thus if update deletes a row, we still have the required data to walk the map
475
+ pre_ids=Hash.new
476
+ @drbdb.moditems_with_base(base){|other_list|
477
+ unless other_list == self
478
+ pre_ids[other_list]=Array.new unless pre_ids.has_key?(other_list)
479
+ ids.each{|i| pre_ids[other_list].push(i)}
480
+ end
481
+ }
482
+
483
+ @relations.each{|relation|
484
+ if (relation['src_table'] == base) || (relation['dst_table'] == base && relation['rel_type'] == 'o')
485
+ #forward, update parent lists for group_by queries
486
+ #update lists with relation.src_table.src_field == relation.dst_table.dst_field
487
+ @drbdb.moditems_with_base(relation['dst_table']){|other_list|
488
+ pre_ids[other_list]=Array.new unless pre_ids.has_key?(other_list) #might already be there if multiple relations to each other
489
+ ids.each{|changed_id|
490
+ if other_id=data_of_column(relation['src_table']+"."+relation['src_field'],changed_id)
491
+ pre_ids[other_list].push(other_id.to_i)
492
+ end
493
+ }
494
+ }
495
+ #else
496
+ #reverse, update client lists, should be used only if this relation_id is used in the client query
497
+ #update lists with dst_field == src_table.src_field
498
+ end
499
+ }
500
+
501
+ rnick=if nick.nil? then nil else nick.clone end
502
+ ids=update(nil,ids,rnick)
503
+
504
+ #postcaching again, if update was insert we have the data to walk the map
505
+ @relations.each{|relation|
506
+ if (relation['src_table'] == base) || (relation['dst_table'] == base && relation['rel_type'] == 'o')
507
+ #forward, update parent lists for group_by queries
508
+ #update lists with relation.src_table.src_field == relation.dst_table.dst_field
509
+ @drbdb.moditems_with_base(relation['dst_table']){|other_list|
510
+ pre_ids[other_list]=Array.new unless pre_ids.has_key?(other_list) #might already be there
511
+ ids.each{|changed_id|
512
+ if other_id=data_of_column(relation['src_table']+"."+relation['src_field'],changed_id)
513
+ pre_ids[other_list].push(other_id.to_i)
514
+ end
515
+ }
516
+ # ecode("postcache #{other_list}:#{pre_ids[other_list].inspect}")
517
+ }
518
+ #else
519
+ #reverse, update client lists, should be used only if this relation_id is used in the client query
520
+ #update lists with dst_field == src_table.src_field
521
+ end
522
+ }
523
+ # ecode("notifying other drblists with base:#{@base} for #{ids.inspect}")
524
+ @drbdb.moditems_with_base(base){|other_list|
525
+ #drblist.rows_changed(ids,nil,chseq) unless drblist == self
526
+ unless other_list == self
527
+ pre_ids[other_list]=Array.new unless pre_ids.has_key?(other_list)
528
+ ids.each{|i| pre_ids[other_list].push(i)}
529
+ # ecode("postcache #{other_list}:#{pre_ids[other_list].inspect}")
530
+ end
531
+ }
532
+
533
+ # ecode("notifying other drblists related to:#{@base} for #{ids.inspect}")
534
+ # ecode("pre_ids:#{pre_ids.inspect}")
535
+ pre_ids.each{|other_model,other_ids|
536
+ other_ids.uniq!
537
+ # ecode("#{other_model}:#{other_ids.inspect}/@#{chseq}")
538
+ other_model.rows_changed(other_ids,nil,chseq)
539
+ }
540
+ end
541
+
542
+ def duplicate_iter(iter_to_dup)
543
+ sql="insert into #{base} set ";
544
+ q=@drbdb.query("select * from #{base} where #{@list_key}='#{iter_to_dup[@column_of_id]}'")
545
+ colon=false
546
+ if row=q.fetch_hash()
547
+ row.each { |field,data|
548
+ if "#{base}.#{field}"!=@list_key and data
549
+ sql="#{sql}, " if colon
550
+ colon=true
551
+ sql="#{sql} `#{field}`='#{@drbdb.escape_string(data)}' "
552
+ end
553
+ }
554
+ end
555
+ @drbdb.query(sql)
556
+ rows_changed("last")
557
+ # load_data(nil,"last")
558
+ end
559
+
560
+ def remove_iters(ids_to_remove,nick=nil)
561
+ unless base.nil?
562
+ @drbdb.query("delete from #{base} where #{@list_key} in (#{ids_to_remove.join(",")})")
563
+ einfo("removing ids: #{ids_to_remove.inspect}")
564
+ rows_changed(ids_to_remove,nick)
565
+ end
566
+ end
567
+ =begin
568
+ #not yet used
569
+ def change_value_of_iter(iter, column_data, new_value)
570
+ sql="update #{base} set `#{column_data}`='#{new_value}' where `id`='#{iter[column_of_id]}' limit 1"
571
+ einfo("changing #{column_data} to #{new_value} updatesql: #{sql}","list")
572
+ @drbdb.query(prepare_sql(sql,self))
573
+ rows_changed(iter[column_of_id].to_i)
574
+ end
575
+ def change_value_of_path(path, column_data, new_value)
576
+ change_value_of_iter(@sorter.get_iter(path), column_data, new_value)
577
+ end
578
+ =end
579
+
580
+ def subscribe(client)
581
+ if @clients.include?(client)
582
+ false
583
+ else
584
+ # ecode("subscribing: #{client}, #{client.inspect}")
585
+ @clients.push(client)
586
+ true
587
+ end
588
+ end
589
+
590
+ def unsubscribe(client)
591
+ # ecode("unsubscribing: #{client}, #{client.inspect}")
592
+ @clients.delete(client)
593
+ end
594
+
595
+ def notify_clients(*args)
596
+ to_remove=Array.new
597
+ th=Array.new
598
+ edebug("notifying #{@clients.size} clients for #{args.inspect}") unless @drbdb.main_server.starting_up || @clients.size==0
599
+ @clients.each{|client|
600
+ th << Thread.new{
601
+ begin
602
+ if client.alive?
603
+ client.update(self.class.name,*args)
604
+ end
605
+ rescue =>err
606
+ ecode("#{err.inspect}\n\t#{err.backtrace.join("\n\t")}")
607
+ to_remove.push(client)
608
+ end
609
+ }
610
+ }
611
+ th.each{|t| t.join}
612
+ to_remove.each{|dead|
613
+ @clients.delete(dead)
614
+ edebug("dead client deleted")
615
+ }
616
+ end
617
+
618
+ def store_history(nick,row_id,operation,header_id=nil,data=nil)
619
+ # ecode("storing history: nick:#{nick},op:#{operation}, id:#{row_id}, header:#{header_id}, data:#{data}")
620
+ sql="insert into `history` set `ctime`=now(), `nick`='#{nick}', `base`='#{@base}', `row_id`='#{row_id}', `operation`='#{operation}'"
621
+ sql+=", `header_id`='#{header_id}'" unless header_id.nil?
622
+ sql+=",`data`='#{@drbdb.escape_string(data.to_s)}'" unless data.nil?
623
+ @drbdb.admin.query(sql)
624
+ end
625
+
626
+ def buttons(user_id)
627
+ ret=Array.new
628
+ @buttons.each{|button|
629
+ ret.push(button) if button["grp_id"].to_i < 1 || @drbdb.user_in_group?(user_id.to_i,button["grp_id"].to_i)
630
+ }
631
+ ret
632
+ end
633
+
634
+ def childs
635
+ @childs
636
+ end
637
+ def cache
638
+ @drbdb.cache
639
+ end
640
+
641
+ def alive?
642
+ @drbdb.alive?
643
+ end
644
+
645
+ def remove_dead_clients
646
+ alive_clients=0
647
+ to_remove=Array.new
648
+ clients.each{|client|
649
+ begin
650
+ client.alive?
651
+ alive_clients+=1
652
+ rescue
653
+ to_remove.push(client)
654
+ end
655
+ }
656
+ to_remove.each{|dead|
657
+ ewarn("removed dead subscription: #{dead.inspect}")
658
+ clients.delete(dead)
659
+ }
660
+ alive_clients
661
+ end
662
+
663
+ # def method_missing(sym,*args)
664
+ # print "\n!#{self} missing method: #{sym}(#{args})\n"
665
+ # end
666
+ def getBinding
667
+ binding
668
+ end
669
+
670
+ end
671
+