Skip to content

Commit

Permalink
feat: handle links without table contents
Browse files Browse the repository at this point in the history
  • Loading branch information
williamdes committed Mar 23, 2024
1 parent 70dafa1 commit 20871d6
Show file tree
Hide file tree
Showing 2 changed files with 316 additions and 14 deletions.
136 changes: 136 additions & 0 deletions src/rust/data/mysql_test_case_9.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<li class="listitem">
<p><a name="sysvar_group_concat_max_len"></a>
<a class="link" href="server-system-variables.html#sysvar_group_concat_max_len"><code
class="literal">group_concat_max_len</code></a>
</p><a class="indexterm" name="idm45428599657216"></a><a class="indexterm" name="idm45428599656176"></a>
<div class="informaltable">
<table frame="box" rules="all" summary="Properties for group_concat_max_len">
<colgroup>
<col style="width: 30%">
<col style="width: 70%">
</colgroup>
<tbody>
<tr>
<th>Command-Line Format</th>
<td><code class="literal">--group-concat-max-len=#</code></td>
</tr>
<tr>
<th>System Variable</th>
<td><code
class="literal"><a class="link" href="server-system-variables.html#sysvar_group_concat_max_len">group_concat_max_len</a></code>
</td>
</tr>
<tr>
<th>Scope</th>
<td>Global, Session</td>
</tr>
<tr>
<th>Dynamic</th>
<td>Yes</td>
</tr>
<tr>
<th><a class="link" href="optimizer-hints.html#optimizer-hints-set-var"
title="Variable-Setting Hint Syntax"><code class="literal">SET_VAR</code></a> Hint Applies
</th>
<td>Yes</td>
</tr>
<tr>
<th>Type</th>
<td>Integer</td>
</tr>
<tr>
<th>Default Value</th>
<td><code class="literal">1024</code></td>
</tr>
<tr>
<th>Minimum Value</th>
<td><code class="literal">4</code></td>
</tr>
<tr>
<th>Maximum Value (64-bit platforms)</th>
<td><code class="literal">18446744073709551615</code></td>
</tr>
<tr>
<th>Maximum Value (32-bit platforms)</th>
<td><code class="literal">4294967295</code></td>
</tr>
</tbody>
</table>
</div>
<p>
The maximum permitted result length in bytes for the
<a class="link" href="aggregate-functions.html#function_group-concat"><code
class="literal">GROUP_CONCAT()</code></a> function. The
default is 1024.
</p>
</li>
<li class="listitem">
<p><a name="sysvar_have_compress"></a>
<a class="link" href="server-system-variables.html#sysvar_have_compress"><code
class="literal">have_compress</code></a>
</p><a class="indexterm" name="idm45428599623024"></a><a class="indexterm" name="idm45428599621936"></a>
<p>
<code class="literal">YES</code> if the <code class="literal">zlib</code>
compression library is available to the server,
<code class="literal">NO</code> if not. If not, the
<a class="link" href="encryption-functions.html#function_compress"><code class="literal">COMPRESS()</code></a>
and
<a class="link" href="encryption-functions.html#function_uncompress"><code
class="literal">UNCOMPRESS()</code></a> functions cannot
be used.
</p>
</li>
<li class="listitem">
<p><a name="sysvar_have_dynamic_loading"></a>
<a class="link" href="server-system-variables.html#sysvar_have_dynamic_loading"><code
class="literal">have_dynamic_loading</code></a>
</p><a class="indexterm" name="idm45428599612960"></a><a class="indexterm" name="idm45428599611920"></a>
<p>
<code class="literal">YES</code> if <a class="link" href="mysqld.html"
title="6.3.1&nbsp;mysqld — The MySQL Server"><span class="command"><strong>mysqld</strong></span></a>
supports
dynamic loading of plugins, <code class="literal">NO</code> if not. If
the value is <code class="literal">NO</code>, you cannot use options
such as <code class="literal">--plugin-load</code> to load
plugins at server startup, or the <a class="link" href="install-plugin.html"
title="15.7.4.4&nbsp;INSTALL PLUGIN Statement"><code class="literal">INSTALL
PLUGIN</code></a> statement to load plugins at runtime.
</p>
</li>
<li class="listitem">
<p><a name="sysvar_have_geometry"></a>
<a class="link" href="server-system-variables.html#sysvar_have_geometry"><code
class="literal">have_geometry</code></a>
</p><a class="indexterm" name="idm45428599602032"></a><a class="indexterm" name="idm45428599600944"></a>
<p>
<code class="literal">YES</code> if the server supports spatial data
types, <code class="literal">NO</code> if not.
</p>
</li>
<li class="listitem">
<p><a name="sysvar_have_openssl"></a>
<a class="link" href="server-system-variables.html#sysvar_have_openssl"><code
class="literal">have_openssl</code></a>
</p><a class="indexterm" name="idm45428599595264"></a><a class="indexterm" name="idm45428599594176"></a>
<p>
This variable is a synonym for
<a class="link" href="server-system-variables.html#sysvar_have_ssl"><code class="literal">have_ssl</code></a>.
</p>
<p>
As of MySQL 8.0.26,
<a class="link" href="server-system-variables.html#sysvar_have_openssl"><code
class="literal">have_openssl</code></a> is deprecated
and subject to removal in a future MySQL version. For
information about TLS properties of MySQL connection
interfaces, use the
<a class="link" href="performance-schema-tls-channel-status-table.html"
title="29.12.21.9&nbsp;The tls_channel_status Table"><code class="literal">tls_channel_status</code></a>
table.
</p>
</li>
<li class="listitem">
<p>
<a class="link" href="innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit"><code
class="literal">innodb_flush_log_at_trx_commit=1</code></a>.
</p>
</li>
194 changes: 180 additions & 14 deletions src/rust/mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::data::{KbParsedEntry, PageProcess, QueryResponse};
use select::document::Document;
use select::node::Node;
use select::predicate::{Class, Name};
use std::collections::HashSet;

fn find_table_archor(node: Node) -> String {
let mut collected_p_nodes: Vec<Node> = vec![];
Expand Down Expand Up @@ -36,21 +37,25 @@ fn find_table_archor(node: Node) -> String {

match anchor_name_node {
Some(node) => node.attr("name").unwrap().to_string(),
None => node
.parent()
.expect("Has a parent")
.find(Class("link"))
.next()
.unwrap()
.attr("href")
.expect("Missing href attr")
.split("#")
.last()
.expect("Anchor to have #")
.to_string(),
None => link_to_archor(
node.parent()
.expect("Has a parent")
.find(Class("link"))
.next()
.unwrap(),
),
}
}

fn link_to_archor(node: Node) -> String {
node.attr("href")
.expect("Missing href attr")
.split("#")
.last()
.expect("Anchor to have #")
.to_string()
}

fn process_row_to_entry(
row_name: String,
row_node: Node,
Expand Down Expand Up @@ -202,6 +207,31 @@ fn process_row_to_entry(
entry
}

fn process_link(li_node: Node) -> KbParsedEntry {
KbParsedEntry {
has_description: false,
is_removed: false,
cli: None,
default: None,
dynamic: None,
id: match li_node.find(Class("link")).next() {
Some(node) => Some(link_to_archor(node)),
None => None,
},
name: match li_node.find(Class("link")).next() {
Some(node) => Some(match node.text().split("=").next() {
Some(data) => data.to_string(),
None => node.text(),
}),
None => None,
},
scope: None,
r#type: None,
valid_values: None,
range: None,
}
}

fn process_table(table_node: Node) -> KbParsedEntry {
let mut entry = KbParsedEntry {
has_description: false,
Expand Down Expand Up @@ -265,6 +295,25 @@ fn process_table(table_node: Node) -> KbParsedEntry {
entry
}

fn filter_link(elem: &Node) -> bool {
if elem.find(Class("table")).count() > 0 {
return false;
}
if elem.find(Class("informaltable")).count() > 0 {
return false;
}
match elem.find(Class("link")).next() {
Some(link) => {
let element_attr = link.attr("href");
match element_attr {
Some(attr) => attr.contains("#sysvar_"),
None => false,
}
}
None => false,
}
}

fn filter_table(elem: &Node) -> bool {
let element_attr = elem.attr("class");
match element_attr {
Expand All @@ -285,15 +334,35 @@ fn filter_table(elem: &Node) -> bool {
}
}

fn dedup_entries(v: &mut Vec<KbParsedEntry>) {
let mut set: HashSet<String> = HashSet::new();

// Will retain when it returns true
// HashSet.insert returns false when the value already exists
v.retain(|e| match &e.id {
Some(data) => set.insert(data.to_string()),
None => false,
});
}

pub fn extract_mysql_from_text(qr: QueryResponse) -> Vec<KbParsedEntry> {
let document = Document::from(qr.body.as_str());

document
let mut final_data = document
.find(Class("table"))
.chain(document.find(Class("informaltable")))
.filter(|elem| filter_table(elem))
.map(|table_node| process_table(table_node))
.collect()
.chain(
&mut document
.find(Class("listitem"))
.filter(|li_node| filter_link(li_node))
.map(|li_node| process_link(li_node)),
)
.collect::<Vec<KbParsedEntry>>();

dedup_entries(&mut final_data);
final_data
}

/*
Expand Down Expand Up @@ -1125,4 +1194,101 @@ mod tests {
entries
);
}

#[test]
fn test_case_9() {
let entries = extract_mysql_from_text(QueryResponse {
body: get_test_data("mysql_test_case_9.html"),
url: "https://example.com".to_string(),
});
assert_eq!(
vec![
KbParsedEntry {
has_description: false,
is_removed: false,
cli: Some("--group-concat-max-len=#".to_string()),
default: Some("1024".to_string()),
dynamic: Some(true),
id: Some("sysvar_group_concat_max_len".to_string()),
name: Some("group_concat_max_len".to_string()),
scope: Some(vec!["global".to_string(), "session".to_string()]),
r#type: Some("integer".to_string()),
valid_values: None,
range: Some(Range {
from: Some(4),
from_f: None,
to: None,
to_f: None,
to_upwards: None,
}),
},
KbParsedEntry {
cli: None,
default: None,
dynamic: None,
id: Some("sysvar_have_compress".to_string()),
name: Some("have_compress".to_string()),
range: None,
scope: None,
r#type: None,
valid_values: None,
has_description: false,
is_removed: false,
},
KbParsedEntry {
cli: None,
default: None,
dynamic: None,
id: Some("sysvar_have_dynamic_loading".to_string()),
name: Some("have_dynamic_loading".to_string()),
range: None,
scope: None,
r#type: None,
valid_values: None,
has_description: false,
is_removed: false,
},
KbParsedEntry {
cli: None,
default: None,
dynamic: None,
id: Some("sysvar_have_geometry".to_string()),
name: Some("have_geometry".to_string()),
range: None,
scope: None,
r#type: None,
valid_values: None,
has_description: false,
is_removed: false,
},
KbParsedEntry {
cli: None,
default: None,
dynamic: None,
id: Some("sysvar_have_openssl".to_string()),
name: Some("have_openssl".to_string()),
range: None,
scope: None,
r#type: None,
valid_values: None,
has_description: false,
is_removed: false,
},
KbParsedEntry {
cli: None,
default: None,
dynamic: None,
id: Some("sysvar_innodb_flush_log_at_trx_commit".to_string()),
name: Some("innodb_flush_log_at_trx_commit".to_string()),
range: None,
scope: None,
r#type: None,
valid_values: None,
has_description: false,
is_removed: false,
},
],
entries
);
}
}

0 comments on commit 20871d6

Please sign in to comment.