Diff -- /var/www/vhosts/3dshawn.com/site1/schema_changes.cgi
Diff

/var/www/vhosts/3dshawn.com/site1/schema_changes.cgi

modified on local at 2026-07-13 20:26:14

Added
+78
lines
Removed
-4
lines
Context
105
unchanged
Blobs
from dbd198527dfc
to 83493eecda27
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
11#!/usr/bin/perl
22use strict;
33use warnings;
44use CGI ();
55use MODS::Config; use MODS::DBConnect; use MODS::Template; use MODS::PageWrapper;
66use MODS::Charts;
77use MODS::RangePicker;
88use POSIX ();
99my $cgi = CGI->new; my $db = MODS::DBConnect->new; my $tpl = MODS::Template->new;
1010$|=1; print "Content-Type: text/html; charset=utf-8\nCache-Control: no-cache\n\n";
1111my $dbh = $db->db_connect or die "DB connect failed\n";
1212
1313my $r = MODS::RangePicker::parse($cgi);
1414my $q = $cgi->param('q') || '';
15my $show_baseline = $cgi->param('baseline') ? 1 : 0;
16# Status tab: modified | added | deleted | all
17my $status_filter = lc($cgi->param('status') // 'all');
18$status_filter = 'all' unless $status_filter =~ /^(modified|added|deleted|all)$/;
1519
16my $where = $r->{sql_where}->('sc.change_datetime');
17$where .= " AND (sc.database_name LIKE " . $dbh->quote('%'.$q.'%')
18 . " OR sc.table_name LIKE " . $dbh->quote('%'.$q.'%') . ")" if length $q;
20my $where_base = $r->{sql_where}->('sc.change_datetime');
21$where_base .= " AND (sc.database_name LIKE " . $dbh->quote('%'.$q.'%')
22 . " OR sc.table_name LIKE " . $dbh->quote('%'.$q.'%') . ")" if length $q;
23$where_base .= " AND sc.is_baseline = 0" unless $show_baseline;
24
25# Classify a schema-change row into modified / added / deleted based on the
26# changes text. We derive the tab counts + filter clause from this.
27# added = "first snapshot" (a brand-new table appears in the DB)
28# deleted = "table dropped" (the table went away between scans)
29# modified = anything else (real DDL diff)
30my $status_expr = q~
31 CASE
32 WHEN sc.changes LIKE 'first snapshot%' THEN 'added'
33 WHEN sc.changes LIKE 'table dropped%' THEN 'deleted'
34 ELSE 'modified'
35 END
36~;
37
38my %status_counts = (all => 0, modified => 0, added => 0, deleted => 0);
39{
40 my @cnt = $db->db_readwrite_multiple($dbh, qq~
41 SELECT $status_expr AS kind, COUNT(*) AS n
42 FROM SCHEMA_CHANGE sc WHERE $where_base GROUP BY kind
43 ~, __FILE__, __LINE__);
44 foreach my $row (@cnt) {
45 my $k = lc($row->{kind} // '');
46 $status_counts{$k} = $row->{n} if exists $status_counts{$k};
47 $status_counts{all} += $row->{n};
48 }
49}
50
51my $where = $where_base;
52if ($status_filter ne 'all') {
53 my %sql_extra = (
54 added => "sc.changes LIKE 'first snapshot%'",
55 deleted => "sc.changes LIKE 'table dropped%'",
56 modified => "sc.changes NOT LIKE 'first snapshot%' AND sc.changes NOT LIKE 'table dropped%'",
57 );
58 $where .= " AND (" . $sql_extra{$status_filter} . ")" if $sql_extra{$status_filter};
59}
1960
2061my @rows = $db->db_readwrite_multiple($dbh, qq~
2162 SELECT sc.schema_change_id AS id, sc.database_name, sc.table_name, sc.changes,
2263 UNIX_TIMESTAMP(sc.change_datetime) AS ts_epoch,
23 sc.change_datetime, sc.is_ts_only, s.server_name
64 sc.change_datetime, sc.is_ts_only, sc.is_baseline, s.server_name
2465 FROM SCHEMA_CHANGE sc
2566 LEFT JOIN SERVERS s ON s.server_id = sc.server_id
2667 WHERE $where
2768 ORDER BY sc.change_datetime DESC
2869 LIMIT 200
2970~, __FILE__, __LINE__);
71
72# Baseline hidden count for the header hint
73my $baseline_hidden = 0;
74unless ($show_baseline) {
75 my $bwhere = $r->{sql_where}->('sc.change_datetime');
76 $bwhere .= " AND (sc.database_name LIKE " . $dbh->quote('%'.$q.'%')
77 . " OR sc.table_name LIKE " . $dbh->quote('%'.$q.'%') . ")" if length $q;
78 $bwhere .= " AND sc.is_baseline = 1";
79 my $bh = $db->db_readwrite($dbh, "SELECT COUNT(*) AS n FROM SCHEMA_CHANGE sc WHERE $bwhere", __FILE__, __LINE__);
80 $baseline_hidden = ($bh && $bh->{n}) || 0;
81}
3082
3183my %spark;
3284{
3385 my %pairs;
3486 foreach my $row (@rows) {
3587 my $key = ($row->{database_name} // '') . '|' . ($row->{table_name} // '');
3688 $pairs{$key} = [ $row->{database_name}, $row->{table_name} ];
3789 }
3890 my @conds;
3991 foreach my $p (values %pairs) {
4092 my $qd = $dbh->quote($p->[0] // '');
4193 my $qt = $dbh->quote($p->[1] // '');
4294 push @conds, "(database_name = $qd AND table_name = $qt)";
4395 }
4496 if (@conds) {
4597 my $or = join(' OR ', @conds);
4698 my @day_rows = $db->db_readwrite_multiple($dbh, qq~
4799 SELECT database_name, table_name,
48100 DATE_FORMAT(change_datetime, '%Y-%m-%d') AS d,
49101 COUNT(*) AS n
50102 FROM SCHEMA_CHANGE
51103 WHERE ($or)
52104 AND change_datetime >= DATE_SUB(NOW(), INTERVAL 30 DAY)
53105 GROUP BY database_name, table_name, d
54106 ~, __FILE__, __LINE__);
55107 my %by;
56108 foreach my $dr (@day_rows) {
57109 my $key = ($dr->{database_name} // '') . '|' . ($dr->{table_name} // '');
58110 $by{$key}{$dr->{d}} = $dr->{n};
59111 }
60112 my $now = time;
61113 my @day_keys;
62114 for (my $i = 29; $i >= 0; $i--) {
63115 push @day_keys, POSIX::strftime('%Y-%m-%d', localtime($now - $i * 86400));
64116 }
65117 foreach my $key (keys %pairs) {
66118 my @series;
67119 for my $k (@day_keys) { push @series, ($by{$key}{$k} || 0); }
68120 $spark{$key} = \@series;
69121 }
70122 }
71123}
72124
73125foreach my $row (@rows) {
74126 my $c = $row->{changes} // '';
75127 $c =~ s/\s+/ /g;
76128 $row->{changes_preview} = length($c) > 100 ? substr($c, 0, 97) . '...' : $c;
77129 $row->{diff_url} = "/diff.cgi?kind=schema&id=$row->{id}";
78130 $row->{ts_epoch} //= 0;
79131 my $key = ($row->{database_name} // '') . '|' . ($row->{table_name} // '');
80132 my $series = $spark{$key};
81133 $row->{sparkline_svg} = $series
82134 ? MODS::Charts::sparkline(values => $series, width => 88, height => 20, color => '#f59e0b')
83135 : '';
84136}
85137my $total = scalar @rows;
86138
87139$db->db_disconnect($dbh);
88140
89141my $picker_html = MODS::RangePicker::picker_html(
90142 action => '/schema_changes.cgi',
91143 range => $r,
92144 hidden => { q => $q },
93145);
94146
95147my $tvars = {
96148 rows => \@rows,
97149 has_rows => $total ? 1 : 0,
98150 total => $total,
99151 q => $q,
100152 picker_html => $picker_html,
101153 range_label => $r->{range_label},
102154 is_day_view => $r->{is_day} ? 1 : 0,
103155 day_label => $r->{on},
156 show_baseline => $show_baseline,
157 baseline_hidden => $baseline_hidden,
158 has_baseline_hidden => $baseline_hidden ? 1 : 0,
159 tab_all_active => ($status_filter eq 'all') ? 1 : 0,
160 tab_modified_active => ($status_filter eq 'modified') ? 1 : 0,
161 tab_added_active => ($status_filter eq 'added') ? 1 : 0,
162 tab_deleted_active => ($status_filter eq 'deleted') ? 1 : 0,
163 tab_all_count => $status_counts{all},
164 tab_modified_count => $status_counts{modified},
165 tab_added_count => $status_counts{added},
166 tab_deleted_count => $status_counts{deleted},
167 status_filter => $status_filter,
168 tab_qs_extra => join('',
169 (length $q ? "&q=" . _urlenc($q) : ''),
170 ($show_baseline ? "&baseline=1" : ''),
171 ),
104172};
105173my @body = $tpl->template('schema_changes.html', $tvars);
106174MODS::PageWrapper->new->wrapper(
107175 page_title => 'Schema changes', page_key => 'schema_changes',
108176 body_html => join('', @body), userinfo => { display_name => 'Operator' },
109177);
178
179sub _urlenc {
180 my $s = shift; $s //= '';
181 $s =~ s/([^A-Za-z0-9\-\._~])/sprintf('%%%02X', ord($1))/eg;
182 return $s;
183}
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help