Class: Qreport::ReportRunner

Inherits:
Object
  • Object
show all
Defined in:
lib/qreport/report_runner.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#argumentsObject

Returns the value of attribute arguments.



11
12
13
# File 'lib/qreport/report_runner.rb', line 11

def arguments
  @arguments
end

#connectionObject Also known as: conn

Returns the value of attribute connection.



10
11
12
# File 'lib/qreport/report_runner.rb', line 10

def connection
  @connection
end

#errorObject

Returns the value of attribute error.



12
13
14
# File 'lib/qreport/report_runner.rb', line 12

def error
  @error
end

#error_1Object

Returns the value of attribute error_1.



12
13
14
# File 'lib/qreport/report_runner.rb', line 12

def error_1
  @error_1
end

#error_2Object

Returns the value of attribute error_2.



12
13
14
# File 'lib/qreport/report_runner.rb', line 12

def error_2
  @error_2
end

#report_runObject

Returns the value of attribute report_run.



11
12
13
# File 'lib/qreport/report_runner.rb', line 11

def report_run
  @report_run
end

#sqlObject

Returns the value of attribute sql.



11
12
13
# File 'lib/qreport/report_runner.rb', line 11

def sql
  @sql
end

#verboseObject

Returns the value of attribute verbose.



10
11
12
# File 'lib/qreport/report_runner.rb', line 10

def verbose
  @verbose
end

Instance Method Details

#infer_base_columns!Object



107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/qreport/report_runner.rb', line 107

def infer_base_columns!
  base_columns = nil
  begin
    conn.transaction do
      # Proof query to infer base columns:
      result = run report_sql(sql, :limit => 'LIMIT 0'), :arguments => arguments, :verbose => @verbose
      base_columns = report_run.base_columns = result.columns
    end # transaction
  rescue ::StandardError => exc
    @error = @error_1 = exc
  end
  base_columns
end

#report_sql(sql, opts = { }) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/qreport/report_runner.rb', line 121

def report_sql sql, opts = { }
  sql = sql.sub(/;\s*\Z/, '')
  sql = <<"END"
SELECT
:qr_run_id
   AS "qr_run_id"
  , nextval('qr_row_seq')
   AS "qr_run_row"
  , _qr_r_.*
FROM (
#{sql}
) AS "_qr_r_"
#{opts[:limit]}
END
  sql
end

#run(*args) ⇒ Object



138
139
140
141
# File 'lib/qreport/report_runner.rb', line 138

def run *args
  # conn.verbose = true
  conn.run *args
end

#run!(report_run) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/qreport/report_runner.rb', line 14

def run! report_run
  @verbose ||= report_run.verbose
  @report_run = report_run
  report_run.created_at ||=
    report_run.started_at = Time.now.utc
  name = report_run.name
  @sql = report_run.sql.strip

  @arguments = report_run.arguments || { }
  @error = @error_1 = @error_2 = nrows = nil

  Connection.current = connection

  # Rewrite query to create result table rows:
  self.arguments = arguments.merge(:qr_run_id => conn.safe_sql("nextval('qr_row_seq')"))
  report_run.report_sql = report_sql(sql)

  conn.transaction do
    # Create a report row sequence:
    run "DROP SEQUENCE IF EXISTS   qr_row_seq"
    run "CREATE TEMPORARY SEQUENCE qr_row_seq"
    # Infer base columns, if not specified.
    if report_run.base_columns.empty?
      infer_base_columns!
    end
  end

  # Construct report_table name from column names and types:
  report_table = report_run.report_table

  unless report_run.id
    conn.transaction do
      # Create new ReportRun row:
      report_run.insert!
    end # transaction
  end
  arguments[:qr_run_id] = report_run.id

  unless error
    # Run query into report table:
    begin
      conn.transaction do
        # Create a report row sequence:
        run "DROP SEQUENCE IF EXISTS   qr_row_seq"
        run "CREATE TEMPORARY SEQUENCE qr_row_seq"

        unless conn.table_exists? report_table
          result =
          run "CREATE TABLE #{report_table} AS #{report_run.report_sql}", :arguments => arguments, :verbose => @verbose
          run "CREATE INDEX #{report_table}_i1 ON #{report_table} (qr_run_id)"
          run "CREATE INDEX #{report_table}_i2 ON #{report_table} (qr_run_row)"
          run "CREATE UNIQUE INDEX #{report_table}_i3 ON #{report_table} (qr_run_id, qr_run_row)"
          report_run.additional_columns.each do | n, t, d |
            run "ALTER TABLE #{report_table} ADD COLUMN #{conn.escape_identifier(n)} #{t} DEFAULT :d", :arguments => { :d => d || nil }
          end
        else
          result =
          run "INSERT INTO #{report_table} #{report_run.report_sql}", :arguments => arguments, :verbose => @verbose
          # Get the number of report run rows from cmd_status:
          unless cs = result.cmd_status and cs[0] == 'INSERT' and cs[1] == 0 and nrows = cs[2]
            raise Error, "cannot determine nrows"
          end
        end
        report_run.raw_sql = result.sql_prepared
        # $stderr.puts ">>>>>>>>>>>>>>>>>>> #{result.sql_prepared}"
        # Get the number of report run rows:
        unless nrows || error
          result = report_run._select :COLUMNS => 'COUNT(*) AS "nrows"' #, :verbose => true
          nrows = result.rows[0]["nrows"] || (raise Error, "cannot determine nrows")
        end

        run "DROP SEQUENCE IF EXISTS qr_row_seq"
        # pp result
        result = nil
      end # transaction
    rescue ::StandardError => exc
      @error = @error_2 = exc
    end # transaction
  end

  conn.transaction do
    run "DROP SEQUENCE IF EXISTS qr_row_seq"

    # Update stats:
    report_run.finished_at = Time.now.utc
    report_run.nrows = nrows.to_i
    report_run.error = error
    report_run.update! :values => [ :nrows, :finished_at, :error ] # , :verbose_result => true
  end # transaction

  report_run
end