Deploying to gh-pages from @ GreptimeTeam/greptimedb@97913b4b3a 🚀

This commit is contained in:
github-merge-queue[bot]
2026-10-07 08:03:01 +00:00
commit ff419bc025
25679 changed files with 2969188 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/api/src/error.rs`."><title>error.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="api" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">api/</div>error.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::any::Any;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_error::ext::ErrorExt;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_error::status_code::StatusCode;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_macro::stack_trace_debug;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_time::timestamp::TimeUnit;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>datatypes::prelude::ConcreteDataType;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>snafu::Location;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>snafu::prelude::<span class="kw-2">*</span>;
<a href=#24 id=24 data-nosnippet>24</a>
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">pub type </span><span class="prelude-ty">Result</span>&lt;T&gt; = std::result::Result&lt;T, Error&gt;;
<a href=#26 id=26 data-nosnippet>26</a>
<a href=#27 id=27 data-nosnippet>27</a><span class="attr">#[derive(Snafu)]
<a href=#28 id=28 data-nosnippet>28</a>#[snafu(visibility(<span class="kw">pub</span>))]
<a href=#29 id=29 data-nosnippet>29</a>#[stack_trace_debug]
<a href=#30 id=30 data-nosnippet>30</a></span><span class="kw">pub enum </span>Error {
<a href=#31 id=31 data-nosnippet>31</a> <span class="attr">#[snafu(display(<span class="string">"Unknown proto column datatype: {}"</span>, datatype))]
<a href=#32 id=32 data-nosnippet>32</a> </span>UnknownColumnDataType {
<a href=#33 id=33 data-nosnippet>33</a> datatype: i32,
<a href=#34 id=34 data-nosnippet>34</a> <span class="attr">#[snafu(implicit)]
<a href=#35 id=35 data-nosnippet>35</a> </span>location: Location,
<a href=#36 id=36 data-nosnippet>36</a> <span class="attr">#[snafu(source)]
<a href=#37 id=37 data-nosnippet>37</a> </span>error: prost::UnknownEnumValue,
<a href=#38 id=38 data-nosnippet>38</a> },
<a href=#39 id=39 data-nosnippet>39</a>
<a href=#40 id=40 data-nosnippet>40</a> <span class="attr">#[snafu(display(<span class="string">"Failed to create column datatype from {:?}"</span>, from))]
<a href=#41 id=41 data-nosnippet>41</a> </span>IntoColumnDataType {
<a href=#42 id=42 data-nosnippet>42</a> from: ConcreteDataType,
<a href=#43 id=43 data-nosnippet>43</a> <span class="attr">#[snafu(implicit)]
<a href=#44 id=44 data-nosnippet>44</a> </span>location: Location,
<a href=#45 id=45 data-nosnippet>45</a> },
<a href=#46 id=46 data-nosnippet>46</a>
<a href=#47 id=47 data-nosnippet>47</a> <span class="attr">#[snafu(display(<span class="string">"Failed to convert column default constraint, column: {}"</span>, column))]
<a href=#48 id=48 data-nosnippet>48</a> </span>ConvertColumnDefaultConstraint {
<a href=#49 id=49 data-nosnippet>49</a> column: String,
<a href=#50 id=50 data-nosnippet>50</a> <span class="attr">#[snafu(implicit)]
<a href=#51 id=51 data-nosnippet>51</a> </span>location: Location,
<a href=#52 id=52 data-nosnippet>52</a> source: datatypes::error::Error,
<a href=#53 id=53 data-nosnippet>53</a> },
<a href=#54 id=54 data-nosnippet>54</a>
<a href=#55 id=55 data-nosnippet>55</a> <span class="attr">#[snafu(display(<span class="string">"Invalid column default constraint, column: {}"</span>, column))]
<a href=#56 id=56 data-nosnippet>56</a> </span>InvalidColumnDefaultConstraint {
<a href=#57 id=57 data-nosnippet>57</a> column: String,
<a href=#58 id=58 data-nosnippet>58</a> <span class="attr">#[snafu(implicit)]
<a href=#59 id=59 data-nosnippet>59</a> </span>location: Location,
<a href=#60 id=60 data-nosnippet>60</a> source: datatypes::error::Error,
<a href=#61 id=61 data-nosnippet>61</a> },
<a href=#62 id=62 data-nosnippet>62</a>
<a href=#63 id=63 data-nosnippet>63</a> <span class="attr">#[snafu(display(<span class="string">"Failed to serialize JSON"</span>))]
<a href=#64 id=64 data-nosnippet>64</a> </span>SerializeJson {
<a href=#65 id=65 data-nosnippet>65</a> <span class="attr">#[snafu(source)]
<a href=#66 id=66 data-nosnippet>66</a> </span>error: serde_json::Error,
<a href=#67 id=67 data-nosnippet>67</a> <span class="attr">#[snafu(implicit)]
<a href=#68 id=68 data-nosnippet>68</a> </span>location: Location,
<a href=#69 id=69 data-nosnippet>69</a> },
<a href=#70 id=70 data-nosnippet>70</a>
<a href=#71 id=71 data-nosnippet>71</a> <span class="attr">#[snafu(display(<span class="string">"Invalid time unit: {time_unit}"</span>))]
<a href=#72 id=72 data-nosnippet>72</a> </span>InvalidTimeUnit {
<a href=#73 id=73 data-nosnippet>73</a> time_unit: i32,
<a href=#74 id=74 data-nosnippet>74</a> <span class="attr">#[snafu(implicit)]
<a href=#75 id=75 data-nosnippet>75</a> </span>location: Location,
<a href=#76 id=76 data-nosnippet>76</a> },
<a href=#77 id=77 data-nosnippet>77</a>
<a href=#78 id=78 data-nosnippet>78</a> <span class="attr">#[snafu(display(<span class="string">"Inconsistent time unit: {:?}"</span>, units))]
<a href=#79 id=79 data-nosnippet>79</a> </span>InconsistentTimeUnit {
<a href=#80 id=80 data-nosnippet>80</a> units: Vec&lt;TimeUnit&gt;,
<a href=#81 id=81 data-nosnippet>81</a> <span class="attr">#[snafu(implicit)]
<a href=#82 id=82 data-nosnippet>82</a> </span>location: Location,
<a href=#83 id=83 data-nosnippet>83</a> },
<a href=#84 id=84 data-nosnippet>84</a>}
<a href=#85 id=85 data-nosnippet>85</a>
<a href=#86 id=86 data-nosnippet>86</a><span class="kw">impl </span>ErrorExt <span class="kw">for </span>Error {
<a href=#87 id=87 data-nosnippet>87</a> <span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
<a href=#88 id=88 data-nosnippet>88</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#89 id=89 data-nosnippet>89</a> Error::UnknownColumnDataType { .. }
<a href=#90 id=90 data-nosnippet>90</a> | Error::InvalidTimeUnit { .. }
<a href=#91 id=91 data-nosnippet>91</a> | Error::InconsistentTimeUnit { .. } =&gt; StatusCode::InvalidArguments,
<a href=#92 id=92 data-nosnippet>92</a> Error::IntoColumnDataType { .. } | Error::SerializeJson { .. } =&gt; {
<a href=#93 id=93 data-nosnippet>93</a> StatusCode::Unexpected
<a href=#94 id=94 data-nosnippet>94</a> }
<a href=#95 id=95 data-nosnippet>95</a> Error::ConvertColumnDefaultConstraint { source, .. }
<a href=#96 id=96 data-nosnippet>96</a> | Error::InvalidColumnDefaultConstraint { source, .. } =&gt; source.status_code(),
<a href=#97 id=97 data-nosnippet>97</a> }
<a href=#98 id=98 data-nosnippet>98</a> }
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>Any {
<a href=#101 id=101 data-nosnippet>101</a> <span class="self">self
<a href=#102 id=102 data-nosnippet>102</a> </span>}
<a href=#103 id=103 data-nosnippet>103</a>}
</code></pre></div></section></main></body></html>
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/api/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="api" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">api/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">pub mod </span>error;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">pub mod </span>helper;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">pub mod </span>prom_store {
<a href=#19 id=19 data-nosnippet>19</a> <span class="kw">pub mod </span>remote {
<a href=#20 id=20 data-nosnippet>20</a> <span class="kw">pub use </span>greptime_proto::prometheus::remote::<span class="kw-2">*</span>;
<a href=#21 id=21 data-nosnippet>21</a> }
<a href=#22 id=22 data-nosnippet>22</a>}
<a href=#23 id=23 data-nosnippet>23</a>
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">pub mod </span>region;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">pub mod </span>v1;
<a href=#26 id=26 data-nosnippet>26</a>
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">pub use </span>greptime_proto;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">pub use </span>prost::DecodeError;
</code></pre></div></section></main></body></html>
+55
View File
@@ -0,0 +1,55 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/api/src/region.rs`."><title>region.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="api" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">api/</div>region.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::collections::HashMap;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_base::AffectedRows;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>greptime_proto::v1::region::RegionResponse <span class="kw">as </span>RegionResponseV1;
<a href=#19 id=19 data-nosnippet>19</a>
<a href=#20 id=20 data-nosnippet>20</a><span class="doccomment">/// This result struct is derived from [RegionResponseV1]
<a href=#21 id=21 data-nosnippet>21</a></span><span class="attr">#[derive(Debug)]
<a href=#22 id=22 data-nosnippet>22</a></span><span class="kw">pub struct </span>RegionResponse {
<a href=#23 id=23 data-nosnippet>23</a> <span class="kw">pub </span>affected_rows: AffectedRows,
<a href=#24 id=24 data-nosnippet>24</a> <span class="kw">pub </span>extensions: HashMap&lt;String, Vec&lt;u8&gt;&gt;,
<a href=#25 id=25 data-nosnippet>25</a> <span class="kw">pub </span>metadata: Vec&lt;u8&gt;,
<a href=#26 id=26 data-nosnippet>26</a>}
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">impl </span>RegionResponse {
<a href=#29 id=29 data-nosnippet>29</a> <span class="kw">pub fn </span>from_region_response(region_response: RegionResponseV1) -&gt; <span class="self">Self </span>{
<a href=#30 id=30 data-nosnippet>30</a> <span class="self">Self </span>{
<a href=#31 id=31 data-nosnippet>31</a> affected_rows: region_response.affected_rows <span class="kw">as _</span>,
<a href=#32 id=32 data-nosnippet>32</a> extensions: region_response.extensions,
<a href=#33 id=33 data-nosnippet>33</a> metadata: region_response.metadata,
<a href=#34 id=34 data-nosnippet>34</a> }
<a href=#35 id=35 data-nosnippet>35</a> }
<a href=#36 id=36 data-nosnippet>36</a>
<a href=#37 id=37 data-nosnippet>37</a> <span class="doccomment">/// Creates one response without extension
<a href=#38 id=38 data-nosnippet>38</a> </span><span class="kw">pub fn </span>new(affected_rows: AffectedRows) -&gt; <span class="self">Self </span>{
<a href=#39 id=39 data-nosnippet>39</a> <span class="self">Self </span>{
<a href=#40 id=40 data-nosnippet>40</a> affected_rows,
<a href=#41 id=41 data-nosnippet>41</a> extensions: Default::default(),
<a href=#42 id=42 data-nosnippet>42</a> metadata: Vec::new(),
<a href=#43 id=43 data-nosnippet>43</a> }
<a href=#44 id=44 data-nosnippet>44</a> }
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a> <span class="doccomment">/// Creates one response with metadata.
<a href=#47 id=47 data-nosnippet>47</a> </span><span class="kw">pub fn </span>from_metadata(metadata: Vec&lt;u8&gt;) -&gt; <span class="self">Self </span>{
<a href=#48 id=48 data-nosnippet>48</a> <span class="self">Self </span>{
<a href=#49 id=49 data-nosnippet>49</a> affected_rows: <span class="number">0</span>,
<a href=#50 id=50 data-nosnippet>50</a> extensions: Default::default(),
<a href=#51 id=51 data-nosnippet>51</a> metadata,
<a href=#52 id=52 data-nosnippet>52</a> }
<a href=#53 id=53 data-nosnippet>53</a> }
<a href=#54 id=54 data-nosnippet>54</a>}
</code></pre></div></section></main></body></html>
+24
View File
@@ -0,0 +1,24 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/api/src/v1.rs`."><title>v1.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="api" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">api/</div>v1.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">pub mod </span>column_def;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">pub mod </span>helper;
<a href=#18 id=18 data-nosnippet>18</a>
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">pub mod </span>meta {
<a href=#20 id=20 data-nosnippet>20</a> <span class="kw">pub use </span>greptime_proto::v1::meta::<span class="kw-2">*</span>;
<a href=#21 id=21 data-nosnippet>21</a>}
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">pub use </span>greptime_proto::v1::<span class="kw-2">*</span>;
</code></pre></div></section></main></body></html>
+373
View File
@@ -0,0 +1,373 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/api/src/v1/column_def.rs`."><title>column_def.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="api" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">api/v1/</div>column_def.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::collections::HashMap;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>arrow_schema::extension::{EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_NAME_KEY};
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>datatypes::schema::{
<a href=#19 id=19 data-nosnippet>19</a> COMMENT_KEY, ColumnDefaultConstraint, ColumnSchema, FULLTEXT_KEY, FulltextAnalyzer,
<a href=#20 id=20 data-nosnippet>20</a> FulltextBackend, FulltextOptions, INVERTED_INDEX_KEY, Metadata, SKIPPING_INDEX_KEY,
<a href=#21 id=21 data-nosnippet>21</a> SkippingIndexOptions, SkippingIndexType,
<a href=#22 id=22 data-nosnippet>22</a>};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>greptime_proto::v1::{
<a href=#24 id=24 data-nosnippet>24</a> Analyzer, FulltextBackend <span class="kw">as </span>PbFulltextBackend, SkippingIndexType <span class="kw">as </span>PbSkippingIndexType,
<a href=#25 id=25 data-nosnippet>25</a>};
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>snafu::ResultExt;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span><span class="kw">crate</span>::error::{<span class="self">self</span>, ConvertColumnDefaultConstraintSnafu, <span class="prelude-ty">Result</span>};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span><span class="kw">crate</span>::helper::ColumnDataTypeWrapper;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span><span class="kw">crate</span>::v1::{ColumnDef, ColumnOptions, SemanticType};
<a href=#31 id=31 data-nosnippet>31</a>
<a href=#32 id=32 data-nosnippet>32</a><span class="doccomment">/// Key used to store fulltext options in gRPC column options.
<a href=#33 id=33 data-nosnippet>33</a></span><span class="kw">const </span>FULLTEXT_GRPC_KEY: <span class="kw-2">&amp;</span>str = <span class="string">"fulltext"</span>;
<a href=#34 id=34 data-nosnippet>34</a><span class="doccomment">/// Key used to store inverted index options in gRPC column options.
<a href=#35 id=35 data-nosnippet>35</a></span><span class="kw">const </span>INVERTED_INDEX_GRPC_KEY: <span class="kw-2">&amp;</span>str = <span class="string">"inverted_index"</span>;
<a href=#36 id=36 data-nosnippet>36</a><span class="doccomment">/// Key used to store skip index options in gRPC column options.
<a href=#37 id=37 data-nosnippet>37</a></span><span class="kw">const </span>SKIPPING_INDEX_GRPC_KEY: <span class="kw-2">&amp;</span>str = <span class="string">"skipping_index"</span>;
<a href=#38 id=38 data-nosnippet>38</a>
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">const </span>COLUMN_OPTION_MAPPINGS: [(<span class="kw-2">&amp;</span>str, <span class="kw-2">&amp;</span>str); <span class="number">5</span>] = [
<a href=#40 id=40 data-nosnippet>40</a> (FULLTEXT_GRPC_KEY, FULLTEXT_KEY),
<a href=#41 id=41 data-nosnippet>41</a> (INVERTED_INDEX_GRPC_KEY, INVERTED_INDEX_KEY),
<a href=#42 id=42 data-nosnippet>42</a> (SKIPPING_INDEX_GRPC_KEY, SKIPPING_INDEX_KEY),
<a href=#43 id=43 data-nosnippet>43</a> (EXTENSION_TYPE_NAME_KEY, EXTENSION_TYPE_NAME_KEY),
<a href=#44 id=44 data-nosnippet>44</a> (EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_METADATA_KEY),
<a href=#45 id=45 data-nosnippet>45</a>];
<a href=#46 id=46 data-nosnippet>46</a>
<a href=#47 id=47 data-nosnippet>47</a><span class="doccomment">/// Tries to construct a `ColumnSchema` from the given `ColumnDef`.
<a href=#48 id=48 data-nosnippet>48</a></span><span class="kw">pub fn </span>try_as_column_schema(column_def: <span class="kw-2">&amp;</span>ColumnDef) -&gt; <span class="prelude-ty">Result</span>&lt;ColumnSchema&gt; {
<a href=#49 id=49 data-nosnippet>49</a> <span class="kw">let </span>data_type = ColumnDataTypeWrapper::try_new(
<a href=#50 id=50 data-nosnippet>50</a> column_def.data_type,
<a href=#51 id=51 data-nosnippet>51</a> column_def.datatype_extension.clone(),
<a href=#52 id=52 data-nosnippet>52</a> )<span class="question-mark">?</span>;
<a href=#53 id=53 data-nosnippet>53</a>
<a href=#54 id=54 data-nosnippet>54</a> <span class="kw">let </span>constraint = <span class="kw">if </span>column_def.default_constraint.is_empty() {
<a href=#55 id=55 data-nosnippet>55</a> <span class="prelude-val">None
<a href=#56 id=56 data-nosnippet>56</a> </span>} <span class="kw">else </span>{
<a href=#57 id=57 data-nosnippet>57</a> <span class="prelude-val">Some</span>(
<a href=#58 id=58 data-nosnippet>58</a> ColumnDefaultConstraint::try_from(column_def.default_constraint.as_slice()).context(
<a href=#59 id=59 data-nosnippet>59</a> error::ConvertColumnDefaultConstraintSnafu {
<a href=#60 id=60 data-nosnippet>60</a> column: <span class="kw-2">&amp;</span>column_def.name,
<a href=#61 id=61 data-nosnippet>61</a> },
<a href=#62 id=62 data-nosnippet>62</a> )<span class="question-mark">?</span>,
<a href=#63 id=63 data-nosnippet>63</a> )
<a href=#64 id=64 data-nosnippet>64</a> };
<a href=#65 id=65 data-nosnippet>65</a>
<a href=#66 id=66 data-nosnippet>66</a> <span class="kw">let </span><span class="kw-2">mut </span>metadata = HashMap::new();
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">if </span>!column_def.comment.is_empty() {
<a href=#68 id=68 data-nosnippet>68</a> metadata.insert(COMMENT_KEY.to_string(), column_def.comment.clone());
<a href=#69 id=69 data-nosnippet>69</a> }
<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(options) = column_def.options.as_ref() {
<a href=#71 id=71 data-nosnippet>71</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(fulltext) = options.options.get(FULLTEXT_GRPC_KEY) {
<a href=#72 id=72 data-nosnippet>72</a> metadata.insert(FULLTEXT_KEY.to_string(), fulltext.to_owned());
<a href=#73 id=73 data-nosnippet>73</a> }
<a href=#74 id=74 data-nosnippet>74</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(inverted_index) = options.options.get(INVERTED_INDEX_GRPC_KEY) {
<a href=#75 id=75 data-nosnippet>75</a> metadata.insert(INVERTED_INDEX_KEY.to_string(), inverted_index.to_owned());
<a href=#76 id=76 data-nosnippet>76</a> }
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(skipping_index) = options.options.get(SKIPPING_INDEX_GRPC_KEY) {
<a href=#78 id=78 data-nosnippet>78</a> metadata.insert(SKIPPING_INDEX_KEY.to_string(), skipping_index.to_owned());
<a href=#79 id=79 data-nosnippet>79</a> }
<a href=#80 id=80 data-nosnippet>80</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(extension_name) = options.options.get(EXTENSION_TYPE_NAME_KEY) {
<a href=#81 id=81 data-nosnippet>81</a> metadata.insert(EXTENSION_TYPE_NAME_KEY.to_string(), extension_name.clone());
<a href=#82 id=82 data-nosnippet>82</a> }
<a href=#83 id=83 data-nosnippet>83</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(extension_metadata) = options.options.get(EXTENSION_TYPE_METADATA_KEY) {
<a href=#84 id=84 data-nosnippet>84</a> metadata.insert(
<a href=#85 id=85 data-nosnippet>85</a> EXTENSION_TYPE_METADATA_KEY.to_string(),
<a href=#86 id=86 data-nosnippet>86</a> extension_metadata.clone(),
<a href=#87 id=87 data-nosnippet>87</a> );
<a href=#88 id=88 data-nosnippet>88</a> }
<a href=#89 id=89 data-nosnippet>89</a> }
<a href=#90 id=90 data-nosnippet>90</a>
<a href=#91 id=91 data-nosnippet>91</a> ColumnSchema::new(<span class="kw-2">&amp;</span>column_def.name, data_type.into(), column_def.is_nullable)
<a href=#92 id=92 data-nosnippet>92</a> .with_metadata(metadata)
<a href=#93 id=93 data-nosnippet>93</a> .with_time_index(column_def.semantic_type() == SemanticType::Timestamp)
<a href=#94 id=94 data-nosnippet>94</a> .with_default_constraint(constraint)
<a href=#95 id=95 data-nosnippet>95</a> .context(error::InvalidColumnDefaultConstraintSnafu {
<a href=#96 id=96 data-nosnippet>96</a> column: <span class="kw-2">&amp;</span>column_def.name,
<a href=#97 id=97 data-nosnippet>97</a> })
<a href=#98 id=98 data-nosnippet>98</a>}
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a><span class="doccomment">/// Tries to construct a `ColumnDef` from the given `ColumnSchema`.
<a href=#101 id=101 data-nosnippet>101</a>///
<a href=#102 id=102 data-nosnippet>102</a>/// TODO(weny): Add tests for this function.
<a href=#103 id=103 data-nosnippet>103</a></span><span class="kw">pub fn </span>try_as_column_def(column_schema: <span class="kw-2">&amp;</span>ColumnSchema, is_primary_key: bool) -&gt; <span class="prelude-ty">Result</span>&lt;ColumnDef&gt; {
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">let </span>column_datatype =
<a href=#105 id=105 data-nosnippet>105</a> ColumnDataTypeWrapper::try_from(column_schema.data_type.clone()).map(|w| w.to_parts())<span class="question-mark">?</span>;
<a href=#106 id=106 data-nosnippet>106</a>
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">let </span>semantic_type = <span class="kw">if </span>column_schema.is_time_index() {
<a href=#108 id=108 data-nosnippet>108</a> SemanticType::Timestamp
<a href=#109 id=109 data-nosnippet>109</a> } <span class="kw">else if </span>is_primary_key {
<a href=#110 id=110 data-nosnippet>110</a> SemanticType::Tag
<a href=#111 id=111 data-nosnippet>111</a> } <span class="kw">else </span>{
<a href=#112 id=112 data-nosnippet>112</a> SemanticType::Field
<a href=#113 id=113 data-nosnippet>113</a> } <span class="kw">as </span>i32;
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">let </span>comment = column_schema
<a href=#115 id=115 data-nosnippet>115</a> .metadata()
<a href=#116 id=116 data-nosnippet>116</a> .get(COMMENT_KEY)
<a href=#117 id=117 data-nosnippet>117</a> .cloned()
<a href=#118 id=118 data-nosnippet>118</a> .unwrap_or_default();
<a href=#119 id=119 data-nosnippet>119</a>
<a href=#120 id=120 data-nosnippet>120</a> <span class="kw">let </span>default_constraint = <span class="kw">match </span>column_schema.default_constraint() {
<a href=#121 id=121 data-nosnippet>121</a> <span class="prelude-val">None </span>=&gt; <span class="macro">vec!</span>[],
<a href=#122 id=122 data-nosnippet>122</a> <span class="prelude-val">Some</span>(v) =&gt; v
<a href=#123 id=123 data-nosnippet>123</a> .clone()
<a href=#124 id=124 data-nosnippet>124</a> .try_into()
<a href=#125 id=125 data-nosnippet>125</a> .context(ConvertColumnDefaultConstraintSnafu {
<a href=#126 id=126 data-nosnippet>126</a> column: <span class="kw-2">&amp;</span>column_schema.name,
<a href=#127 id=127 data-nosnippet>127</a> })<span class="question-mark">?</span>,
<a href=#128 id=128 data-nosnippet>128</a> };
<a href=#129 id=129 data-nosnippet>129</a> <span class="kw">let </span>options = options_from_column_schema(column_schema);
<a href=#130 id=130 data-nosnippet>130</a> <span class="prelude-val">Ok</span>(ColumnDef {
<a href=#131 id=131 data-nosnippet>131</a> name: column_schema.name.clone(),
<a href=#132 id=132 data-nosnippet>132</a> data_type: column_datatype.<span class="number">0 </span><span class="kw">as </span>i32,
<a href=#133 id=133 data-nosnippet>133</a> is_nullable: column_schema.is_nullable(),
<a href=#134 id=134 data-nosnippet>134</a> default_constraint,
<a href=#135 id=135 data-nosnippet>135</a> semantic_type,
<a href=#136 id=136 data-nosnippet>136</a> comment,
<a href=#137 id=137 data-nosnippet>137</a> datatype_extension: column_datatype.<span class="number">1</span>,
<a href=#138 id=138 data-nosnippet>138</a> options,
<a href=#139 id=139 data-nosnippet>139</a> })
<a href=#140 id=140 data-nosnippet>140</a>}
<a href=#141 id=141 data-nosnippet>141</a>
<a href=#142 id=142 data-nosnippet>142</a><span class="doccomment">/// Collect the [ColumnOptions] into the [Metadata] that can be used in, for example, [ColumnSchema].
<a href=#143 id=143 data-nosnippet>143</a></span><span class="kw">pub fn </span>collect_column_options(column_options: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>ColumnOptions&gt;) -&gt; Metadata {
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">let </span><span class="prelude-val">Some</span>(ColumnOptions { options }) = column_options <span class="kw">else </span>{
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">return </span>Metadata::default();
<a href=#146 id=146 data-nosnippet>146</a> };
<a href=#147 id=147 data-nosnippet>147</a>
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">let </span><span class="kw-2">mut </span>metadata = Metadata::with_capacity(options.len());
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">for </span>(x, y) <span class="kw">in </span>COLUMN_OPTION_MAPPINGS {
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(v) = options.get(x) {
<a href=#151 id=151 data-nosnippet>151</a> metadata.insert(y.to_string(), v.clone());
<a href=#152 id=152 data-nosnippet>152</a> }
<a href=#153 id=153 data-nosnippet>153</a> }
<a href=#154 id=154 data-nosnippet>154</a> metadata
<a href=#155 id=155 data-nosnippet>155</a>}
<a href=#156 id=156 data-nosnippet>156</a>
<a href=#157 id=157 data-nosnippet>157</a><span class="doccomment">/// Constructs a `ColumnOptions` from the given `ColumnSchema`.
<a href=#158 id=158 data-nosnippet>158</a></span><span class="kw">pub fn </span>options_from_column_schema(column_schema: <span class="kw-2">&amp;</span>ColumnSchema) -&gt; <span class="prelude-ty">Option</span>&lt;ColumnOptions&gt; {
<a href=#159 id=159 data-nosnippet>159</a> <span class="kw">let </span><span class="kw-2">mut </span>options = ColumnOptions::default();
<a href=#160 id=160 data-nosnippet>160</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(fulltext) = column_schema.metadata().get(FULLTEXT_KEY) {
<a href=#161 id=161 data-nosnippet>161</a> options
<a href=#162 id=162 data-nosnippet>162</a> .options
<a href=#163 id=163 data-nosnippet>163</a> .insert(FULLTEXT_GRPC_KEY.to_string(), fulltext.to_owned());
<a href=#164 id=164 data-nosnippet>164</a> }
<a href=#165 id=165 data-nosnippet>165</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(inverted_index) = column_schema.metadata().get(INVERTED_INDEX_KEY) {
<a href=#166 id=166 data-nosnippet>166</a> options
<a href=#167 id=167 data-nosnippet>167</a> .options
<a href=#168 id=168 data-nosnippet>168</a> .insert(INVERTED_INDEX_GRPC_KEY.to_string(), inverted_index.clone());
<a href=#169 id=169 data-nosnippet>169</a> }
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(skipping_index) = column_schema.metadata().get(SKIPPING_INDEX_KEY) {
<a href=#171 id=171 data-nosnippet>171</a> options
<a href=#172 id=172 data-nosnippet>172</a> .options
<a href=#173 id=173 data-nosnippet>173</a> .insert(SKIPPING_INDEX_GRPC_KEY.to_string(), skipping_index.clone());
<a href=#174 id=174 data-nosnippet>174</a> }
<a href=#175 id=175 data-nosnippet>175</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(extension_name) = column_schema.metadata().get(EXTENSION_TYPE_NAME_KEY) {
<a href=#176 id=176 data-nosnippet>176</a> options
<a href=#177 id=177 data-nosnippet>177</a> .options
<a href=#178 id=178 data-nosnippet>178</a> .insert(EXTENSION_TYPE_NAME_KEY.to_string(), extension_name.clone());
<a href=#179 id=179 data-nosnippet>179</a> }
<a href=#180 id=180 data-nosnippet>180</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(extension_metadata) = column_schema.metadata().get(EXTENSION_TYPE_METADATA_KEY) {
<a href=#181 id=181 data-nosnippet>181</a> options.options.insert(
<a href=#182 id=182 data-nosnippet>182</a> EXTENSION_TYPE_METADATA_KEY.to_string(),
<a href=#183 id=183 data-nosnippet>183</a> extension_metadata.clone(),
<a href=#184 id=184 data-nosnippet>184</a> );
<a href=#185 id=185 data-nosnippet>185</a> }
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a> (!options.options.is_empty()).then_some(options)
<a href=#188 id=188 data-nosnippet>188</a>}
<a href=#189 id=189 data-nosnippet>189</a>
<a href=#190 id=190 data-nosnippet>190</a><span class="doccomment">/// Checks if the `ColumnOptions` contains fulltext options.
<a href=#191 id=191 data-nosnippet>191</a></span><span class="kw">pub fn </span>contains_fulltext(options: <span class="kw-2">&amp;</span><span class="prelude-ty">Option</span>&lt;ColumnOptions&gt;) -&gt; bool {
<a href=#192 id=192 data-nosnippet>192</a> options
<a href=#193 id=193 data-nosnippet>193</a> .as_ref()
<a href=#194 id=194 data-nosnippet>194</a> .is_some_and(|o| o.options.contains_key(FULLTEXT_GRPC_KEY))
<a href=#195 id=195 data-nosnippet>195</a>}
<a href=#196 id=196 data-nosnippet>196</a>
<a href=#197 id=197 data-nosnippet>197</a><span class="doccomment">/// Checks if the `ColumnOptions` contains skipping index options.
<a href=#198 id=198 data-nosnippet>198</a></span><span class="kw">pub fn </span>contains_skipping(options: <span class="kw-2">&amp;</span><span class="prelude-ty">Option</span>&lt;ColumnOptions&gt;) -&gt; bool {
<a href=#199 id=199 data-nosnippet>199</a> options
<a href=#200 id=200 data-nosnippet>200</a> .as_ref()
<a href=#201 id=201 data-nosnippet>201</a> .is_some_and(|o| o.options.contains_key(SKIPPING_INDEX_GRPC_KEY))
<a href=#202 id=202 data-nosnippet>202</a>}
<a href=#203 id=203 data-nosnippet>203</a>
<a href=#204 id=204 data-nosnippet>204</a><span class="doccomment">/// Tries to construct a `ColumnOptions` from the given `FulltextOptions`.
<a href=#205 id=205 data-nosnippet>205</a></span><span class="kw">pub fn </span>options_from_fulltext(fulltext: <span class="kw-2">&amp;</span>FulltextOptions) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;ColumnOptions&gt;&gt; {
<a href=#206 id=206 data-nosnippet>206</a> <span class="kw">let </span><span class="kw-2">mut </span>options = ColumnOptions::default();
<a href=#207 id=207 data-nosnippet>207</a>
<a href=#208 id=208 data-nosnippet>208</a> <span class="kw">let </span>v = serde_json::to_string(fulltext).context(error::SerializeJsonSnafu)<span class="question-mark">?</span>;
<a href=#209 id=209 data-nosnippet>209</a> options.options.insert(FULLTEXT_GRPC_KEY.to_string(), v);
<a href=#210 id=210 data-nosnippet>210</a>
<a href=#211 id=211 data-nosnippet>211</a> <span class="prelude-val">Ok</span>((!options.options.is_empty()).then_some(options))
<a href=#212 id=212 data-nosnippet>212</a>}
<a href=#213 id=213 data-nosnippet>213</a>
<a href=#214 id=214 data-nosnippet>214</a><span class="doccomment">/// Tries to construct a `ColumnOptions` from the given `SkippingIndexOptions`.
<a href=#215 id=215 data-nosnippet>215</a></span><span class="kw">pub fn </span>options_from_skipping(skipping: <span class="kw-2">&amp;</span>SkippingIndexOptions) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;ColumnOptions&gt;&gt; {
<a href=#216 id=216 data-nosnippet>216</a> <span class="kw">let </span><span class="kw-2">mut </span>options = ColumnOptions::default();
<a href=#217 id=217 data-nosnippet>217</a>
<a href=#218 id=218 data-nosnippet>218</a> <span class="kw">let </span>v = serde_json::to_string(skipping).context(error::SerializeJsonSnafu)<span class="question-mark">?</span>;
<a href=#219 id=219 data-nosnippet>219</a> options
<a href=#220 id=220 data-nosnippet>220</a> .options
<a href=#221 id=221 data-nosnippet>221</a> .insert(SKIPPING_INDEX_GRPC_KEY.to_string(), v);
<a href=#222 id=222 data-nosnippet>222</a>
<a href=#223 id=223 data-nosnippet>223</a> <span class="prelude-val">Ok</span>((!options.options.is_empty()).then_some(options))
<a href=#224 id=224 data-nosnippet>224</a>}
<a href=#225 id=225 data-nosnippet>225</a>
<a href=#226 id=226 data-nosnippet>226</a><span class="doccomment">/// Tries to construct a `ColumnOptions` for inverted index.
<a href=#227 id=227 data-nosnippet>227</a></span><span class="kw">pub fn </span>options_from_inverted() -&gt; ColumnOptions {
<a href=#228 id=228 data-nosnippet>228</a> <span class="kw">let </span><span class="kw-2">mut </span>options = ColumnOptions::default();
<a href=#229 id=229 data-nosnippet>229</a> options
<a href=#230 id=230 data-nosnippet>230</a> .options
<a href=#231 id=231 data-nosnippet>231</a> .insert(INVERTED_INDEX_GRPC_KEY.to_string(), <span class="string">"true"</span>.to_string());
<a href=#232 id=232 data-nosnippet>232</a> options
<a href=#233 id=233 data-nosnippet>233</a>}
<a href=#234 id=234 data-nosnippet>234</a>
<a href=#235 id=235 data-nosnippet>235</a><span class="doccomment">/// Tries to construct a `FulltextAnalyzer` from the given analyzer.
<a href=#236 id=236 data-nosnippet>236</a></span><span class="kw">pub fn </span>as_fulltext_option_analyzer(analyzer: Analyzer) -&gt; FulltextAnalyzer {
<a href=#237 id=237 data-nosnippet>237</a> <span class="kw">match </span>analyzer {
<a href=#238 id=238 data-nosnippet>238</a> Analyzer::English =&gt; FulltextAnalyzer::English,
<a href=#239 id=239 data-nosnippet>239</a> Analyzer::Chinese =&gt; FulltextAnalyzer::Chinese,
<a href=#240 id=240 data-nosnippet>240</a> }
<a href=#241 id=241 data-nosnippet>241</a>}
<a href=#242 id=242 data-nosnippet>242</a>
<a href=#243 id=243 data-nosnippet>243</a><span class="doccomment">/// Tries to construct a `FulltextBackend` from the given backend.
<a href=#244 id=244 data-nosnippet>244</a></span><span class="kw">pub fn </span>as_fulltext_option_backend(backend: PbFulltextBackend) -&gt; FulltextBackend {
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw">match </span>backend {
<a href=#246 id=246 data-nosnippet>246</a> PbFulltextBackend::Bloom =&gt; FulltextBackend::Bloom,
<a href=#247 id=247 data-nosnippet>247</a> PbFulltextBackend::Tantivy =&gt; FulltextBackend::Tantivy,
<a href=#248 id=248 data-nosnippet>248</a> }
<a href=#249 id=249 data-nosnippet>249</a>}
<a href=#250 id=250 data-nosnippet>250</a>
<a href=#251 id=251 data-nosnippet>251</a><span class="doccomment">/// Tries to construct a `SkippingIndexType` from the given skipping index type.
<a href=#252 id=252 data-nosnippet>252</a></span><span class="kw">pub fn </span>as_skipping_index_type(skipping_index_type: PbSkippingIndexType) -&gt; SkippingIndexType {
<a href=#253 id=253 data-nosnippet>253</a> <span class="kw">match </span>skipping_index_type {
<a href=#254 id=254 data-nosnippet>254</a> PbSkippingIndexType::BloomFilter =&gt; SkippingIndexType::BloomFilter,
<a href=#255 id=255 data-nosnippet>255</a> }
<a href=#256 id=256 data-nosnippet>256</a>}
<a href=#257 id=257 data-nosnippet>257</a>
<a href=#258 id=258 data-nosnippet>258</a><span class="attr">#[cfg(test)]
<a href=#259 id=259 data-nosnippet>259</a></span><span class="kw">mod </span>tests {
<a href=#260 id=260 data-nosnippet>260</a>
<a href=#261 id=261 data-nosnippet>261</a> <span class="kw">use </span>datatypes::data_type::ConcreteDataType;
<a href=#262 id=262 data-nosnippet>262</a> <span class="kw">use </span>datatypes::schema::{FulltextAnalyzer, FulltextBackend};
<a href=#263 id=263 data-nosnippet>263</a>
<a href=#264 id=264 data-nosnippet>264</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">use </span><span class="kw">crate</span>::v1::ColumnDataType;
<a href=#266 id=266 data-nosnippet>266</a>
<a href=#267 id=267 data-nosnippet>267</a> <span class="attr">#[test]
<a href=#268 id=268 data-nosnippet>268</a> </span><span class="kw">fn </span>test_try_as_column_schema() {
<a href=#269 id=269 data-nosnippet>269</a> <span class="kw">let </span>column_def = ColumnDef {
<a href=#270 id=270 data-nosnippet>270</a> name: <span class="string">"test"</span>.to_string(),
<a href=#271 id=271 data-nosnippet>271</a> data_type: ColumnDataType::String <span class="kw">as </span>i32,
<a href=#272 id=272 data-nosnippet>272</a> is_nullable: <span class="bool-val">true</span>,
<a href=#273 id=273 data-nosnippet>273</a> default_constraint: ColumnDefaultConstraint::Value(<span class="string">"test_default"</span>.into())
<a href=#274 id=274 data-nosnippet>274</a> .try_into()
<a href=#275 id=275 data-nosnippet>275</a> .unwrap(),
<a href=#276 id=276 data-nosnippet>276</a> semantic_type: SemanticType::Field <span class="kw">as </span>i32,
<a href=#277 id=277 data-nosnippet>277</a> comment: <span class="string">"test_comment"</span>.to_string(),
<a href=#278 id=278 data-nosnippet>278</a> datatype_extension: <span class="prelude-val">None</span>,
<a href=#279 id=279 data-nosnippet>279</a> options: <span class="prelude-val">Some</span>(ColumnOptions {
<a href=#280 id=280 data-nosnippet>280</a> options: HashMap::from([
<a href=#281 id=281 data-nosnippet>281</a> (
<a href=#282 id=282 data-nosnippet>282</a> FULLTEXT_GRPC_KEY.to_string(),
<a href=#283 id=283 data-nosnippet>283</a> <span class="string">"{\"enable\":true}"</span>.to_string(),
<a href=#284 id=284 data-nosnippet>284</a> ),
<a href=#285 id=285 data-nosnippet>285</a> (INVERTED_INDEX_GRPC_KEY.to_string(), <span class="string">"true"</span>.to_string()),
<a href=#286 id=286 data-nosnippet>286</a> ]),
<a href=#287 id=287 data-nosnippet>287</a> }),
<a href=#288 id=288 data-nosnippet>288</a> };
<a href=#289 id=289 data-nosnippet>289</a>
<a href=#290 id=290 data-nosnippet>290</a> <span class="kw">let </span>schema = try_as_column_schema(<span class="kw-2">&amp;</span>column_def).unwrap();
<a href=#291 id=291 data-nosnippet>291</a> <span class="macro">assert_eq!</span>(schema.name, <span class="string">"test"</span>);
<a href=#292 id=292 data-nosnippet>292</a> <span class="macro">assert_eq!</span>(schema.data_type, ConcreteDataType::string_datatype());
<a href=#293 id=293 data-nosnippet>293</a> <span class="macro">assert!</span>(!schema.is_time_index());
<a href=#294 id=294 data-nosnippet>294</a> <span class="macro">assert!</span>(schema.is_nullable());
<a href=#295 id=295 data-nosnippet>295</a> <span class="macro">assert_eq!</span>(
<a href=#296 id=296 data-nosnippet>296</a> schema.default_constraint().unwrap(),
<a href=#297 id=297 data-nosnippet>297</a> <span class="kw-2">&amp;</span>ColumnDefaultConstraint::Value(<span class="string">"test_default"</span>.into())
<a href=#298 id=298 data-nosnippet>298</a> );
<a href=#299 id=299 data-nosnippet>299</a> <span class="macro">assert_eq!</span>(schema.metadata().get(COMMENT_KEY).unwrap(), <span class="string">"test_comment"</span>);
<a href=#300 id=300 data-nosnippet>300</a> <span class="macro">assert_eq!</span>(
<a href=#301 id=301 data-nosnippet>301</a> schema.fulltext_options().unwrap().unwrap(),
<a href=#302 id=302 data-nosnippet>302</a> FulltextOptions {
<a href=#303 id=303 data-nosnippet>303</a> enable: <span class="bool-val">true</span>,
<a href=#304 id=304 data-nosnippet>304</a> ..Default::default()
<a href=#305 id=305 data-nosnippet>305</a> }
<a href=#306 id=306 data-nosnippet>306</a> );
<a href=#307 id=307 data-nosnippet>307</a> <span class="macro">assert!</span>(schema.is_inverted_indexed());
<a href=#308 id=308 data-nosnippet>308</a> }
<a href=#309 id=309 data-nosnippet>309</a>
<a href=#310 id=310 data-nosnippet>310</a> <span class="attr">#[test]
<a href=#311 id=311 data-nosnippet>311</a> </span><span class="kw">fn </span>test_options_from_column_schema() {
<a href=#312 id=312 data-nosnippet>312</a> <span class="kw">let </span>schema = ColumnSchema::new(<span class="string">"test"</span>, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>);
<a href=#313 id=313 data-nosnippet>313</a> <span class="kw">let </span>options = options_from_column_schema(<span class="kw-2">&amp;</span>schema);
<a href=#314 id=314 data-nosnippet>314</a> <span class="macro">assert!</span>(options.is_none());
<a href=#315 id=315 data-nosnippet>315</a>
<a href=#316 id=316 data-nosnippet>316</a> <span class="kw">let </span><span class="kw-2">mut </span>schema = ColumnSchema::new(<span class="string">"test"</span>, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>)
<a href=#317 id=317 data-nosnippet>317</a> .with_fulltext_options(FulltextOptions::new_unchecked(
<a href=#318 id=318 data-nosnippet>318</a> <span class="bool-val">true</span>,
<a href=#319 id=319 data-nosnippet>319</a> FulltextAnalyzer::English,
<a href=#320 id=320 data-nosnippet>320</a> <span class="bool-val">false</span>,
<a href=#321 id=321 data-nosnippet>321</a> FulltextBackend::Bloom,
<a href=#322 id=322 data-nosnippet>322</a> <span class="number">10240</span>,
<a href=#323 id=323 data-nosnippet>323</a> <span class="number">0.01</span>,
<a href=#324 id=324 data-nosnippet>324</a> ))
<a href=#325 id=325 data-nosnippet>325</a> .unwrap();
<a href=#326 id=326 data-nosnippet>326</a> schema.set_inverted_index(<span class="bool-val">true</span>);
<a href=#327 id=327 data-nosnippet>327</a> <span class="kw">let </span>options = options_from_column_schema(<span class="kw-2">&amp;</span>schema).unwrap();
<a href=#328 id=328 data-nosnippet>328</a> <span class="macro">assert_eq!</span>(
<a href=#329 id=329 data-nosnippet>329</a> options.options.get(FULLTEXT_GRPC_KEY).unwrap(),
<a href=#330 id=330 data-nosnippet>330</a> <span class="string">"{\"enable\":true,\"analyzer\":\"English\",\"case-sensitive\":false,\"backend\":\"bloom\",\"granularity\":10240,\"false-positive-rate-in-10000\":100}"
<a href=#331 id=331 data-nosnippet>331</a> </span>);
<a href=#332 id=332 data-nosnippet>332</a> <span class="macro">assert_eq!</span>(
<a href=#333 id=333 data-nosnippet>333</a> options.options.get(INVERTED_INDEX_GRPC_KEY).unwrap(),
<a href=#334 id=334 data-nosnippet>334</a> <span class="string">"true"
<a href=#335 id=335 data-nosnippet>335</a> </span>);
<a href=#336 id=336 data-nosnippet>336</a> }
<a href=#337 id=337 data-nosnippet>337</a>
<a href=#338 id=338 data-nosnippet>338</a> <span class="attr">#[test]
<a href=#339 id=339 data-nosnippet>339</a> </span><span class="kw">fn </span>test_options_with_fulltext() {
<a href=#340 id=340 data-nosnippet>340</a> <span class="kw">let </span>fulltext = FulltextOptions::new_unchecked(
<a href=#341 id=341 data-nosnippet>341</a> <span class="bool-val">true</span>,
<a href=#342 id=342 data-nosnippet>342</a> FulltextAnalyzer::English,
<a href=#343 id=343 data-nosnippet>343</a> <span class="bool-val">false</span>,
<a href=#344 id=344 data-nosnippet>344</a> FulltextBackend::Bloom,
<a href=#345 id=345 data-nosnippet>345</a> <span class="number">10240</span>,
<a href=#346 id=346 data-nosnippet>346</a> <span class="number">0.01</span>,
<a href=#347 id=347 data-nosnippet>347</a> );
<a href=#348 id=348 data-nosnippet>348</a> <span class="kw">let </span>options = options_from_fulltext(<span class="kw-2">&amp;</span>fulltext).unwrap().unwrap();
<a href=#349 id=349 data-nosnippet>349</a> <span class="macro">assert_eq!</span>(
<a href=#350 id=350 data-nosnippet>350</a> options.options.get(FULLTEXT_GRPC_KEY).unwrap(),
<a href=#351 id=351 data-nosnippet>351</a> <span class="string">"{\"enable\":true,\"analyzer\":\"English\",\"case-sensitive\":false,\"backend\":\"bloom\",\"granularity\":10240,\"false-positive-rate-in-10000\":100}"
<a href=#352 id=352 data-nosnippet>352</a> </span>);
<a href=#353 id=353 data-nosnippet>353</a> }
<a href=#354 id=354 data-nosnippet>354</a>
<a href=#355 id=355 data-nosnippet>355</a> <span class="attr">#[test]
<a href=#356 id=356 data-nosnippet>356</a> </span><span class="kw">fn </span>test_contains_fulltext() {
<a href=#357 id=357 data-nosnippet>357</a> <span class="kw">let </span>options = ColumnOptions {
<a href=#358 id=358 data-nosnippet>358</a> options: HashMap::from([(
<a href=#359 id=359 data-nosnippet>359</a> FULLTEXT_GRPC_KEY.to_string(),
<a href=#360 id=360 data-nosnippet>360</a> <span class="string">"{\"enable\":true}"</span>.to_string(),
<a href=#361 id=361 data-nosnippet>361</a> )]),
<a href=#362 id=362 data-nosnippet>362</a> };
<a href=#363 id=363 data-nosnippet>363</a> <span class="macro">assert!</span>(contains_fulltext(<span class="kw-2">&amp;</span><span class="prelude-val">Some</span>(options)));
<a href=#364 id=364 data-nosnippet>364</a>
<a href=#365 id=365 data-nosnippet>365</a> <span class="kw">let </span>options = ColumnOptions {
<a href=#366 id=366 data-nosnippet>366</a> options: HashMap::new(),
<a href=#367 id=367 data-nosnippet>367</a> };
<a href=#368 id=368 data-nosnippet>368</a> <span class="macro">assert!</span>(!contains_fulltext(<span class="kw-2">&amp;</span><span class="prelude-val">Some</span>(options)));
<a href=#369 id=369 data-nosnippet>369</a>
<a href=#370 id=370 data-nosnippet>370</a> <span class="macro">assert!</span>(!contains_fulltext(<span class="kw-2">&amp;</span><span class="prelude-val">None</span>));
<a href=#371 id=371 data-nosnippet>371</a> }
<a href=#372 id=372 data-nosnippet>372</a>}
</code></pre></div></section></main></body></html>
+66
View File
@@ -0,0 +1,66 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/api/src/v1/helper.rs`."><title>helper.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="api" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">api/v1/</div>helper.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>greptime_proto::v1::value::ValueData;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>greptime_proto::v1::{ColumnDataType, ColumnSchema, Row, SemanticType, Value};
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="doccomment">/// Create a time index [ColumnSchema] with column's name and datatype.
<a href=#19 id=19 data-nosnippet>19</a>/// Other fields are left default.
<a href=#20 id=20 data-nosnippet>20</a>/// Useful when you just want to create a simple [ColumnSchema] without providing much struct fields.
<a href=#21 id=21 data-nosnippet>21</a></span><span class="kw">pub fn </span>time_index_column_schema(name: <span class="kw-2">&amp;</span>str, datatype: ColumnDataType) -&gt; ColumnSchema {
<a href=#22 id=22 data-nosnippet>22</a> ColumnSchema {
<a href=#23 id=23 data-nosnippet>23</a> column_name: name.to_string(),
<a href=#24 id=24 data-nosnippet>24</a> datatype: datatype <span class="kw">as </span>i32,
<a href=#25 id=25 data-nosnippet>25</a> semantic_type: SemanticType::Timestamp <span class="kw">as </span>i32,
<a href=#26 id=26 data-nosnippet>26</a> ..Default::default()
<a href=#27 id=27 data-nosnippet>27</a> }
<a href=#28 id=28 data-nosnippet>28</a>}
<a href=#29 id=29 data-nosnippet>29</a>
<a href=#30 id=30 data-nosnippet>30</a><span class="doccomment">/// Create a tag [ColumnSchema] with column's name and datatype.
<a href=#31 id=31 data-nosnippet>31</a>/// Other fields are left default.
<a href=#32 id=32 data-nosnippet>32</a>/// Useful when you just want to create a simple [ColumnSchema] without providing much struct fields.
<a href=#33 id=33 data-nosnippet>33</a></span><span class="kw">pub fn </span>tag_column_schema(name: <span class="kw-2">&amp;</span>str, datatype: ColumnDataType) -&gt; ColumnSchema {
<a href=#34 id=34 data-nosnippet>34</a> ColumnSchema {
<a href=#35 id=35 data-nosnippet>35</a> column_name: name.to_string(),
<a href=#36 id=36 data-nosnippet>36</a> datatype: datatype <span class="kw">as </span>i32,
<a href=#37 id=37 data-nosnippet>37</a> semantic_type: SemanticType::Tag <span class="kw">as </span>i32,
<a href=#38 id=38 data-nosnippet>38</a> ..Default::default()
<a href=#39 id=39 data-nosnippet>39</a> }
<a href=#40 id=40 data-nosnippet>40</a>}
<a href=#41 id=41 data-nosnippet>41</a>
<a href=#42 id=42 data-nosnippet>42</a><span class="doccomment">/// Create a field [ColumnSchema] with column's name and datatype.
<a href=#43 id=43 data-nosnippet>43</a>/// Other fields are left default.
<a href=#44 id=44 data-nosnippet>44</a>/// Useful when you just want to create a simple [ColumnSchema] without providing much struct fields.
<a href=#45 id=45 data-nosnippet>45</a></span><span class="kw">pub fn </span>field_column_schema(name: <span class="kw-2">&amp;</span>str, datatype: ColumnDataType) -&gt; ColumnSchema {
<a href=#46 id=46 data-nosnippet>46</a> ColumnSchema {
<a href=#47 id=47 data-nosnippet>47</a> column_name: name.to_string(),
<a href=#48 id=48 data-nosnippet>48</a> datatype: datatype <span class="kw">as </span>i32,
<a href=#49 id=49 data-nosnippet>49</a> semantic_type: SemanticType::Field <span class="kw">as </span>i32,
<a href=#50 id=50 data-nosnippet>50</a> ..Default::default()
<a href=#51 id=51 data-nosnippet>51</a> }
<a href=#52 id=52 data-nosnippet>52</a>}
<a href=#53 id=53 data-nosnippet>53</a>
<a href=#54 id=54 data-nosnippet>54</a><span class="doccomment">/// Create a [Row] from [ValueData]s.
<a href=#55 id=55 data-nosnippet>55</a>/// Useful when you don't want to write much verbose codes.
<a href=#56 id=56 data-nosnippet>56</a></span><span class="kw">pub fn </span>row(values: Vec&lt;ValueData&gt;) -&gt; Row {
<a href=#57 id=57 data-nosnippet>57</a> Row {
<a href=#58 id=58 data-nosnippet>58</a> values: values
<a href=#59 id=59 data-nosnippet>59</a> .into_iter()
<a href=#60 id=60 data-nosnippet>60</a> .map(|x| Value {
<a href=#61 id=61 data-nosnippet>61</a> value_data: <span class="prelude-val">Some</span>(x),
<a href=#62 id=62 data-nosnippet>62</a> })
<a href=#63 id=63 data-nosnippet>63</a> .collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;(),
<a href=#64 id=64 data-nosnippet>64</a> }
<a href=#65 id=65 data-nosnippet>65</a>}
</code></pre></div></section></main></body></html>
+664
View File
@@ -0,0 +1,664 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/auth/src/common.rs`."><title>common.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="auth" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">auth/</div>common.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, LazyLock};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_base::secrets::SecretString;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>digest::Digest;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>hmac::{Hmac, Mac};
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>pbkdf2::pbkdf2_hmac;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>sha1::Sha1;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>sha2::Sha256;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>snafu::{OptionExt, ensure};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>subtle::ConstantTimeEq;
<a href=#25 id=25 data-nosnippet>25</a>
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span><span class="kw">crate</span>::error::{IllegalParamSnafu, InvalidConfigSnafu, <span class="prelude-ty">Result</span>, UserPasswordMismatchSnafu};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span><span class="kw">crate</span>::user_info::DefaultUserInfo;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span><span class="kw">crate</span>::user_provider::static_user_provider::{STATIC_USER_PROVIDER, StaticUserProvider};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span><span class="kw">crate</span>::user_provider::watch_file_user_provider::{
<a href=#30 id=30 data-nosnippet>30</a> WATCH_FILE_USER_PROVIDER, WatchFileUserProvider,
<a href=#31 id=31 data-nosnippet>31</a>};
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>crate::{UserInfoRef, UserProviderRef};
<a href=#33 id=33 data-nosnippet>33</a>
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>DEFAULT_USERNAME: <span class="kw-2">&amp;</span>str = <span class="string">"greptime"</span>;
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">pub const </span>DEFAULT_PBKDF2_SHA256_ITERATIONS: u32 = <span class="number">4096</span>;
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">pub const </span>DEFAULT_PBKDF2_SHA256_SALT_LEN: usize = <span class="number">16</span>;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">pub const </span>PBKDF2_SHA256_HASH_LEN: usize = <span class="number">32</span>;
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">pub const </span>MAX_PBKDF2_SHA256_ITERATIONS: u32 = <span class="number">1_000_000</span>;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">pub const </span>MAX_PBKDF2_SHA256_SALT_LEN: usize = <span class="number">1024</span>;
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">pub const </span>PG_SCRAM_SHA256_KEY_LEN: usize = <span class="number">32</span>;
<a href=#41 id=41 data-nosnippet>41</a>
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">type </span>HmacSha256 = Hmac&lt;Sha256&gt;;
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="doccomment">/// Process-wide secret used to derive a stable mock salt for unknown users, so
<a href=#45 id=45 data-nosnippet>45</a>/// the SCRAM `server-first-message` can't be used to enumerate usernames.
<a href=#46 id=46 data-nosnippet>46</a></span><span class="kw">static </span>PG_SCRAM_MOCK_SECRET: LazyLock&lt;[u8; PG_SCRAM_SHA256_KEY_LEN]&gt; = LazyLock::new(rand::random);
<a href=#47 id=47 data-nosnippet>47</a>
<a href=#48 id=48 data-nosnippet>48</a><span class="doccomment">/// construct a [`UserInfo`](crate::user_info::UserInfo) impl with name
<a href=#49 id=49 data-nosnippet>49</a>/// use default username `greptime` if None is provided
<a href=#50 id=50 data-nosnippet>50</a></span><span class="kw">pub fn </span>userinfo_by_name(username: <span class="prelude-ty">Option</span>&lt;String&gt;) -&gt; UserInfoRef {
<a href=#51 id=51 data-nosnippet>51</a> DefaultUserInfo::with_name(username.unwrap_or_else(|| DEFAULT_USERNAME.to_string()))
<a href=#52 id=52 data-nosnippet>52</a>}
<a href=#53 id=53 data-nosnippet>53</a>
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">pub fn </span>user_provider_from_option(opt: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;UserProviderRef&gt; {
<a href=#55 id=55 data-nosnippet>55</a> <span class="kw">let </span>(name, content) = opt.split_once(<span class="string">':'</span>).with_context(|| InvalidConfigSnafu {
<a href=#56 id=56 data-nosnippet>56</a> value: opt.to_string(),
<a href=#57 id=57 data-nosnippet>57</a> msg: <span class="string">"UserProviderOption must be in format `&lt;option&gt;:&lt;value&gt;`"</span>,
<a href=#58 id=58 data-nosnippet>58</a> })<span class="question-mark">?</span>;
<a href=#59 id=59 data-nosnippet>59</a> <span class="kw">match </span>name {
<a href=#60 id=60 data-nosnippet>60</a> STATIC_USER_PROVIDER =&gt; {
<a href=#61 id=61 data-nosnippet>61</a> <span class="kw">let </span>provider =
<a href=#62 id=62 data-nosnippet>62</a> StaticUserProvider::new(content).map(|p| Arc::new(p) <span class="kw">as </span>UserProviderRef)<span class="question-mark">?</span>;
<a href=#63 id=63 data-nosnippet>63</a> <span class="prelude-val">Ok</span>(provider)
<a href=#64 id=64 data-nosnippet>64</a> }
<a href=#65 id=65 data-nosnippet>65</a> WATCH_FILE_USER_PROVIDER =&gt; {
<a href=#66 id=66 data-nosnippet>66</a> WatchFileUserProvider::new(content).map(|p| Arc::new(p) <span class="kw">as </span>UserProviderRef)
<a href=#67 id=67 data-nosnippet>67</a> }
<a href=#68 id=68 data-nosnippet>68</a> <span class="kw">_ </span>=&gt; InvalidConfigSnafu {
<a href=#69 id=69 data-nosnippet>69</a> value: name.to_string(),
<a href=#70 id=70 data-nosnippet>70</a> msg: <span class="string">"Invalid UserProviderOption"</span>,
<a href=#71 id=71 data-nosnippet>71</a> }
<a href=#72 id=72 data-nosnippet>72</a> .fail(),
<a href=#73 id=73 data-nosnippet>73</a> }
<a href=#74 id=74 data-nosnippet>74</a>}
<a href=#75 id=75 data-nosnippet>75</a>
<a href=#76 id=76 data-nosnippet>76</a><span class="kw">pub fn </span>static_user_provider_from_option(opt: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;StaticUserProvider&gt; {
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">let </span>(name, content) = opt.split_once(<span class="string">':'</span>).with_context(|| InvalidConfigSnafu {
<a href=#78 id=78 data-nosnippet>78</a> value: opt.to_string(),
<a href=#79 id=79 data-nosnippet>79</a> msg: <span class="string">"UserProviderOption must be in format `&lt;option&gt;:&lt;value&gt;`"</span>,
<a href=#80 id=80 data-nosnippet>80</a> })<span class="question-mark">?</span>;
<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">match </span>name {
<a href=#82 id=82 data-nosnippet>82</a> STATIC_USER_PROVIDER =&gt; {
<a href=#83 id=83 data-nosnippet>83</a> <span class="kw">let </span>provider = StaticUserProvider::new(content)<span class="question-mark">?</span>;
<a href=#84 id=84 data-nosnippet>84</a> <span class="prelude-val">Ok</span>(provider)
<a href=#85 id=85 data-nosnippet>85</a> }
<a href=#86 id=86 data-nosnippet>86</a> <span class="kw">_ </span>=&gt; InvalidConfigSnafu {
<a href=#87 id=87 data-nosnippet>87</a> value: name.to_string(),
<a href=#88 id=88 data-nosnippet>88</a> msg: <span class="macro">format!</span>(<span class="string">"Invalid UserProviderOption, expect only {STATIC_USER_PROVIDER}"</span>),
<a href=#89 id=89 data-nosnippet>89</a> }
<a href=#90 id=90 data-nosnippet>90</a> .fail(),
<a href=#91 id=91 data-nosnippet>91</a> }
<a href=#92 id=92 data-nosnippet>92</a>}
<a href=#93 id=93 data-nosnippet>93</a>
<a href=#94 id=94 data-nosnippet>94</a><span class="kw">type </span>Username&lt;<span class="lifetime">'a</span>&gt; = <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str;
<a href=#95 id=95 data-nosnippet>95</a><span class="kw">type </span>HostOrIp&lt;<span class="lifetime">'a</span>&gt; = <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str;
<a href=#96 id=96 data-nosnippet>96</a>
<a href=#97 id=97 data-nosnippet>97</a><span class="attr">#[derive(Debug, Clone)]
<a href=#98 id=98 data-nosnippet>98</a></span><span class="kw">pub enum </span>Identity&lt;<span class="lifetime">'a</span>&gt; {
<a href=#99 id=99 data-nosnippet>99</a> UserId(Username&lt;<span class="lifetime">'a</span>&gt;, <span class="prelude-ty">Option</span>&lt;HostOrIp&lt;<span class="lifetime">'a</span>&gt;&gt;),
<a href=#100 id=100 data-nosnippet>100</a>}
<a href=#101 id=101 data-nosnippet>101</a>
<a href=#102 id=102 data-nosnippet>102</a><span class="kw">pub type </span>HashedPassword&lt;<span class="lifetime">'a</span>&gt; = <span class="kw-2">&amp;</span><span class="lifetime">'a </span>[u8];
<a href=#103 id=103 data-nosnippet>103</a><span class="kw">pub type </span>Salt&lt;<span class="lifetime">'a</span>&gt; = <span class="kw-2">&amp;</span><span class="lifetime">'a </span>[u8];
<a href=#104 id=104 data-nosnippet>104</a>
<a href=#105 id=105 data-nosnippet>105</a><span class="doccomment">/// Authentication information sent by the client.
<a href=#106 id=106 data-nosnippet>106</a></span><span class="kw">pub enum </span>Password&lt;<span class="lifetime">'a</span>&gt; {
<a href=#107 id=107 data-nosnippet>107</a> PlainText(SecretString),
<a href=#108 id=108 data-nosnippet>108</a> MysqlNativePassword(HashedPassword&lt;<span class="lifetime">'a</span>&gt;, Salt&lt;<span class="lifetime">'a</span>&gt;),
<a href=#109 id=109 data-nosnippet>109</a> PgMD5(HashedPassword&lt;<span class="lifetime">'a</span>&gt;, Salt&lt;<span class="lifetime">'a</span>&gt;),
<a href=#110 id=110 data-nosnippet>110</a>}
<a href=#111 id=111 data-nosnippet>111</a>
<a href=#112 id=112 data-nosnippet>112</a><span class="kw">impl </span>Password&lt;<span class="lifetime">'_</span>&gt; {
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">pub fn </span>r#type(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#115 id=115 data-nosnippet>115</a> Password::PlainText(<span class="kw">_</span>) =&gt; <span class="string">"plain_text"</span>,
<a href=#116 id=116 data-nosnippet>116</a> Password::MysqlNativePassword(<span class="kw">_</span>, <span class="kw">_</span>) =&gt; <span class="string">"mysql_native_password"</span>,
<a href=#117 id=117 data-nosnippet>117</a> Password::PgMD5(<span class="kw">_</span>, <span class="kw">_</span>) =&gt; <span class="string">"pg_md5"</span>,
<a href=#118 id=118 data-nosnippet>118</a> }
<a href=#119 id=119 data-nosnippet>119</a> }
<a href=#120 id=120 data-nosnippet>120</a>}
<a href=#121 id=121 data-nosnippet>121</a>
<a href=#122 id=122 data-nosnippet>122</a><span class="kw">pub fn </span>auth_mysql(
<a href=#123 id=123 data-nosnippet>123</a> auth_data: HashedPassword,
<a href=#124 id=124 data-nosnippet>124</a> salt: Salt,
<a href=#125 id=125 data-nosnippet>125</a> username: <span class="kw-2">&amp;</span>str,
<a href=#126 id=126 data-nosnippet>126</a> save_pwd: <span class="kw-2">&amp;</span>[u8],
<a href=#127 id=127 data-nosnippet>127</a>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw">let </span>hash_stage_2 = mysql_native_password_hash(save_pwd);
<a href=#129 id=129 data-nosnippet>129</a> auth_mysql_with_hash_stage_2(auth_data, salt, username, <span class="kw-2">&amp;</span>hash_stage_2)
<a href=#130 id=130 data-nosnippet>130</a>}
<a href=#131 id=131 data-nosnippet>131</a>
<a href=#132 id=132 data-nosnippet>132</a><span class="doccomment">/// Authenticates a MySQL native password response against an encoded verifier.
<a href=#133 id=133 data-nosnippet>133</a></span><span class="kw">pub fn </span>auth_mysql_with_verifier(
<a href=#134 id=134 data-nosnippet>134</a> auth_data: HashedPassword,
<a href=#135 id=135 data-nosnippet>135</a> salt: Salt,
<a href=#136 id=136 data-nosnippet>136</a> username: <span class="kw-2">&amp;</span>str,
<a href=#137 id=137 data-nosnippet>137</a> verifier: <span class="kw-2">&amp;</span>str,
<a href=#138 id=138 data-nosnippet>138</a>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#139 id=139 data-nosnippet>139</a> <span class="kw">let </span>hash_stage_2 = parse_mysql_native_password_verifier(verifier)<span class="question-mark">?</span>;
<a href=#140 id=140 data-nosnippet>140</a> auth_mysql_with_hash_stage_2(auth_data, salt, username, <span class="kw-2">&amp;</span>hash_stage_2)
<a href=#141 id=141 data-nosnippet>141</a>}
<a href=#142 id=142 data-nosnippet>142</a>
<a href=#143 id=143 data-nosnippet>143</a><span class="kw">pub fn </span>validate_mysql_native_password_verifier(verifier: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#144 id=144 data-nosnippet>144</a> parse_mysql_native_password_verifier(verifier).map(|<span class="kw">_</span>| ())
<a href=#145 id=145 data-nosnippet>145</a>}
<a href=#146 id=146 data-nosnippet>146</a>
<a href=#147 id=147 data-nosnippet>147</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>parse_mysql_native_password_verifier(verifier: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;u8&gt;&gt; {
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">let </span><span class="prelude-val">Some</span>(verifier) = verifier.strip_prefix(<span class="string">"mysql_native_password:"</span>) <span class="kw">else </span>{
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">return </span>InvalidConfigSnafu {
<a href=#150 id=150 data-nosnippet>150</a> value: <span class="string">"mysql_native_password"</span>.to_string(),
<a href=#151 id=151 data-nosnippet>151</a> msg: <span class="string">"Invalid mysql native password verifier format"</span>,
<a href=#152 id=152 data-nosnippet>152</a> }
<a href=#153 id=153 data-nosnippet>153</a> .fail();
<a href=#154 id=154 data-nosnippet>154</a> };
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">let </span><span class="prelude-val">Ok</span>(hash_stage_2) = hex::decode(verifier) <span class="kw">else </span>{
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">return </span>InvalidConfigSnafu {
<a href=#157 id=157 data-nosnippet>157</a> value: <span class="string">"mysql_native_password"</span>.to_string(),
<a href=#158 id=158 data-nosnippet>158</a> msg: <span class="string">"Invalid mysql native password verifier encoding"</span>,
<a href=#159 id=159 data-nosnippet>159</a> }
<a href=#160 id=160 data-nosnippet>160</a> .fail();
<a href=#161 id=161 data-nosnippet>161</a> };
<a href=#162 id=162 data-nosnippet>162</a> <span class="macro">ensure!</span>(
<a href=#163 id=163 data-nosnippet>163</a> hash_stage_2.len() == <span class="number">20</span>,
<a href=#164 id=164 data-nosnippet>164</a> InvalidConfigSnafu {
<a href=#165 id=165 data-nosnippet>165</a> value: <span class="string">"mysql_native_password"</span>.to_string(),
<a href=#166 id=166 data-nosnippet>166</a> msg: <span class="string">"Illegal mysql native password verifier length"</span>,
<a href=#167 id=167 data-nosnippet>167</a> }
<a href=#168 id=168 data-nosnippet>168</a> );
<a href=#169 id=169 data-nosnippet>169</a> <span class="prelude-val">Ok</span>(hash_stage_2)
<a href=#170 id=170 data-nosnippet>170</a>}
<a href=#171 id=171 data-nosnippet>171</a>
<a href=#172 id=172 data-nosnippet>172</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>auth_mysql_with_hash_stage_2(
<a href=#173 id=173 data-nosnippet>173</a> auth_data: HashedPassword,
<a href=#174 id=174 data-nosnippet>174</a> salt: Salt,
<a href=#175 id=175 data-nosnippet>175</a> username: <span class="kw-2">&amp;</span>str,
<a href=#176 id=176 data-nosnippet>176</a> hash_stage_2: <span class="kw-2">&amp;</span>[u8],
<a href=#177 id=177 data-nosnippet>177</a>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#178 id=178 data-nosnippet>178</a> <span class="macro">ensure!</span>(
<a href=#179 id=179 data-nosnippet>179</a> auth_data.len() == <span class="number">20</span>,
<a href=#180 id=180 data-nosnippet>180</a> IllegalParamSnafu {
<a href=#181 id=181 data-nosnippet>181</a> msg: <span class="string">"Illegal mysql password length"
<a href=#182 id=182 data-nosnippet>182</a> </span>}
<a href=#183 id=183 data-nosnippet>183</a> );
<a href=#184 id=184 data-nosnippet>184</a> <span class="macro">ensure!</span>(
<a href=#185 id=185 data-nosnippet>185</a> hash_stage_2.len() == <span class="number">20</span>,
<a href=#186 id=186 data-nosnippet>186</a> InvalidConfigSnafu {
<a href=#187 id=187 data-nosnippet>187</a> value: hash_stage_2.len().to_string(),
<a href=#188 id=188 data-nosnippet>188</a> msg: <span class="string">"Illegal mysql native password verifier length"</span>,
<a href=#189 id=189 data-nosnippet>189</a> }
<a href=#190 id=190 data-nosnippet>190</a> );
<a href=#191 id=191 data-nosnippet>191</a> <span class="comment">// ref: https://github.com/mysql/mysql-server/blob/a246bad76b9271cb4333634e954040a970222e0a/sql/auth/password.cc#L62
<a href=#192 id=192 data-nosnippet>192</a> </span><span class="kw">let </span>tmp = sha1_two(salt, hash_stage_2);
<a href=#193 id=193 data-nosnippet>193</a> <span class="comment">// xor auth_data and tmp
<a href=#194 id=194 data-nosnippet>194</a> </span><span class="kw">let </span><span class="kw-2">mut </span>xor_result = [<span class="number">0u8</span>; <span class="number">20</span>];
<a href=#195 id=195 data-nosnippet>195</a> <span class="kw">for </span>i <span class="kw">in </span><span class="number">0</span>..<span class="number">20 </span>{
<a href=#196 id=196 data-nosnippet>196</a> xor_result[i] = auth_data[i] ^ tmp[i];
<a href=#197 id=197 data-nosnippet>197</a> }
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">let </span>candidate_stage_2 = sha1_one(<span class="kw-2">&amp;</span>xor_result);
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">if </span>candidate_stage_2 == hash_stage_2 {
<a href=#200 id=200 data-nosnippet>200</a> <span class="prelude-val">Ok</span>(())
<a href=#201 id=201 data-nosnippet>201</a> } <span class="kw">else </span>{
<a href=#202 id=202 data-nosnippet>202</a> UserPasswordMismatchSnafu {
<a href=#203 id=203 data-nosnippet>203</a> username: username.to_string(),
<a href=#204 id=204 data-nosnippet>204</a> }
<a href=#205 id=205 data-nosnippet>205</a> .fail()
<a href=#206 id=206 data-nosnippet>206</a> }
<a href=#207 id=207 data-nosnippet>207</a>}
<a href=#208 id=208 data-nosnippet>208</a>
<a href=#209 id=209 data-nosnippet>209</a><span class="kw">pub fn </span>mysql_native_password_hash(save_pwd: <span class="kw-2">&amp;</span>[u8]) -&gt; Vec&lt;u8&gt; {
<a href=#210 id=210 data-nosnippet>210</a> double_sha1(save_pwd)
<a href=#211 id=211 data-nosnippet>211</a>}
<a href=#212 id=212 data-nosnippet>212</a>
<a href=#213 id=213 data-nosnippet>213</a><span class="kw">pub fn </span>format_mysql_native_password_verifier(password: <span class="kw-2">&amp;</span>[u8]) -&gt; String {
<a href=#214 id=214 data-nosnippet>214</a> <span class="macro">format!</span>(
<a href=#215 id=215 data-nosnippet>215</a> <span class="string">"mysql_native_password:{}"</span>,
<a href=#216 id=216 data-nosnippet>216</a> hex::encode(mysql_native_password_hash(password))
<a href=#217 id=217 data-nosnippet>217</a> )
<a href=#218 id=218 data-nosnippet>218</a>}
<a href=#219 id=219 data-nosnippet>219</a>
<a href=#220 id=220 data-nosnippet>220</a><span class="kw">pub fn </span>format_pbkdf2_sha256_password_verifier(
<a href=#221 id=221 data-nosnippet>221</a> password: <span class="kw-2">&amp;</span>[u8],
<a href=#222 id=222 data-nosnippet>222</a> salt: <span class="kw-2">&amp;</span>[u8],
<a href=#223 id=223 data-nosnippet>223</a> iterations: u32,
<a href=#224 id=224 data-nosnippet>224</a>) -&gt; <span class="prelude-ty">Result</span>&lt;String&gt; {
<a href=#225 id=225 data-nosnippet>225</a> <span class="macro">ensure!</span>(
<a href=#226 id=226 data-nosnippet>226</a> iterations &gt; <span class="number">0 </span>&amp;&amp; iterations &lt;= MAX_PBKDF2_SHA256_ITERATIONS,
<a href=#227 id=227 data-nosnippet>227</a> IllegalParamSnafu {
<a href=#228 id=228 data-nosnippet>228</a> msg: <span class="macro">format!</span>(
<a href=#229 id=229 data-nosnippet>229</a> <span class="string">"pbkdf2_sha256 iterations must be in 1..={}"</span>,
<a href=#230 id=230 data-nosnippet>230</a> MAX_PBKDF2_SHA256_ITERATIONS
<a href=#231 id=231 data-nosnippet>231</a> )
<a href=#232 id=232 data-nosnippet>232</a> }
<a href=#233 id=233 data-nosnippet>233</a> );
<a href=#234 id=234 data-nosnippet>234</a> <span class="macro">ensure!</span>(
<a href=#235 id=235 data-nosnippet>235</a> !salt.is_empty() &amp;&amp; salt.len() &lt;= MAX_PBKDF2_SHA256_SALT_LEN,
<a href=#236 id=236 data-nosnippet>236</a> IllegalParamSnafu {
<a href=#237 id=237 data-nosnippet>237</a> msg: <span class="macro">format!</span>(
<a href=#238 id=238 data-nosnippet>238</a> <span class="string">"pbkdf2_sha256 salt length must be in 1..={}"</span>,
<a href=#239 id=239 data-nosnippet>239</a> MAX_PBKDF2_SHA256_SALT_LEN
<a href=#240 id=240 data-nosnippet>240</a> )
<a href=#241 id=241 data-nosnippet>241</a> }
<a href=#242 id=242 data-nosnippet>242</a> );
<a href=#243 id=243 data-nosnippet>243</a>
<a href=#244 id=244 data-nosnippet>244</a> <span class="kw">let </span><span class="kw-2">mut </span>hash = [<span class="number">0u8</span>; PBKDF2_SHA256_HASH_LEN];
<a href=#245 id=245 data-nosnippet>245</a> pbkdf2_hmac::&lt;Sha256&gt;(password, salt, iterations, <span class="kw-2">&amp;mut </span>hash);
<a href=#246 id=246 data-nosnippet>246</a> <span class="prelude-val">Ok</span>(<span class="macro">format!</span>(
<a href=#247 id=247 data-nosnippet>247</a> <span class="string">"pbkdf2_sha256:{iterations}:{}:{}"</span>,
<a href=#248 id=248 data-nosnippet>248</a> hex::encode(salt),
<a href=#249 id=249 data-nosnippet>249</a> hex::encode(hash)
<a href=#250 id=250 data-nosnippet>250</a> ))
<a href=#251 id=251 data-nosnippet>251</a>}
<a href=#252 id=252 data-nosnippet>252</a>
<a href=#253 id=253 data-nosnippet>253</a><span class="attr">#[derive(Clone, PartialEq, Eq)]
<a href=#254 id=254 data-nosnippet>254</a></span><span class="kw">pub struct </span>PgScramSha256Verifier {
<a href=#255 id=255 data-nosnippet>255</a> iterations: u32,
<a href=#256 id=256 data-nosnippet>256</a> salt: Vec&lt;u8&gt;,
<a href=#257 id=257 data-nosnippet>257</a> stored_key: Vec&lt;u8&gt;,
<a href=#258 id=258 data-nosnippet>258</a> server_key: Vec&lt;u8&gt;,
<a href=#259 id=259 data-nosnippet>259</a>}
<a href=#260 id=260 data-nosnippet>260</a>
<a href=#261 id=261 data-nosnippet>261</a><span class="kw">impl </span>std::fmt::Debug <span class="kw">for </span>PgScramSha256Verifier {
<a href=#262 id=262 data-nosnippet>262</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>std::fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; std::fmt::Result {
<a href=#263 id=263 data-nosnippet>263</a> f.debug_struct(<span class="string">"PgScramSha256Verifier"</span>)
<a href=#264 id=264 data-nosnippet>264</a> .field(<span class="string">"iterations"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.iterations)
<a href=#265 id=265 data-nosnippet>265</a> .field(<span class="string">"salt"</span>, <span class="kw-2">&amp;</span><span class="string">"&lt;REDACTED&gt;"</span>)
<a href=#266 id=266 data-nosnippet>266</a> .field(<span class="string">"stored_key"</span>, <span class="kw-2">&amp;</span><span class="string">"&lt;REDACTED&gt;"</span>)
<a href=#267 id=267 data-nosnippet>267</a> .field(<span class="string">"server_key"</span>, <span class="kw-2">&amp;</span><span class="string">"&lt;REDACTED&gt;"</span>)
<a href=#268 id=268 data-nosnippet>268</a> .finish()
<a href=#269 id=269 data-nosnippet>269</a> }
<a href=#270 id=270 data-nosnippet>270</a>}
<a href=#271 id=271 data-nosnippet>271</a>
<a href=#272 id=272 data-nosnippet>272</a><span class="kw">impl </span>PgScramSha256Verifier {
<a href=#273 id=273 data-nosnippet>273</a> <span class="kw">pub fn </span>new(
<a href=#274 id=274 data-nosnippet>274</a> iterations: u32,
<a href=#275 id=275 data-nosnippet>275</a> salt: Vec&lt;u8&gt;,
<a href=#276 id=276 data-nosnippet>276</a> stored_key: Vec&lt;u8&gt;,
<a href=#277 id=277 data-nosnippet>277</a> server_key: Vec&lt;u8&gt;,
<a href=#278 id=278 data-nosnippet>278</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>&gt; {
<a href=#279 id=279 data-nosnippet>279</a> <span class="macro">ensure!</span>(
<a href=#280 id=280 data-nosnippet>280</a> iterations &gt; <span class="number">0 </span>&amp;&amp; iterations &lt;= MAX_PBKDF2_SHA256_ITERATIONS,
<a href=#281 id=281 data-nosnippet>281</a> IllegalParamSnafu {
<a href=#282 id=282 data-nosnippet>282</a> msg: <span class="macro">format!</span>(
<a href=#283 id=283 data-nosnippet>283</a> <span class="string">"pg_scram_sha256 iterations must be in 1..={}"</span>,
<a href=#284 id=284 data-nosnippet>284</a> MAX_PBKDF2_SHA256_ITERATIONS
<a href=#285 id=285 data-nosnippet>285</a> )
<a href=#286 id=286 data-nosnippet>286</a> }
<a href=#287 id=287 data-nosnippet>287</a> );
<a href=#288 id=288 data-nosnippet>288</a> <span class="macro">ensure!</span>(
<a href=#289 id=289 data-nosnippet>289</a> !salt.is_empty() &amp;&amp; salt.len() &lt;= MAX_PBKDF2_SHA256_SALT_LEN,
<a href=#290 id=290 data-nosnippet>290</a> IllegalParamSnafu {
<a href=#291 id=291 data-nosnippet>291</a> msg: <span class="macro">format!</span>(
<a href=#292 id=292 data-nosnippet>292</a> <span class="string">"pg_scram_sha256 salt length must be in 1..={}"</span>,
<a href=#293 id=293 data-nosnippet>293</a> MAX_PBKDF2_SHA256_SALT_LEN
<a href=#294 id=294 data-nosnippet>294</a> )
<a href=#295 id=295 data-nosnippet>295</a> }
<a href=#296 id=296 data-nosnippet>296</a> );
<a href=#297 id=297 data-nosnippet>297</a> <span class="macro">ensure!</span>(
<a href=#298 id=298 data-nosnippet>298</a> stored_key.len() == PG_SCRAM_SHA256_KEY_LEN,
<a href=#299 id=299 data-nosnippet>299</a> IllegalParamSnafu {
<a href=#300 id=300 data-nosnippet>300</a> msg: <span class="string">"pg_scram_sha256 stored key must be 32 bytes"
<a href=#301 id=301 data-nosnippet>301</a> </span>}
<a href=#302 id=302 data-nosnippet>302</a> );
<a href=#303 id=303 data-nosnippet>303</a> <span class="macro">ensure!</span>(
<a href=#304 id=304 data-nosnippet>304</a> server_key.len() == PG_SCRAM_SHA256_KEY_LEN,
<a href=#305 id=305 data-nosnippet>305</a> IllegalParamSnafu {
<a href=#306 id=306 data-nosnippet>306</a> msg: <span class="string">"pg_scram_sha256 server key must be 32 bytes"
<a href=#307 id=307 data-nosnippet>307</a> </span>}
<a href=#308 id=308 data-nosnippet>308</a> );
<a href=#309 id=309 data-nosnippet>309</a>
<a href=#310 id=310 data-nosnippet>310</a> <span class="prelude-val">Ok</span>(<span class="self">Self </span>{
<a href=#311 id=311 data-nosnippet>311</a> iterations,
<a href=#312 id=312 data-nosnippet>312</a> salt,
<a href=#313 id=313 data-nosnippet>313</a> stored_key,
<a href=#314 id=314 data-nosnippet>314</a> server_key,
<a href=#315 id=315 data-nosnippet>315</a> })
<a href=#316 id=316 data-nosnippet>316</a> }
<a href=#317 id=317 data-nosnippet>317</a>
<a href=#318 id=318 data-nosnippet>318</a> <span class="kw">pub fn </span>from_password(password: <span class="kw-2">&amp;</span>[u8], salt: <span class="kw-2">&amp;</span>[u8], iterations: u32) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>&gt; {
<a href=#319 id=319 data-nosnippet>319</a> <span class="kw">let </span>salted_password = pg_scram_sha256_salted_password(password, salt, iterations)<span class="question-mark">?</span>;
<a href=#320 id=320 data-nosnippet>320</a> <span class="self">Self</span>::from_salted_password(salted_password, salt.to_vec(), iterations)
<a href=#321 id=321 data-nosnippet>321</a> }
<a href=#322 id=322 data-nosnippet>322</a>
<a href=#323 id=323 data-nosnippet>323</a> <span class="kw">pub fn </span>from_salted_password(
<a href=#324 id=324 data-nosnippet>324</a> salted_password: Vec&lt;u8&gt;,
<a href=#325 id=325 data-nosnippet>325</a> salt: Vec&lt;u8&gt;,
<a href=#326 id=326 data-nosnippet>326</a> iterations: u32,
<a href=#327 id=327 data-nosnippet>327</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>&gt; {
<a href=#328 id=328 data-nosnippet>328</a> <span class="macro">ensure!</span>(
<a href=#329 id=329 data-nosnippet>329</a> salted_password.len() == PG_SCRAM_SHA256_KEY_LEN,
<a href=#330 id=330 data-nosnippet>330</a> IllegalParamSnafu {
<a href=#331 id=331 data-nosnippet>331</a> msg: <span class="string">"pg_scram_sha256 salted password must be 32 bytes"
<a href=#332 id=332 data-nosnippet>332</a> </span>}
<a href=#333 id=333 data-nosnippet>333</a> );
<a href=#334 id=334 data-nosnippet>334</a> <span class="kw">let </span>client_key = hmac_sha256(<span class="kw-2">&amp;</span>salted_password, <span class="string">b"Client Key"</span>);
<a href=#335 id=335 data-nosnippet>335</a> <span class="kw">let </span>stored_key = sha256(<span class="kw-2">&amp;</span>client_key);
<a href=#336 id=336 data-nosnippet>336</a> <span class="kw">let </span>server_key = hmac_sha256(<span class="kw-2">&amp;</span>salted_password, <span class="string">b"Server Key"</span>);
<a href=#337 id=337 data-nosnippet>337</a> <span class="self">Self</span>::new(iterations, salt, stored_key, server_key)
<a href=#338 id=338 data-nosnippet>338</a> }
<a href=#339 id=339 data-nosnippet>339</a>
<a href=#340 id=340 data-nosnippet>340</a> <span class="doccomment">/// Builds a throwaway verifier for an unknown user. The salt is derived
<a href=#341 id=341 data-nosnippet>341</a> /// deterministically from the username and a process-wide secret, so the
<a href=#342 id=342 data-nosnippet>342</a> /// SCRAM `server-first-message` (salt + iterations) stays stable per
<a href=#343 id=343 data-nosnippet>343</a> /// username and indistinguishable from a real user across reconnects. No
<a href=#344 id=344 data-nosnippet>344</a> /// PBKDF2 is run (avoids a CPU-exhaustion DoS keyed on unknown usernames),
<a href=#345 id=345 data-nosnippet>345</a> /// and the random keys guarantee the client proof never matches.
<a href=#346 id=346 data-nosnippet>346</a> </span><span class="kw">pub fn </span>mock_for_unknown_user(username: <span class="kw-2">&amp;</span>[u8]) -&gt; <span class="self">Self </span>{
<a href=#347 id=347 data-nosnippet>347</a> <span class="kw">let </span>mock_salt = hmac_sha256(PG_SCRAM_MOCK_SECRET.as_slice(), username);
<a href=#348 id=348 data-nosnippet>348</a> <span class="self">Self </span>{
<a href=#349 id=349 data-nosnippet>349</a> iterations: DEFAULT_PBKDF2_SHA256_ITERATIONS,
<a href=#350 id=350 data-nosnippet>350</a> salt: mock_salt[..DEFAULT_PBKDF2_SHA256_SALT_LEN].to_vec(),
<a href=#351 id=351 data-nosnippet>351</a> stored_key: rand::random::&lt;[u8; PG_SCRAM_SHA256_KEY_LEN]&gt;().to_vec(),
<a href=#352 id=352 data-nosnippet>352</a> server_key: rand::random::&lt;[u8; PG_SCRAM_SHA256_KEY_LEN]&gt;().to_vec(),
<a href=#353 id=353 data-nosnippet>353</a> }
<a href=#354 id=354 data-nosnippet>354</a> }
<a href=#355 id=355 data-nosnippet>355</a>
<a href=#356 id=356 data-nosnippet>356</a> <span class="kw">pub fn </span>iterations(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; u32 {
<a href=#357 id=357 data-nosnippet>357</a> <span class="self">self</span>.iterations
<a href=#358 id=358 data-nosnippet>358</a> }
<a href=#359 id=359 data-nosnippet>359</a>
<a href=#360 id=360 data-nosnippet>360</a> <span class="kw">pub fn </span>salt(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>[u8] {
<a href=#361 id=361 data-nosnippet>361</a> <span class="kw-2">&amp;</span><span class="self">self</span>.salt
<a href=#362 id=362 data-nosnippet>362</a> }
<a href=#363 id=363 data-nosnippet>363</a>
<a href=#364 id=364 data-nosnippet>364</a> <span class="kw">pub fn </span>verify_plain_password(<span class="kw-2">&amp;</span><span class="self">self</span>, password: <span class="kw-2">&amp;</span>[u8]) -&gt; <span class="prelude-ty">Result</span>&lt;bool&gt; {
<a href=#365 id=365 data-nosnippet>365</a> <span class="kw">let </span>salted_password =
<a href=#366 id=366 data-nosnippet>366</a> pg_scram_sha256_salted_password(password, <span class="kw-2">&amp;</span><span class="self">self</span>.salt, <span class="self">self</span>.iterations)<span class="question-mark">?</span>;
<a href=#367 id=367 data-nosnippet>367</a> <span class="kw">let </span>client_key = hmac_sha256(<span class="kw-2">&amp;</span>salted_password, <span class="string">b"Client Key"</span>);
<a href=#368 id=368 data-nosnippet>368</a> <span class="kw">let </span>stored_key = sha256(<span class="kw-2">&amp;</span>client_key);
<a href=#369 id=369 data-nosnippet>369</a> <span class="prelude-val">Ok</span>(<span class="self">self</span>.stored_key.ct_eq(<span class="kw-2">&amp;</span>stored_key).into())
<a href=#370 id=370 data-nosnippet>370</a> }
<a href=#371 id=371 data-nosnippet>371</a>
<a href=#372 id=372 data-nosnippet>372</a> <span class="kw">pub fn </span>verify_client_proof(
<a href=#373 id=373 data-nosnippet>373</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#374 id=374 data-nosnippet>374</a> auth_message: <span class="kw-2">&amp;</span>[u8],
<a href=#375 id=375 data-nosnippet>375</a> client_proof: <span class="kw-2">&amp;</span>[u8],
<a href=#376 id=376 data-nosnippet>376</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Vec&lt;u8&gt;&gt;&gt; {
<a href=#377 id=377 data-nosnippet>377</a> <span class="kw">if </span>client_proof.len() != PG_SCRAM_SHA256_KEY_LEN {
<a href=#378 id=378 data-nosnippet>378</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>);
<a href=#379 id=379 data-nosnippet>379</a> }
<a href=#380 id=380 data-nosnippet>380</a>
<a href=#381 id=381 data-nosnippet>381</a> <span class="kw">let </span>client_signature = hmac_sha256(<span class="kw-2">&amp;</span><span class="self">self</span>.stored_key, auth_message);
<a href=#382 id=382 data-nosnippet>382</a> <span class="kw">let </span>client_key = xor(client_proof, <span class="kw-2">&amp;</span>client_signature);
<a href=#383 id=383 data-nosnippet>383</a> <span class="kw">let </span>stored_key = sha256(<span class="kw-2">&amp;</span>client_key);
<a href=#384 id=384 data-nosnippet>384</a> <span class="kw">if </span><span class="self">self</span>.stored_key.ct_eq(<span class="kw-2">&amp;</span>stored_key).into() {
<a href=#385 id=385 data-nosnippet>385</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(hmac_sha256(<span class="kw-2">&amp;</span><span class="self">self</span>.server_key, auth_message)))
<a href=#386 id=386 data-nosnippet>386</a> } <span class="kw">else </span>{
<a href=#387 id=387 data-nosnippet>387</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
<a href=#388 id=388 data-nosnippet>388</a> }
<a href=#389 id=389 data-nosnippet>389</a> }
<a href=#390 id=390 data-nosnippet>390</a>}
<a href=#391 id=391 data-nosnippet>391</a>
<a href=#392 id=392 data-nosnippet>392</a><span class="kw">pub fn </span>format_pg_scram_sha256_password_verifier(
<a href=#393 id=393 data-nosnippet>393</a> password: <span class="kw-2">&amp;</span>[u8],
<a href=#394 id=394 data-nosnippet>394</a> salt: <span class="kw-2">&amp;</span>[u8],
<a href=#395 id=395 data-nosnippet>395</a> iterations: u32,
<a href=#396 id=396 data-nosnippet>396</a>) -&gt; <span class="prelude-ty">Result</span>&lt;String&gt; {
<a href=#397 id=397 data-nosnippet>397</a> <span class="kw">let </span>verifier = PgScramSha256Verifier::from_password(password, salt, iterations)<span class="question-mark">?</span>;
<a href=#398 id=398 data-nosnippet>398</a> <span class="prelude-val">Ok</span>(<span class="macro">format!</span>(
<a href=#399 id=399 data-nosnippet>399</a> <span class="string">"pg_scram_sha256:{iterations}:{}:{}:{}"</span>,
<a href=#400 id=400 data-nosnippet>400</a> hex::encode(verifier.salt),
<a href=#401 id=401 data-nosnippet>401</a> hex::encode(verifier.stored_key),
<a href=#402 id=402 data-nosnippet>402</a> hex::encode(verifier.server_key)
<a href=#403 id=403 data-nosnippet>403</a> ))
<a href=#404 id=404 data-nosnippet>404</a>}
<a href=#405 id=405 data-nosnippet>405</a>
<a href=#406 id=406 data-nosnippet>406</a><span class="doccomment">/// Parses and validates an encoded PostgreSQL SCRAM-SHA-256 verifier.
<a href=#407 id=407 data-nosnippet>407</a></span><span class="kw">pub fn </span>parse_pg_scram_sha256_password_verifier(verifier: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;PgScramSha256Verifier&gt; {
<a href=#408 id=408 data-nosnippet>408</a> <span class="kw">let </span><span class="prelude-val">Some</span>(verifier) = verifier.strip_prefix(<span class="string">"pg_scram_sha256:"</span>) <span class="kw">else </span>{
<a href=#409 id=409 data-nosnippet>409</a> <span class="kw">return </span>InvalidConfigSnafu {
<a href=#410 id=410 data-nosnippet>410</a> value: <span class="string">"pg_scram_sha256"</span>.to_string(),
<a href=#411 id=411 data-nosnippet>411</a> msg: <span class="string">"Invalid pg scram sha256 verifier format"</span>,
<a href=#412 id=412 data-nosnippet>412</a> }
<a href=#413 id=413 data-nosnippet>413</a> .fail();
<a href=#414 id=414 data-nosnippet>414</a> };
<a href=#415 id=415 data-nosnippet>415</a> <span class="kw">let </span><span class="kw-2">mut </span>parts = verifier.split(<span class="string">':'</span>);
<a href=#416 id=416 data-nosnippet>416</a> <span class="kw">let </span>(<span class="prelude-val">Some</span>(iterations), <span class="prelude-val">Some</span>(salt), <span class="prelude-val">Some</span>(stored_key), <span class="prelude-val">Some</span>(server_key), <span class="prelude-val">None</span>) = (
<a href=#417 id=417 data-nosnippet>417</a> parts.next(),
<a href=#418 id=418 data-nosnippet>418</a> parts.next(),
<a href=#419 id=419 data-nosnippet>419</a> parts.next(),
<a href=#420 id=420 data-nosnippet>420</a> parts.next(),
<a href=#421 id=421 data-nosnippet>421</a> parts.next(),
<a href=#422 id=422 data-nosnippet>422</a> ) <span class="kw">else </span>{
<a href=#423 id=423 data-nosnippet>423</a> <span class="kw">return </span>InvalidConfigSnafu {
<a href=#424 id=424 data-nosnippet>424</a> value: <span class="string">"pg_scram_sha256"</span>.to_string(),
<a href=#425 id=425 data-nosnippet>425</a> msg: <span class="string">"Invalid pg scram sha256 verifier format"</span>,
<a href=#426 id=426 data-nosnippet>426</a> }
<a href=#427 id=427 data-nosnippet>427</a> .fail();
<a href=#428 id=428 data-nosnippet>428</a> };
<a href=#429 id=429 data-nosnippet>429</a> <span class="kw">let </span>(<span class="prelude-val">Ok</span>(iterations), <span class="prelude-val">Ok</span>(salt), <span class="prelude-val">Ok</span>(stored_key), <span class="prelude-val">Ok</span>(server_key)) = (
<a href=#430 id=430 data-nosnippet>430</a> iterations.parse::&lt;u32&gt;(),
<a href=#431 id=431 data-nosnippet>431</a> hex::decode(salt),
<a href=#432 id=432 data-nosnippet>432</a> hex::decode(stored_key),
<a href=#433 id=433 data-nosnippet>433</a> hex::decode(server_key),
<a href=#434 id=434 data-nosnippet>434</a> ) <span class="kw">else </span>{
<a href=#435 id=435 data-nosnippet>435</a> <span class="kw">return </span>InvalidConfigSnafu {
<a href=#436 id=436 data-nosnippet>436</a> value: <span class="string">"pg_scram_sha256"</span>.to_string(),
<a href=#437 id=437 data-nosnippet>437</a> msg: <span class="string">"Invalid pg scram sha256 verifier encoding"</span>,
<a href=#438 id=438 data-nosnippet>438</a> }
<a href=#439 id=439 data-nosnippet>439</a> .fail();
<a href=#440 id=440 data-nosnippet>440</a> };
<a href=#441 id=441 data-nosnippet>441</a>
<a href=#442 id=442 data-nosnippet>442</a> PgScramSha256Verifier::new(iterations, salt, stored_key, server_key)
<a href=#443 id=443 data-nosnippet>443</a>}
<a href=#444 id=444 data-nosnippet>444</a>
<a href=#445 id=445 data-nosnippet>445</a><span class="kw">fn </span>pg_scram_sha256_salted_password(
<a href=#446 id=446 data-nosnippet>446</a> password: <span class="kw-2">&amp;</span>[u8],
<a href=#447 id=447 data-nosnippet>447</a> salt: <span class="kw-2">&amp;</span>[u8],
<a href=#448 id=448 data-nosnippet>448</a> iterations: u32,
<a href=#449 id=449 data-nosnippet>449</a>) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;u8&gt;&gt; {
<a href=#450 id=450 data-nosnippet>450</a> <span class="macro">ensure!</span>(
<a href=#451 id=451 data-nosnippet>451</a> iterations &gt; <span class="number">0 </span>&amp;&amp; iterations &lt;= MAX_PBKDF2_SHA256_ITERATIONS,
<a href=#452 id=452 data-nosnippet>452</a> IllegalParamSnafu {
<a href=#453 id=453 data-nosnippet>453</a> msg: <span class="macro">format!</span>(
<a href=#454 id=454 data-nosnippet>454</a> <span class="string">"pg_scram_sha256 iterations must be in 1..={}"</span>,
<a href=#455 id=455 data-nosnippet>455</a> MAX_PBKDF2_SHA256_ITERATIONS
<a href=#456 id=456 data-nosnippet>456</a> )
<a href=#457 id=457 data-nosnippet>457</a> }
<a href=#458 id=458 data-nosnippet>458</a> );
<a href=#459 id=459 data-nosnippet>459</a> <span class="macro">ensure!</span>(
<a href=#460 id=460 data-nosnippet>460</a> !salt.is_empty() &amp;&amp; salt.len() &lt;= MAX_PBKDF2_SHA256_SALT_LEN,
<a href=#461 id=461 data-nosnippet>461</a> IllegalParamSnafu {
<a href=#462 id=462 data-nosnippet>462</a> msg: <span class="macro">format!</span>(
<a href=#463 id=463 data-nosnippet>463</a> <span class="string">"pg_scram_sha256 salt length must be in 1..={}"</span>,
<a href=#464 id=464 data-nosnippet>464</a> MAX_PBKDF2_SHA256_SALT_LEN
<a href=#465 id=465 data-nosnippet>465</a> )
<a href=#466 id=466 data-nosnippet>466</a> }
<a href=#467 id=467 data-nosnippet>467</a> );
<a href=#468 id=468 data-nosnippet>468</a>
<a href=#469 id=469 data-nosnippet>469</a> <span class="kw">let </span>prepared_password = std::str::from_utf8(password)
<a href=#470 id=470 data-nosnippet>470</a> .ok()
<a href=#471 id=471 data-nosnippet>471</a> .and_then(|password| stringprep::saslprep(password).ok());
<a href=#472 id=472 data-nosnippet>472</a> <span class="kw">let </span>password = prepared_password
<a href=#473 id=473 data-nosnippet>473</a> .as_deref()
<a href=#474 id=474 data-nosnippet>474</a> .map(str::as_bytes)
<a href=#475 id=475 data-nosnippet>475</a> .unwrap_or(password);
<a href=#476 id=476 data-nosnippet>476</a>
<a href=#477 id=477 data-nosnippet>477</a> <span class="kw">let </span><span class="kw-2">mut </span>salted_password = [<span class="number">0u8</span>; PG_SCRAM_SHA256_KEY_LEN];
<a href=#478 id=478 data-nosnippet>478</a> pbkdf2_hmac::&lt;Sha256&gt;(password, salt, iterations, <span class="kw-2">&amp;mut </span>salted_password);
<a href=#479 id=479 data-nosnippet>479</a> <span class="prelude-val">Ok</span>(salted_password.to_vec())
<a href=#480 id=480 data-nosnippet>480</a>}
<a href=#481 id=481 data-nosnippet>481</a>
<a href=#482 id=482 data-nosnippet>482</a><span class="kw">fn </span>hmac_sha256(key: <span class="kw-2">&amp;</span>[u8], msg: <span class="kw-2">&amp;</span>[u8]) -&gt; Vec&lt;u8&gt; {
<a href=#483 id=483 data-nosnippet>483</a> <span class="kw">let </span><span class="kw-2">mut </span>mac = HmacSha256::new_from_slice(key).expect(<span class="string">"HMAC accepts any key length"</span>);
<a href=#484 id=484 data-nosnippet>484</a> mac.update(msg);
<a href=#485 id=485 data-nosnippet>485</a> mac.finalize().into_bytes().to_vec()
<a href=#486 id=486 data-nosnippet>486</a>}
<a href=#487 id=487 data-nosnippet>487</a>
<a href=#488 id=488 data-nosnippet>488</a><span class="kw">fn </span>sha256(data: <span class="kw-2">&amp;</span>[u8]) -&gt; Vec&lt;u8&gt; {
<a href=#489 id=489 data-nosnippet>489</a> <span class="kw">let </span><span class="kw-2">mut </span>hasher = Sha256::new();
<a href=#490 id=490 data-nosnippet>490</a> hasher.update(data);
<a href=#491 id=491 data-nosnippet>491</a> hasher.finalize().to_vec()
<a href=#492 id=492 data-nosnippet>492</a>}
<a href=#493 id=493 data-nosnippet>493</a>
<a href=#494 id=494 data-nosnippet>494</a><span class="kw">fn </span>xor(lhs: <span class="kw-2">&amp;</span>[u8], rhs: <span class="kw-2">&amp;</span>[u8]) -&gt; Vec&lt;u8&gt; {
<a href=#495 id=495 data-nosnippet>495</a> lhs.iter().zip(rhs).map(|(l, r)| l ^ r).collect()
<a href=#496 id=496 data-nosnippet>496</a>}
<a href=#497 id=497 data-nosnippet>497</a>
<a href=#498 id=498 data-nosnippet>498</a><span class="kw">fn </span>sha1_two(input_1: <span class="kw-2">&amp;</span>[u8], input_2: <span class="kw-2">&amp;</span>[u8]) -&gt; Vec&lt;u8&gt; {
<a href=#499 id=499 data-nosnippet>499</a> <span class="kw">let </span><span class="kw-2">mut </span>hasher = Sha1::new();
<a href=#500 id=500 data-nosnippet>500</a> hasher.update(input_1);
<a href=#501 id=501 data-nosnippet>501</a> hasher.update(input_2);
<a href=#502 id=502 data-nosnippet>502</a> hasher.finalize().to_vec()
<a href=#503 id=503 data-nosnippet>503</a>}
<a href=#504 id=504 data-nosnippet>504</a>
<a href=#505 id=505 data-nosnippet>505</a><span class="kw">fn </span>sha1_one(data: <span class="kw-2">&amp;</span>[u8]) -&gt; Vec&lt;u8&gt; {
<a href=#506 id=506 data-nosnippet>506</a> <span class="kw">let </span><span class="kw-2">mut </span>hasher = Sha1::new();
<a href=#507 id=507 data-nosnippet>507</a> hasher.update(data);
<a href=#508 id=508 data-nosnippet>508</a> hasher.finalize().to_vec()
<a href=#509 id=509 data-nosnippet>509</a>}
<a href=#510 id=510 data-nosnippet>510</a>
<a href=#511 id=511 data-nosnippet>511</a><span class="kw">fn </span>double_sha1(data: <span class="kw-2">&amp;</span>[u8]) -&gt; Vec&lt;u8&gt; {
<a href=#512 id=512 data-nosnippet>512</a> sha1_one(<span class="kw-2">&amp;</span>sha1_one(data))
<a href=#513 id=513 data-nosnippet>513</a>}
<a href=#514 id=514 data-nosnippet>514</a>
<a href=#515 id=515 data-nosnippet>515</a><span class="attr">#[cfg(test)]
<a href=#516 id=516 data-nosnippet>516</a></span><span class="kw">mod </span>tests {
<a href=#517 id=517 data-nosnippet>517</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#518 id=518 data-nosnippet>518</a>
<a href=#519 id=519 data-nosnippet>519</a> <span class="kw">fn </span>mysql_native_password_auth_data(password: <span class="kw-2">&amp;</span>[u8], salt: <span class="kw-2">&amp;</span>[u8]) -&gt; Vec&lt;u8&gt; {
<a href=#520 id=520 data-nosnippet>520</a> <span class="kw">let </span>hash_stage_1 = sha1_one(password);
<a href=#521 id=521 data-nosnippet>521</a> <span class="kw">let </span>hash_stage_2 = mysql_native_password_hash(password);
<a href=#522 id=522 data-nosnippet>522</a> <span class="kw">let </span>scramble = sha1_two(salt, <span class="kw-2">&amp;</span>hash_stage_2);
<a href=#523 id=523 data-nosnippet>523</a> hash_stage_1
<a href=#524 id=524 data-nosnippet>524</a> .iter()
<a href=#525 id=525 data-nosnippet>525</a> .zip(scramble)
<a href=#526 id=526 data-nosnippet>526</a> .map(|(lhs, rhs)| lhs ^ rhs)
<a href=#527 id=527 data-nosnippet>527</a> .collect()
<a href=#528 id=528 data-nosnippet>528</a> }
<a href=#529 id=529 data-nosnippet>529</a>
<a href=#530 id=530 data-nosnippet>530</a> <span class="attr">#[test]
<a href=#531 id=531 data-nosnippet>531</a> </span><span class="kw">fn </span>test_sha() {
<a href=#532 id=532 data-nosnippet>532</a> <span class="kw">let </span>sha_1_answer: Vec&lt;u8&gt; = <span class="macro">vec!</span>[
<a href=#533 id=533 data-nosnippet>533</a> <span class="number">124</span>, <span class="number">74</span>, <span class="number">141</span>, <span class="number">9</span>, <span class="number">202</span>, <span class="number">55</span>, <span class="number">98</span>, <span class="number">175</span>, <span class="number">97</span>, <span class="number">229</span>, <span class="number">149</span>, <span class="number">32</span>, <span class="number">148</span>, <span class="number">61</span>, <span class="number">194</span>, <span class="number">100</span>, <span class="number">148</span>, <span class="number">248</span>, <span class="number">148</span>,
<a href=#534 id=534 data-nosnippet>534</a> <span class="number">27</span>,
<a href=#535 id=535 data-nosnippet>535</a> ];
<a href=#536 id=536 data-nosnippet>536</a> <span class="kw">let </span>sha_1 = sha1_one(<span class="string">"123456"</span>.as_bytes());
<a href=#537 id=537 data-nosnippet>537</a> <span class="macro">assert_eq!</span>(sha_1, sha_1_answer);
<a href=#538 id=538 data-nosnippet>538</a>
<a href=#539 id=539 data-nosnippet>539</a> <span class="kw">let </span>double_sha1_answer: Vec&lt;u8&gt; = <span class="macro">vec!</span>[
<a href=#540 id=540 data-nosnippet>540</a> <span class="number">107</span>, <span class="number">180</span>, <span class="number">131</span>, <span class="number">126</span>, <span class="number">183</span>, <span class="number">67</span>, <span class="number">41</span>, <span class="number">16</span>, <span class="number">94</span>, <span class="number">228</span>, <span class="number">86</span>, <span class="number">141</span>, <span class="number">218</span>, <span class="number">125</span>, <span class="number">198</span>, <span class="number">126</span>, <span class="number">210</span>, <span class="number">202</span>,
<a href=#541 id=541 data-nosnippet>541</a> <span class="number">42</span>, <span class="number">217</span>,
<a href=#542 id=542 data-nosnippet>542</a> ];
<a href=#543 id=543 data-nosnippet>543</a> <span class="kw">let </span>double_sha1 = double_sha1(<span class="string">"123456"</span>.as_bytes());
<a href=#544 id=544 data-nosnippet>544</a> <span class="macro">assert_eq!</span>(double_sha1, double_sha1_answer);
<a href=#545 id=545 data-nosnippet>545</a>
<a href=#546 id=546 data-nosnippet>546</a> <span class="kw">let </span>sha1_2_answer: Vec&lt;u8&gt; = <span class="macro">vec!</span>[
<a href=#547 id=547 data-nosnippet>547</a> <span class="number">132</span>, <span class="number">115</span>, <span class="number">215</span>, <span class="number">211</span>, <span class="number">99</span>, <span class="number">186</span>, <span class="number">164</span>, <span class="number">206</span>, <span class="number">168</span>, <span class="number">152</span>, <span class="number">217</span>, <span class="number">192</span>, <span class="number">117</span>, <span class="number">47</span>, <span class="number">240</span>, <span class="number">252</span>, <span class="number">142</span>, <span class="number">244</span>,
<a href=#548 id=548 data-nosnippet>548</a> <span class="number">37</span>, <span class="number">204</span>,
<a href=#549 id=549 data-nosnippet>549</a> ];
<a href=#550 id=550 data-nosnippet>550</a> <span class="kw">let </span>sha1_2 = sha1_two(<span class="string">"123456"</span>.as_bytes(), <span class="string">"654321"</span>.as_bytes());
<a href=#551 id=551 data-nosnippet>551</a> <span class="macro">assert_eq!</span>(sha1_2, sha1_2_answer);
<a href=#552 id=552 data-nosnippet>552</a> }
<a href=#553 id=553 data-nosnippet>553</a>
<a href=#554 id=554 data-nosnippet>554</a> <span class="attr">#[test]
<a href=#555 id=555 data-nosnippet>555</a> </span><span class="kw">fn </span>test_format_mysql_native_password_verifier() {
<a href=#556 id=556 data-nosnippet>556</a> <span class="kw">let </span>verifier = format_mysql_native_password_verifier(<span class="string">"123456"</span>.as_bytes());
<a href=#557 id=557 data-nosnippet>557</a> <span class="macro">assert_eq!</span>(
<a href=#558 id=558 data-nosnippet>558</a> <span class="string">"mysql_native_password:6bb4837eb74329105ee4568dda7dc67ed2ca2ad9"</span>,
<a href=#559 id=559 data-nosnippet>559</a> verifier
<a href=#560 id=560 data-nosnippet>560</a> );
<a href=#561 id=561 data-nosnippet>561</a> <span class="macro">assert_eq!</span>(
<a href=#562 id=562 data-nosnippet>562</a> mysql_native_password_hash(<span class="string">b"123456"</span>),
<a href=#563 id=563 data-nosnippet>563</a> parse_mysql_native_password_verifier(<span class="kw-2">&amp;</span>verifier).unwrap()
<a href=#564 id=564 data-nosnippet>564</a> );
<a href=#565 id=565 data-nosnippet>565</a> <span class="macro">assert!</span>(parse_mysql_native_password_verifier(<span class="string">"mysql_native_password:00"</span>).is_err());
<a href=#566 id=566 data-nosnippet>566</a>
<a href=#567 id=567 data-nosnippet>567</a> <span class="kw">let </span>salt = <span class="string">b"01234567890123456789"</span>;
<a href=#568 id=568 data-nosnippet>568</a> <span class="kw">let </span>auth_data = mysql_native_password_auth_data(<span class="string">b"123456"</span>, salt);
<a href=#569 id=569 data-nosnippet>569</a> auth_mysql_with_verifier(<span class="kw-2">&amp;</span>auth_data, salt, <span class="string">"greptime"</span>, <span class="kw-2">&amp;</span>verifier).unwrap();
<a href=#570 id=570 data-nosnippet>570</a> <span class="macro">assert!</span>(
<a href=#571 id=571 data-nosnippet>571</a> auth_mysql_with_verifier(
<a href=#572 id=572 data-nosnippet>572</a> <span class="kw-2">&amp;</span>auth_data,
<a href=#573 id=573 data-nosnippet>573</a> salt,
<a href=#574 id=574 data-nosnippet>574</a> <span class="string">"greptime"</span>,
<a href=#575 id=575 data-nosnippet>575</a> <span class="kw-2">&amp;</span>format_mysql_native_password_verifier(<span class="string">b"wrong"</span>)
<a href=#576 id=576 data-nosnippet>576</a> )
<a href=#577 id=577 data-nosnippet>577</a> .is_err()
<a href=#578 id=578 data-nosnippet>578</a> );
<a href=#579 id=579 data-nosnippet>579</a> }
<a href=#580 id=580 data-nosnippet>580</a>
<a href=#581 id=581 data-nosnippet>581</a> <span class="attr">#[test]
<a href=#582 id=582 data-nosnippet>582</a> </span><span class="kw">fn </span>test_format_pbkdf2_sha256_password_verifier() {
<a href=#583 id=583 data-nosnippet>583</a> <span class="kw">let </span>verifier =
<a href=#584 id=584 data-nosnippet>584</a> format_pbkdf2_sha256_password_verifier(<span class="string">"password"</span>.as_bytes(), <span class="string">b"salt"</span>, <span class="number">4096</span>).unwrap();
<a href=#585 id=585 data-nosnippet>585</a> <span class="macro">assert_eq!</span>(
<a href=#586 id=586 data-nosnippet>586</a> <span class="string">"pbkdf2_sha256:4096:73616c74:c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a"</span>,
<a href=#587 id=587 data-nosnippet>587</a> verifier
<a href=#588 id=588 data-nosnippet>588</a> );
<a href=#589 id=589 data-nosnippet>589</a>
<a href=#590 id=590 data-nosnippet>590</a> <span class="macro">assert!</span>(format_pbkdf2_sha256_password_verifier(<span class="string">b"password"</span>, <span class="string">b""</span>, <span class="number">4096</span>).is_err());
<a href=#591 id=591 data-nosnippet>591</a> <span class="macro">assert!</span>(format_pbkdf2_sha256_password_verifier(<span class="string">b"password"</span>, <span class="string">b"salt"</span>, <span class="number">0</span>).is_err());
<a href=#592 id=592 data-nosnippet>592</a> <span class="macro">assert!</span>(
<a href=#593 id=593 data-nosnippet>593</a> format_pbkdf2_sha256_password_verifier(
<a href=#594 id=594 data-nosnippet>594</a> <span class="string">b"password"</span>,
<a href=#595 id=595 data-nosnippet>595</a> <span class="string">b"salt"</span>,
<a href=#596 id=596 data-nosnippet>596</a> MAX_PBKDF2_SHA256_ITERATIONS + <span class="number">1</span>,
<a href=#597 id=597 data-nosnippet>597</a> )
<a href=#598 id=598 data-nosnippet>598</a> .is_err()
<a href=#599 id=599 data-nosnippet>599</a> );
<a href=#600 id=600 data-nosnippet>600</a> }
<a href=#601 id=601 data-nosnippet>601</a>
<a href=#602 id=602 data-nosnippet>602</a> <span class="attr">#[test]
<a href=#603 id=603 data-nosnippet>603</a> </span><span class="kw">fn </span>test_format_pg_scram_sha256_password_verifier() {
<a href=#604 id=604 data-nosnippet>604</a> <span class="kw">let </span>verifier =
<a href=#605 id=605 data-nosnippet>605</a> format_pg_scram_sha256_password_verifier(<span class="string">"password"</span>.as_bytes(), <span class="string">b"salt"</span>, <span class="number">4096</span>).unwrap();
<a href=#606 id=606 data-nosnippet>606</a> <span class="macro">assert_eq!</span>(
<a href=#607 id=607 data-nosnippet>607</a> <span class="string">"pg_scram_sha256:4096:73616c74:945e1c466fc9932efadc23781edc5d1e78d5e10f005933652af1a6105154f084:b9bf0e811b1fb6793671c0cc3adedf7c75cd72291191092ad65878c5a02aad2c"</span>,
<a href=#608 id=608 data-nosnippet>608</a> verifier
<a href=#609 id=609 data-nosnippet>609</a> );
<a href=#610 id=610 data-nosnippet>610</a> <span class="kw">let </span>parsed = parse_pg_scram_sha256_password_verifier(<span class="kw-2">&amp;</span>verifier).unwrap();
<a href=#611 id=611 data-nosnippet>611</a> <span class="macro">assert_eq!</span>(<span class="number">4096</span>, parsed.iterations());
<a href=#612 id=612 data-nosnippet>612</a> <span class="macro">assert_eq!</span>(<span class="string">b"salt"</span>, parsed.salt());
<a href=#613 id=613 data-nosnippet>613</a> <span class="macro">assert!</span>(parse_pg_scram_sha256_password_verifier(<span class="string">"pg_scram_sha256:bad"</span>).is_err());
<a href=#614 id=614 data-nosnippet>614</a> }
<a href=#615 id=615 data-nosnippet>615</a>
<a href=#616 id=616 data-nosnippet>616</a> <span class="attr">#[test]
<a href=#617 id=617 data-nosnippet>617</a> </span><span class="kw">fn </span>test_pg_scram_sha256_applies_saslprep() {
<a href=#618 id=618 data-nosnippet>618</a> <span class="kw">let </span>normalized = PgScramSha256Verifier::from_password(<span class="string">b"pass word"</span>, <span class="string">b"salt"</span>, <span class="number">4096</span>).unwrap();
<a href=#619 id=619 data-nosnippet>619</a> <span class="kw">let </span>non_breaking_space =
<a href=#620 id=620 data-nosnippet>620</a> PgScramSha256Verifier::from_password(<span class="string">"pass\u{00a0}word"</span>.as_bytes(), <span class="string">b"salt"</span>, <span class="number">4096</span>)
<a href=#621 id=621 data-nosnippet>621</a> .unwrap();
<a href=#622 id=622 data-nosnippet>622</a>
<a href=#623 id=623 data-nosnippet>623</a> <span class="macro">assert_eq!</span>(normalized, non_breaking_space);
<a href=#624 id=624 data-nosnippet>624</a> <span class="macro">assert!</span>(
<a href=#625 id=625 data-nosnippet>625</a> non_breaking_space
<a href=#626 id=626 data-nosnippet>626</a> .verify_plain_password(<span class="string">b"pass word"</span>)
<a href=#627 id=627 data-nosnippet>627</a> .unwrap()
<a href=#628 id=628 data-nosnippet>628</a> );
<a href=#629 id=629 data-nosnippet>629</a> }
<a href=#630 id=630 data-nosnippet>630</a>
<a href=#631 id=631 data-nosnippet>631</a> <span class="attr">#[test]
<a href=#632 id=632 data-nosnippet>632</a> </span><span class="kw">fn </span>test_pg_scram_sha256_uses_original_bytes_when_saslprep_is_not_possible() {
<a href=#633 id=633 data-nosnippet>633</a> <span class="kw">let </span>invalid_utf8 = <span class="string">b"password\xff"</span>;
<a href=#634 id=634 data-nosnippet>634</a> <span class="kw">let </span>prohibited = <span class="string">b"password\x07"</span>;
<a href=#635 id=635 data-nosnippet>635</a>
<a href=#636 id=636 data-nosnippet>636</a> <span class="kw">for </span>password <span class="kw">in </span>[invalid_utf8.as_slice(), prohibited.as_slice()] {
<a href=#637 id=637 data-nosnippet>637</a> <span class="kw">let </span>verifier = PgScramSha256Verifier::from_password(password, <span class="string">b"salt"</span>, <span class="number">4096</span>).unwrap();
<a href=#638 id=638 data-nosnippet>638</a> <span class="macro">assert!</span>(verifier.verify_plain_password(password).unwrap());
<a href=#639 id=639 data-nosnippet>639</a> }
<a href=#640 id=640 data-nosnippet>640</a> }
<a href=#641 id=641 data-nosnippet>641</a>
<a href=#642 id=642 data-nosnippet>642</a> <span class="attr">#[test]
<a href=#643 id=643 data-nosnippet>643</a> </span><span class="kw">fn </span>test_mock_verifier_is_stable_per_username() {
<a href=#644 id=644 data-nosnippet>644</a> <span class="kw">let </span>alice = PgScramSha256Verifier::mock_for_unknown_user(<span class="string">b"alice"</span>);
<a href=#645 id=645 data-nosnippet>645</a> <span class="kw">let </span>alice_again = PgScramSha256Verifier::mock_for_unknown_user(<span class="string">b"alice"</span>);
<a href=#646 id=646 data-nosnippet>646</a> <span class="kw">let </span>bob = PgScramSha256Verifier::mock_for_unknown_user(<span class="string">b"bob"</span>);
<a href=#647 id=647 data-nosnippet>647</a>
<a href=#648 id=648 data-nosnippet>648</a> <span class="comment">// Same username must yield the same salt and iterations across reconnects,
<a href=#649 id=649 data-nosnippet>649</a> // otherwise the SCRAM server-first message leaks user (non-)existence.
<a href=#650 id=650 data-nosnippet>650</a> </span><span class="macro">assert_eq!</span>(alice.salt(), alice_again.salt());
<a href=#651 id=651 data-nosnippet>651</a> <span class="macro">assert_ne!</span>(alice.salt(), bob.salt());
<a href=#652 id=652 data-nosnippet>652</a> <span class="macro">assert_eq!</span>(alice.iterations(), DEFAULT_PBKDF2_SHA256_ITERATIONS);
<a href=#653 id=653 data-nosnippet>653</a> <span class="macro">assert_eq!</span>(alice.salt().len(), DEFAULT_PBKDF2_SHA256_SALT_LEN);
<a href=#654 id=654 data-nosnippet>654</a>
<a href=#655 id=655 data-nosnippet>655</a> <span class="comment">// The mock verifier must never accept a client proof.
<a href=#656 id=656 data-nosnippet>656</a> </span><span class="macro">assert!</span>(
<a href=#657 id=657 data-nosnippet>657</a> alice
<a href=#658 id=658 data-nosnippet>658</a> .verify_client_proof(<span class="string">b"auth-message"</span>, <span class="kw-2">&amp;</span>[<span class="number">0u8</span>; PG_SCRAM_SHA256_KEY_LEN])
<a href=#659 id=659 data-nosnippet>659</a> .unwrap()
<a href=#660 id=660 data-nosnippet>660</a> .is_none()
<a href=#661 id=661 data-nosnippet>661</a> );
<a href=#662 id=662 data-nosnippet>662</a> }
<a href=#663 id=663 data-nosnippet>663</a>}
</code></pre></div></section></main></body></html>
+133
View File
@@ -0,0 +1,133 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/auth/src/error.rs`."><title>error.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="auth" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">auth/</div>error.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>common_error::ext::{BoxedError, ErrorExt, RetryHint, retry_hint_from_io_error};
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>common_error::status_code::StatusCode;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_macro::stack_trace_debug;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>snafu::{Location, Snafu};
<a href=#19 id=19 data-nosnippet>19</a>
<a href=#20 id=20 data-nosnippet>20</a><span class="attr">#[derive(Snafu)]
<a href=#21 id=21 data-nosnippet>21</a>#[snafu(visibility(<span class="kw">pub</span>))]
<a href=#22 id=22 data-nosnippet>22</a>#[stack_trace_debug]
<a href=#23 id=23 data-nosnippet>23</a></span><span class="kw">pub enum </span>Error {
<a href=#24 id=24 data-nosnippet>24</a> <span class="attr">#[snafu(display(<span class="string">"Invalid config value: {}, {}"</span>, value, msg))]
<a href=#25 id=25 data-nosnippet>25</a> </span>InvalidConfig { value: String, msg: String },
<a href=#26 id=26 data-nosnippet>26</a>
<a href=#27 id=27 data-nosnippet>27</a> <span class="attr">#[snafu(display(<span class="string">"Illegal param: {}"</span>, msg))]
<a href=#28 id=28 data-nosnippet>28</a> </span>IllegalParam { msg: String },
<a href=#29 id=29 data-nosnippet>29</a>
<a href=#30 id=30 data-nosnippet>30</a> <span class="attr">#[snafu(display(<span class="string">"Internal state error: {}"</span>, msg))]
<a href=#31 id=31 data-nosnippet>31</a> </span>InternalState { msg: String },
<a href=#32 id=32 data-nosnippet>32</a>
<a href=#33 id=33 data-nosnippet>33</a> <span class="attr">#[snafu(display(<span class="string">"IO error"</span>))]
<a href=#34 id=34 data-nosnippet>34</a> </span>Io {
<a href=#35 id=35 data-nosnippet>35</a> <span class="attr">#[snafu(source)]
<a href=#36 id=36 data-nosnippet>36</a> </span>error: std::io::Error,
<a href=#37 id=37 data-nosnippet>37</a> <span class="attr">#[snafu(implicit)]
<a href=#38 id=38 data-nosnippet>38</a> </span>location: Location,
<a href=#39 id=39 data-nosnippet>39</a> },
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a> <span class="attr">#[snafu(display(<span class="string">"Failed to convert to utf8"</span>))]
<a href=#42 id=42 data-nosnippet>42</a> </span>FromUtf8 {
<a href=#43 id=43 data-nosnippet>43</a> <span class="attr">#[snafu(source)]
<a href=#44 id=44 data-nosnippet>44</a> </span>error: std::string::FromUtf8Error,
<a href=#45 id=45 data-nosnippet>45</a> <span class="attr">#[snafu(implicit)]
<a href=#46 id=46 data-nosnippet>46</a> </span>location: Location,
<a href=#47 id=47 data-nosnippet>47</a> },
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a> <span class="attr">#[snafu(display(<span class="string">"Authentication source failure"</span>))]
<a href=#50 id=50 data-nosnippet>50</a> </span>AuthBackend {
<a href=#51 id=51 data-nosnippet>51</a> <span class="attr">#[snafu(implicit)]
<a href=#52 id=52 data-nosnippet>52</a> </span>location: Location,
<a href=#53 id=53 data-nosnippet>53</a> <span class="attr">#[snafu(source)]
<a href=#54 id=54 data-nosnippet>54</a> </span>source: BoxedError,
<a href=#55 id=55 data-nosnippet>55</a> },
<a href=#56 id=56 data-nosnippet>56</a>
<a href=#57 id=57 data-nosnippet>57</a> <span class="attr">#[snafu(display(<span class="string">"User not found, username: {}"</span>, username))]
<a href=#58 id=58 data-nosnippet>58</a> </span>UserNotFound { username: String },
<a href=#59 id=59 data-nosnippet>59</a>
<a href=#60 id=60 data-nosnippet>60</a> <span class="attr">#[snafu(display(<span class="string">"Unsupported password type: {}"</span>, password_type))]
<a href=#61 id=61 data-nosnippet>61</a> </span>UnsupportedPasswordType { password_type: String },
<a href=#62 id=62 data-nosnippet>62</a>
<a href=#63 id=63 data-nosnippet>63</a> <span class="attr">#[snafu(display(<span class="string">"Username and password does not match, username: {}"</span>, username))]
<a href=#64 id=64 data-nosnippet>64</a> </span>UserPasswordMismatch { username: String },
<a href=#65 id=65 data-nosnippet>65</a>
<a href=#66 id=66 data-nosnippet>66</a> <span class="attr">#[snafu(display(
<a href=#67 id=67 data-nosnippet>67</a> <span class="string">"Access denied for user '{}' to database '{}-{}'"</span>,
<a href=#68 id=68 data-nosnippet>68</a> username,
<a href=#69 id=69 data-nosnippet>69</a> catalog,
<a href=#70 id=70 data-nosnippet>70</a> schema
<a href=#71 id=71 data-nosnippet>71</a> ))]
<a href=#72 id=72 data-nosnippet>72</a> </span>AccessDenied {
<a href=#73 id=73 data-nosnippet>73</a> catalog: String,
<a href=#74 id=74 data-nosnippet>74</a> schema: String,
<a href=#75 id=75 data-nosnippet>75</a> username: String,
<a href=#76 id=76 data-nosnippet>76</a> },
<a href=#77 id=77 data-nosnippet>77</a>
<a href=#78 id=78 data-nosnippet>78</a> <span class="attr">#[snafu(display(<span class="string">"Failed to initialize a file watcher"</span>))]
<a href=#79 id=79 data-nosnippet>79</a> </span>FileWatch {
<a href=#80 id=80 data-nosnippet>80</a> <span class="attr">#[snafu(source)]
<a href=#81 id=81 data-nosnippet>81</a> </span>source: common_config::error::Error,
<a href=#82 id=82 data-nosnippet>82</a> <span class="attr">#[snafu(implicit)]
<a href=#83 id=83 data-nosnippet>83</a> </span>location: Location,
<a href=#84 id=84 data-nosnippet>84</a> },
<a href=#85 id=85 data-nosnippet>85</a>
<a href=#86 id=86 data-nosnippet>86</a> <span class="attr">#[snafu(display(<span class="string">"User is not authorized to perform this action"</span>))]
<a href=#87 id=87 data-nosnippet>87</a> </span>PermissionDenied {
<a href=#88 id=88 data-nosnippet>88</a> <span class="attr">#[snafu(implicit)]
<a href=#89 id=89 data-nosnippet>89</a> </span>location: Location,
<a href=#90 id=90 data-nosnippet>90</a> },
<a href=#91 id=91 data-nosnippet>91</a>
<a href=#92 id=92 data-nosnippet>92</a> <span class="attr">#[snafu(display(<span class="string">"Unsupported authentication method: {}"</span>, method))]
<a href=#93 id=93 data-nosnippet>93</a> </span>UnsupportedAuthMethod {
<a href=#94 id=94 data-nosnippet>94</a> method: String,
<a href=#95 id=95 data-nosnippet>95</a> <span class="attr">#[snafu(implicit)]
<a href=#96 id=96 data-nosnippet>96</a> </span>location: Location,
<a href=#97 id=97 data-nosnippet>97</a> },
<a href=#98 id=98 data-nosnippet>98</a>}
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a><span class="kw">impl </span>ErrorExt <span class="kw">for </span>Error {
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
<a href=#102 id=102 data-nosnippet>102</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#103 id=103 data-nosnippet>103</a> Error::InvalidConfig { .. } =&gt; StatusCode::InvalidArguments,
<a href=#104 id=104 data-nosnippet>104</a> Error::IllegalParam { .. } | Error::FromUtf8 { .. } =&gt; StatusCode::InvalidArguments,
<a href=#105 id=105 data-nosnippet>105</a> Error::FileWatch { .. } =&gt; StatusCode::InvalidArguments,
<a href=#106 id=106 data-nosnippet>106</a> Error::InternalState { .. } =&gt; StatusCode::Unexpected,
<a href=#107 id=107 data-nosnippet>107</a> Error::Io { .. } =&gt; StatusCode::StorageUnavailable,
<a href=#108 id=108 data-nosnippet>108</a> Error::AuthBackend { source, .. } =&gt; source.status_code(),
<a href=#109 id=109 data-nosnippet>109</a>
<a href=#110 id=110 data-nosnippet>110</a> Error::UserNotFound { .. } =&gt; StatusCode::UserNotFound,
<a href=#111 id=111 data-nosnippet>111</a> Error::UnsupportedPasswordType { .. } =&gt; StatusCode::UnsupportedPasswordType,
<a href=#112 id=112 data-nosnippet>112</a> Error::UserPasswordMismatch { .. } =&gt; StatusCode::UserPasswordMismatch,
<a href=#113 id=113 data-nosnippet>113</a> Error::AccessDenied { .. } =&gt; StatusCode::AccessDenied,
<a href=#114 id=114 data-nosnippet>114</a> Error::PermissionDenied { .. } =&gt; StatusCode::PermissionDenied,
<a href=#115 id=115 data-nosnippet>115</a> Error::UnsupportedAuthMethod { .. } =&gt; StatusCode::UserPasswordMismatch,
<a href=#116 id=116 data-nosnippet>116</a> }
<a href=#117 id=117 data-nosnippet>117</a> }
<a href=#118 id=118 data-nosnippet>118</a>
<a href=#119 id=119 data-nosnippet>119</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>std::any::Any {
<a href=#120 id=120 data-nosnippet>120</a> <span class="self">self
<a href=#121 id=121 data-nosnippet>121</a> </span>}
<a href=#122 id=122 data-nosnippet>122</a>
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">fn </span>retry_hint(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; RetryHint {
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#125 id=125 data-nosnippet>125</a> Error::Io { error, .. } =&gt; retry_hint_from_io_error(error),
<a href=#126 id=126 data-nosnippet>126</a> Error::AuthBackend { source, .. } =&gt; source.retry_hint(),
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw">_ </span>=&gt; RetryHint::NonRetryable,
<a href=#128 id=128 data-nosnippet>128</a> }
<a href=#129 id=129 data-nosnippet>129</a> }
<a href=#130 id=130 data-nosnippet>130</a>}
<a href=#131 id=131 data-nosnippet>131</a>
<a href=#132 id=132 data-nosnippet>132</a><span class="kw">pub type </span><span class="prelude-ty">Result</span>&lt;T&gt; = std::result::Result&lt;T, Error&gt;;
</code></pre></div></section></main></body></html>
+48
View File
@@ -0,0 +1,48 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/auth/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="auth" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">auth/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">mod </span>common;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">pub mod </span>error;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">mod </span>permission;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">mod </span>user_info;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">mod </span>user_provider;
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="attr">#[cfg(feature = <span class="string">"testing"</span>)]
<a href=#22 id=22 data-nosnippet>22</a></span><span class="kw">pub mod </span>tests;
<a href=#23 id=23 data-nosnippet>23</a>
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">pub use </span>common::{
<a href=#25 id=25 data-nosnippet>25</a> DEFAULT_PBKDF2_SHA256_ITERATIONS, DEFAULT_PBKDF2_SHA256_SALT_LEN, HashedPassword, Identity,
<a href=#26 id=26 data-nosnippet>26</a> MAX_PBKDF2_SHA256_ITERATIONS, MAX_PBKDF2_SHA256_SALT_LEN, PBKDF2_SHA256_HASH_LEN,
<a href=#27 id=27 data-nosnippet>27</a> PG_SCRAM_SHA256_KEY_LEN, Password, PgScramSha256Verifier, auth_mysql, auth_mysql_with_verifier,
<a href=#28 id=28 data-nosnippet>28</a> format_mysql_native_password_verifier, format_pbkdf2_sha256_password_verifier,
<a href=#29 id=29 data-nosnippet>29</a> format_pg_scram_sha256_password_verifier, mysql_native_password_hash,
<a href=#30 id=30 data-nosnippet>30</a> parse_pg_scram_sha256_password_verifier, static_user_provider_from_option,
<a href=#31 id=31 data-nosnippet>31</a> user_provider_from_option, userinfo_by_name, validate_mysql_native_password_verifier,
<a href=#32 id=32 data-nosnippet>32</a>};
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">pub use </span>permission::{
<a href=#34 id=34 data-nosnippet>34</a> ALL_ACTIONS, AccessMode, DASHBOARD_DELETE, DASHBOARD_QUERY, DASHBOARD_SAVE,
<a href=#35 id=35 data-nosnippet>35</a> DefaultPermissionChecker, INFLUXDB_WRITE, JAEGER_QUERY, LOG_QUERY, LOG_WRITE, OPENTSDB_WRITE,
<a href=#36 id=36 data-nosnippet>36</a> OTLP_WRITE, PIPELINE_DELETE, PIPELINE_INSERT, PIPELINE_QUERY, PROM_STORE_READ,
<a href=#37 id=37 data-nosnippet>37</a> PROM_STORE_WRITE, PROMQL_QUERY, PermissionAction, PermissionChecker, PermissionReq,
<a href=#38 id=38 data-nosnippet>38</a> PermissionResp, PermissionTableTarget, PermissionTableTargets, SEMANTIC_GRAPH_QUERY,
<a href=#39 id=39 data-nosnippet>39</a>};
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">pub use </span>user_info::UserInfo;
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">pub use </span>user_provider::static_user_provider::StaticUserProvider;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">pub use </span>user_provider::{BEARER_TOKEN_USER, MysqlAuthMethod, PgAuthInfo, UserProvider};
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="doccomment">/// pub type alias
<a href=#45 id=45 data-nosnippet>45</a></span><span class="kw">pub type </span>UserInfoRef = std::sync::Arc&lt;<span class="kw">dyn </span>UserInfo&gt;;
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">pub type </span>UserProviderRef = std::sync::Arc&lt;<span class="kw">dyn </span>UserProvider&gt;;
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">pub type </span>PermissionCheckerRef = std::sync::Arc&lt;<span class="kw">dyn </span>PermissionChecker&gt;;
</code></pre></div></section></main></body></html>
+707
View File
@@ -0,0 +1,707 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/auth/src/permission.rs`."><title>permission.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="auth" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">auth/</div>permission.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::fmt::Debug;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::sync::Arc;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>api::v1::RowInsertRequests;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>api::v1::greptime_request::Request;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>api::v1::query_request::Query;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_telemetry::debug;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>sql::statements::statement::Statement;
<a href=#23 id=23 data-nosnippet>23</a>
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span><span class="kw">crate</span>::error::{PermissionDeniedSnafu, <span class="prelude-ty">Result</span>};
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span><span class="kw">crate</span>::user_info::DefaultUserInfo;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>crate::{PermissionCheckerRef, UserInfo, UserInfoRef};
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="doccomment">/// A user-visible table target for permission checks.
<a href=#29 id=29 data-nosnippet>29</a>///
<a href=#30 id=30 data-nosnippet>30</a>/// Use [`PermissionTableTargets::resolved`] to validate that all components are
<a href=#31 id=31 data-nosnippet>31</a>/// non-empty before passing targets to a permission checker.
<a href=#32 id=32 data-nosnippet>32</a></span><span class="attr">#[derive(Debug, Clone, PartialEq, Eq, Hash)]
<a href=#33 id=33 data-nosnippet>33</a></span><span class="kw">pub struct </span>PermissionTableTarget {
<a href=#34 id=34 data-nosnippet>34</a> <span class="kw">pub </span>catalog: String,
<a href=#35 id=35 data-nosnippet>35</a> <span class="kw">pub </span>schema: String,
<a href=#36 id=36 data-nosnippet>36</a> <span class="kw">pub </span>table: String,
<a href=#37 id=37 data-nosnippet>37</a>}
<a href=#38 id=38 data-nosnippet>38</a>
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">impl </span>PermissionTableTarget {
<a href=#40 id=40 data-nosnippet>40</a> <span class="doccomment">/// Creates a table target candidate.
<a href=#41 id=41 data-nosnippet>41</a> </span><span class="kw">pub fn </span>new(
<a href=#42 id=42 data-nosnippet>42</a> catalog: <span class="kw">impl </span>Into&lt;String&gt;,
<a href=#43 id=43 data-nosnippet>43</a> schema: <span class="kw">impl </span>Into&lt;String&gt;,
<a href=#44 id=44 data-nosnippet>44</a> table: <span class="kw">impl </span>Into&lt;String&gt;,
<a href=#45 id=45 data-nosnippet>45</a> ) -&gt; <span class="self">Self </span>{
<a href=#46 id=46 data-nosnippet>46</a> <span class="self">Self </span>{
<a href=#47 id=47 data-nosnippet>47</a> catalog: catalog.into(),
<a href=#48 id=48 data-nosnippet>48</a> schema: schema.into(),
<a href=#49 id=49 data-nosnippet>49</a> table: table.into(),
<a href=#50 id=50 data-nosnippet>50</a> }
<a href=#51 id=51 data-nosnippet>51</a> }
<a href=#52 id=52 data-nosnippet>52</a>}
<a href=#53 id=53 data-nosnippet>53</a>
<a href=#54 id=54 data-nosnippet>54</a><span class="doccomment">/// The result of resolving every table target in a permission request.
<a href=#55 id=55 data-nosnippet>55</a>///
<a href=#56 id=56 data-nosnippet>56</a>/// `Resolved(vec![])` means the request contains no table targets. The operation
<a href=#57 id=57 data-nosnippet>57</a>/// privilege must still be checked, but there are no table ACLs to evaluate.
<a href=#58 id=58 data-nosnippet>58</a>/// [`PermissionTableTargets::Unresolved`] means the targets could not be
<a href=#59 id=59 data-nosnippet>59</a>/// determined safely.
<a href=#60 id=60 data-nosnippet>60</a></span><span class="attr">#[derive(Debug, Clone, PartialEq, Eq)]
<a href=#61 id=61 data-nosnippet>61</a></span><span class="kw">pub enum </span>PermissionTableTargets {
<a href=#62 id=62 data-nosnippet>62</a> <span class="doccomment">/// Every target was resolved, including the valid empty-target case.
<a href=#63 id=63 data-nosnippet>63</a> </span>Resolved(Vec&lt;PermissionTableTarget&gt;),
<a href=#64 id=64 data-nosnippet>64</a> <span class="doccomment">/// One or more targets could not be determined safely.
<a href=#65 id=65 data-nosnippet>65</a> </span>Unresolved,
<a href=#66 id=66 data-nosnippet>66</a>}
<a href=#67 id=67 data-nosnippet>67</a>
<a href=#68 id=68 data-nosnippet>68</a><span class="kw">impl </span>PermissionTableTargets {
<a href=#69 id=69 data-nosnippet>69</a> <span class="doccomment">/// Marks targets as resolved only when every component is non-empty.
<a href=#70 id=70 data-nosnippet>70</a> </span><span class="kw">pub fn </span>resolved(targets: Vec&lt;PermissionTableTarget&gt;) -&gt; <span class="self">Self </span>{
<a href=#71 id=71 data-nosnippet>71</a> <span class="kw">if </span>targets.iter().any(|target| {
<a href=#72 id=72 data-nosnippet>72</a> target.catalog.is_empty() || target.schema.is_empty() || target.table.is_empty()
<a href=#73 id=73 data-nosnippet>73</a> }) {
<a href=#74 id=74 data-nosnippet>74</a> <span class="self">Self</span>::Unresolved
<a href=#75 id=75 data-nosnippet>75</a> } <span class="kw">else </span>{
<a href=#76 id=76 data-nosnippet>76</a> <span class="self">Self</span>::Resolved(targets)
<a href=#77 id=77 data-nosnippet>77</a> }
<a href=#78 id=78 data-nosnippet>78</a> }
<a href=#79 id=79 data-nosnippet>79</a>
<a href=#80 id=80 data-nosnippet>80</a> <span class="doccomment">/// Resolves logical table targets from normalized row insert requests.
<a href=#81 id=81 data-nosnippet>81</a> </span><span class="kw">pub fn </span>from_row_insert_requests(
<a href=#82 id=82 data-nosnippet>82</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#83 id=83 data-nosnippet>83</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#84 id=84 data-nosnippet>84</a> requests: <span class="kw-2">&amp;</span>RowInsertRequests,
<a href=#85 id=85 data-nosnippet>85</a> ) -&gt; <span class="self">Self </span>{
<a href=#86 id=86 data-nosnippet>86</a> <span class="self">Self</span>::resolved(
<a href=#87 id=87 data-nosnippet>87</a> requests
<a href=#88 id=88 data-nosnippet>88</a> .inserts
<a href=#89 id=89 data-nosnippet>89</a> .iter()
<a href=#90 id=90 data-nosnippet>90</a> .map(|request| PermissionTableTarget::new(catalog, schema, <span class="kw-2">&amp;</span>request.table_name))
<a href=#91 id=91 data-nosnippet>91</a> .collect(),
<a href=#92 id=92 data-nosnippet>92</a> )
<a href=#93 id=93 data-nosnippet>93</a> }
<a href=#94 id=94 data-nosnippet>94</a>}
<a href=#95 id=95 data-nosnippet>95</a>
<a href=#96 id=96 data-nosnippet>96</a><span class="doccomment">/// The access mode of a named permission action.
<a href=#97 id=97 data-nosnippet>97</a></span><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq)]
<a href=#98 id=98 data-nosnippet>98</a></span><span class="kw">pub enum </span>AccessMode {
<a href=#99 id=99 data-nosnippet>99</a> Read,
<a href=#100 id=100 data-nosnippet>100</a> Write,
<a href=#101 id=101 data-nosnippet>101</a>}
<a href=#102 id=102 data-nosnippet>102</a>
<a href=#103 id=103 data-nosnippet>103</a><span class="doccomment">/// A named permission action.
<a href=#104 id=104 data-nosnippet>104</a></span><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq)]
<a href=#105 id=105 data-nosnippet>105</a></span><span class="kw">pub struct </span>PermissionAction {
<a href=#106 id=106 data-nosnippet>106</a> name: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str,
<a href=#107 id=107 data-nosnippet>107</a> access_mode: AccessMode,
<a href=#108 id=108 data-nosnippet>108</a>}
<a href=#109 id=109 data-nosnippet>109</a>
<a href=#110 id=110 data-nosnippet>110</a><span class="kw">impl </span>PermissionAction {
<a href=#111 id=111 data-nosnippet>111</a> <span class="doccomment">/// Creates a read action with a stable name.
<a href=#112 id=112 data-nosnippet>112</a> </span><span class="kw">pub const fn </span>read(name: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str) -&gt; <span class="self">Self </span>{
<a href=#113 id=113 data-nosnippet>113</a> <span class="self">Self </span>{
<a href=#114 id=114 data-nosnippet>114</a> name,
<a href=#115 id=115 data-nosnippet>115</a> access_mode: AccessMode::Read,
<a href=#116 id=116 data-nosnippet>116</a> }
<a href=#117 id=117 data-nosnippet>117</a> }
<a href=#118 id=118 data-nosnippet>118</a>
<a href=#119 id=119 data-nosnippet>119</a> <span class="doccomment">/// Creates a write action with a stable name.
<a href=#120 id=120 data-nosnippet>120</a> </span><span class="kw">pub const fn </span>write(name: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str) -&gt; <span class="self">Self </span>{
<a href=#121 id=121 data-nosnippet>121</a> <span class="self">Self </span>{
<a href=#122 id=122 data-nosnippet>122</a> name,
<a href=#123 id=123 data-nosnippet>123</a> access_mode: AccessMode::Write,
<a href=#124 id=124 data-nosnippet>124</a> }
<a href=#125 id=125 data-nosnippet>125</a> }
<a href=#126 id=126 data-nosnippet>126</a>
<a href=#127 id=127 data-nosnippet>127</a> <span class="doccomment">/// Returns the stable action name.
<a href=#128 id=128 data-nosnippet>128</a> </span><span class="kw">pub const fn </span>name(<span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#129 id=129 data-nosnippet>129</a> <span class="self">self</span>.name
<a href=#130 id=130 data-nosnippet>130</a> }
<a href=#131 id=131 data-nosnippet>131</a>
<a href=#132 id=132 data-nosnippet>132</a> <span class="doccomment">/// Returns the action's access mode.
<a href=#133 id=133 data-nosnippet>133</a> </span><span class="kw">pub const fn </span>access_mode(<span class="self">self</span>) -&gt; AccessMode {
<a href=#134 id=134 data-nosnippet>134</a> <span class="self">self</span>.access_mode
<a href=#135 id=135 data-nosnippet>135</a> }
<a href=#136 id=136 data-nosnippet>136</a>}
<a href=#137 id=137 data-nosnippet>137</a>
<a href=#138 id=138 data-nosnippet>138</a><span class="kw">pub const </span>PROMQL_QUERY: PermissionAction = PermissionAction::read(<span class="string">"promql.query"</span>);
<a href=#139 id=139 data-nosnippet>139</a><span class="kw">pub const </span>LOG_QUERY: PermissionAction = PermissionAction::read(<span class="string">"log.query"</span>);
<a href=#140 id=140 data-nosnippet>140</a><span class="kw">pub const </span>OPENTSDB_WRITE: PermissionAction = PermissionAction::write(<span class="string">"opentsdb.write"</span>);
<a href=#141 id=141 data-nosnippet>141</a><span class="kw">pub const </span>INFLUXDB_WRITE: PermissionAction = PermissionAction::write(<span class="string">"influxdb.write"</span>);
<a href=#142 id=142 data-nosnippet>142</a><span class="kw">pub const </span>PROM_STORE_WRITE: PermissionAction = PermissionAction::write(<span class="string">"prom_store.write"</span>);
<a href=#143 id=143 data-nosnippet>143</a><span class="kw">pub const </span>PROM_STORE_READ: PermissionAction = PermissionAction::read(<span class="string">"prom_store.read"</span>);
<a href=#144 id=144 data-nosnippet>144</a><span class="kw">pub const </span>OTLP_WRITE: PermissionAction = PermissionAction::write(<span class="string">"otlp.write"</span>);
<a href=#145 id=145 data-nosnippet>145</a><span class="kw">pub const </span>LOG_WRITE: PermissionAction = PermissionAction::write(<span class="string">"log.write"</span>);
<a href=#146 id=146 data-nosnippet>146</a><span class="kw">pub const </span>JAEGER_QUERY: PermissionAction = PermissionAction::read(<span class="string">"jaeger.query"</span>);
<a href=#147 id=147 data-nosnippet>147</a><span class="kw">pub const </span>PIPELINE_QUERY: PermissionAction = PermissionAction::read(<span class="string">"pipeline.query"</span>);
<a href=#148 id=148 data-nosnippet>148</a><span class="kw">pub const </span>PIPELINE_INSERT: PermissionAction = PermissionAction::write(<span class="string">"pipeline.insert"</span>);
<a href=#149 id=149 data-nosnippet>149</a><span class="kw">pub const </span>PIPELINE_DELETE: PermissionAction = PermissionAction::write(<span class="string">"pipeline.delete"</span>);
<a href=#150 id=150 data-nosnippet>150</a><span class="kw">pub const </span>DASHBOARD_QUERY: PermissionAction = PermissionAction::read(<span class="string">"dashboard.query"</span>);
<a href=#151 id=151 data-nosnippet>151</a><span class="kw">pub const </span>DASHBOARD_SAVE: PermissionAction = PermissionAction::write(<span class="string">"dashboard.save"</span>);
<a href=#152 id=152 data-nosnippet>152</a><span class="kw">pub const </span>DASHBOARD_DELETE: PermissionAction = PermissionAction::write(<span class="string">"dashboard.delete"</span>);
<a href=#153 id=153 data-nosnippet>153</a><span class="doccomment">/// Reading a telemetry table through the entity-graph derivation
<a href=#154 id=154 data-nosnippet>154</a>/// (`greptime_private.semantic_entities` / `semantic_relationships`); checked
<a href=#155 id=155 data-nosnippet>155</a>/// once per candidate source table with that table as the target.
<a href=#156 id=156 data-nosnippet>156</a></span><span class="kw">pub const </span>SEMANTIC_GRAPH_QUERY: PermissionAction = PermissionAction::read(<span class="string">"semantic_graph.query"</span>);
<a href=#157 id=157 data-nosnippet>157</a>
<a href=#158 id=158 data-nosnippet>158</a><span class="doccomment">/// All permission actions built into GreptimeDB.
<a href=#159 id=159 data-nosnippet>159</a>///
<a href=#160 id=160 data-nosnippet>160</a>/// Downstream crates may define additional actions with [`PermissionAction::read`] and
<a href=#161 id=161 data-nosnippet>161</a>/// [`PermissionAction::write`].
<a href=#162 id=162 data-nosnippet>162</a></span><span class="kw">pub const </span>ALL_ACTIONS: <span class="kw-2">&amp;</span>[PermissionAction] = <span class="kw-2">&amp;</span>[
<a href=#163 id=163 data-nosnippet>163</a> PROMQL_QUERY,
<a href=#164 id=164 data-nosnippet>164</a> LOG_QUERY,
<a href=#165 id=165 data-nosnippet>165</a> OPENTSDB_WRITE,
<a href=#166 id=166 data-nosnippet>166</a> INFLUXDB_WRITE,
<a href=#167 id=167 data-nosnippet>167</a> PROM_STORE_WRITE,
<a href=#168 id=168 data-nosnippet>168</a> PROM_STORE_READ,
<a href=#169 id=169 data-nosnippet>169</a> OTLP_WRITE,
<a href=#170 id=170 data-nosnippet>170</a> LOG_WRITE,
<a href=#171 id=171 data-nosnippet>171</a> JAEGER_QUERY,
<a href=#172 id=172 data-nosnippet>172</a> PIPELINE_QUERY,
<a href=#173 id=173 data-nosnippet>173</a> PIPELINE_INSERT,
<a href=#174 id=174 data-nosnippet>174</a> PIPELINE_DELETE,
<a href=#175 id=175 data-nosnippet>175</a> DASHBOARD_QUERY,
<a href=#176 id=176 data-nosnippet>176</a> DASHBOARD_SAVE,
<a href=#177 id=177 data-nosnippet>177</a> DASHBOARD_DELETE,
<a href=#178 id=178 data-nosnippet>178</a> SEMANTIC_GRAPH_QUERY,
<a href=#179 id=179 data-nosnippet>179</a>];
<a href=#180 id=180 data-nosnippet>180</a>
<a href=#181 id=181 data-nosnippet>181</a><span class="attr">#[derive(Debug, Clone)]
<a href=#182 id=182 data-nosnippet>182</a></span><span class="kw">pub enum </span>PermissionReq&lt;<span class="lifetime">'a</span>&gt; {
<a href=#183 id=183 data-nosnippet>183</a> GrpcRequest(<span class="kw-2">&amp;</span><span class="lifetime">'a </span>Request),
<a href=#184 id=184 data-nosnippet>184</a> SqlStatement(<span class="kw-2">&amp;</span><span class="lifetime">'a </span>Statement),
<a href=#185 id=185 data-nosnippet>185</a> Action(PermissionAction),
<a href=#186 id=186 data-nosnippet>186</a> BulkInsert {
<a href=#187 id=187 data-nosnippet>187</a> catalog: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str,
<a href=#188 id=188 data-nosnippet>188</a> schema: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str,
<a href=#189 id=189 data-nosnippet>189</a> table: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str,
<a href=#190 id=190 data-nosnippet>190</a> },
<a href=#191 id=191 data-nosnippet>191</a>}
<a href=#192 id=192 data-nosnippet>192</a>
<a href=#193 id=193 data-nosnippet>193</a><span class="kw">impl</span>&lt;<span class="lifetime">'a</span>&gt; PermissionReq&lt;<span class="lifetime">'a</span>&gt; {
<a href=#194 id=194 data-nosnippet>194</a> <span class="doccomment">/// Returns true if the permission request is for read operations.
<a href=#195 id=195 data-nosnippet>195</a> </span><span class="kw">pub fn </span>is_readonly(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#197 id=197 data-nosnippet>197</a> PermissionReq::GrpcRequest(Request::Query(query_request)) =&gt; {
<a href=#198 id=198 data-nosnippet>198</a> !<span class="macro">matches!</span>(query_request.query, <span class="prelude-val">Some</span>(Query::InsertIntoPlan(<span class="kw">_</span>)))
<a href=#199 id=199 data-nosnippet>199</a> }
<a href=#200 id=200 data-nosnippet>200</a> PermissionReq::SqlStatement(stmt) =&gt; stmt.is_readonly(),
<a href=#201 id=201 data-nosnippet>201</a> PermissionReq::Action(action) =&gt; action.access_mode() == AccessMode::Read,
<a href=#202 id=202 data-nosnippet>202</a>
<a href=#203 id=203 data-nosnippet>203</a> PermissionReq::GrpcRequest(<span class="kw">_</span>) | PermissionReq::BulkInsert { .. } =&gt; <span class="bool-val">false</span>,
<a href=#204 id=204 data-nosnippet>204</a> }
<a href=#205 id=205 data-nosnippet>205</a> }
<a href=#206 id=206 data-nosnippet>206</a>
<a href=#207 id=207 data-nosnippet>207</a> <span class="doccomment">/// Returns true if the permission request is for write operations.
<a href=#208 id=208 data-nosnippet>208</a> </span><span class="kw">pub fn </span>is_write(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#209 id=209 data-nosnippet>209</a> !<span class="self">self</span>.is_readonly()
<a href=#210 id=210 data-nosnippet>210</a> }
<a href=#211 id=211 data-nosnippet>211</a>}
<a href=#212 id=212 data-nosnippet>212</a>
<a href=#213 id=213 data-nosnippet>213</a><span class="attr">#[derive(Debug)]
<a href=#214 id=214 data-nosnippet>214</a></span><span class="kw">pub enum </span>PermissionResp {
<a href=#215 id=215 data-nosnippet>215</a> Allow,
<a href=#216 id=216 data-nosnippet>216</a> Reject,
<a href=#217 id=217 data-nosnippet>217</a>}
<a href=#218 id=218 data-nosnippet>218</a>
<a href=#219 id=219 data-nosnippet>219</a><span class="kw">pub trait </span>PermissionChecker: Send + Sync {
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">fn </span>check_permission(
<a href=#221 id=221 data-nosnippet>221</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#222 id=222 data-nosnippet>222</a> user_info: UserInfoRef,
<a href=#223 id=223 data-nosnippet>223</a> req: PermissionReq,
<a href=#224 id=224 data-nosnippet>224</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;PermissionResp&gt;;
<a href=#225 id=225 data-nosnippet>225</a>
<a href=#226 id=226 data-nosnippet>226</a> <span class="kw">fn </span>check_permission_with_context(
<a href=#227 id=227 data-nosnippet>227</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#228 id=228 data-nosnippet>228</a> user_info: UserInfoRef,
<a href=#229 id=229 data-nosnippet>229</a> req: PermissionReq,
<a href=#230 id=230 data-nosnippet>230</a> _current_schema: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt;,
<a href=#231 id=231 data-nosnippet>231</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;PermissionResp&gt; {
<a href=#232 id=232 data-nosnippet>232</a> <span class="self">self</span>.check_permission(user_info, req)
<a href=#233 id=233 data-nosnippet>233</a> }
<a href=#234 id=234 data-nosnippet>234</a>
<a href=#235 id=235 data-nosnippet>235</a> <span class="doccomment">/// Returns whether authorization depends on resolved table targets.
<a href=#236 id=236 data-nosnippet>236</a> ///
<a href=#237 id=237 data-nosnippet>237</a> /// The conservative default keeps target resolution enabled. Implementations
<a href=#238 id=238 data-nosnippet>238</a> /// may return `false` only when their authorization result is independent of
<a href=#239 id=239 data-nosnippet>239</a> /// the `targets` passed to [`Self::check_permission_with_table_targets`].
<a href=#240 id=240 data-nosnippet>240</a> </span><span class="kw">fn </span>uses_table_targets(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#241 id=241 data-nosnippet>241</a> <span class="bool-val">true
<a href=#242 id=242 data-nosnippet>242</a> </span>}
<a href=#243 id=243 data-nosnippet>243</a>
<a href=#244 id=244 data-nosnippet>244</a> <span class="doccomment">/// Checks the operation privilege and its resolved user-visible table targets.
<a href=#245 id=245 data-nosnippet>245</a> ///
<a href=#246 id=246 data-nosnippet>246</a> /// [`PermissionTableTargets::Resolved`] with an empty vector still requires
<a href=#247 id=247 data-nosnippet>247</a> /// checking the operation privilege in `req`, but has no table ACLs to check.
<a href=#248 id=248 data-nosnippet>248</a> ///
<a href=#249 id=249 data-nosnippet>249</a> /// ACL-aware implementations must apply any admin bypass first, then reject
<a href=#250 id=250 data-nosnippet>250</a> /// [`PermissionTableTargets::Unresolved`] for non-admin users.
<a href=#251 id=251 data-nosnippet>251</a> </span><span class="kw">fn </span>check_permission_with_table_targets(
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#253 id=253 data-nosnippet>253</a> user_info: UserInfoRef,
<a href=#254 id=254 data-nosnippet>254</a> req: PermissionReq,
<a href=#255 id=255 data-nosnippet>255</a> targets: PermissionTableTargets,
<a href=#256 id=256 data-nosnippet>256</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;PermissionResp&gt;;
<a href=#257 id=257 data-nosnippet>257</a>}
<a href=#258 id=258 data-nosnippet>258</a>
<a href=#259 id=259 data-nosnippet>259</a><span class="kw">fn </span>check_permission_result(result: <span class="prelude-ty">Result</span>&lt;PermissionResp&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;PermissionResp&gt; {
<a href=#260 id=260 data-nosnippet>260</a> <span class="kw">match </span>result {
<a href=#261 id=261 data-nosnippet>261</a> <span class="prelude-val">Ok</span>(PermissionResp::Reject) =&gt; PermissionDeniedSnafu.fail(),
<a href=#262 id=262 data-nosnippet>262</a> <span class="prelude-val">Ok</span>(PermissionResp::Allow) =&gt; <span class="prelude-val">Ok</span>(PermissionResp::Allow),
<a href=#263 id=263 data-nosnippet>263</a> <span class="prelude-val">Err</span>(e) =&gt; <span class="prelude-val">Err</span>(e),
<a href=#264 id=264 data-nosnippet>264</a> }
<a href=#265 id=265 data-nosnippet>265</a>}
<a href=#266 id=266 data-nosnippet>266</a>
<a href=#267 id=267 data-nosnippet>267</a><span class="kw">impl </span>PermissionChecker <span class="kw">for </span><span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>PermissionCheckerRef&gt; {
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw">fn </span>check_permission(
<a href=#269 id=269 data-nosnippet>269</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#270 id=270 data-nosnippet>270</a> user_info: UserInfoRef,
<a href=#271 id=271 data-nosnippet>271</a> req: PermissionReq,
<a href=#272 id=272 data-nosnippet>272</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;PermissionResp&gt; {
<a href=#273 id=273 data-nosnippet>273</a> <span class="self">self</span>.check_permission_with_context(user_info, req, <span class="prelude-val">None</span>)
<a href=#274 id=274 data-nosnippet>274</a> }
<a href=#275 id=275 data-nosnippet>275</a>
<a href=#276 id=276 data-nosnippet>276</a> <span class="kw">fn </span>check_permission_with_context(
<a href=#277 id=277 data-nosnippet>277</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#278 id=278 data-nosnippet>278</a> user_info: UserInfoRef,
<a href=#279 id=279 data-nosnippet>279</a> req: PermissionReq,
<a href=#280 id=280 data-nosnippet>280</a> current_schema: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt;,
<a href=#281 id=281 data-nosnippet>281</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;PermissionResp&gt; {
<a href=#282 id=282 data-nosnippet>282</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#283 id=283 data-nosnippet>283</a> <span class="prelude-val">Some</span>(checker) =&gt; check_permission_result(checker.check_permission_with_context(
<a href=#284 id=284 data-nosnippet>284</a> user_info,
<a href=#285 id=285 data-nosnippet>285</a> req,
<a href=#286 id=286 data-nosnippet>286</a> current_schema,
<a href=#287 id=287 data-nosnippet>287</a> )),
<a href=#288 id=288 data-nosnippet>288</a> <span class="prelude-val">None </span>=&gt; <span class="prelude-val">Ok</span>(PermissionResp::Allow),
<a href=#289 id=289 data-nosnippet>289</a> }
<a href=#290 id=290 data-nosnippet>290</a> }
<a href=#291 id=291 data-nosnippet>291</a>
<a href=#292 id=292 data-nosnippet>292</a> <span class="kw">fn </span>uses_table_targets(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#293 id=293 data-nosnippet>293</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#294 id=294 data-nosnippet>294</a> <span class="prelude-val">Some</span>(checker) =&gt; checker.uses_table_targets(),
<a href=#295 id=295 data-nosnippet>295</a> <span class="prelude-val">None </span>=&gt; <span class="bool-val">false</span>,
<a href=#296 id=296 data-nosnippet>296</a> }
<a href=#297 id=297 data-nosnippet>297</a> }
<a href=#298 id=298 data-nosnippet>298</a>
<a href=#299 id=299 data-nosnippet>299</a> <span class="kw">fn </span>check_permission_with_table_targets(
<a href=#300 id=300 data-nosnippet>300</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#301 id=301 data-nosnippet>301</a> user_info: UserInfoRef,
<a href=#302 id=302 data-nosnippet>302</a> req: PermissionReq,
<a href=#303 id=303 data-nosnippet>303</a> targets: PermissionTableTargets,
<a href=#304 id=304 data-nosnippet>304</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;PermissionResp&gt; {
<a href=#305 id=305 data-nosnippet>305</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#306 id=306 data-nosnippet>306</a> <span class="prelude-val">Some</span>(checker) =&gt; check_permission_result(
<a href=#307 id=307 data-nosnippet>307</a> checker.check_permission_with_table_targets(user_info, req, targets),
<a href=#308 id=308 data-nosnippet>308</a> ),
<a href=#309 id=309 data-nosnippet>309</a> <span class="prelude-val">None </span>=&gt; <span class="prelude-val">Ok</span>(PermissionResp::Allow),
<a href=#310 id=310 data-nosnippet>310</a> }
<a href=#311 id=311 data-nosnippet>311</a> }
<a href=#312 id=312 data-nosnippet>312</a>}
<a href=#313 id=313 data-nosnippet>313</a>
<a href=#314 id=314 data-nosnippet>314</a><span class="doccomment">/// The default permission checker implementation.
<a href=#315 id=315 data-nosnippet>315</a>/// It checks the permission mode of [DefaultUserInfo].
<a href=#316 id=316 data-nosnippet>316</a></span><span class="kw">pub struct </span>DefaultPermissionChecker;
<a href=#317 id=317 data-nosnippet>317</a>
<a href=#318 id=318 data-nosnippet>318</a><span class="kw">impl </span>DefaultPermissionChecker {
<a href=#319 id=319 data-nosnippet>319</a> <span class="doccomment">/// Returns a new [PermissionCheckerRef] instance.
<a href=#320 id=320 data-nosnippet>320</a> </span><span class="kw">pub fn </span>arc() -&gt; PermissionCheckerRef {
<a href=#321 id=321 data-nosnippet>321</a> Arc::new(DefaultPermissionChecker)
<a href=#322 id=322 data-nosnippet>322</a> }
<a href=#323 id=323 data-nosnippet>323</a>}
<a href=#324 id=324 data-nosnippet>324</a>
<a href=#325 id=325 data-nosnippet>325</a><span class="kw">impl </span>PermissionChecker <span class="kw">for </span>DefaultPermissionChecker {
<a href=#326 id=326 data-nosnippet>326</a> <span class="kw">fn </span>check_permission(
<a href=#327 id=327 data-nosnippet>327</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#328 id=328 data-nosnippet>328</a> user_info: UserInfoRef,
<a href=#329 id=329 data-nosnippet>329</a> req: PermissionReq,
<a href=#330 id=330 data-nosnippet>330</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;PermissionResp&gt; {
<a href=#331 id=331 data-nosnippet>331</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(default_user) = user_info.as_any().downcast_ref::&lt;DefaultUserInfo&gt;() {
<a href=#332 id=332 data-nosnippet>332</a> <span class="kw">let </span>permission_mode = default_user.permission_mode();
<a href=#333 id=333 data-nosnippet>333</a>
<a href=#334 id=334 data-nosnippet>334</a> <span class="kw">if </span>req.is_readonly() &amp;&amp; !permission_mode.can_read() {
<a href=#335 id=335 data-nosnippet>335</a> <span class="macro">debug!</span>(
<a href=#336 id=336 data-nosnippet>336</a> <span class="string">"Permission denied: read operation not allowed, user = {}, permission = {}"</span>,
<a href=#337 id=337 data-nosnippet>337</a> default_user.username(),
<a href=#338 id=338 data-nosnippet>338</a> permission_mode.as_str()
<a href=#339 id=339 data-nosnippet>339</a> );
<a href=#340 id=340 data-nosnippet>340</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(PermissionResp::Reject);
<a href=#341 id=341 data-nosnippet>341</a> }
<a href=#342 id=342 data-nosnippet>342</a>
<a href=#343 id=343 data-nosnippet>343</a> <span class="kw">if </span>req.is_write() &amp;&amp; !permission_mode.can_write() {
<a href=#344 id=344 data-nosnippet>344</a> <span class="macro">debug!</span>(
<a href=#345 id=345 data-nosnippet>345</a> <span class="string">"Permission denied: write operation not allowed, user = {}, permission = {}"</span>,
<a href=#346 id=346 data-nosnippet>346</a> default_user.username(),
<a href=#347 id=347 data-nosnippet>347</a> permission_mode.as_str()
<a href=#348 id=348 data-nosnippet>348</a> );
<a href=#349 id=349 data-nosnippet>349</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(PermissionResp::Reject);
<a href=#350 id=350 data-nosnippet>350</a> }
<a href=#351 id=351 data-nosnippet>351</a> }
<a href=#352 id=352 data-nosnippet>352</a>
<a href=#353 id=353 data-nosnippet>353</a> <span class="comment">// default allow all
<a href=#354 id=354 data-nosnippet>354</a> </span><span class="prelude-val">Ok</span>(PermissionResp::Allow)
<a href=#355 id=355 data-nosnippet>355</a> }
<a href=#356 id=356 data-nosnippet>356</a>
<a href=#357 id=357 data-nosnippet>357</a> <span class="kw">fn </span>uses_table_targets(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#358 id=358 data-nosnippet>358</a> <span class="bool-val">false
<a href=#359 id=359 data-nosnippet>359</a> </span>}
<a href=#360 id=360 data-nosnippet>360</a>
<a href=#361 id=361 data-nosnippet>361</a> <span class="kw">fn </span>check_permission_with_table_targets(
<a href=#362 id=362 data-nosnippet>362</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#363 id=363 data-nosnippet>363</a> user_info: UserInfoRef,
<a href=#364 id=364 data-nosnippet>364</a> req: PermissionReq,
<a href=#365 id=365 data-nosnippet>365</a> _targets: PermissionTableTargets,
<a href=#366 id=366 data-nosnippet>366</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;PermissionResp&gt; {
<a href=#367 id=367 data-nosnippet>367</a> <span class="self">self</span>.check_permission(user_info, req)
<a href=#368 id=368 data-nosnippet>368</a> }
<a href=#369 id=369 data-nosnippet>369</a>}
<a href=#370 id=370 data-nosnippet>370</a><span class="attr">#[cfg(test)]
<a href=#371 id=371 data-nosnippet>371</a></span><span class="kw">mod </span>tests {
<a href=#372 id=372 data-nosnippet>372</a> <span class="kw">use </span>std::collections::HashSet;
<a href=#373 id=373 data-nosnippet>373</a>
<a href=#374 id=374 data-nosnippet>374</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#375 id=375 data-nosnippet>375</a> <span class="kw">use </span><span class="kw">crate</span>::error::{Error, InternalStateSnafu};
<a href=#376 id=376 data-nosnippet>376</a> <span class="kw">use </span><span class="kw">crate</span>::user_info::PermissionMode;
<a href=#377 id=377 data-nosnippet>377</a>
<a href=#378 id=378 data-nosnippet>378</a> <span class="kw">struct </span>TargetAwarePermissionChecker;
<a href=#379 id=379 data-nosnippet>379</a>
<a href=#380 id=380 data-nosnippet>380</a> <span class="kw">impl </span>PermissionChecker <span class="kw">for </span>TargetAwarePermissionChecker {
<a href=#381 id=381 data-nosnippet>381</a> <span class="kw">fn </span>check_permission(
<a href=#382 id=382 data-nosnippet>382</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#383 id=383 data-nosnippet>383</a> _user_info: UserInfoRef,
<a href=#384 id=384 data-nosnippet>384</a> _req: PermissionReq,
<a href=#385 id=385 data-nosnippet>385</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;PermissionResp&gt; {
<a href=#386 id=386 data-nosnippet>386</a> <span class="prelude-val">Ok</span>(PermissionResp::Reject)
<a href=#387 id=387 data-nosnippet>387</a> }
<a href=#388 id=388 data-nosnippet>388</a>
<a href=#389 id=389 data-nosnippet>389</a> <span class="kw">fn </span>check_permission_with_table_targets(
<a href=#390 id=390 data-nosnippet>390</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#391 id=391 data-nosnippet>391</a> _user_info: UserInfoRef,
<a href=#392 id=392 data-nosnippet>392</a> req: PermissionReq,
<a href=#393 id=393 data-nosnippet>393</a> targets: PermissionTableTargets,
<a href=#394 id=394 data-nosnippet>394</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;PermissionResp&gt; {
<a href=#395 id=395 data-nosnippet>395</a> <span class="kw">if </span>!<span class="macro">matches!</span>(req, PermissionReq::Action(PROM_STORE_READ)) {
<a href=#396 id=396 data-nosnippet>396</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(PermissionResp::Reject);
<a href=#397 id=397 data-nosnippet>397</a> }
<a href=#398 id=398 data-nosnippet>398</a> <span class="kw">let </span>PermissionTableTargets::Resolved(targets) = targets <span class="kw">else </span>{
<a href=#399 id=399 data-nosnippet>399</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(PermissionResp::Reject);
<a href=#400 id=400 data-nosnippet>400</a> };
<a href=#401 id=401 data-nosnippet>401</a> <span class="kw">if </span>targets.iter().any(|target| target.table == <span class="string">"error"</span>) {
<a href=#402 id=402 data-nosnippet>402</a> <span class="kw">return </span>InternalStateSnafu {
<a href=#403 id=403 data-nosnippet>403</a> msg: <span class="string">"testing"</span>.to_string(),
<a href=#404 id=404 data-nosnippet>404</a> }
<a href=#405 id=405 data-nosnippet>405</a> .fail();
<a href=#406 id=406 data-nosnippet>406</a> }
<a href=#407 id=407 data-nosnippet>407</a> <span class="prelude-val">Ok</span>(<span class="kw">if </span>targets.iter().all(|target| target.table == <span class="string">"allowed"</span>) {
<a href=#408 id=408 data-nosnippet>408</a> PermissionResp::Allow
<a href=#409 id=409 data-nosnippet>409</a> } <span class="kw">else </span>{
<a href=#410 id=410 data-nosnippet>410</a> PermissionResp::Reject
<a href=#411 id=411 data-nosnippet>411</a> })
<a href=#412 id=412 data-nosnippet>412</a> }
<a href=#413 id=413 data-nosnippet>413</a> }
<a href=#414 id=414 data-nosnippet>414</a>
<a href=#415 id=415 data-nosnippet>415</a> <span class="kw">fn </span>resolved_targets(table: <span class="kw-2">&amp;</span>str) -&gt; PermissionTableTargets {
<a href=#416 id=416 data-nosnippet>416</a> PermissionTableTargets::resolved(<span class="macro">vec!</span>[PermissionTableTarget::new(
<a href=#417 id=417 data-nosnippet>417</a> <span class="string">"greptime"</span>, <span class="string">"public"</span>, table,
<a href=#418 id=418 data-nosnippet>418</a> )])
<a href=#419 id=419 data-nosnippet>419</a> }
<a href=#420 id=420 data-nosnippet>420</a>
<a href=#421 id=421 data-nosnippet>421</a> <span class="attr">#[test]
<a href=#422 id=422 data-nosnippet>422</a> </span><span class="kw">fn </span>test_resolve_permission_table_targets() {
<a href=#423 id=423 data-nosnippet>423</a> <span class="macro">assert_eq!</span>(
<a href=#424 id=424 data-nosnippet>424</a> PermissionTableTargets::Resolved(Vec::new()),
<a href=#425 id=425 data-nosnippet>425</a> PermissionTableTargets::resolved(Vec::new())
<a href=#426 id=426 data-nosnippet>426</a> );
<a href=#427 id=427 data-nosnippet>427</a> <span class="macro">assert_eq!</span>(
<a href=#428 id=428 data-nosnippet>428</a> resolved_targets(<span class="string">"metrics"</span>),
<a href=#429 id=429 data-nosnippet>429</a> PermissionTableTargets::Resolved(<span class="macro">vec!</span>[PermissionTableTarget::new(
<a href=#430 id=430 data-nosnippet>430</a> <span class="string">"greptime"</span>, <span class="string">"public"</span>, <span class="string">"metrics"
<a href=#431 id=431 data-nosnippet>431</a> </span>)])
<a href=#432 id=432 data-nosnippet>432</a> );
<a href=#433 id=433 data-nosnippet>433</a>
<a href=#434 id=434 data-nosnippet>434</a> <span class="kw">for </span>target <span class="kw">in </span>[
<a href=#435 id=435 data-nosnippet>435</a> PermissionTableTarget::new(<span class="string">""</span>, <span class="string">"public"</span>, <span class="string">"metrics"</span>),
<a href=#436 id=436 data-nosnippet>436</a> PermissionTableTarget::new(<span class="string">"greptime"</span>, <span class="string">""</span>, <span class="string">"metrics"</span>),
<a href=#437 id=437 data-nosnippet>437</a> PermissionTableTarget::new(<span class="string">"greptime"</span>, <span class="string">"public"</span>, <span class="string">""</span>),
<a href=#438 id=438 data-nosnippet>438</a> ] {
<a href=#439 id=439 data-nosnippet>439</a> <span class="macro">assert_eq!</span>(
<a href=#440 id=440 data-nosnippet>440</a> PermissionTableTargets::Unresolved,
<a href=#441 id=441 data-nosnippet>441</a> PermissionTableTargets::resolved(<span class="macro">vec!</span>[target])
<a href=#442 id=442 data-nosnippet>442</a> );
<a href=#443 id=443 data-nosnippet>443</a> }
<a href=#444 id=444 data-nosnippet>444</a> }
<a href=#445 id=445 data-nosnippet>445</a>
<a href=#446 id=446 data-nosnippet>446</a> <span class="attr">#[test]
<a href=#447 id=447 data-nosnippet>447</a> </span><span class="kw">fn </span>test_resolve_row_insert_request_targets() {
<a href=#448 id=448 data-nosnippet>448</a> <span class="kw">let </span>requests = RowInsertRequests {
<a href=#449 id=449 data-nosnippet>449</a> inserts: [<span class="string">"cpu"</span>, <span class="string">"mem"</span>]
<a href=#450 id=450 data-nosnippet>450</a> .into_iter()
<a href=#451 id=451 data-nosnippet>451</a> .map(|table_name| api::v1::RowInsertRequest {
<a href=#452 id=452 data-nosnippet>452</a> table_name: table_name.to_string(),
<a href=#453 id=453 data-nosnippet>453</a> ..Default::default()
<a href=#454 id=454 data-nosnippet>454</a> })
<a href=#455 id=455 data-nosnippet>455</a> .collect(),
<a href=#456 id=456 data-nosnippet>456</a> };
<a href=#457 id=457 data-nosnippet>457</a>
<a href=#458 id=458 data-nosnippet>458</a> <span class="macro">assert_eq!</span>(
<a href=#459 id=459 data-nosnippet>459</a> PermissionTableTargets::Resolved(<span class="macro">vec!</span>[
<a href=#460 id=460 data-nosnippet>460</a> PermissionTableTarget::new(<span class="string">"greptime"</span>, <span class="string">"public"</span>, <span class="string">"cpu"</span>),
<a href=#461 id=461 data-nosnippet>461</a> PermissionTableTarget::new(<span class="string">"greptime"</span>, <span class="string">"public"</span>, <span class="string">"mem"</span>),
<a href=#462 id=462 data-nosnippet>462</a> ]),
<a href=#463 id=463 data-nosnippet>463</a> PermissionTableTargets::from_row_insert_requests(<span class="string">"greptime"</span>, <span class="string">"public"</span>, <span class="kw-2">&amp;</span>requests)
<a href=#464 id=464 data-nosnippet>464</a> );
<a href=#465 id=465 data-nosnippet>465</a> <span class="macro">assert_eq!</span>(
<a href=#466 id=466 data-nosnippet>466</a> PermissionTableTargets::Unresolved,
<a href=#467 id=467 data-nosnippet>467</a> PermissionTableTargets::from_row_insert_requests(<span class="string">""</span>, <span class="string">"public"</span>, <span class="kw-2">&amp;</span>requests)
<a href=#468 id=468 data-nosnippet>468</a> );
<a href=#469 id=469 data-nosnippet>469</a> <span class="macro">assert_eq!</span>(
<a href=#470 id=470 data-nosnippet>470</a> PermissionTableTargets::Unresolved,
<a href=#471 id=471 data-nosnippet>471</a> PermissionTableTargets::from_row_insert_requests(<span class="string">"greptime"</span>, <span class="string">""</span>, <span class="kw-2">&amp;</span>requests)
<a href=#472 id=472 data-nosnippet>472</a> );
<a href=#473 id=473 data-nosnippet>473</a>
<a href=#474 id=474 data-nosnippet>474</a> <span class="kw">let </span>unresolved = RowInsertRequests {
<a href=#475 id=475 data-nosnippet>475</a> inserts: <span class="macro">vec!</span>[api::v1::RowInsertRequest::default()],
<a href=#476 id=476 data-nosnippet>476</a> };
<a href=#477 id=477 data-nosnippet>477</a> <span class="macro">assert_eq!</span>(
<a href=#478 id=478 data-nosnippet>478</a> PermissionTableTargets::Unresolved,
<a href=#479 id=479 data-nosnippet>479</a> PermissionTableTargets::from_row_insert_requests(<span class="string">"greptime"</span>, <span class="string">"public"</span>, <span class="kw-2">&amp;</span>unresolved)
<a href=#480 id=480 data-nosnippet>480</a> );
<a href=#481 id=481 data-nosnippet>481</a>
<a href=#482 id=482 data-nosnippet>482</a> <span class="kw">let </span>empty = RowInsertRequests::default();
<a href=#483 id=483 data-nosnippet>483</a> <span class="macro">assert_eq!</span>(
<a href=#484 id=484 data-nosnippet>484</a> PermissionTableTargets::Resolved(Vec::new()),
<a href=#485 id=485 data-nosnippet>485</a> PermissionTableTargets::from_row_insert_requests(<span class="string">"greptime"</span>, <span class="string">"public"</span>, <span class="kw-2">&amp;</span>empty)
<a href=#486 id=486 data-nosnippet>486</a> );
<a href=#487 id=487 data-nosnippet>487</a> }
<a href=#488 id=488 data-nosnippet>488</a>
<a href=#489 id=489 data-nosnippet>489</a> <span class="attr">#[test]
<a href=#490 id=490 data-nosnippet>490</a> </span><span class="kw">fn </span>test_default_permission_checker_allow_all_operations() {
<a href=#491 id=491 data-nosnippet>491</a> <span class="kw">let </span>checker = DefaultPermissionChecker;
<a href=#492 id=492 data-nosnippet>492</a> <span class="kw">let </span>user_info =
<a href=#493 id=493 data-nosnippet>493</a> DefaultUserInfo::with_name_and_permission(<span class="string">"test_user"</span>, PermissionMode::ReadWrite);
<a href=#494 id=494 data-nosnippet>494</a>
<a href=#495 id=495 data-nosnippet>495</a> <span class="kw">let </span>read_req = PermissionReq::Action(PROMQL_QUERY);
<a href=#496 id=496 data-nosnippet>496</a> <span class="kw">let </span>write_req = PermissionReq::Action(PROM_STORE_WRITE);
<a href=#497 id=497 data-nosnippet>497</a>
<a href=#498 id=498 data-nosnippet>498</a> <span class="kw">let </span>read_result = checker
<a href=#499 id=499 data-nosnippet>499</a> .check_permission(user_info.clone(), read_req)
<a href=#500 id=500 data-nosnippet>500</a> .unwrap();
<a href=#501 id=501 data-nosnippet>501</a> <span class="kw">let </span>write_result = checker.check_permission(user_info, write_req).unwrap();
<a href=#502 id=502 data-nosnippet>502</a>
<a href=#503 id=503 data-nosnippet>503</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(read_result, PermissionResp::Allow));
<a href=#504 id=504 data-nosnippet>504</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(write_result, PermissionResp::Allow));
<a href=#505 id=505 data-nosnippet>505</a> }
<a href=#506 id=506 data-nosnippet>506</a>
<a href=#507 id=507 data-nosnippet>507</a> <span class="attr">#[test]
<a href=#508 id=508 data-nosnippet>508</a> </span><span class="kw">fn </span>test_default_permission_checker_readonly_user() {
<a href=#509 id=509 data-nosnippet>509</a> <span class="kw">let </span>checker = DefaultPermissionChecker;
<a href=#510 id=510 data-nosnippet>510</a> <span class="kw">let </span>user_info =
<a href=#511 id=511 data-nosnippet>511</a> DefaultUserInfo::with_name_and_permission(<span class="string">"readonly_user"</span>, PermissionMode::ReadOnly);
<a href=#512 id=512 data-nosnippet>512</a>
<a href=#513 id=513 data-nosnippet>513</a> <span class="kw">let </span>read_req = PermissionReq::Action(PROMQL_QUERY);
<a href=#514 id=514 data-nosnippet>514</a> <span class="kw">let </span>write_req = PermissionReq::Action(PROM_STORE_WRITE);
<a href=#515 id=515 data-nosnippet>515</a>
<a href=#516 id=516 data-nosnippet>516</a> <span class="kw">let </span>read_result = checker
<a href=#517 id=517 data-nosnippet>517</a> .check_permission(user_info.clone(), read_req)
<a href=#518 id=518 data-nosnippet>518</a> .unwrap();
<a href=#519 id=519 data-nosnippet>519</a> <span class="kw">let </span>write_result = checker.check_permission(user_info, write_req).unwrap();
<a href=#520 id=520 data-nosnippet>520</a>
<a href=#521 id=521 data-nosnippet>521</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(read_result, PermissionResp::Allow));
<a href=#522 id=522 data-nosnippet>522</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(write_result, PermissionResp::Reject));
<a href=#523 id=523 data-nosnippet>523</a> }
<a href=#524 id=524 data-nosnippet>524</a>
<a href=#525 id=525 data-nosnippet>525</a> <span class="attr">#[test]
<a href=#526 id=526 data-nosnippet>526</a> </span><span class="kw">fn </span>test_default_permission_checker_writeonly_user() {
<a href=#527 id=527 data-nosnippet>527</a> <span class="kw">let </span>checker = DefaultPermissionChecker;
<a href=#528 id=528 data-nosnippet>528</a> <span class="kw">let </span>user_info =
<a href=#529 id=529 data-nosnippet>529</a> DefaultUserInfo::with_name_and_permission(<span class="string">"writeonly_user"</span>, PermissionMode::WriteOnly);
<a href=#530 id=530 data-nosnippet>530</a>
<a href=#531 id=531 data-nosnippet>531</a> <span class="kw">let </span>read_req = PermissionReq::Action(LOG_QUERY);
<a href=#532 id=532 data-nosnippet>532</a> <span class="kw">let </span>write_req = PermissionReq::Action(LOG_WRITE);
<a href=#533 id=533 data-nosnippet>533</a>
<a href=#534 id=534 data-nosnippet>534</a> <span class="kw">let </span>read_result = checker
<a href=#535 id=535 data-nosnippet>535</a> .check_permission(user_info.clone(), read_req)
<a href=#536 id=536 data-nosnippet>536</a> .unwrap();
<a href=#537 id=537 data-nosnippet>537</a> <span class="kw">let </span>write_result = checker.check_permission(user_info, write_req).unwrap();
<a href=#538 id=538 data-nosnippet>538</a>
<a href=#539 id=539 data-nosnippet>539</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(read_result, PermissionResp::Reject));
<a href=#540 id=540 data-nosnippet>540</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(write_result, PermissionResp::Allow));
<a href=#541 id=541 data-nosnippet>541</a> }
<a href=#542 id=542 data-nosnippet>542</a>
<a href=#543 id=543 data-nosnippet>543</a> <span class="attr">#[test]
<a href=#544 id=544 data-nosnippet>544</a> </span><span class="kw">fn </span>test_grpc_insert_into_plan_is_write_request() {
<a href=#545 id=545 data-nosnippet>545</a> <span class="kw">let </span>request = Request::Query(api::v1::QueryRequest {
<a href=#546 id=546 data-nosnippet>546</a> query: <span class="prelude-val">Some</span>(Query::InsertIntoPlan(api::v1::InsertIntoPlan::default())),
<a href=#547 id=547 data-nosnippet>547</a> });
<a href=#548 id=548 data-nosnippet>548</a> <span class="kw">let </span>req = PermissionReq::GrpcRequest(<span class="kw-2">&amp;</span>request);
<a href=#549 id=549 data-nosnippet>549</a>
<a href=#550 id=550 data-nosnippet>550</a> <span class="macro">assert!</span>(req.is_write());
<a href=#551 id=551 data-nosnippet>551</a> }
<a href=#552 id=552 data-nosnippet>552</a>
<a href=#553 id=553 data-nosnippet>553</a> <span class="attr">#[test]
<a href=#554 id=554 data-nosnippet>554</a> </span><span class="kw">fn </span>test_bulk_insert_is_write_request() {
<a href=#555 id=555 data-nosnippet>555</a> <span class="kw">let </span>req = PermissionReq::BulkInsert {
<a href=#556 id=556 data-nosnippet>556</a> catalog: <span class="string">"greptime"</span>,
<a href=#557 id=557 data-nosnippet>557</a> schema: <span class="string">"public"</span>,
<a href=#558 id=558 data-nosnippet>558</a> table: <span class="string">"metrics"</span>,
<a href=#559 id=559 data-nosnippet>559</a> };
<a href=#560 id=560 data-nosnippet>560</a>
<a href=#561 id=561 data-nosnippet>561</a> <span class="macro">assert!</span>(req.is_write());
<a href=#562 id=562 data-nosnippet>562</a> }
<a href=#563 id=563 data-nosnippet>563</a>
<a href=#564 id=564 data-nosnippet>564</a> <span class="attr">#[test]
<a href=#565 id=565 data-nosnippet>565</a> </span><span class="kw">fn </span>test_action_access_modes() {
<a href=#566 id=566 data-nosnippet>566</a> <span class="kw">let </span>checker = DefaultPermissionChecker;
<a href=#567 id=567 data-nosnippet>567</a> <span class="kw">let </span><span class="kw-2">mut </span>names = HashSet::new();
<a href=#568 id=568 data-nosnippet>568</a>
<a href=#569 id=569 data-nosnippet>569</a> <span class="kw">for </span><span class="kw-2">&amp;</span>action <span class="kw">in </span>ALL_ACTIONS {
<a href=#570 id=570 data-nosnippet>570</a> <span class="macro">assert!</span>(
<a href=#571 id=571 data-nosnippet>571</a> names.insert(action.name()),
<a href=#572 id=572 data-nosnippet>572</a> <span class="string">"duplicate permission action: {}"</span>,
<a href=#573 id=573 data-nosnippet>573</a> action.name()
<a href=#574 id=574 data-nosnippet>574</a> );
<a href=#575 id=575 data-nosnippet>575</a> <span class="kw">let </span>access_mode = action.access_mode();
<a href=#576 id=576 data-nosnippet>576</a> <span class="kw">let </span>req = PermissionReq::Action(action);
<a href=#577 id=577 data-nosnippet>577</a> <span class="macro">assert_eq!</span>(
<a href=#578 id=578 data-nosnippet>578</a> access_mode == AccessMode::Read,
<a href=#579 id=579 data-nosnippet>579</a> req.is_readonly(),
<a href=#580 id=580 data-nosnippet>580</a> <span class="string">"{}"</span>,
<a href=#581 id=581 data-nosnippet>581</a> action.name()
<a href=#582 id=582 data-nosnippet>582</a> );
<a href=#583 id=583 data-nosnippet>583</a>
<a href=#584 id=584 data-nosnippet>584</a> <span class="kw">for </span>(permission_mode, allowed) <span class="kw">in </span>[
<a href=#585 id=585 data-nosnippet>585</a> (PermissionMode::ReadOnly, access_mode == AccessMode::Read),
<a href=#586 id=586 data-nosnippet>586</a> (PermissionMode::WriteOnly, access_mode == AccessMode::Write),
<a href=#587 id=587 data-nosnippet>587</a> (PermissionMode::ReadWrite, <span class="bool-val">true</span>),
<a href=#588 id=588 data-nosnippet>588</a> ] {
<a href=#589 id=589 data-nosnippet>589</a> <span class="kw">let </span>user = DefaultUserInfo::with_name_and_permission(<span class="string">"test_user"</span>, permission_mode);
<a href=#590 id=590 data-nosnippet>590</a> <span class="kw">let </span>result = checker.check_permission(user, req.clone()).unwrap();
<a href=#591 id=591 data-nosnippet>591</a> <span class="macro">assert_eq!</span>(
<a href=#592 id=592 data-nosnippet>592</a> allowed,
<a href=#593 id=593 data-nosnippet>593</a> <span class="macro">matches!</span>(result, PermissionResp::Allow),
<a href=#594 id=594 data-nosnippet>594</a> <span class="string">"{permission_mode:?}: {}"</span>,
<a href=#595 id=595 data-nosnippet>595</a> action.name()
<a href=#596 id=596 data-nosnippet>596</a> );
<a href=#597 id=597 data-nosnippet>597</a> }
<a href=#598 id=598 data-nosnippet>598</a> }
<a href=#599 id=599 data-nosnippet>599</a> }
<a href=#600 id=600 data-nosnippet>600</a>
<a href=#601 id=601 data-nosnippet>601</a> <span class="attr">#[test]
<a href=#602 id=602 data-nosnippet>602</a> </span><span class="kw">fn </span>test_table_target_permission_forwarding() {
<a href=#603 id=603 data-nosnippet>603</a> <span class="kw">let </span>checker: PermissionCheckerRef = Arc::new(TargetAwarePermissionChecker);
<a href=#604 id=604 data-nosnippet>604</a> <span class="kw">let </span>checker = <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>checker);
<a href=#605 id=605 data-nosnippet>605</a> <span class="macro">assert!</span>(checker.uses_table_targets());
<a href=#606 id=606 data-nosnippet>606</a>
<a href=#607 id=607 data-nosnippet>607</a> <span class="kw">let </span>allowed = checker
<a href=#608 id=608 data-nosnippet>608</a> .check_permission_with_table_targets(
<a href=#609 id=609 data-nosnippet>609</a> <span class="kw">crate</span>::userinfo_by_name(<span class="prelude-val">None</span>),
<a href=#610 id=610 data-nosnippet>610</a> PermissionReq::Action(PROM_STORE_READ),
<a href=#611 id=611 data-nosnippet>611</a> resolved_targets(<span class="string">"allowed"</span>),
<a href=#612 id=612 data-nosnippet>612</a> )
<a href=#613 id=613 data-nosnippet>613</a> .unwrap();
<a href=#614 id=614 data-nosnippet>614</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(allowed, PermissionResp::Allow));
<a href=#615 id=615 data-nosnippet>615</a>
<a href=#616 id=616 data-nosnippet>616</a> <span class="kw">let </span>empty = checker
<a href=#617 id=617 data-nosnippet>617</a> .check_permission_with_table_targets(
<a href=#618 id=618 data-nosnippet>618</a> <span class="kw">crate</span>::userinfo_by_name(<span class="prelude-val">None</span>),
<a href=#619 id=619 data-nosnippet>619</a> PermissionReq::Action(PROM_STORE_READ),
<a href=#620 id=620 data-nosnippet>620</a> PermissionTableTargets::resolved(Vec::new()),
<a href=#621 id=621 data-nosnippet>621</a> )
<a href=#622 id=622 data-nosnippet>622</a> .unwrap();
<a href=#623 id=623 data-nosnippet>623</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(empty, PermissionResp::Allow));
<a href=#624 id=624 data-nosnippet>624</a>
<a href=#625 id=625 data-nosnippet>625</a> <span class="kw">let </span>rejected_operation = checker.check_permission_with_table_targets(
<a href=#626 id=626 data-nosnippet>626</a> <span class="kw">crate</span>::userinfo_by_name(<span class="prelude-val">None</span>),
<a href=#627 id=627 data-nosnippet>627</a> PermissionReq::Action(PROM_STORE_WRITE),
<a href=#628 id=628 data-nosnippet>628</a> PermissionTableTargets::resolved(Vec::new()),
<a href=#629 id=629 data-nosnippet>629</a> );
<a href=#630 id=630 data-nosnippet>630</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(
<a href=#631 id=631 data-nosnippet>631</a> rejected_operation,
<a href=#632 id=632 data-nosnippet>632</a> <span class="prelude-val">Err</span>(Error::PermissionDenied { .. })
<a href=#633 id=633 data-nosnippet>633</a> ));
<a href=#634 id=634 data-nosnippet>634</a>
<a href=#635 id=635 data-nosnippet>635</a> <span class="kw">let </span>rejected = checker.check_permission_with_table_targets(
<a href=#636 id=636 data-nosnippet>636</a> <span class="kw">crate</span>::userinfo_by_name(<span class="prelude-val">None</span>),
<a href=#637 id=637 data-nosnippet>637</a> PermissionReq::Action(PROM_STORE_READ),
<a href=#638 id=638 data-nosnippet>638</a> resolved_targets(<span class="string">"denied"</span>),
<a href=#639 id=639 data-nosnippet>639</a> );
<a href=#640 id=640 data-nosnippet>640</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(rejected, <span class="prelude-val">Err</span>(Error::PermissionDenied { .. })));
<a href=#641 id=641 data-nosnippet>641</a>
<a href=#642 id=642 data-nosnippet>642</a> <span class="kw">let </span>mixed = checker.check_permission_with_table_targets(
<a href=#643 id=643 data-nosnippet>643</a> <span class="kw">crate</span>::userinfo_by_name(<span class="prelude-val">None</span>),
<a href=#644 id=644 data-nosnippet>644</a> PermissionReq::Action(PROM_STORE_READ),
<a href=#645 id=645 data-nosnippet>645</a> PermissionTableTargets::resolved(<span class="macro">vec!</span>[
<a href=#646 id=646 data-nosnippet>646</a> PermissionTableTarget::new(<span class="string">"greptime"</span>, <span class="string">"public"</span>, <span class="string">"allowed"</span>),
<a href=#647 id=647 data-nosnippet>647</a> PermissionTableTarget::new(<span class="string">"greptime"</span>, <span class="string">"public"</span>, <span class="string">"denied"</span>),
<a href=#648 id=648 data-nosnippet>648</a> ]),
<a href=#649 id=649 data-nosnippet>649</a> );
<a href=#650 id=650 data-nosnippet>650</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(mixed, <span class="prelude-val">Err</span>(Error::PermissionDenied { .. })));
<a href=#651 id=651 data-nosnippet>651</a>
<a href=#652 id=652 data-nosnippet>652</a> <span class="kw">let </span>error = checker.check_permission_with_table_targets(
<a href=#653 id=653 data-nosnippet>653</a> <span class="kw">crate</span>::userinfo_by_name(<span class="prelude-val">None</span>),
<a href=#654 id=654 data-nosnippet>654</a> PermissionReq::Action(PROM_STORE_READ),
<a href=#655 id=655 data-nosnippet>655</a> resolved_targets(<span class="string">"error"</span>),
<a href=#656 id=656 data-nosnippet>656</a> );
<a href=#657 id=657 data-nosnippet>657</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(error, <span class="prelude-val">Err</span>(Error::InternalState { msg }) <span class="kw">if </span>msg == <span class="string">"testing"</span>));
<a href=#658 id=658 data-nosnippet>658</a>
<a href=#659 id=659 data-nosnippet>659</a> <span class="kw">let </span>no_checker: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>PermissionCheckerRef&gt; = <span class="prelude-val">None</span>;
<a href=#660 id=660 data-nosnippet>660</a> <span class="macro">assert!</span>(!no_checker.uses_table_targets());
<a href=#661 id=661 data-nosnippet>661</a> <span class="kw">let </span>allowed = no_checker
<a href=#662 id=662 data-nosnippet>662</a> .check_permission_with_table_targets(
<a href=#663 id=663 data-nosnippet>663</a> <span class="kw">crate</span>::userinfo_by_name(<span class="prelude-val">None</span>),
<a href=#664 id=664 data-nosnippet>664</a> PermissionReq::Action(PROM_STORE_READ),
<a href=#665 id=665 data-nosnippet>665</a> PermissionTableTargets::Unresolved,
<a href=#666 id=666 data-nosnippet>666</a> )
<a href=#667 id=667 data-nosnippet>667</a> .unwrap();
<a href=#668 id=668 data-nosnippet>668</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(allowed, PermissionResp::Allow));
<a href=#669 id=669 data-nosnippet>669</a> }
<a href=#670 id=670 data-nosnippet>670</a>
<a href=#671 id=671 data-nosnippet>671</a> <span class="attr">#[test]
<a href=#672 id=672 data-nosnippet>672</a> </span><span class="kw">fn </span>test_default_permission_checker_table_target_parity() {
<a href=#673 id=673 data-nosnippet>673</a> <span class="kw">let </span>checker = DefaultPermissionChecker;
<a href=#674 id=674 data-nosnippet>674</a> <span class="macro">assert!</span>(!checker.uses_table_targets());
<a href=#675 id=675 data-nosnippet>675</a>
<a href=#676 id=676 data-nosnippet>676</a> <span class="kw">for </span>(permission, req) <span class="kw">in </span>[
<a href=#677 id=677 data-nosnippet>677</a> (
<a href=#678 id=678 data-nosnippet>678</a> PermissionMode::ReadOnly,
<a href=#679 id=679 data-nosnippet>679</a> PermissionReq::Action(PROMQL_QUERY),
<a href=#680 id=680 data-nosnippet>680</a> ),
<a href=#681 id=681 data-nosnippet>681</a> (
<a href=#682 id=682 data-nosnippet>682</a> PermissionMode::ReadOnly,
<a href=#683 id=683 data-nosnippet>683</a> PermissionReq::Action(PROM_STORE_WRITE),
<a href=#684 id=684 data-nosnippet>684</a> ),
<a href=#685 id=685 data-nosnippet>685</a> (
<a href=#686 id=686 data-nosnippet>686</a> PermissionMode::WriteOnly,
<a href=#687 id=687 data-nosnippet>687</a> PermissionReq::Action(PROMQL_QUERY),
<a href=#688 id=688 data-nosnippet>688</a> ),
<a href=#689 id=689 data-nosnippet>689</a> (
<a href=#690 id=690 data-nosnippet>690</a> PermissionMode::WriteOnly,
<a href=#691 id=691 data-nosnippet>691</a> PermissionReq::Action(PROM_STORE_WRITE),
<a href=#692 id=692 data-nosnippet>692</a> ),
<a href=#693 id=693 data-nosnippet>693</a> ] {
<a href=#694 id=694 data-nosnippet>694</a> <span class="kw">let </span>user = DefaultUserInfo::with_name_and_permission(<span class="string">"test_user"</span>, permission);
<a href=#695 id=695 data-nosnippet>695</a> <span class="kw">let </span>direct = checker.check_permission(user.clone(), req.clone()).unwrap();
<a href=#696 id=696 data-nosnippet>696</a> <span class="kw">let </span>targeted = checker
<a href=#697 id=697 data-nosnippet>697</a> .check_permission_with_table_targets(user, req, resolved_targets(<span class="string">"metrics"</span>))
<a href=#698 id=698 data-nosnippet>698</a> .unwrap();
<a href=#699 id=699 data-nosnippet>699</a>
<a href=#700 id=700 data-nosnippet>700</a> <span class="macro">assert_eq!</span>(
<a href=#701 id=701 data-nosnippet>701</a> <span class="macro">matches!</span>(direct, PermissionResp::Allow),
<a href=#702 id=702 data-nosnippet>702</a> <span class="macro">matches!</span>(targeted, PermissionResp::Allow)
<a href=#703 id=703 data-nosnippet>703</a> );
<a href=#704 id=704 data-nosnippet>704</a> }
<a href=#705 id=705 data-nosnippet>705</a> }
<a href=#706 id=706 data-nosnippet>706</a>}
</code></pre></div></section></main></body></html>
+233
View File
@@ -0,0 +1,233 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/auth/src/user_info.rs`."><title>user_info.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="auth" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">auth/</div>user_info.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::any::Any;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::fmt::Debug;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>std::sync::Arc;
<a href=#18 id=18 data-nosnippet>18</a>
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span><span class="kw">crate</span>::UserInfoRef;
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">pub trait </span>UserInfo: Debug + Sync + Send {
<a href=#22 id=22 data-nosnippet>22</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>Any;
<a href=#23 id=23 data-nosnippet>23</a> <span class="kw">fn </span>username(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str;
<a href=#24 id=24 data-nosnippet>24</a>
<a href=#25 id=25 data-nosnippet>25</a> <span class="kw">fn </span>is_admin(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#26 id=26 data-nosnippet>26</a> <span class="bool-val">false
<a href=#27 id=27 data-nosnippet>27</a> </span>}
<a href=#28 id=28 data-nosnippet>28</a>}
<a href=#29 id=29 data-nosnippet>29</a>
<a href=#30 id=30 data-nosnippet>30</a><span class="doccomment">/// The user permission mode
<a href=#31 id=31 data-nosnippet>31</a></span><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
<a href=#32 id=32 data-nosnippet>32</a></span><span class="kw">pub enum </span>PermissionMode {
<a href=#33 id=33 data-nosnippet>33</a> <span class="attr">#[default]
<a href=#34 id=34 data-nosnippet>34</a> </span>ReadWrite,
<a href=#35 id=35 data-nosnippet>35</a> ReadOnly,
<a href=#36 id=36 data-nosnippet>36</a> WriteOnly,
<a href=#37 id=37 data-nosnippet>37</a>}
<a href=#38 id=38 data-nosnippet>38</a>
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">impl </span>PermissionMode {
<a href=#40 id=40 data-nosnippet>40</a> <span class="doccomment">/// Parse permission mode from string.
<a href=#41 id=41 data-nosnippet>41</a> /// Supported values are:
<a href=#42 id=42 data-nosnippet>42</a> /// - "rw", "readwrite", "read_write" =&gt; ReadWrite
<a href=#43 id=43 data-nosnippet>43</a> /// - "ro", "readonly", "read_only" =&gt; ReadOnly
<a href=#44 id=44 data-nosnippet>44</a> /// - "wo", "writeonly", "write_only" =&gt; WriteOnly
<a href=#45 id=45 data-nosnippet>45</a> ///
<a href=#46 id=46 data-nosnippet>46</a> /// Returns `None` if the input string is not a valid permission mode.
<a href=#47 id=47 data-nosnippet>47</a> </span><span class="kw">pub fn </span>from_str(s: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>&gt; {
<a href=#48 id=48 data-nosnippet>48</a> <span class="kw">match </span>s.to_lowercase().as_str() {
<a href=#49 id=49 data-nosnippet>49</a> <span class="string">"readwrite" </span>| <span class="string">"read_write" </span>| <span class="string">"rw" </span>=&gt; <span class="prelude-val">Some</span>(PermissionMode::ReadWrite),
<a href=#50 id=50 data-nosnippet>50</a> <span class="string">"readonly" </span>| <span class="string">"read_only" </span>| <span class="string">"ro" </span>=&gt; <span class="prelude-val">Some</span>(PermissionMode::ReadOnly),
<a href=#51 id=51 data-nosnippet>51</a> <span class="string">"writeonly" </span>| <span class="string">"write_only" </span>| <span class="string">"wo" </span>=&gt; <span class="prelude-val">Some</span>(PermissionMode::WriteOnly),
<a href=#52 id=52 data-nosnippet>52</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
<a href=#53 id=53 data-nosnippet>53</a> }
<a href=#54 id=54 data-nosnippet>54</a> }
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a> <span class="doccomment">/// Convert permission mode to string.
<a href=#57 id=57 data-nosnippet>57</a> /// - ReadWrite =&gt; "rw"
<a href=#58 id=58 data-nosnippet>58</a> /// - ReadOnly =&gt; "ro"
<a href=#59 id=59 data-nosnippet>59</a> /// - WriteOnly =&gt; "wo"
<a href=#60 id=60 data-nosnippet>60</a> /// The returned string is a static string slice.
<a href=#61 id=61 data-nosnippet>61</a> </span><span class="kw">pub fn </span>as_str(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#62 id=62 data-nosnippet>62</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#63 id=63 data-nosnippet>63</a> PermissionMode::ReadWrite =&gt; <span class="string">"rw"</span>,
<a href=#64 id=64 data-nosnippet>64</a> PermissionMode::ReadOnly =&gt; <span class="string">"ro"</span>,
<a href=#65 id=65 data-nosnippet>65</a> PermissionMode::WriteOnly =&gt; <span class="string">"wo"</span>,
<a href=#66 id=66 data-nosnippet>66</a> }
<a href=#67 id=67 data-nosnippet>67</a> }
<a href=#68 id=68 data-nosnippet>68</a>
<a href=#69 id=69 data-nosnippet>69</a> <span class="doccomment">/// Returns true if the permission mode allows read operations.
<a href=#70 id=70 data-nosnippet>70</a> </span><span class="kw">pub fn </span>can_read(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#71 id=71 data-nosnippet>71</a> <span class="macro">matches!</span>(<span class="self">self</span>, PermissionMode::ReadWrite | PermissionMode::ReadOnly)
<a href=#72 id=72 data-nosnippet>72</a> }
<a href=#73 id=73 data-nosnippet>73</a>
<a href=#74 id=74 data-nosnippet>74</a> <span class="doccomment">/// Returns true if the permission mode allows write operations.
<a href=#75 id=75 data-nosnippet>75</a> </span><span class="kw">pub fn </span>can_write(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#76 id=76 data-nosnippet>76</a> <span class="macro">matches!</span>(<span class="self">self</span>, PermissionMode::ReadWrite | PermissionMode::WriteOnly)
<a href=#77 id=77 data-nosnippet>77</a> }
<a href=#78 id=78 data-nosnippet>78</a>}
<a href=#79 id=79 data-nosnippet>79</a>
<a href=#80 id=80 data-nosnippet>80</a><span class="kw">impl </span>std::fmt::Display <span class="kw">for </span>PermissionMode {
<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>std::fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; std::fmt::Result {
<a href=#82 id=82 data-nosnippet>82</a> <span class="macro">write!</span>(f, <span class="string">"{}"</span>, <span class="self">self</span>.as_str())
<a href=#83 id=83 data-nosnippet>83</a> }
<a href=#84 id=84 data-nosnippet>84</a>}
<a href=#85 id=85 data-nosnippet>85</a>
<a href=#86 id=86 data-nosnippet>86</a><span class="attr">#[derive(Debug)]
<a href=#87 id=87 data-nosnippet>87</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>DefaultUserInfo {
<a href=#88 id=88 data-nosnippet>88</a> username: String,
<a href=#89 id=89 data-nosnippet>89</a> permission_mode: PermissionMode,
<a href=#90 id=90 data-nosnippet>90</a>}
<a href=#91 id=91 data-nosnippet>91</a>
<a href=#92 id=92 data-nosnippet>92</a><span class="kw">impl </span>DefaultUserInfo {
<a href=#93 id=93 data-nosnippet>93</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>with_name(username: <span class="kw">impl </span>Into&lt;String&gt;) -&gt; UserInfoRef {
<a href=#94 id=94 data-nosnippet>94</a> <span class="self">Self</span>::with_name_and_permission(username, PermissionMode::default())
<a href=#95 id=95 data-nosnippet>95</a> }
<a href=#96 id=96 data-nosnippet>96</a>
<a href=#97 id=97 data-nosnippet>97</a> <span class="doccomment">/// Create a UserInfo with specified permission mode.
<a href=#98 id=98 data-nosnippet>98</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>with_name_and_permission(
<a href=#99 id=99 data-nosnippet>99</a> username: <span class="kw">impl </span>Into&lt;String&gt;,
<a href=#100 id=100 data-nosnippet>100</a> permission_mode: PermissionMode,
<a href=#101 id=101 data-nosnippet>101</a> ) -&gt; UserInfoRef {
<a href=#102 id=102 data-nosnippet>102</a> Arc::new(<span class="self">Self </span>{
<a href=#103 id=103 data-nosnippet>103</a> username: username.into(),
<a href=#104 id=104 data-nosnippet>104</a> permission_mode,
<a href=#105 id=105 data-nosnippet>105</a> })
<a href=#106 id=106 data-nosnippet>106</a> }
<a href=#107 id=107 data-nosnippet>107</a>
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>permission_mode(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>PermissionMode {
<a href=#109 id=109 data-nosnippet>109</a> <span class="kw-2">&amp;</span><span class="self">self</span>.permission_mode
<a href=#110 id=110 data-nosnippet>110</a> }
<a href=#111 id=111 data-nosnippet>111</a>}
<a href=#112 id=112 data-nosnippet>112</a>
<a href=#113 id=113 data-nosnippet>113</a><span class="kw">impl </span>UserInfo <span class="kw">for </span>DefaultUserInfo {
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>Any {
<a href=#115 id=115 data-nosnippet>115</a> <span class="self">self
<a href=#116 id=116 data-nosnippet>116</a> </span>}
<a href=#117 id=117 data-nosnippet>117</a>
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">fn </span>username(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#119 id=119 data-nosnippet>119</a> <span class="self">self</span>.username.as_str()
<a href=#120 id=120 data-nosnippet>120</a> }
<a href=#121 id=121 data-nosnippet>121</a>}
<a href=#122 id=122 data-nosnippet>122</a><span class="attr">#[cfg(test)]
<a href=#123 id=123 data-nosnippet>123</a></span><span class="kw">mod </span>tests {
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#125 id=125 data-nosnippet>125</a>
<a href=#126 id=126 data-nosnippet>126</a> <span class="attr">#[test]
<a href=#127 id=127 data-nosnippet>127</a> </span><span class="kw">fn </span>test_permission_mode_from_str() {
<a href=#128 id=128 data-nosnippet>128</a> <span class="comment">// Test ReadWrite variants
<a href=#129 id=129 data-nosnippet>129</a> </span><span class="macro">assert_eq!</span>(
<a href=#130 id=130 data-nosnippet>130</a> PermissionMode::from_str(<span class="string">"readwrite"</span>),
<a href=#131 id=131 data-nosnippet>131</a> <span class="prelude-val">Some</span>(PermissionMode::ReadWrite)
<a href=#132 id=132 data-nosnippet>132</a> );
<a href=#133 id=133 data-nosnippet>133</a> <span class="macro">assert_eq!</span>(
<a href=#134 id=134 data-nosnippet>134</a> PermissionMode::from_str(<span class="string">"read_write"</span>),
<a href=#135 id=135 data-nosnippet>135</a> <span class="prelude-val">Some</span>(PermissionMode::ReadWrite)
<a href=#136 id=136 data-nosnippet>136</a> );
<a href=#137 id=137 data-nosnippet>137</a> <span class="macro">assert_eq!</span>(
<a href=#138 id=138 data-nosnippet>138</a> PermissionMode::from_str(<span class="string">"rw"</span>),
<a href=#139 id=139 data-nosnippet>139</a> <span class="prelude-val">Some</span>(PermissionMode::ReadWrite)
<a href=#140 id=140 data-nosnippet>140</a> );
<a href=#141 id=141 data-nosnippet>141</a> <span class="macro">assert_eq!</span>(
<a href=#142 id=142 data-nosnippet>142</a> PermissionMode::from_str(<span class="string">"ReadWrite"</span>),
<a href=#143 id=143 data-nosnippet>143</a> <span class="prelude-val">Some</span>(PermissionMode::ReadWrite)
<a href=#144 id=144 data-nosnippet>144</a> );
<a href=#145 id=145 data-nosnippet>145</a> <span class="macro">assert_eq!</span>(
<a href=#146 id=146 data-nosnippet>146</a> PermissionMode::from_str(<span class="string">"RW"</span>),
<a href=#147 id=147 data-nosnippet>147</a> <span class="prelude-val">Some</span>(PermissionMode::ReadWrite)
<a href=#148 id=148 data-nosnippet>148</a> );
<a href=#149 id=149 data-nosnippet>149</a>
<a href=#150 id=150 data-nosnippet>150</a> <span class="comment">// Test ReadOnly variants
<a href=#151 id=151 data-nosnippet>151</a> </span><span class="macro">assert_eq!</span>(
<a href=#152 id=152 data-nosnippet>152</a> PermissionMode::from_str(<span class="string">"readonly"</span>),
<a href=#153 id=153 data-nosnippet>153</a> <span class="prelude-val">Some</span>(PermissionMode::ReadOnly)
<a href=#154 id=154 data-nosnippet>154</a> );
<a href=#155 id=155 data-nosnippet>155</a> <span class="macro">assert_eq!</span>(
<a href=#156 id=156 data-nosnippet>156</a> PermissionMode::from_str(<span class="string">"read_only"</span>),
<a href=#157 id=157 data-nosnippet>157</a> <span class="prelude-val">Some</span>(PermissionMode::ReadOnly)
<a href=#158 id=158 data-nosnippet>158</a> );
<a href=#159 id=159 data-nosnippet>159</a> <span class="macro">assert_eq!</span>(
<a href=#160 id=160 data-nosnippet>160</a> PermissionMode::from_str(<span class="string">"ro"</span>),
<a href=#161 id=161 data-nosnippet>161</a> <span class="prelude-val">Some</span>(PermissionMode::ReadOnly)
<a href=#162 id=162 data-nosnippet>162</a> );
<a href=#163 id=163 data-nosnippet>163</a> <span class="macro">assert_eq!</span>(
<a href=#164 id=164 data-nosnippet>164</a> PermissionMode::from_str(<span class="string">"ReadOnly"</span>),
<a href=#165 id=165 data-nosnippet>165</a> <span class="prelude-val">Some</span>(PermissionMode::ReadOnly)
<a href=#166 id=166 data-nosnippet>166</a> );
<a href=#167 id=167 data-nosnippet>167</a> <span class="macro">assert_eq!</span>(
<a href=#168 id=168 data-nosnippet>168</a> PermissionMode::from_str(<span class="string">"RO"</span>),
<a href=#169 id=169 data-nosnippet>169</a> <span class="prelude-val">Some</span>(PermissionMode::ReadOnly)
<a href=#170 id=170 data-nosnippet>170</a> );
<a href=#171 id=171 data-nosnippet>171</a>
<a href=#172 id=172 data-nosnippet>172</a> <span class="comment">// Test WriteOnly variants
<a href=#173 id=173 data-nosnippet>173</a> </span><span class="macro">assert_eq!</span>(
<a href=#174 id=174 data-nosnippet>174</a> PermissionMode::from_str(<span class="string">"writeonly"</span>),
<a href=#175 id=175 data-nosnippet>175</a> <span class="prelude-val">Some</span>(PermissionMode::WriteOnly)
<a href=#176 id=176 data-nosnippet>176</a> );
<a href=#177 id=177 data-nosnippet>177</a> <span class="macro">assert_eq!</span>(
<a href=#178 id=178 data-nosnippet>178</a> PermissionMode::from_str(<span class="string">"write_only"</span>),
<a href=#179 id=179 data-nosnippet>179</a> <span class="prelude-val">Some</span>(PermissionMode::WriteOnly)
<a href=#180 id=180 data-nosnippet>180</a> );
<a href=#181 id=181 data-nosnippet>181</a> <span class="macro">assert_eq!</span>(
<a href=#182 id=182 data-nosnippet>182</a> PermissionMode::from_str(<span class="string">"wo"</span>),
<a href=#183 id=183 data-nosnippet>183</a> <span class="prelude-val">Some</span>(PermissionMode::WriteOnly)
<a href=#184 id=184 data-nosnippet>184</a> );
<a href=#185 id=185 data-nosnippet>185</a> <span class="macro">assert_eq!</span>(
<a href=#186 id=186 data-nosnippet>186</a> PermissionMode::from_str(<span class="string">"WriteOnly"</span>),
<a href=#187 id=187 data-nosnippet>187</a> <span class="prelude-val">Some</span>(PermissionMode::WriteOnly)
<a href=#188 id=188 data-nosnippet>188</a> );
<a href=#189 id=189 data-nosnippet>189</a> <span class="macro">assert_eq!</span>(
<a href=#190 id=190 data-nosnippet>190</a> PermissionMode::from_str(<span class="string">"WO"</span>),
<a href=#191 id=191 data-nosnippet>191</a> <span class="prelude-val">Some</span>(PermissionMode::WriteOnly)
<a href=#192 id=192 data-nosnippet>192</a> );
<a href=#193 id=193 data-nosnippet>193</a>
<a href=#194 id=194 data-nosnippet>194</a> <span class="kw">for </span>invalid <span class="kw">in </span>[<span class="string">"readonyl"</span>, <span class="string">""</span>, <span class="string">"xyz"</span>] {
<a href=#195 id=195 data-nosnippet>195</a> <span class="macro">assert_eq!</span>(PermissionMode::from_str(invalid), <span class="prelude-val">None</span>);
<a href=#196 id=196 data-nosnippet>196</a> }
<a href=#197 id=197 data-nosnippet>197</a> }
<a href=#198 id=198 data-nosnippet>198</a>
<a href=#199 id=199 data-nosnippet>199</a> <span class="attr">#[test]
<a href=#200 id=200 data-nosnippet>200</a> </span><span class="kw">fn </span>test_permission_mode_as_str() {
<a href=#201 id=201 data-nosnippet>201</a> <span class="macro">assert_eq!</span>(PermissionMode::ReadWrite.as_str(), <span class="string">"rw"</span>);
<a href=#202 id=202 data-nosnippet>202</a> <span class="macro">assert_eq!</span>(PermissionMode::ReadOnly.as_str(), <span class="string">"ro"</span>);
<a href=#203 id=203 data-nosnippet>203</a> <span class="macro">assert_eq!</span>(PermissionMode::WriteOnly.as_str(), <span class="string">"wo"</span>);
<a href=#204 id=204 data-nosnippet>204</a> }
<a href=#205 id=205 data-nosnippet>205</a>
<a href=#206 id=206 data-nosnippet>206</a> <span class="attr">#[test]
<a href=#207 id=207 data-nosnippet>207</a> </span><span class="kw">fn </span>test_permission_mode_default() {
<a href=#208 id=208 data-nosnippet>208</a> <span class="macro">assert_eq!</span>(PermissionMode::default(), PermissionMode::ReadWrite);
<a href=#209 id=209 data-nosnippet>209</a> }
<a href=#210 id=210 data-nosnippet>210</a>
<a href=#211 id=211 data-nosnippet>211</a> <span class="attr">#[test]
<a href=#212 id=212 data-nosnippet>212</a> </span><span class="kw">fn </span>test_permission_mode_round_trip() {
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">let </span>modes = [
<a href=#214 id=214 data-nosnippet>214</a> PermissionMode::ReadWrite,
<a href=#215 id=215 data-nosnippet>215</a> PermissionMode::ReadOnly,
<a href=#216 id=216 data-nosnippet>216</a> PermissionMode::WriteOnly,
<a href=#217 id=217 data-nosnippet>217</a> ];
<a href=#218 id=218 data-nosnippet>218</a>
<a href=#219 id=219 data-nosnippet>219</a> <span class="kw">for </span>mode <span class="kw">in </span>modes {
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">let </span>str_repr = mode.as_str();
<a href=#221 id=221 data-nosnippet>221</a> <span class="kw">let </span>parsed = PermissionMode::from_str(str_repr);
<a href=#222 id=222 data-nosnippet>222</a> <span class="macro">assert_eq!</span>(<span class="prelude-val">Some</span>(mode), parsed);
<a href=#223 id=223 data-nosnippet>223</a> }
<a href=#224 id=224 data-nosnippet>224</a> }
<a href=#225 id=225 data-nosnippet>225</a>
<a href=#226 id=226 data-nosnippet>226</a> <span class="attr">#[test]
<a href=#227 id=227 data-nosnippet>227</a> </span><span class="kw">fn </span>test_user_info_as_any() {
<a href=#228 id=228 data-nosnippet>228</a> <span class="kw">let </span>user_info = DefaultUserInfo::with_name(<span class="string">"test_user"</span>);
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">let </span>any_ref = user_info.as_any();
<a href=#230 id=230 data-nosnippet>230</a> <span class="macro">assert!</span>(any_ref.downcast_ref::&lt;DefaultUserInfo&gt;().is_some());
<a href=#231 id=231 data-nosnippet>231</a> }
<a href=#232 id=232 data-nosnippet>232</a>}
</code></pre></div></section></main></body></html>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,191 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/auth/src/user_provider/static_user_provider.rs`."><title>static_user_provider.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="auth" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">auth/user_provider/</div>static_user_provider.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>async_trait::async_trait;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>snafu::OptionExt;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span><span class="kw">crate</span>::error::{InvalidConfigSnafu, <span class="prelude-ty">Result</span>};
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span><span class="kw">crate</span>::user_provider::{
<a href=#20 id=20 data-nosnippet>20</a> PgAuthInfo, UserInfoMap, authenticate_with_credential, load_credential_from_file,
<a href=#21 id=21 data-nosnippet>21</a> parse_credential_line, postgres_auth_info_with_credential, warn_if_pg_scram_disabled,
<a href=#22 id=22 data-nosnippet>22</a>};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>crate::{Identity, Password, UserInfoRef, UserProvider};
<a href=#24 id=24 data-nosnippet>24</a>
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>STATIC_USER_PROVIDER: <span class="kw-2">&amp;</span>str = <span class="string">"static_user_provider"</span>;
<a href=#26 id=26 data-nosnippet>26</a>
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">pub struct </span>StaticUserProvider {
<a href=#28 id=28 data-nosnippet>28</a> users: UserInfoMap,
<a href=#29 id=29 data-nosnippet>29</a>}
<a href=#30 id=30 data-nosnippet>30</a>
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">impl </span>StaticUserProvider {
<a href=#32 id=32 data-nosnippet>32</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new(value: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>&gt; {
<a href=#33 id=33 data-nosnippet>33</a> <span class="kw">let </span>(mode, content) = value.split_once(<span class="string">':'</span>).context(InvalidConfigSnafu {
<a href=#34 id=34 data-nosnippet>34</a> value: value.to_string(),
<a href=#35 id=35 data-nosnippet>35</a> msg: <span class="string">"StaticUserProviderOption must be in format `&lt;option&gt;:&lt;value&gt;`"</span>,
<a href=#36 id=36 data-nosnippet>36</a> })<span class="question-mark">?</span>;
<a href=#37 id=37 data-nosnippet>37</a> <span class="kw">match </span>mode {
<a href=#38 id=38 data-nosnippet>38</a> <span class="string">"file" </span>=&gt; {
<a href=#39 id=39 data-nosnippet>39</a> <span class="kw">let </span>users = load_credential_from_file(content)<span class="question-mark">?</span>;
<a href=#40 id=40 data-nosnippet>40</a> <span class="prelude-val">Ok</span>(StaticUserProvider { users })
<a href=#41 id=41 data-nosnippet>41</a> }
<a href=#42 id=42 data-nosnippet>42</a> <span class="string">"cmd" </span>=&gt; content
<a href=#43 id=43 data-nosnippet>43</a> .split(<span class="string">','</span>)
<a href=#44 id=44 data-nosnippet>44</a> .map(|kv| {
<a href=#45 id=45 data-nosnippet>45</a> parse_credential_line(kv).context(InvalidConfigSnafu {
<a href=#46 id=46 data-nosnippet>46</a> value: kv.to_string(),
<a href=#47 id=47 data-nosnippet>47</a> msg: <span class="string">"StaticUserProviderOption cmd values must be in format `user=pwd[,user=pwd]`"</span>,
<a href=#48 id=48 data-nosnippet>48</a> })
<a href=#49 id=49 data-nosnippet>49</a> })
<a href=#50 id=50 data-nosnippet>50</a> .collect::&lt;<span class="prelude-ty">Result</span>&lt;UserInfoMap&gt;&gt;()
<a href=#51 id=51 data-nosnippet>51</a> .map(|users| {
<a href=#52 id=52 data-nosnippet>52</a> warn_if_pg_scram_disabled(<span class="kw-2">&amp;</span>users);
<a href=#53 id=53 data-nosnippet>53</a> StaticUserProvider { users }
<a href=#54 id=54 data-nosnippet>54</a> }),
<a href=#55 id=55 data-nosnippet>55</a> <span class="kw">_ </span>=&gt; InvalidConfigSnafu {
<a href=#56 id=56 data-nosnippet>56</a> value: mode.to_string(),
<a href=#57 id=57 data-nosnippet>57</a> msg: <span class="string">"StaticUserProviderOption must be in format `file:&lt;path&gt;` or `cmd:&lt;values&gt;`"</span>,
<a href=#58 id=58 data-nosnippet>58</a> }
<a href=#59 id=59 data-nosnippet>59</a> .fail(),
<a href=#60 id=60 data-nosnippet>60</a> }
<a href=#61 id=61 data-nosnippet>61</a> }
<a href=#62 id=62 data-nosnippet>62</a>}
<a href=#63 id=63 data-nosnippet>63</a>
<a href=#64 id=64 data-nosnippet>64</a><span class="attr">#[async_trait]
<a href=#65 id=65 data-nosnippet>65</a></span><span class="kw">impl </span>UserProvider <span class="kw">for </span>StaticUserProvider {
<a href=#66 id=66 data-nosnippet>66</a> <span class="kw">fn </span>name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#67 id=67 data-nosnippet>67</a> STATIC_USER_PROVIDER
<a href=#68 id=68 data-nosnippet>68</a> }
<a href=#69 id=69 data-nosnippet>69</a>
<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">async fn </span>authenticate(<span class="kw-2">&amp;</span><span class="self">self</span>, id: Identity&lt;<span class="lifetime">'_</span>&gt;, pwd: Password&lt;<span class="lifetime">'_</span>&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;UserInfoRef&gt; {
<a href=#71 id=71 data-nosnippet>71</a> authenticate_with_credential(<span class="kw-2">&amp;</span><span class="self">self</span>.users, id, pwd)
<a href=#72 id=72 data-nosnippet>72</a> }
<a href=#73 id=73 data-nosnippet>73</a>
<a href=#74 id=74 data-nosnippet>74</a> <span class="kw">async fn </span>postgres_auth_info(<span class="kw-2">&amp;</span><span class="self">self</span>, id: Identity&lt;<span class="lifetime">'_</span>&gt;, _catalog: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;PgAuthInfo&gt; {
<a href=#75 id=75 data-nosnippet>75</a> postgres_auth_info_with_credential(<span class="kw-2">&amp;</span><span class="self">self</span>.users, id)
<a href=#76 id=76 data-nosnippet>76</a> }
<a href=#77 id=77 data-nosnippet>77</a>
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">async fn </span>authorize(
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#80 id=80 data-nosnippet>80</a> _catalog: <span class="kw-2">&amp;</span>str,
<a href=#81 id=81 data-nosnippet>81</a> _schema: <span class="kw-2">&amp;</span>str,
<a href=#82 id=82 data-nosnippet>82</a> _user_info: <span class="kw-2">&amp;</span>UserInfoRef,
<a href=#83 id=83 data-nosnippet>83</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#84 id=84 data-nosnippet>84</a> <span class="comment">// default allow all
<a href=#85 id=85 data-nosnippet>85</a> </span><span class="prelude-val">Ok</span>(())
<a href=#86 id=86 data-nosnippet>86</a> }
<a href=#87 id=87 data-nosnippet>87</a>}
<a href=#88 id=88 data-nosnippet>88</a>
<a href=#89 id=89 data-nosnippet>89</a><span class="attr">#[cfg(test)]
<a href=#90 id=90 data-nosnippet>90</a></span><span class="kw">pub mod </span>test {
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">use </span>std::fs::File;
<a href=#92 id=92 data-nosnippet>92</a> <span class="kw">use </span>std::io::{LineWriter, Write};
<a href=#93 id=93 data-nosnippet>93</a>
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">use </span>common_test_util::temp_dir::create_temp_dir;
<a href=#95 id=95 data-nosnippet>95</a> <span class="kw">use </span>pbkdf2::pbkdf2_hmac;
<a href=#96 id=96 data-nosnippet>96</a> <span class="kw">use </span>sha2::Sha256;
<a href=#97 id=97 data-nosnippet>97</a>
<a href=#98 id=98 data-nosnippet>98</a> <span class="kw">use </span><span class="kw">crate</span>::UserProvider;
<a href=#99 id=99 data-nosnippet>99</a> <span class="kw">use </span><span class="kw">crate</span>::user_info::DefaultUserInfo;
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">use </span><span class="kw">crate</span>::user_provider::static_user_provider::StaticUserProvider;
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">use </span><span class="kw">crate</span>::user_provider::{Identity, Password};
<a href=#102 id=102 data-nosnippet>102</a>
<a href=#103 id=103 data-nosnippet>103</a> <span class="kw">async fn </span>test_authenticate(provider: <span class="kw-2">&amp;</span><span class="kw">dyn </span>UserProvider, username: <span class="kw-2">&amp;</span>str, password: <span class="kw-2">&amp;</span>str) {
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">let </span>re = provider
<a href=#105 id=105 data-nosnippet>105</a> .authenticate(
<a href=#106 id=106 data-nosnippet>106</a> Identity::UserId(username, <span class="prelude-val">None</span>),
<a href=#107 id=107 data-nosnippet>107</a> Password::PlainText(password.to_string().into()),
<a href=#108 id=108 data-nosnippet>108</a> )
<a href=#109 id=109 data-nosnippet>109</a> .<span class="kw">await</span>;
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">let _ </span>= re.unwrap();
<a href=#111 id=111 data-nosnippet>111</a> }
<a href=#112 id=112 data-nosnippet>112</a>
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">async fn </span>test_authenticate_fails(provider: <span class="kw-2">&amp;</span><span class="kw">dyn </span>UserProvider, username: <span class="kw-2">&amp;</span>str, password: <span class="kw-2">&amp;</span>str) {
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">let </span>re = provider
<a href=#115 id=115 data-nosnippet>115</a> .authenticate(
<a href=#116 id=116 data-nosnippet>116</a> Identity::UserId(username, <span class="prelude-val">None</span>),
<a href=#117 id=117 data-nosnippet>117</a> Password::PlainText(password.to_string().into()),
<a href=#118 id=118 data-nosnippet>118</a> )
<a href=#119 id=119 data-nosnippet>119</a> .<span class="kw">await</span>;
<a href=#120 id=120 data-nosnippet>120</a> <span class="macro">assert!</span>(re.is_err());
<a href=#121 id=121 data-nosnippet>121</a> }
<a href=#122 id=122 data-nosnippet>122</a>
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">fn </span>pbkdf2_sha256_verifier(password: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">let </span>iterations = <span class="number">4096</span>;
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw">let </span>salt = <span class="string">b"salt"</span>;
<a href=#126 id=126 data-nosnippet>126</a> <span class="kw">let </span><span class="kw-2">mut </span>hash = [<span class="number">0u8</span>; <span class="number">32</span>];
<a href=#127 id=127 data-nosnippet>127</a> pbkdf2_hmac::&lt;Sha256&gt;(password.as_bytes(), salt, iterations, <span class="kw-2">&amp;mut </span>hash);
<a href=#128 id=128 data-nosnippet>128</a> <span class="macro">format!</span>(
<a href=#129 id=129 data-nosnippet>129</a> <span class="string">"pbkdf2_sha256:{iterations}:{}:{}"</span>,
<a href=#130 id=130 data-nosnippet>130</a> hex::encode(salt),
<a href=#131 id=131 data-nosnippet>131</a> hex::encode(hash)
<a href=#132 id=132 data-nosnippet>132</a> )
<a href=#133 id=133 data-nosnippet>133</a> }
<a href=#134 id=134 data-nosnippet>134</a>
<a href=#135 id=135 data-nosnippet>135</a> <span class="attr">#[tokio::test]
<a href=#136 id=136 data-nosnippet>136</a> </span><span class="kw">async fn </span>test_authorize() {
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">let </span>user_info = DefaultUserInfo::with_name(<span class="string">"root"</span>);
<a href=#138 id=138 data-nosnippet>138</a> <span class="kw">let </span>provider = StaticUserProvider::new(<span class="string">"cmd:root=123456,admin=654321"</span>).unwrap();
<a href=#139 id=139 data-nosnippet>139</a> provider
<a href=#140 id=140 data-nosnippet>140</a> .authorize(<span class="string">"catalog"</span>, <span class="string">"schema"</span>, <span class="kw-2">&amp;</span>user_info)
<a href=#141 id=141 data-nosnippet>141</a> .<span class="kw">await
<a href=#142 id=142 data-nosnippet>142</a> </span>.unwrap();
<a href=#143 id=143 data-nosnippet>143</a> }
<a href=#144 id=144 data-nosnippet>144</a>
<a href=#145 id=145 data-nosnippet>145</a> <span class="attr">#[tokio::test]
<a href=#146 id=146 data-nosnippet>146</a> </span><span class="kw">async fn </span>test_inline_provider() {
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">let </span>provider = StaticUserProvider::new(<span class="string">"cmd:root=123456,admin=654321"</span>).unwrap();
<a href=#148 id=148 data-nosnippet>148</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"123456"</span>).<span class="kw">await</span>;
<a href=#149 id=149 data-nosnippet>149</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"admin"</span>, <span class="string">"654321"</span>).<span class="kw">await</span>;
<a href=#150 id=150 data-nosnippet>150</a>
<a href=#151 id=151 data-nosnippet>151</a> <span class="macro">assert!</span>(StaticUserProvider::new(<span class="string">"cmd:user:readonyl=password"</span>).is_err());
<a href=#152 id=152 data-nosnippet>152</a> }
<a href=#153 id=153 data-nosnippet>153</a>
<a href=#154 id=154 data-nosnippet>154</a> <span class="attr">#[tokio::test]
<a href=#155 id=155 data-nosnippet>155</a> </span><span class="kw">async fn </span>test_inline_provider_with_pbkdf2_sha256_verifier() {
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">let </span>provider =
<a href=#157 id=157 data-nosnippet>157</a> StaticUserProvider::new(<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"cmd:root={}"</span>, pbkdf2_sha256_verifier(<span class="string">"123456"</span>)))
<a href=#158 id=158 data-nosnippet>158</a> .unwrap();
<a href=#159 id=159 data-nosnippet>159</a>
<a href=#160 id=160 data-nosnippet>160</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"123456"</span>).<span class="kw">await</span>;
<a href=#161 id=161 data-nosnippet>161</a> test_authenticate_fails(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"654321"</span>).<span class="kw">await</span>;
<a href=#162 id=162 data-nosnippet>162</a> }
<a href=#163 id=163 data-nosnippet>163</a>
<a href=#164 id=164 data-nosnippet>164</a> <span class="attr">#[tokio::test]
<a href=#165 id=165 data-nosnippet>165</a> </span><span class="kw">async fn </span>test_file_provider() {
<a href=#166 id=166 data-nosnippet>166</a> <span class="kw">let </span>dir = create_temp_dir(<span class="string">"test_file_provider"</span>);
<a href=#167 id=167 data-nosnippet>167</a> <span class="kw">let </span>file_path = <span class="macro">format!</span>(<span class="string">"{}/test_file_provider"</span>, dir.path().to_str().unwrap());
<a href=#168 id=168 data-nosnippet>168</a> {
<a href=#169 id=169 data-nosnippet>169</a> <span class="comment">// write a tmp file
<a href=#170 id=170 data-nosnippet>170</a> </span><span class="kw">let </span>file = File::create(<span class="kw-2">&amp;</span>file_path);
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">let </span>file = file.unwrap();
<a href=#172 id=172 data-nosnippet>172</a> <span class="kw">let </span><span class="kw-2">mut </span>lw = LineWriter::new(file);
<a href=#173 id=173 data-nosnippet>173</a> <span class="macro">assert!</span>(
<a href=#174 id=174 data-nosnippet>174</a> lw.write_all(
<a href=#175 id=175 data-nosnippet>175</a> <span class="string">b"root=123456
<a href=#176 id=176 data-nosnippet>176</a>invalid:readonyl=password
<a href=#177 id=177 data-nosnippet>177</a>admin=654321"</span>,
<a href=#178 id=178 data-nosnippet>178</a> )
<a href=#179 id=179 data-nosnippet>179</a> .is_ok()
<a href=#180 id=180 data-nosnippet>180</a> );
<a href=#181 id=181 data-nosnippet>181</a> lw.flush().unwrap();
<a href=#182 id=182 data-nosnippet>182</a> }
<a href=#183 id=183 data-nosnippet>183</a>
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">let </span>param = <span class="macro">format!</span>(<span class="string">"file:{file_path}"</span>);
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">let </span>provider = StaticUserProvider::new(param.as_str()).unwrap();
<a href=#186 id=186 data-nosnippet>186</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"123456"</span>).<span class="kw">await</span>;
<a href=#187 id=187 data-nosnippet>187</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"admin"</span>, <span class="string">"654321"</span>).<span class="kw">await</span>;
<a href=#188 id=188 data-nosnippet>188</a> test_authenticate_fails(<span class="kw-2">&amp;</span>provider, <span class="string">"invalid"</span>, <span class="string">"password"</span>).<span class="kw">await</span>;
<a href=#189 id=189 data-nosnippet>189</a> }
<a href=#190 id=190 data-nosnippet>190</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,245 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/auth/src/user_provider/watch_file_user_provider.rs`."><title>watch_file_user_provider.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="auth" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">auth/user_provider/</div>watch_file_user_provider.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Mutex};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>async_trait::async_trait;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_config::file_watcher::{FileWatcherBuilder, FileWatcherConfig};
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_telemetry::{info, warn};
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>snafu::ResultExt;
<a href=#21 id=21 data-nosnippet>21</a>
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span><span class="kw">crate</span>::error::{FileWatchSnafu, <span class="prelude-ty">Result</span>};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span><span class="kw">crate</span>::user_provider::{
<a href=#24 id=24 data-nosnippet>24</a> PgAuthInfo, UserInfoMap, authenticate_with_credential, load_credential_from_file,
<a href=#25 id=25 data-nosnippet>25</a> postgres_auth_info_with_credential,
<a href=#26 id=26 data-nosnippet>26</a>};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>crate::{Identity, Password, UserInfoRef, UserProvider};
<a href=#28 id=28 data-nosnippet>28</a>
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>WATCH_FILE_USER_PROVIDER: <span class="kw-2">&amp;</span>str = <span class="string">"watch_file_user_provider"</span>;
<a href=#30 id=30 data-nosnippet>30</a>
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">type </span>WatchedCredentialRef = Arc&lt;Mutex&lt;UserInfoMap&gt;&gt;;
<a href=#32 id=32 data-nosnippet>32</a>
<a href=#33 id=33 data-nosnippet>33</a><span class="doccomment">/// A user provider that reads user credential from a file and watches the file for changes.
<a href=#34 id=34 data-nosnippet>34</a>///
<a href=#35 id=35 data-nosnippet>35</a>/// Both empty file and non-existent file are invalid and will cause initialization to fail.
<a href=#36 id=36 data-nosnippet>36</a></span><span class="attr">#[derive(Debug)]
<a href=#37 id=37 data-nosnippet>37</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>WatchFileUserProvider {
<a href=#38 id=38 data-nosnippet>38</a> users: WatchedCredentialRef,
<a href=#39 id=39 data-nosnippet>39</a>}
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">impl </span>WatchFileUserProvider {
<a href=#42 id=42 data-nosnippet>42</a> <span class="kw">pub fn </span>new(filepath: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>&gt; {
<a href=#43 id=43 data-nosnippet>43</a> <span class="kw">let </span>credential = load_credential_from_file(filepath)<span class="question-mark">?</span>;
<a href=#44 id=44 data-nosnippet>44</a> <span class="kw">let </span>users = Arc::new(Mutex::new(credential));
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a> <span class="kw">let </span>users_clone = users.clone();
<a href=#47 id=47 data-nosnippet>47</a> <span class="kw">let </span>filepath_owned = filepath.to_string();
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a> FileWatcherBuilder::new()
<a href=#50 id=50 data-nosnippet>50</a> .watch_path(filepath)
<a href=#51 id=51 data-nosnippet>51</a> .context(FileWatchSnafu)<span class="question-mark">?
<a href=#52 id=52 data-nosnippet>52</a> </span>.config(FileWatcherConfig::new())
<a href=#53 id=53 data-nosnippet>53</a> .spawn(<span class="kw">move </span>|| <span class="kw">match </span>load_credential_from_file(<span class="kw-2">&amp;</span>filepath_owned) {
<a href=#54 id=54 data-nosnippet>54</a> <span class="prelude-val">Ok</span>(credential) =&gt; {
<a href=#55 id=55 data-nosnippet>55</a> <span class="kw">let </span><span class="kw-2">mut </span>users = users_clone.lock().expect(<span class="string">"users credential must be valid"</span>);
<a href=#56 id=56 data-nosnippet>56</a> <span class="attr">#[cfg(not(test))]
<a href=#57 id=57 data-nosnippet>57</a> </span><span class="macro">info!</span>(<span class="string">"User provider file {} reloaded"</span>, <span class="kw-2">&amp;</span>filepath_owned);
<a href=#58 id=58 data-nosnippet>58</a> <span class="attr">#[cfg(test)]
<a href=#59 id=59 data-nosnippet>59</a> </span><span class="macro">info!</span>(
<a href=#60 id=60 data-nosnippet>60</a> <span class="string">"User provider file {} reloaded: {:?}"</span>,
<a href=#61 id=61 data-nosnippet>61</a> <span class="kw-2">&amp;</span>filepath_owned, credential
<a href=#62 id=62 data-nosnippet>62</a> );
<a href=#63 id=63 data-nosnippet>63</a> <span class="kw-2">*</span>users = credential;
<a href=#64 id=64 data-nosnippet>64</a> }
<a href=#65 id=65 data-nosnippet>65</a> <span class="prelude-val">Err</span>(err) =&gt; {
<a href=#66 id=66 data-nosnippet>66</a> <span class="macro">warn!</span>(
<a href=#67 id=67 data-nosnippet>67</a> <span class="question-mark">?</span>err,
<a href=#68 id=68 data-nosnippet>68</a> <span class="string">"Fail to load credential from file {}; keep the old one"</span>, <span class="kw-2">&amp;</span>filepath_owned
<a href=#69 id=69 data-nosnippet>69</a> )
<a href=#70 id=70 data-nosnippet>70</a> }
<a href=#71 id=71 data-nosnippet>71</a> })
<a href=#72 id=72 data-nosnippet>72</a> .context(FileWatchSnafu)<span class="question-mark">?</span>;
<a href=#73 id=73 data-nosnippet>73</a>
<a href=#74 id=74 data-nosnippet>74</a> <span class="prelude-val">Ok</span>(WatchFileUserProvider { users })
<a href=#75 id=75 data-nosnippet>75</a> }
<a href=#76 id=76 data-nosnippet>76</a>}
<a href=#77 id=77 data-nosnippet>77</a>
<a href=#78 id=78 data-nosnippet>78</a><span class="attr">#[async_trait]
<a href=#79 id=79 data-nosnippet>79</a></span><span class="kw">impl </span>UserProvider <span class="kw">for </span>WatchFileUserProvider {
<a href=#80 id=80 data-nosnippet>80</a> <span class="kw">fn </span>name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#81 id=81 data-nosnippet>81</a> WATCH_FILE_USER_PROVIDER
<a href=#82 id=82 data-nosnippet>82</a> }
<a href=#83 id=83 data-nosnippet>83</a>
<a href=#84 id=84 data-nosnippet>84</a> <span class="kw">async fn </span>authenticate(<span class="kw-2">&amp;</span><span class="self">self</span>, id: Identity&lt;<span class="lifetime">'_</span>&gt;, password: Password&lt;<span class="lifetime">'_</span>&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;UserInfoRef&gt; {
<a href=#85 id=85 data-nosnippet>85</a> <span class="kw">let </span>users = <span class="self">self</span>.users.lock().expect(<span class="string">"users credential must be valid"</span>);
<a href=#86 id=86 data-nosnippet>86</a> authenticate_with_credential(<span class="kw-2">&amp;</span>users, id, password)
<a href=#87 id=87 data-nosnippet>87</a> }
<a href=#88 id=88 data-nosnippet>88</a>
<a href=#89 id=89 data-nosnippet>89</a> <span class="kw">async fn </span>postgres_auth_info(<span class="kw-2">&amp;</span><span class="self">self</span>, id: Identity&lt;<span class="lifetime">'_</span>&gt;, _catalog: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;PgAuthInfo&gt; {
<a href=#90 id=90 data-nosnippet>90</a> <span class="kw">let </span>users = <span class="self">self</span>.users.lock().expect(<span class="string">"users credential must be valid"</span>);
<a href=#91 id=91 data-nosnippet>91</a> postgres_auth_info_with_credential(<span class="kw-2">&amp;</span>users, id)
<a href=#92 id=92 data-nosnippet>92</a> }
<a href=#93 id=93 data-nosnippet>93</a>
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">async fn </span>authorize(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: <span class="kw-2">&amp;</span>str, <span class="kw">_</span>: <span class="kw-2">&amp;</span>str, <span class="kw">_</span>: <span class="kw-2">&amp;</span>UserInfoRef) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#95 id=95 data-nosnippet>95</a> <span class="comment">// default allow all
<a href=#96 id=96 data-nosnippet>96</a> </span><span class="prelude-val">Ok</span>(())
<a href=#97 id=97 data-nosnippet>97</a> }
<a href=#98 id=98 data-nosnippet>98</a>}
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a><span class="attr">#[cfg(test)]
<a href=#101 id=101 data-nosnippet>101</a></span><span class="kw">pub mod </span>test {
<a href=#102 id=102 data-nosnippet>102</a> <span class="kw">use </span>std::time::{Duration, Instant};
<a href=#103 id=103 data-nosnippet>103</a>
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">use </span>common_test_util::temp_dir::create_temp_dir;
<a href=#105 id=105 data-nosnippet>105</a> <span class="kw">use </span>tokio::time::sleep;
<a href=#106 id=106 data-nosnippet>106</a>
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">use </span><span class="kw">crate</span>::UserProvider;
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">use </span><span class="kw">crate</span>::user_provider::watch_file_user_provider::WatchFileUserProvider;
<a href=#109 id=109 data-nosnippet>109</a> <span class="kw">use </span><span class="kw">crate</span>::user_provider::{Identity, Password};
<a href=#110 id=110 data-nosnippet>110</a>
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">async fn </span>test_authenticate(
<a href=#112 id=112 data-nosnippet>112</a> provider: <span class="kw-2">&amp;</span><span class="kw">dyn </span>UserProvider,
<a href=#113 id=113 data-nosnippet>113</a> username: <span class="kw-2">&amp;</span>str,
<a href=#114 id=114 data-nosnippet>114</a> password: <span class="kw-2">&amp;</span>str,
<a href=#115 id=115 data-nosnippet>115</a> ok: bool,
<a href=#116 id=116 data-nosnippet>116</a> timeout: <span class="prelude-ty">Option</span>&lt;Duration&gt;,
<a href=#117 id=117 data-nosnippet>117</a> ) {
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(timeout) = timeout {
<a href=#119 id=119 data-nosnippet>119</a> <span class="kw">let </span>deadline = Instant::now().checked_add(timeout).unwrap();
<a href=#120 id=120 data-nosnippet>120</a> <span class="kw">loop </span>{
<a href=#121 id=121 data-nosnippet>121</a> <span class="kw">let </span>re = provider
<a href=#122 id=122 data-nosnippet>122</a> .authenticate(
<a href=#123 id=123 data-nosnippet>123</a> Identity::UserId(username, <span class="prelude-val">None</span>),
<a href=#124 id=124 data-nosnippet>124</a> Password::PlainText(password.to_string().into()),
<a href=#125 id=125 data-nosnippet>125</a> )
<a href=#126 id=126 data-nosnippet>126</a> .<span class="kw">await</span>;
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw">if </span>re.is_ok() == ok {
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw">break</span>;
<a href=#129 id=129 data-nosnippet>129</a> } <span class="kw">else if </span>Instant::now() &lt; deadline {
<a href=#130 id=130 data-nosnippet>130</a> sleep(Duration::from_millis(<span class="number">100</span>)).<span class="kw">await</span>;
<a href=#131 id=131 data-nosnippet>131</a> } <span class="kw">else </span>{
<a href=#132 id=132 data-nosnippet>132</a> <span class="macro">panic!</span>(<span class="string">"timeout (username: {username}, password: {password}, expected: {ok})"</span>);
<a href=#133 id=133 data-nosnippet>133</a> }
<a href=#134 id=134 data-nosnippet>134</a> }
<a href=#135 id=135 data-nosnippet>135</a> } <span class="kw">else </span>{
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw">let </span>re = provider
<a href=#137 id=137 data-nosnippet>137</a> .authenticate(
<a href=#138 id=138 data-nosnippet>138</a> Identity::UserId(username, <span class="prelude-val">None</span>),
<a href=#139 id=139 data-nosnippet>139</a> Password::PlainText(password.to_string().into()),
<a href=#140 id=140 data-nosnippet>140</a> )
<a href=#141 id=141 data-nosnippet>141</a> .<span class="kw">await</span>;
<a href=#142 id=142 data-nosnippet>142</a> <span class="macro">assert_eq!</span>(
<a href=#143 id=143 data-nosnippet>143</a> re.is_ok(),
<a href=#144 id=144 data-nosnippet>144</a> ok,
<a href=#145 id=145 data-nosnippet>145</a> <span class="string">"username: {}, password: {}"</span>,
<a href=#146 id=146 data-nosnippet>146</a> username,
<a href=#147 id=147 data-nosnippet>147</a> password
<a href=#148 id=148 data-nosnippet>148</a> );
<a href=#149 id=149 data-nosnippet>149</a> }
<a href=#150 id=150 data-nosnippet>150</a> }
<a href=#151 id=151 data-nosnippet>151</a>
<a href=#152 id=152 data-nosnippet>152</a> <span class="attr">#[tokio::test]
<a href=#153 id=153 data-nosnippet>153</a> </span><span class="kw">async fn </span>test_file_provider_initialization_with_missing_file() {
<a href=#154 id=154 data-nosnippet>154</a> common_telemetry::init_default_ut_logging();
<a href=#155 id=155 data-nosnippet>155</a>
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">let </span>dir = create_temp_dir(<span class="string">"test_missing_file"</span>);
<a href=#157 id=157 data-nosnippet>157</a> <span class="kw">let </span>file_path = <span class="macro">format!</span>(<span class="string">"{}/non_existent_file"</span>, dir.path().to_str().unwrap());
<a href=#158 id=158 data-nosnippet>158</a>
<a href=#159 id=159 data-nosnippet>159</a> <span class="comment">// Try to create provider with non-existent file should fail
<a href=#160 id=160 data-nosnippet>160</a> </span><span class="kw">let </span>result = WatchFileUserProvider::new(file_path.as_str());
<a href=#161 id=161 data-nosnippet>161</a> <span class="macro">assert!</span>(result.is_err());
<a href=#162 id=162 data-nosnippet>162</a>
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">let </span>error = result.unwrap_err();
<a href=#164 id=164 data-nosnippet>164</a> <span class="macro">assert!</span>(error.to_string().contains(<span class="string">"UserProvider file must exist"</span>));
<a href=#165 id=165 data-nosnippet>165</a> }
<a href=#166 id=166 data-nosnippet>166</a>
<a href=#167 id=167 data-nosnippet>167</a> <span class="attr">#[tokio::test]
<a href=#168 id=168 data-nosnippet>168</a> </span><span class="kw">async fn </span>test_file_provider() {
<a href=#169 id=169 data-nosnippet>169</a> common_telemetry::init_default_ut_logging();
<a href=#170 id=170 data-nosnippet>170</a>
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">let </span>dir = create_temp_dir(<span class="string">"test_file_provider"</span>);
<a href=#172 id=172 data-nosnippet>172</a> <span class="kw">let </span>file_path = <span class="macro">format!</span>(<span class="string">"{}/test_file_provider"</span>, dir.path().to_str().unwrap());
<a href=#173 id=173 data-nosnippet>173</a>
<a href=#174 id=174 data-nosnippet>174</a> <span class="comment">// write a tmp file
<a href=#175 id=175 data-nosnippet>175</a> </span><span class="macro">assert!</span>(std::fs::write(<span class="kw-2">&amp;</span>file_path, <span class="string">"root=123456\nadmin=654321\n"</span>).is_ok());
<a href=#176 id=176 data-nosnippet>176</a> <span class="kw">let </span>provider = WatchFileUserProvider::new(file_path.as_str()).unwrap();
<a href=#177 id=177 data-nosnippet>177</a> <span class="kw">let </span>timeout = Duration::from_secs(<span class="number">60</span>);
<a href=#178 id=178 data-nosnippet>178</a>
<a href=#179 id=179 data-nosnippet>179</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"123456"</span>, <span class="bool-val">true</span>, <span class="prelude-val">None</span>).<span class="kw">await</span>;
<a href=#180 id=180 data-nosnippet>180</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"admin"</span>, <span class="string">"654321"</span>, <span class="bool-val">true</span>, <span class="prelude-val">None</span>).<span class="kw">await</span>;
<a href=#181 id=181 data-nosnippet>181</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"654321"</span>, <span class="bool-val">false</span>, <span class="prelude-val">None</span>).<span class="kw">await</span>;
<a href=#182 id=182 data-nosnippet>182</a>
<a href=#183 id=183 data-nosnippet>183</a> <span class="comment">// update the tmp file
<a href=#184 id=184 data-nosnippet>184</a> </span><span class="macro">assert!</span>(std::fs::write(<span class="kw-2">&amp;</span>file_path, <span class="string">"root=654321\n"</span>).is_ok());
<a href=#185 id=185 data-nosnippet>185</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"123456"</span>, <span class="bool-val">false</span>, <span class="prelude-val">Some</span>(timeout)).<span class="kw">await</span>;
<a href=#186 id=186 data-nosnippet>186</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"654321"</span>, <span class="bool-val">true</span>, <span class="prelude-val">Some</span>(timeout)).<span class="kw">await</span>;
<a href=#187 id=187 data-nosnippet>187</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"admin"</span>, <span class="string">"654321"</span>, <span class="bool-val">false</span>, <span class="prelude-val">Some</span>(timeout)).<span class="kw">await</span>;
<a href=#188 id=188 data-nosnippet>188</a>
<a href=#189 id=189 data-nosnippet>189</a> <span class="comment">// remove the tmp file
<a href=#190 id=190 data-nosnippet>190</a> </span><span class="macro">assert!</span>(std::fs::remove_file(<span class="kw-2">&amp;</span>file_path).is_ok());
<a href=#191 id=191 data-nosnippet>191</a> <span class="comment">// When file is deleted during runtime, keep the last known good credentials
<a href=#192 id=192 data-nosnippet>192</a> </span>test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"654321"</span>, <span class="bool-val">true</span>, <span class="prelude-val">Some</span>(timeout)).<span class="kw">await</span>;
<a href=#193 id=193 data-nosnippet>193</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"123456"</span>, <span class="bool-val">false</span>, <span class="prelude-val">Some</span>(timeout)).<span class="kw">await</span>;
<a href=#194 id=194 data-nosnippet>194</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"admin"</span>, <span class="string">"654321"</span>, <span class="bool-val">false</span>, <span class="prelude-val">Some</span>(timeout)).<span class="kw">await</span>;
<a href=#195 id=195 data-nosnippet>195</a>
<a href=#196 id=196 data-nosnippet>196</a> <span class="comment">// recreate the tmp file
<a href=#197 id=197 data-nosnippet>197</a> </span><span class="macro">assert!</span>(std::fs::write(<span class="kw-2">&amp;</span>file_path, <span class="string">"root=123456\n"</span>).is_ok());
<a href=#198 id=198 data-nosnippet>198</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"123456"</span>, <span class="bool-val">true</span>, <span class="prelude-val">Some</span>(timeout)).<span class="kw">await</span>;
<a href=#199 id=199 data-nosnippet>199</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"654321"</span>, <span class="bool-val">false</span>, <span class="prelude-val">Some</span>(timeout)).<span class="kw">await</span>;
<a href=#200 id=200 data-nosnippet>200</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"admin"</span>, <span class="string">"654321"</span>, <span class="bool-val">false</span>, <span class="prelude-val">Some</span>(timeout)).<span class="kw">await</span>;
<a href=#201 id=201 data-nosnippet>201</a> }
<a href=#202 id=202 data-nosnippet>202</a>
<a href=#203 id=203 data-nosnippet>203</a> <span class="doccomment">/// Regression test for #9310: the users file is reached through a chain
<a href=#204 id=204 data-nosnippet>204</a> /// of symlinks and a directory symlink in the chain gets swapped
<a href=#205 id=205 data-nosnippet>205</a> /// atomically (like `ln -sfn`, as done by sops-nix).
<a href=#206 id=206 data-nosnippet>206</a> </span><span class="attr">#[cfg(unix)]
<a href=#207 id=207 data-nosnippet>207</a> #[tokio::test]
<a href=#208 id=208 data-nosnippet>208</a> </span><span class="kw">async fn </span>test_file_provider_symlink_chain() {
<a href=#209 id=209 data-nosnippet>209</a> <span class="kw">use </span>std::os::unix::fs::symlink;
<a href=#210 id=210 data-nosnippet>210</a>
<a href=#211 id=211 data-nosnippet>211</a> common_telemetry::init_default_ut_logging();
<a href=#212 id=212 data-nosnippet>212</a>
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">let </span>dir = create_temp_dir(<span class="string">"test_file_provider_symlink_chain"</span>);
<a href=#214 id=214 data-nosnippet>214</a> <span class="kw">let </span>base = dir.path();
<a href=#215 id=215 data-nosnippet>215</a> <span class="kw">let </span>timeout = Duration::from_secs(<span class="number">10</span>);
<a href=#216 id=216 data-nosnippet>216</a>
<a href=#217 id=217 data-nosnippet>217</a> <span class="comment">// secrets.1/users &lt;- secrets (dir symlink) &lt;- conf/users (file symlink)
<a href=#218 id=218 data-nosnippet>218</a> </span>std::fs::create_dir(base.join(<span class="string">"secrets.1"</span>)).unwrap();
<a href=#219 id=219 data-nosnippet>219</a> std::fs::write(base.join(<span class="string">"secrets.1/users"</span>), <span class="string">"root=123456\n"</span>).unwrap();
<a href=#220 id=220 data-nosnippet>220</a> symlink(base.join(<span class="string">"secrets.1"</span>), base.join(<span class="string">"secrets"</span>)).unwrap();
<a href=#221 id=221 data-nosnippet>221</a> std::fs::create_dir(base.join(<span class="string">"conf"</span>)).unwrap();
<a href=#222 id=222 data-nosnippet>222</a> symlink(base.join(<span class="string">"secrets/users"</span>), base.join(<span class="string">"conf/users"</span>)).unwrap();
<a href=#223 id=223 data-nosnippet>223</a>
<a href=#224 id=224 data-nosnippet>224</a> <span class="kw">let </span>file_path = base.join(<span class="string">"conf/users"</span>);
<a href=#225 id=225 data-nosnippet>225</a> <span class="kw">let </span>provider = WatchFileUserProvider::new(file_path.to_str().unwrap()).unwrap();
<a href=#226 id=226 data-nosnippet>226</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"123456"</span>, <span class="bool-val">true</span>, <span class="prelude-val">None</span>).<span class="kw">await</span>;
<a href=#227 id=227 data-nosnippet>227</a>
<a href=#228 id=228 data-nosnippet>228</a> <span class="comment">// Atomically swap the directory symlink to a new generation.
<a href=#229 id=229 data-nosnippet>229</a> </span>std::fs::create_dir(base.join(<span class="string">"secrets.2"</span>)).unwrap();
<a href=#230 id=230 data-nosnippet>230</a> std::fs::write(base.join(<span class="string">"secrets.2/users"</span>), <span class="string">"root=654321\n"</span>).unwrap();
<a href=#231 id=231 data-nosnippet>231</a> symlink(base.join(<span class="string">"secrets.2"</span>), base.join(<span class="string">"secrets.tmp"</span>)).unwrap();
<a href=#232 id=232 data-nosnippet>232</a> std::fs::rename(base.join(<span class="string">"secrets.tmp"</span>), base.join(<span class="string">"secrets"</span>)).unwrap();
<a href=#233 id=233 data-nosnippet>233</a> std::fs::remove_dir_all(base.join(<span class="string">"secrets.1"</span>)).unwrap();
<a href=#234 id=234 data-nosnippet>234</a>
<a href=#235 id=235 data-nosnippet>235</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"654321"</span>, <span class="bool-val">true</span>, <span class="prelude-val">Some</span>(timeout)).<span class="kw">await</span>;
<a href=#236 id=236 data-nosnippet>236</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"123456"</span>, <span class="bool-val">false</span>, <span class="prelude-val">None</span>).<span class="kw">await</span>;
<a href=#237 id=237 data-nosnippet>237</a>
<a href=#238 id=238 data-nosnippet>238</a> <span class="comment">// In-place edits of the new target are picked up too, which requires
<a href=#239 id=239 data-nosnippet>239</a> // the watch to follow the chain to the new directory.
<a href=#240 id=240 data-nosnippet>240</a> </span>std::fs::write(base.join(<span class="string">"secrets.2/users"</span>), <span class="string">"root=abcdef\n"</span>).unwrap();
<a href=#241 id=241 data-nosnippet>241</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"abcdef"</span>, <span class="bool-val">true</span>, <span class="prelude-val">Some</span>(timeout)).<span class="kw">await</span>;
<a href=#242 id=242 data-nosnippet>242</a> test_authenticate(<span class="kw-2">&amp;</span>provider, <span class="string">"root"</span>, <span class="string">"654321"</span>, <span class="bool-val">false</span>, <span class="prelude-val">None</span>).<span class="kw">await</span>;
<a href=#243 id=243 data-nosnippet>243</a> }
<a href=#244 id=244 data-nosnippet>244</a>}
</code></pre></div></section></main></body></html>
+45
View File
@@ -0,0 +1,45 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cache/src/error.rs`."><title>error.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="cache" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cache/</div>error.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>common_error::ext::ErrorExt;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>common_error::status_code::StatusCode;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_macro::stack_trace_debug;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>snafu::{Location, Snafu};
<a href=#19 id=19 data-nosnippet>19</a>
<a href=#20 id=20 data-nosnippet>20</a><span class="attr">#[derive(Snafu)]
<a href=#21 id=21 data-nosnippet>21</a>#[snafu(visibility(<span class="kw">pub</span>))]
<a href=#22 id=22 data-nosnippet>22</a>#[stack_trace_debug]
<a href=#23 id=23 data-nosnippet>23</a></span><span class="kw">pub enum </span>Error {
<a href=#24 id=24 data-nosnippet>24</a> <span class="attr">#[snafu(display(<span class="string">"Failed to get cache from cache registry: {}"</span>, name))]
<a href=#25 id=25 data-nosnippet>25</a> </span>CacheRequired {
<a href=#26 id=26 data-nosnippet>26</a> <span class="attr">#[snafu(implicit)]
<a href=#27 id=27 data-nosnippet>27</a> </span>location: Location,
<a href=#28 id=28 data-nosnippet>28</a> name: String,
<a href=#29 id=29 data-nosnippet>29</a> },
<a href=#30 id=30 data-nosnippet>30</a>}
<a href=#31 id=31 data-nosnippet>31</a>
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">pub type </span><span class="prelude-ty">Result</span>&lt;T&gt; = std::result::Result&lt;T, Error&gt;;
<a href=#33 id=33 data-nosnippet>33</a>
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">impl </span>ErrorExt <span class="kw">for </span>Error {
<a href=#35 id=35 data-nosnippet>35</a> <span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
<a href=#36 id=36 data-nosnippet>36</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#37 id=37 data-nosnippet>37</a> Error::CacheRequired { .. } =&gt; StatusCode::Unexpected,
<a href=#38 id=38 data-nosnippet>38</a> }
<a href=#39 id=39 data-nosnippet>39</a> }
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>std::any::Any {
<a href=#42 id=42 data-nosnippet>42</a> <span class="self">self
<a href=#43 id=43 data-nosnippet>43</a> </span>}
<a href=#44 id=44 data-nosnippet>44</a>}
</code></pre></div></section></main></body></html>
+190
View File
@@ -0,0 +1,190 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cache/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="cache" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cache/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">pub mod </span>error;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>std::hash::Hash;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>std::sync::Arc;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>std::time::Duration;
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>catalog::kvbackend::new_table_cache;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_meta::cache::{
<a href=#23 id=23 data-nosnippet>23</a> CacheRegistry, CacheRegistryBuilder, LayeredCacheRegistryBuilder, new_schema_cache,
<a href=#24 id=24 data-nosnippet>24</a> new_table_flownode_set_cache, new_table_info_cache, new_table_name_cache,
<a href=#25 id=25 data-nosnippet>25</a> new_table_route_cache, new_table_schema_cache, new_view_info_cache,
<a href=#26 id=26 data-nosnippet>26</a>};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>common_meta::kv_backend::KvBackendRef;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>moka::future::{Cache, CacheBuilder};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>partition::cache::new_partition_info_cache;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>snafu::OptionExt;
<a href=#31 id=31 data-nosnippet>31</a>
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span><span class="kw">crate</span>::error::Result;
<a href=#33 id=33 data-nosnippet>33</a>
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">const </span>DEFAULT_CACHE_MAX_CAPACITY: u64 = <span class="number">65536</span>;
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">const </span>DEFAULT_CACHE_TTL: Duration = Duration::from_secs(<span class="number">10 </span>* <span class="number">60</span>);
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">const </span>DEFAULT_CACHE_TTI: Duration = Duration::from_secs(<span class="number">5 </span>* <span class="number">60</span>);
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">fn </span>default_cache&lt;K: Send + Sync + Hash + Eq + <span class="lifetime">'static</span>, V: Send + Sync + Clone + <span class="lifetime">'static</span>&gt;()
<a href=#39 id=39 data-nosnippet>39</a>-&gt; Cache&lt;K, V&gt; {
<a href=#40 id=40 data-nosnippet>40</a> CacheBuilder::new(DEFAULT_CACHE_MAX_CAPACITY)
<a href=#41 id=41 data-nosnippet>41</a> .time_to_live(DEFAULT_CACHE_TTL)
<a href=#42 id=42 data-nosnippet>42</a> .time_to_idle(DEFAULT_CACHE_TTI)
<a href=#43 id=43 data-nosnippet>43</a> .build()
<a href=#44 id=44 data-nosnippet>44</a>}
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">pub const </span>TABLE_INFO_CACHE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_info_cache"</span>;
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">pub const </span>VIEW_INFO_CACHE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"view_info_cache"</span>;
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">pub const </span>TABLE_NAME_CACHE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_name_cache"</span>;
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">pub const </span>TABLE_CACHE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_cache"</span>;
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">pub const </span>SCHEMA_CACHE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"schema_cache"</span>;
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">pub const </span>TABLE_SCHEMA_NAME_CACHE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_schema_name_cache"</span>;
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">pub const </span>TABLE_FLOWNODE_SET_CACHE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_flownode_set_cache"</span>;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">pub const </span>TABLE_ROUTE_CACHE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_route_cache"</span>;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">pub const </span>PARTITION_INFO_CACHE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"partition_info_cache"</span>;
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a><span class="doccomment">/// Builds cache registry for datanode, including:
<a href=#57 id=57 data-nosnippet>57</a>/// - Schema cache.
<a href=#58 id=58 data-nosnippet>58</a>/// - Table id to schema name cache.
<a href=#59 id=59 data-nosnippet>59</a></span><span class="kw">pub fn </span>build_datanode_cache_registry(kv_backend: KvBackendRef) -&gt; CacheRegistry {
<a href=#60 id=60 data-nosnippet>60</a> <span class="comment">// Builds table id schema name cache that never expires.
<a href=#61 id=61 data-nosnippet>61</a> </span><span class="kw">let </span>cache = CacheBuilder::new(DEFAULT_CACHE_MAX_CAPACITY).build();
<a href=#62 id=62 data-nosnippet>62</a> <span class="kw">let </span>table_id_schema_cache = Arc::new(new_table_schema_cache(
<a href=#63 id=63 data-nosnippet>63</a> TABLE_SCHEMA_NAME_CACHE_NAME.to_string(),
<a href=#64 id=64 data-nosnippet>64</a> cache,
<a href=#65 id=65 data-nosnippet>65</a> kv_backend.clone(),
<a href=#66 id=66 data-nosnippet>66</a> ));
<a href=#67 id=67 data-nosnippet>67</a>
<a href=#68 id=68 data-nosnippet>68</a> <span class="comment">// Builds schema cache
<a href=#69 id=69 data-nosnippet>69</a> </span><span class="kw">let </span>cache = default_cache();
<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">let </span>schema_cache = Arc::new(new_schema_cache(
<a href=#71 id=71 data-nosnippet>71</a> SCHEMA_CACHE_NAME.to_string(),
<a href=#72 id=72 data-nosnippet>72</a> cache,
<a href=#73 id=73 data-nosnippet>73</a> kv_backend.clone(),
<a href=#74 id=74 data-nosnippet>74</a> ));
<a href=#75 id=75 data-nosnippet>75</a>
<a href=#76 id=76 data-nosnippet>76</a> CacheRegistryBuilder::default()
<a href=#77 id=77 data-nosnippet>77</a> .add_cache(table_id_schema_cache)
<a href=#78 id=78 data-nosnippet>78</a> .add_cache(schema_cache)
<a href=#79 id=79 data-nosnippet>79</a> .build()
<a href=#80 id=80 data-nosnippet>80</a>}
<a href=#81 id=81 data-nosnippet>81</a>
<a href=#82 id=82 data-nosnippet>82</a><span class="doccomment">/// Builds cache registry for frontend and datanode, including:
<a href=#83 id=83 data-nosnippet>83</a>/// - Table info cache
<a href=#84 id=84 data-nosnippet>84</a>/// - Table name cache
<a href=#85 id=85 data-nosnippet>85</a>/// - Table route cache
<a href=#86 id=86 data-nosnippet>86</a>/// - Table flow node cache
<a href=#87 id=87 data-nosnippet>87</a>/// - View cache
<a href=#88 id=88 data-nosnippet>88</a>/// - Schema cache
<a href=#89 id=89 data-nosnippet>89</a></span><span class="kw">pub fn </span>build_fundamental_cache_registry(kv_backend: KvBackendRef) -&gt; CacheRegistry {
<a href=#90 id=90 data-nosnippet>90</a> <span class="comment">// Builds table info cache
<a href=#91 id=91 data-nosnippet>91</a> </span><span class="kw">let </span>cache = default_cache();
<a href=#92 id=92 data-nosnippet>92</a> <span class="kw">let </span>table_info_cache = Arc::new(new_table_info_cache(
<a href=#93 id=93 data-nosnippet>93</a> TABLE_INFO_CACHE_NAME.to_string(),
<a href=#94 id=94 data-nosnippet>94</a> cache,
<a href=#95 id=95 data-nosnippet>95</a> kv_backend.clone(),
<a href=#96 id=96 data-nosnippet>96</a> ));
<a href=#97 id=97 data-nosnippet>97</a>
<a href=#98 id=98 data-nosnippet>98</a> <span class="comment">// Builds table name cache
<a href=#99 id=99 data-nosnippet>99</a> </span><span class="kw">let </span>cache = default_cache();
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">let </span>table_name_cache = Arc::new(new_table_name_cache(
<a href=#101 id=101 data-nosnippet>101</a> TABLE_NAME_CACHE_NAME.to_string(),
<a href=#102 id=102 data-nosnippet>102</a> cache,
<a href=#103 id=103 data-nosnippet>103</a> kv_backend.clone(),
<a href=#104 id=104 data-nosnippet>104</a> ));
<a href=#105 id=105 data-nosnippet>105</a>
<a href=#106 id=106 data-nosnippet>106</a> <span class="comment">// Builds table route cache
<a href=#107 id=107 data-nosnippet>107</a> </span><span class="kw">let </span>cache = default_cache();
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">let </span>table_route_cache = Arc::new(new_table_route_cache(
<a href=#109 id=109 data-nosnippet>109</a> TABLE_ROUTE_CACHE_NAME.to_string(),
<a href=#110 id=110 data-nosnippet>110</a> cache,
<a href=#111 id=111 data-nosnippet>111</a> kv_backend.clone(),
<a href=#112 id=112 data-nosnippet>112</a> ));
<a href=#113 id=113 data-nosnippet>113</a>
<a href=#114 id=114 data-nosnippet>114</a> <span class="comment">// Builds table flownode set cache
<a href=#115 id=115 data-nosnippet>115</a> </span><span class="kw">let </span>cache = default_cache();
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw">let </span>table_flownode_set_cache = Arc::new(new_table_flownode_set_cache(
<a href=#117 id=117 data-nosnippet>117</a> TABLE_FLOWNODE_SET_CACHE_NAME.to_string(),
<a href=#118 id=118 data-nosnippet>118</a> cache,
<a href=#119 id=119 data-nosnippet>119</a> kv_backend.clone(),
<a href=#120 id=120 data-nosnippet>120</a> ));
<a href=#121 id=121 data-nosnippet>121</a> <span class="comment">// Builds the view info cache
<a href=#122 id=122 data-nosnippet>122</a> </span><span class="kw">let </span>cache = default_cache();
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">let </span>view_info_cache = Arc::new(new_view_info_cache(
<a href=#124 id=124 data-nosnippet>124</a> VIEW_INFO_CACHE_NAME.to_string(),
<a href=#125 id=125 data-nosnippet>125</a> cache,
<a href=#126 id=126 data-nosnippet>126</a> kv_backend.clone(),
<a href=#127 id=127 data-nosnippet>127</a> ));
<a href=#128 id=128 data-nosnippet>128</a>
<a href=#129 id=129 data-nosnippet>129</a> <span class="comment">// Builds schema cache
<a href=#130 id=130 data-nosnippet>130</a> </span><span class="kw">let </span>cache = default_cache();
<a href=#131 id=131 data-nosnippet>131</a> <span class="kw">let </span>schema_cache = Arc::new(new_schema_cache(
<a href=#132 id=132 data-nosnippet>132</a> SCHEMA_CACHE_NAME.to_string(),
<a href=#133 id=133 data-nosnippet>133</a> cache,
<a href=#134 id=134 data-nosnippet>134</a> kv_backend.clone(),
<a href=#135 id=135 data-nosnippet>135</a> ));
<a href=#136 id=136 data-nosnippet>136</a>
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">let </span>table_id_schema_cache = Arc::new(new_table_schema_cache(
<a href=#138 id=138 data-nosnippet>138</a> TABLE_SCHEMA_NAME_CACHE_NAME.to_string(),
<a href=#139 id=139 data-nosnippet>139</a> CacheBuilder::new(DEFAULT_CACHE_MAX_CAPACITY).build(),
<a href=#140 id=140 data-nosnippet>140</a> kv_backend,
<a href=#141 id=141 data-nosnippet>141</a> ));
<a href=#142 id=142 data-nosnippet>142</a> CacheRegistryBuilder::default()
<a href=#143 id=143 data-nosnippet>143</a> .add_cache(table_info_cache)
<a href=#144 id=144 data-nosnippet>144</a> .add_cache(table_name_cache)
<a href=#145 id=145 data-nosnippet>145</a> .add_cache(table_route_cache)
<a href=#146 id=146 data-nosnippet>146</a> .add_cache(view_info_cache)
<a href=#147 id=147 data-nosnippet>147</a> .add_cache(table_flownode_set_cache)
<a href=#148 id=148 data-nosnippet>148</a> .add_cache(schema_cache)
<a href=#149 id=149 data-nosnippet>149</a> .add_cache(table_id_schema_cache)
<a href=#150 id=150 data-nosnippet>150</a> .build()
<a href=#151 id=151 data-nosnippet>151</a>}
<a href=#152 id=152 data-nosnippet>152</a>
<a href=#153 id=153 data-nosnippet>153</a><span class="comment">// TODO(weny): Make the cache configurable.
<a href=#154 id=154 data-nosnippet>154</a></span><span class="kw">pub fn </span>with_default_composite_cache_registry(
<a href=#155 id=155 data-nosnippet>155</a> builder: LayeredCacheRegistryBuilder,
<a href=#156 id=156 data-nosnippet>156</a>) -&gt; <span class="prelude-ty">Result</span>&lt;LayeredCacheRegistryBuilder&gt; {
<a href=#157 id=157 data-nosnippet>157</a> <span class="kw">let </span>table_info_cache = builder.get().context(error::CacheRequiredSnafu {
<a href=#158 id=158 data-nosnippet>158</a> name: TABLE_INFO_CACHE_NAME,
<a href=#159 id=159 data-nosnippet>159</a> })<span class="question-mark">?</span>;
<a href=#160 id=160 data-nosnippet>160</a> <span class="kw">let </span>table_name_cache = builder.get().context(error::CacheRequiredSnafu {
<a href=#161 id=161 data-nosnippet>161</a> name: TABLE_NAME_CACHE_NAME,
<a href=#162 id=162 data-nosnippet>162</a> })<span class="question-mark">?</span>;
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">let </span>table_route_cache = builder.get().context(error::CacheRequiredSnafu {
<a href=#164 id=164 data-nosnippet>164</a> name: TABLE_ROUTE_CACHE_NAME,
<a href=#165 id=165 data-nosnippet>165</a> })<span class="question-mark">?</span>;
<a href=#166 id=166 data-nosnippet>166</a>
<a href=#167 id=167 data-nosnippet>167</a> <span class="comment">// Builds table cache
<a href=#168 id=168 data-nosnippet>168</a> </span><span class="kw">let </span>cache = default_cache();
<a href=#169 id=169 data-nosnippet>169</a> <span class="kw">let </span>table_cache = Arc::new(new_table_cache(
<a href=#170 id=170 data-nosnippet>170</a> TABLE_CACHE_NAME.to_string(),
<a href=#171 id=171 data-nosnippet>171</a> cache,
<a href=#172 id=172 data-nosnippet>172</a> table_info_cache,
<a href=#173 id=173 data-nosnippet>173</a> table_name_cache,
<a href=#174 id=174 data-nosnippet>174</a> ));
<a href=#175 id=175 data-nosnippet>175</a>
<a href=#176 id=176 data-nosnippet>176</a> <span class="kw">let </span>cache = default_cache();
<a href=#177 id=177 data-nosnippet>177</a> <span class="kw">let </span>partition_info_cache = Arc::new(new_partition_info_cache(
<a href=#178 id=178 data-nosnippet>178</a> PARTITION_INFO_CACHE_NAME.to_string(),
<a href=#179 id=179 data-nosnippet>179</a> cache,
<a href=#180 id=180 data-nosnippet>180</a> table_route_cache,
<a href=#181 id=181 data-nosnippet>181</a> ));
<a href=#182 id=182 data-nosnippet>182</a>
<a href=#183 id=183 data-nosnippet>183</a> <span class="kw">let </span>registry = CacheRegistryBuilder::default()
<a href=#184 id=184 data-nosnippet>184</a> .add_cache(table_cache)
<a href=#185 id=185 data-nosnippet>185</a> .add_cache(partition_info_cache)
<a href=#186 id=186 data-nosnippet>186</a> .build();
<a href=#187 id=187 data-nosnippet>187</a>
<a href=#188 id=188 data-nosnippet>188</a> <span class="prelude-val">Ok</span>(builder.add_cache_registry(registry))
<a href=#189 id=189 data-nosnippet>189</a>}
</code></pre></div></section></main></body></html>
+415
View File
@@ -0,0 +1,415 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/error.rs`."><title>error.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/</div>error.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::any::Any;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::fmt::Debug;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_error::ext::{BoxedError, ErrorExt};
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_error::status_code::StatusCode;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_macro::stack_trace_debug;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_query::error::datafusion_status_code;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>datafusion::error::DataFusionError;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>snafu::{Location, Snafu};
<a href=#24 id=24 data-nosnippet>24</a>
<a href=#25 id=25 data-nosnippet>25</a><span class="attr">#[derive(Snafu)]
<a href=#26 id=26 data-nosnippet>26</a>#[snafu(visibility(<span class="kw">pub</span>))]
<a href=#27 id=27 data-nosnippet>27</a>#[stack_trace_debug]
<a href=#28 id=28 data-nosnippet>28</a></span><span class="kw">pub enum </span>Error {
<a href=#29 id=29 data-nosnippet>29</a> <span class="attr">#[snafu(display(<span class="string">"Failed to list catalogs"</span>))]
<a href=#30 id=30 data-nosnippet>30</a> </span>ListCatalogs {
<a href=#31 id=31 data-nosnippet>31</a> <span class="attr">#[snafu(implicit)]
<a href=#32 id=32 data-nosnippet>32</a> </span>location: Location,
<a href=#33 id=33 data-nosnippet>33</a> source: BoxedError,
<a href=#34 id=34 data-nosnippet>34</a> },
<a href=#35 id=35 data-nosnippet>35</a>
<a href=#36 id=36 data-nosnippet>36</a> <span class="attr">#[snafu(display(<span class="string">"Failed to list {}'s schemas"</span>, catalog))]
<a href=#37 id=37 data-nosnippet>37</a> </span>ListSchemas {
<a href=#38 id=38 data-nosnippet>38</a> <span class="attr">#[snafu(implicit)]
<a href=#39 id=39 data-nosnippet>39</a> </span>location: Location,
<a href=#40 id=40 data-nosnippet>40</a> catalog: String,
<a href=#41 id=41 data-nosnippet>41</a> source: BoxedError,
<a href=#42 id=42 data-nosnippet>42</a> },
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a> <span class="attr">#[snafu(display(<span class="string">"Failed to list {}.{}'s tables"</span>, catalog, schema))]
<a href=#45 id=45 data-nosnippet>45</a> </span>ListTables {
<a href=#46 id=46 data-nosnippet>46</a> <span class="attr">#[snafu(implicit)]
<a href=#47 id=47 data-nosnippet>47</a> </span>location: Location,
<a href=#48 id=48 data-nosnippet>48</a> catalog: String,
<a href=#49 id=49 data-nosnippet>49</a> schema: String,
<a href=#50 id=50 data-nosnippet>50</a> source: BoxedError,
<a href=#51 id=51 data-nosnippet>51</a> },
<a href=#52 id=52 data-nosnippet>52</a>
<a href=#53 id=53 data-nosnippet>53</a> <span class="attr">#[snafu(display(<span class="string">"Failed to list nodes in cluster"</span>))]
<a href=#54 id=54 data-nosnippet>54</a> </span>ListNodes {
<a href=#55 id=55 data-nosnippet>55</a> <span class="attr">#[snafu(implicit)]
<a href=#56 id=56 data-nosnippet>56</a> </span>location: Location,
<a href=#57 id=57 data-nosnippet>57</a> source: BoxedError,
<a href=#58 id=58 data-nosnippet>58</a> },
<a href=#59 id=59 data-nosnippet>59</a>
<a href=#60 id=60 data-nosnippet>60</a> <span class="attr">#[snafu(display(<span class="string">"Failed to region stats in cluster"</span>))]
<a href=#61 id=61 data-nosnippet>61</a> </span>ListRegionStats {
<a href=#62 id=62 data-nosnippet>62</a> <span class="attr">#[snafu(implicit)]
<a href=#63 id=63 data-nosnippet>63</a> </span>location: Location,
<a href=#64 id=64 data-nosnippet>64</a> source: BoxedError,
<a href=#65 id=65 data-nosnippet>65</a> },
<a href=#66 id=66 data-nosnippet>66</a>
<a href=#67 id=67 data-nosnippet>67</a> <span class="attr">#[snafu(display(<span class="string">"Failed to list flow stats"</span>))]
<a href=#68 id=68 data-nosnippet>68</a> </span>ListFlowStats {
<a href=#69 id=69 data-nosnippet>69</a> <span class="attr">#[snafu(implicit)]
<a href=#70 id=70 data-nosnippet>70</a> </span>location: Location,
<a href=#71 id=71 data-nosnippet>71</a> source: BoxedError,
<a href=#72 id=72 data-nosnippet>72</a> },
<a href=#73 id=73 data-nosnippet>73</a>
<a href=#74 id=74 data-nosnippet>74</a> <span class="attr">#[snafu(display(<span class="string">"Failed to list flows in catalog {catalog}"</span>))]
<a href=#75 id=75 data-nosnippet>75</a> </span>ListFlows {
<a href=#76 id=76 data-nosnippet>76</a> <span class="attr">#[snafu(implicit)]
<a href=#77 id=77 data-nosnippet>77</a> </span>location: Location,
<a href=#78 id=78 data-nosnippet>78</a> catalog: String,
<a href=#79 id=79 data-nosnippet>79</a> source: BoxedError,
<a href=#80 id=80 data-nosnippet>80</a> },
<a href=#81 id=81 data-nosnippet>81</a>
<a href=#82 id=82 data-nosnippet>82</a> <span class="attr">#[snafu(display(<span class="string">"Flow info not found: {flow_name} in catalog {catalog_name}"</span>))]
<a href=#83 id=83 data-nosnippet>83</a> </span>FlowInfoNotFound {
<a href=#84 id=84 data-nosnippet>84</a> flow_name: String,
<a href=#85 id=85 data-nosnippet>85</a> catalog_name: String,
<a href=#86 id=86 data-nosnippet>86</a> <span class="attr">#[snafu(implicit)]
<a href=#87 id=87 data-nosnippet>87</a> </span>location: Location,
<a href=#88 id=88 data-nosnippet>88</a> },
<a href=#89 id=89 data-nosnippet>89</a>
<a href=#90 id=90 data-nosnippet>90</a> <span class="attr">#[snafu(display(<span class="string">"Can't convert value to json, input={input}"</span>))]
<a href=#91 id=91 data-nosnippet>91</a> </span>Json {
<a href=#92 id=92 data-nosnippet>92</a> input: String,
<a href=#93 id=93 data-nosnippet>93</a> <span class="attr">#[snafu(source)]
<a href=#94 id=94 data-nosnippet>94</a> </span>error: serde_json::error::Error,
<a href=#95 id=95 data-nosnippet>95</a> <span class="attr">#[snafu(implicit)]
<a href=#96 id=96 data-nosnippet>96</a> </span>location: Location,
<a href=#97 id=97 data-nosnippet>97</a> },
<a href=#98 id=98 data-nosnippet>98</a>
<a href=#99 id=99 data-nosnippet>99</a> <span class="attr">#[snafu(display(<span class="string">"Failed to get information extension client"</span>))]
<a href=#100 id=100 data-nosnippet>100</a> </span>GetInformationExtension {
<a href=#101 id=101 data-nosnippet>101</a> <span class="attr">#[snafu(implicit)]
<a href=#102 id=102 data-nosnippet>102</a> </span>location: Location,
<a href=#103 id=103 data-nosnippet>103</a> },
<a href=#104 id=104 data-nosnippet>104</a>
<a href=#105 id=105 data-nosnippet>105</a> <span class="attr">#[snafu(display(<span class="string">"Failed to list procedures"</span>))]
<a href=#106 id=106 data-nosnippet>106</a> </span>ListProcedures {
<a href=#107 id=107 data-nosnippet>107</a> <span class="attr">#[snafu(implicit)]
<a href=#108 id=108 data-nosnippet>108</a> </span>location: Location,
<a href=#109 id=109 data-nosnippet>109</a> source: BoxedError,
<a href=#110 id=110 data-nosnippet>110</a> },
<a href=#111 id=111 data-nosnippet>111</a>
<a href=#112 id=112 data-nosnippet>112</a> <span class="attr">#[snafu(display(<span class="string">"Procedure id not found"</span>))]
<a href=#113 id=113 data-nosnippet>113</a> </span>ProcedureIdNotFound {
<a href=#114 id=114 data-nosnippet>114</a> <span class="attr">#[snafu(implicit)]
<a href=#115 id=115 data-nosnippet>115</a> </span>location: Location,
<a href=#116 id=116 data-nosnippet>116</a> },
<a href=#117 id=117 data-nosnippet>117</a>
<a href=#118 id=118 data-nosnippet>118</a> <span class="attr">#[snafu(display(<span class="string">"convert proto data error"</span>))]
<a href=#119 id=119 data-nosnippet>119</a> </span>ConvertProtoData {
<a href=#120 id=120 data-nosnippet>120</a> <span class="attr">#[snafu(implicit)]
<a href=#121 id=121 data-nosnippet>121</a> </span>location: Location,
<a href=#122 id=122 data-nosnippet>122</a> source: BoxedError,
<a href=#123 id=123 data-nosnippet>123</a> },
<a href=#124 id=124 data-nosnippet>124</a>
<a href=#125 id=125 data-nosnippet>125</a> <span class="attr">#[snafu(display(<span class="string">"Failed to create table, table info: {}"</span>, table_info))]
<a href=#126 id=126 data-nosnippet>126</a> </span>CreateTable {
<a href=#127 id=127 data-nosnippet>127</a> table_info: String,
<a href=#128 id=128 data-nosnippet>128</a> <span class="attr">#[snafu(implicit)]
<a href=#129 id=129 data-nosnippet>129</a> </span>location: Location,
<a href=#130 id=130 data-nosnippet>130</a> source: table::error::Error,
<a href=#131 id=131 data-nosnippet>131</a> },
<a href=#132 id=132 data-nosnippet>132</a>
<a href=#133 id=133 data-nosnippet>133</a> <span class="attr">#[snafu(display(<span class="string">"Cannot find catalog by name: {}"</span>, catalog_name))]
<a href=#134 id=134 data-nosnippet>134</a> </span>CatalogNotFound {
<a href=#135 id=135 data-nosnippet>135</a> catalog_name: String,
<a href=#136 id=136 data-nosnippet>136</a> <span class="attr">#[snafu(implicit)]
<a href=#137 id=137 data-nosnippet>137</a> </span>location: Location,
<a href=#138 id=138 data-nosnippet>138</a> },
<a href=#139 id=139 data-nosnippet>139</a>
<a href=#140 id=140 data-nosnippet>140</a> <span class="attr">#[snafu(display(<span class="string">"Cannot find schema {} in catalog {}"</span>, schema, catalog))]
<a href=#141 id=141 data-nosnippet>141</a> </span>SchemaNotFound {
<a href=#142 id=142 data-nosnippet>142</a> catalog: String,
<a href=#143 id=143 data-nosnippet>143</a> schema: String,
<a href=#144 id=144 data-nosnippet>144</a> <span class="attr">#[snafu(implicit)]
<a href=#145 id=145 data-nosnippet>145</a> </span>location: Location,
<a href=#146 id=146 data-nosnippet>146</a> },
<a href=#147 id=147 data-nosnippet>147</a>
<a href=#148 id=148 data-nosnippet>148</a> <span class="attr">#[snafu(display(<span class="string">"Table `{}` already exists"</span>, table))]
<a href=#149 id=149 data-nosnippet>149</a> </span>TableExists {
<a href=#150 id=150 data-nosnippet>150</a> table: String,
<a href=#151 id=151 data-nosnippet>151</a> <span class="attr">#[snafu(implicit)]
<a href=#152 id=152 data-nosnippet>152</a> </span>location: Location,
<a href=#153 id=153 data-nosnippet>153</a> },
<a href=#154 id=154 data-nosnippet>154</a>
<a href=#155 id=155 data-nosnippet>155</a> <span class="attr">#[snafu(display(<span class="string">"Table not found: {}"</span>, table))]
<a href=#156 id=156 data-nosnippet>156</a> </span>TableNotExist {
<a href=#157 id=157 data-nosnippet>157</a> table: String,
<a href=#158 id=158 data-nosnippet>158</a> <span class="attr">#[snafu(implicit)]
<a href=#159 id=159 data-nosnippet>159</a> </span>location: Location,
<a href=#160 id=160 data-nosnippet>160</a> },
<a href=#161 id=161 data-nosnippet>161</a>
<a href=#162 id=162 data-nosnippet>162</a> <span class="attr">#[snafu(display(<span class="string">"View info not found: {}"</span>, name))]
<a href=#163 id=163 data-nosnippet>163</a> </span>ViewInfoNotFound {
<a href=#164 id=164 data-nosnippet>164</a> name: String,
<a href=#165 id=165 data-nosnippet>165</a> <span class="attr">#[snafu(implicit)]
<a href=#166 id=166 data-nosnippet>166</a> </span>location: Location,
<a href=#167 id=167 data-nosnippet>167</a> },
<a href=#168 id=168 data-nosnippet>168</a>
<a href=#169 id=169 data-nosnippet>169</a> <span class="attr">#[snafu(display(
<a href=#170 id=170 data-nosnippet>170</a> <span class="string">"View plan columns changed from: {} to: {}"</span>,
<a href=#171 id=171 data-nosnippet>171</a> origin_names,
<a href=#172 id=172 data-nosnippet>172</a> actual_names
<a href=#173 id=173 data-nosnippet>173</a> ))]
<a href=#174 id=174 data-nosnippet>174</a> </span>ViewPlanColumnsChanged {
<a href=#175 id=175 data-nosnippet>175</a> origin_names: String,
<a href=#176 id=176 data-nosnippet>176</a> actual_names: String,
<a href=#177 id=177 data-nosnippet>177</a> <span class="attr">#[snafu(implicit)]
<a href=#178 id=178 data-nosnippet>178</a> </span>location: Location,
<a href=#179 id=179 data-nosnippet>179</a> },
<a href=#180 id=180 data-nosnippet>180</a>
<a href=#181 id=181 data-nosnippet>181</a> <span class="attr">#[snafu(display(<span class="string">"Partition manager not found, it's not expected."</span>))]
<a href=#182 id=182 data-nosnippet>182</a> </span>PartitionManagerNotFound {
<a href=#183 id=183 data-nosnippet>183</a> <span class="attr">#[snafu(implicit)]
<a href=#184 id=184 data-nosnippet>184</a> </span>location: Location,
<a href=#185 id=185 data-nosnippet>185</a> },
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a> <span class="attr">#[snafu(display(<span class="string">"Failed to find table partitions"</span>))]
<a href=#188 id=188 data-nosnippet>188</a> </span>FindPartitions { source: partition::error::Error },
<a href=#189 id=189 data-nosnippet>189</a>
<a href=#190 id=190 data-nosnippet>190</a> <span class="attr">#[snafu(display(<span class="string">"Failed to find region routes"</span>))]
<a href=#191 id=191 data-nosnippet>191</a> </span>FindRegionRoutes { source: partition::error::Error },
<a href=#192 id=192 data-nosnippet>192</a>
<a href=#193 id=193 data-nosnippet>193</a> <span class="attr">#[snafu(display(<span class="string">"Failed to create recordbatch"</span>))]
<a href=#194 id=194 data-nosnippet>194</a> </span>CreateRecordBatch {
<a href=#195 id=195 data-nosnippet>195</a> <span class="attr">#[snafu(implicit)]
<a href=#196 id=196 data-nosnippet>196</a> </span>location: Location,
<a href=#197 id=197 data-nosnippet>197</a> source: common_recordbatch::error::Error,
<a href=#198 id=198 data-nosnippet>198</a> },
<a href=#199 id=199 data-nosnippet>199</a>
<a href=#200 id=200 data-nosnippet>200</a> <span class="attr">#[snafu(display(<span class="string">"Internal error"</span>))]
<a href=#201 id=201 data-nosnippet>201</a> </span>Internal {
<a href=#202 id=202 data-nosnippet>202</a> <span class="attr">#[snafu(implicit)]
<a href=#203 id=203 data-nosnippet>203</a> </span>location: Location,
<a href=#204 id=204 data-nosnippet>204</a> source: BoxedError,
<a href=#205 id=205 data-nosnippet>205</a> },
<a href=#206 id=206 data-nosnippet>206</a>
<a href=#207 id=207 data-nosnippet>207</a> <span class="attr">#[snafu(display(<span class="string">"Failed to upgrade weak catalog manager reference"</span>))]
<a href=#208 id=208 data-nosnippet>208</a> </span>UpgradeWeakCatalogManagerRef {
<a href=#209 id=209 data-nosnippet>209</a> <span class="attr">#[snafu(implicit)]
<a href=#210 id=210 data-nosnippet>210</a> </span>location: Location,
<a href=#211 id=211 data-nosnippet>211</a> },
<a href=#212 id=212 data-nosnippet>212</a>
<a href=#213 id=213 data-nosnippet>213</a> <span class="attr">#[snafu(display(<span class="string">"Failed to decode logical plan for view: {}"</span>, name))]
<a href=#214 id=214 data-nosnippet>214</a> </span>DecodePlan {
<a href=#215 id=215 data-nosnippet>215</a> name: String,
<a href=#216 id=216 data-nosnippet>216</a> <span class="attr">#[snafu(implicit)]
<a href=#217 id=217 data-nosnippet>217</a> </span>location: Location,
<a href=#218 id=218 data-nosnippet>218</a> source: common_query::error::Error,
<a href=#219 id=219 data-nosnippet>219</a> },
<a href=#220 id=220 data-nosnippet>220</a>
<a href=#221 id=221 data-nosnippet>221</a> <span class="attr">#[snafu(display(<span class="string">"Illegal access to catalog: {} and schema: {}"</span>, catalog, schema))]
<a href=#222 id=222 data-nosnippet>222</a> </span>QueryAccessDenied { catalog: String, schema: String },
<a href=#223 id=223 data-nosnippet>223</a>
<a href=#224 id=224 data-nosnippet>224</a> <span class="attr">#[snafu(display(<span class="string">"DataFusion error"</span>))]
<a href=#225 id=225 data-nosnippet>225</a> </span>Datafusion {
<a href=#226 id=226 data-nosnippet>226</a> <span class="attr">#[snafu(source)]
<a href=#227 id=227 data-nosnippet>227</a> </span>error: DataFusionError,
<a href=#228 id=228 data-nosnippet>228</a> <span class="attr">#[snafu(implicit)]
<a href=#229 id=229 data-nosnippet>229</a> </span>location: Location,
<a href=#230 id=230 data-nosnippet>230</a> },
<a href=#231 id=231 data-nosnippet>231</a>
<a href=#232 id=232 data-nosnippet>232</a> <span class="attr">#[snafu(display(<span class="string">"Failed to project view columns"</span>))]
<a href=#233 id=233 data-nosnippet>233</a> </span>ProjectViewColumns {
<a href=#234 id=234 data-nosnippet>234</a> <span class="attr">#[snafu(source)]
<a href=#235 id=235 data-nosnippet>235</a> </span>error: DataFusionError,
<a href=#236 id=236 data-nosnippet>236</a> <span class="attr">#[snafu(implicit)]
<a href=#237 id=237 data-nosnippet>237</a> </span>location: Location,
<a href=#238 id=238 data-nosnippet>238</a> },
<a href=#239 id=239 data-nosnippet>239</a>
<a href=#240 id=240 data-nosnippet>240</a> <span class="attr">#[snafu(display(<span class="string">"Table metadata manager error"</span>))]
<a href=#241 id=241 data-nosnippet>241</a> </span>TableMetadataManager {
<a href=#242 id=242 data-nosnippet>242</a> source: common_meta::error::Error,
<a href=#243 id=243 data-nosnippet>243</a> <span class="attr">#[snafu(implicit)]
<a href=#244 id=244 data-nosnippet>244</a> </span>location: Location,
<a href=#245 id=245 data-nosnippet>245</a> },
<a href=#246 id=246 data-nosnippet>246</a>
<a href=#247 id=247 data-nosnippet>247</a> <span class="attr">#[snafu(display(<span class="string">"Failed to get table cache"</span>))]
<a href=#248 id=248 data-nosnippet>248</a> </span>GetTableCache {
<a href=#249 id=249 data-nosnippet>249</a> source: common_meta::error::Error,
<a href=#250 id=250 data-nosnippet>250</a> <span class="attr">#[snafu(implicit)]
<a href=#251 id=251 data-nosnippet>251</a> </span>location: Location,
<a href=#252 id=252 data-nosnippet>252</a> },
<a href=#253 id=253 data-nosnippet>253</a>
<a href=#254 id=254 data-nosnippet>254</a> <span class="attr">#[snafu(display(<span class="string">"Failed to get view info from cache"</span>))]
<a href=#255 id=255 data-nosnippet>255</a> </span>GetViewCache {
<a href=#256 id=256 data-nosnippet>256</a> source: common_meta::error::Error,
<a href=#257 id=257 data-nosnippet>257</a> <span class="attr">#[snafu(implicit)]
<a href=#258 id=258 data-nosnippet>258</a> </span>location: Location,
<a href=#259 id=259 data-nosnippet>259</a> },
<a href=#260 id=260 data-nosnippet>260</a>
<a href=#261 id=261 data-nosnippet>261</a> <span class="attr">#[snafu(display(<span class="string">"Cache not found: {name}"</span>))]
<a href=#262 id=262 data-nosnippet>262</a> </span>CacheNotFound {
<a href=#263 id=263 data-nosnippet>263</a> name: String,
<a href=#264 id=264 data-nosnippet>264</a> <span class="attr">#[snafu(implicit)]
<a href=#265 id=265 data-nosnippet>265</a> </span>location: Location,
<a href=#266 id=266 data-nosnippet>266</a> },
<a href=#267 id=267 data-nosnippet>267</a>
<a href=#268 id=268 data-nosnippet>268</a> <span class="attr">#[snafu(display(<span class="string">"Failed to cast the catalog manager"</span>))]
<a href=#269 id=269 data-nosnippet>269</a> </span>CastManager {
<a href=#270 id=270 data-nosnippet>270</a> <span class="attr">#[snafu(implicit)]
<a href=#271 id=271 data-nosnippet>271</a> </span>location: Location,
<a href=#272 id=272 data-nosnippet>272</a> },
<a href=#273 id=273 data-nosnippet>273</a>
<a href=#274 id=274 data-nosnippet>274</a> <span class="attr">#[snafu(display(<span class="string">"Failed to invoke frontend services"</span>))]
<a href=#275 id=275 data-nosnippet>275</a> </span>InvokeFrontend {
<a href=#276 id=276 data-nosnippet>276</a> source: common_frontend::error::Error,
<a href=#277 id=277 data-nosnippet>277</a> <span class="attr">#[snafu(implicit)]
<a href=#278 id=278 data-nosnippet>278</a> </span>location: Location,
<a href=#279 id=279 data-nosnippet>279</a> },
<a href=#280 id=280 data-nosnippet>280</a>
<a href=#281 id=281 data-nosnippet>281</a> <span class="attr">#[snafu(display(<span class="string">"Meta client is not provided"</span>))]
<a href=#282 id=282 data-nosnippet>282</a> </span>MetaClientMissing {
<a href=#283 id=283 data-nosnippet>283</a> <span class="attr">#[snafu(implicit)]
<a href=#284 id=284 data-nosnippet>284</a> </span>location: Location,
<a href=#285 id=285 data-nosnippet>285</a> },
<a href=#286 id=286 data-nosnippet>286</a>
<a href=#287 id=287 data-nosnippet>287</a> <span class="attr">#[snafu(display(<span class="string">"Failed to find frontend node: {}"</span>, addr))]
<a href=#288 id=288 data-nosnippet>288</a> </span>FrontendNotFound {
<a href=#289 id=289 data-nosnippet>289</a> addr: String,
<a href=#290 id=290 data-nosnippet>290</a> <span class="attr">#[snafu(implicit)]
<a href=#291 id=291 data-nosnippet>291</a> </span>location: Location,
<a href=#292 id=292 data-nosnippet>292</a> },
<a href=#293 id=293 data-nosnippet>293</a>
<a href=#294 id=294 data-nosnippet>294</a> <span class="attr">#[snafu(display(<span class="string">"Failed to handle query"</span>))]
<a href=#295 id=295 data-nosnippet>295</a> </span>HandleQuery {
<a href=#296 id=296 data-nosnippet>296</a> source: common_meta::error::Error,
<a href=#297 id=297 data-nosnippet>297</a> <span class="attr">#[snafu(implicit)]
<a href=#298 id=298 data-nosnippet>298</a> </span>location: Location,
<a href=#299 id=299 data-nosnippet>299</a> },
<a href=#300 id=300 data-nosnippet>300</a>
<a href=#301 id=301 data-nosnippet>301</a> <span class="attr">#[snafu(display(<span class="string">"Failed to project schema"</span>))]
<a href=#302 id=302 data-nosnippet>302</a> </span>ProjectSchema {
<a href=#303 id=303 data-nosnippet>303</a> source: datatypes::error::Error,
<a href=#304 id=304 data-nosnippet>304</a> <span class="attr">#[snafu(implicit)]
<a href=#305 id=305 data-nosnippet>305</a> </span>location: Location,
<a href=#306 id=306 data-nosnippet>306</a> },
<a href=#307 id=307 data-nosnippet>307</a>}
<a href=#308 id=308 data-nosnippet>308</a>
<a href=#309 id=309 data-nosnippet>309</a><span class="kw">impl </span>Error {
<a href=#310 id=310 data-nosnippet>310</a> <span class="kw">pub fn </span>should_fail(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#311 id=311 data-nosnippet>311</a> <span class="kw">use </span>Error::<span class="kw-2">*</span>;
<a href=#312 id=312 data-nosnippet>312</a>
<a href=#313 id=313 data-nosnippet>313</a> <span class="macro">matches!</span>(
<a href=#314 id=314 data-nosnippet>314</a> <span class="self">self</span>,
<a href=#315 id=315 data-nosnippet>315</a> GetViewCache { .. }
<a href=#316 id=316 data-nosnippet>316</a> | ViewInfoNotFound { .. }
<a href=#317 id=317 data-nosnippet>317</a> | DecodePlan { .. }
<a href=#318 id=318 data-nosnippet>318</a> | ViewPlanColumnsChanged { .. }
<a href=#319 id=319 data-nosnippet>319</a> | ProjectViewColumns { .. }
<a href=#320 id=320 data-nosnippet>320</a> )
<a href=#321 id=321 data-nosnippet>321</a> }
<a href=#322 id=322 data-nosnippet>322</a>}
<a href=#323 id=323 data-nosnippet>323</a>
<a href=#324 id=324 data-nosnippet>324</a><span class="kw">pub type </span><span class="prelude-ty">Result</span>&lt;T&gt; = std::result::Result&lt;T, Error&gt;;
<a href=#325 id=325 data-nosnippet>325</a>
<a href=#326 id=326 data-nosnippet>326</a><span class="kw">impl </span>ErrorExt <span class="kw">for </span>Error {
<a href=#327 id=327 data-nosnippet>327</a> <span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
<a href=#328 id=328 data-nosnippet>328</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#329 id=329 data-nosnippet>329</a> Error::SchemaNotFound { .. }
<a href=#330 id=330 data-nosnippet>330</a> | Error::CatalogNotFound { .. }
<a href=#331 id=331 data-nosnippet>331</a> | Error::FindPartitions { .. }
<a href=#332 id=332 data-nosnippet>332</a> | Error::FindRegionRoutes { .. }
<a href=#333 id=333 data-nosnippet>333</a> | Error::CacheNotFound { .. }
<a href=#334 id=334 data-nosnippet>334</a> | Error::CastManager { .. }
<a href=#335 id=335 data-nosnippet>335</a> | Error::Json { .. }
<a href=#336 id=336 data-nosnippet>336</a> | Error::GetInformationExtension { .. }
<a href=#337 id=337 data-nosnippet>337</a> | Error::PartitionManagerNotFound { .. }
<a href=#338 id=338 data-nosnippet>338</a> | Error::ProcedureIdNotFound { .. } =&gt; StatusCode::Unexpected,
<a href=#339 id=339 data-nosnippet>339</a>
<a href=#340 id=340 data-nosnippet>340</a> Error::ViewPlanColumnsChanged { .. } =&gt; StatusCode::InvalidArguments,
<a href=#341 id=341 data-nosnippet>341</a>
<a href=#342 id=342 data-nosnippet>342</a> Error::ViewInfoNotFound { .. } =&gt; StatusCode::TableNotFound,
<a href=#343 id=343 data-nosnippet>343</a>
<a href=#344 id=344 data-nosnippet>344</a> Error::FlowInfoNotFound { .. } =&gt; StatusCode::FlowNotFound,
<a href=#345 id=345 data-nosnippet>345</a>
<a href=#346 id=346 data-nosnippet>346</a> Error::UpgradeWeakCatalogManagerRef { .. } =&gt; StatusCode::Internal,
<a href=#347 id=347 data-nosnippet>347</a>
<a href=#348 id=348 data-nosnippet>348</a> Error::CreateRecordBatch { source, .. } =&gt; source.status_code(),
<a href=#349 id=349 data-nosnippet>349</a> Error::TableExists { .. } =&gt; StatusCode::TableAlreadyExists,
<a href=#350 id=350 data-nosnippet>350</a> Error::TableNotExist { .. } =&gt; StatusCode::TableNotFound,
<a href=#351 id=351 data-nosnippet>351</a> Error::ListCatalogs { source, .. }
<a href=#352 id=352 data-nosnippet>352</a> | Error::ListNodes { source, .. }
<a href=#353 id=353 data-nosnippet>353</a> | Error::ListSchemas { source, .. }
<a href=#354 id=354 data-nosnippet>354</a> | Error::ListTables { source, .. }
<a href=#355 id=355 data-nosnippet>355</a> | Error::ListFlows { source, .. }
<a href=#356 id=356 data-nosnippet>356</a> | Error::ListFlowStats { source, .. }
<a href=#357 id=357 data-nosnippet>357</a> | Error::ListProcedures { source, .. }
<a href=#358 id=358 data-nosnippet>358</a> | Error::ListRegionStats { source, .. }
<a href=#359 id=359 data-nosnippet>359</a> | Error::ConvertProtoData { source, .. } =&gt; source.status_code(),
<a href=#360 id=360 data-nosnippet>360</a>
<a href=#361 id=361 data-nosnippet>361</a> Error::CreateTable { source, .. } =&gt; source.status_code(),
<a href=#362 id=362 data-nosnippet>362</a>
<a href=#363 id=363 data-nosnippet>363</a> Error::DecodePlan { source, .. } =&gt; source.status_code(),
<a href=#364 id=364 data-nosnippet>364</a>
<a href=#365 id=365 data-nosnippet>365</a> Error::Internal { source, .. } =&gt; source.status_code(),
<a href=#366 id=366 data-nosnippet>366</a>
<a href=#367 id=367 data-nosnippet>367</a> Error::QueryAccessDenied { .. } =&gt; StatusCode::AccessDenied,
<a href=#368 id=368 data-nosnippet>368</a> Error::Datafusion { error, .. } =&gt; datafusion_status_code::&lt;<span class="self">Self</span>&gt;(error, <span class="prelude-val">None</span>),
<a href=#369 id=369 data-nosnippet>369</a> Error::ProjectViewColumns { .. } =&gt; StatusCode::EngineExecuteQuery,
<a href=#370 id=370 data-nosnippet>370</a> Error::TableMetadataManager { source, .. } =&gt; source.status_code(),
<a href=#371 id=371 data-nosnippet>371</a> Error::GetViewCache { source, .. } | Error::GetTableCache { source, .. } =&gt; {
<a href=#372 id=372 data-nosnippet>372</a> source.status_code()
<a href=#373 id=373 data-nosnippet>373</a> }
<a href=#374 id=374 data-nosnippet>374</a> Error::InvokeFrontend { source, .. } =&gt; source.status_code(),
<a href=#375 id=375 data-nosnippet>375</a> Error::FrontendNotFound { .. } | Error::MetaClientMissing { .. } =&gt; {
<a href=#376 id=376 data-nosnippet>376</a> StatusCode::Unexpected
<a href=#377 id=377 data-nosnippet>377</a> }
<a href=#378 id=378 data-nosnippet>378</a> Error::HandleQuery { source, .. } =&gt; source.status_code(),
<a href=#379 id=379 data-nosnippet>379</a> Error::ProjectSchema { source, .. } =&gt; source.status_code(),
<a href=#380 id=380 data-nosnippet>380</a> }
<a href=#381 id=381 data-nosnippet>381</a> }
<a href=#382 id=382 data-nosnippet>382</a>
<a href=#383 id=383 data-nosnippet>383</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>Any {
<a href=#384 id=384 data-nosnippet>384</a> <span class="self">self
<a href=#385 id=385 data-nosnippet>385</a> </span>}
<a href=#386 id=386 data-nosnippet>386</a>}
<a href=#387 id=387 data-nosnippet>387</a>
<a href=#388 id=388 data-nosnippet>388</a><span class="kw">impl </span>From&lt;Error&gt; <span class="kw">for </span>DataFusionError {
<a href=#389 id=389 data-nosnippet>389</a> <span class="kw">fn </span>from(e: Error) -&gt; <span class="self">Self </span>{
<a href=#390 id=390 data-nosnippet>390</a> DataFusionError::External(Box::new(e))
<a href=#391 id=391 data-nosnippet>391</a> }
<a href=#392 id=392 data-nosnippet>392</a>}
<a href=#393 id=393 data-nosnippet>393</a>
<a href=#394 id=394 data-nosnippet>394</a><span class="attr">#[cfg(test)]
<a href=#395 id=395 data-nosnippet>395</a></span><span class="kw">mod </span>tests {
<a href=#396 id=396 data-nosnippet>396</a> <span class="kw">use </span>snafu::GenerateImplicitData;
<a href=#397 id=397 data-nosnippet>397</a>
<a href=#398 id=398 data-nosnippet>398</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#399 id=399 data-nosnippet>399</a>
<a href=#400 id=400 data-nosnippet>400</a> <span class="attr">#[test]
<a href=#401 id=401 data-nosnippet>401</a> </span><span class="kw">pub fn </span>test_errors_to_datafusion_error() {
<a href=#402 id=402 data-nosnippet>402</a> <span class="kw">let </span>e: DataFusionError = Error::TableExists {
<a href=#403 id=403 data-nosnippet>403</a> table: <span class="string">"test_table"</span>.to_string(),
<a href=#404 id=404 data-nosnippet>404</a> location: Location::generate(),
<a href=#405 id=405 data-nosnippet>405</a> }
<a href=#406 id=406 data-nosnippet>406</a> .into();
<a href=#407 id=407 data-nosnippet>407</a> <span class="kw">match </span>e {
<a href=#408 id=408 data-nosnippet>408</a> DataFusionError::External(<span class="kw">_</span>) =&gt; {}
<a href=#409 id=409 data-nosnippet>409</a> <span class="kw">_ </span>=&gt; {
<a href=#410 id=410 data-nosnippet>410</a> <span class="macro">panic!</span>(<span class="string">"catalog error should be converted to DataFusionError::Internal"</span>)
<a href=#411 id=411 data-nosnippet>411</a> }
<a href=#412 id=412 data-nosnippet>412</a> }
<a href=#413 id=413 data-nosnippet>413</a> }
<a href=#414 id=414 data-nosnippet>414</a>}
</code></pre></div></section></main></body></html>
+313
View File
@@ -0,0 +1,313 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/information_extension.rs`."><title>information_extension.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/</div>information_extension.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::Arc;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>api::v1::meta::ProcedureStatus;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_meta::cluster::{ClusterInfo, NodeInfo, Role};
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::datanode::RegionStat;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_meta::key::flow::flow_state::FlowStat;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_meta::node_manager::DatanodeManagerRef;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_meta::procedure_executor::{ExecutorContext, ProcedureExecutor};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_meta::rpc::procedure;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>common_procedure::{ProcedureInfo, ProcedureState};
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>common_query::request::QueryRequest;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>common_recordbatch::adapter::{AsyncRecordBatchStreamAdapter, DfRecordBatchStreamAdapter};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>common_recordbatch::util::{ChainedRecordBatchStream, LimitedRecordBatchStream};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>common_recordbatch::{DfSendableRecordBatchStream, SendableRecordBatchStream};
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datafusion::common::Result;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>datafusion::common::tree_node::TreeNodeRecursion;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>datafusion::physical_expr::{EquivalenceProperties, Partitioning, PhysicalExpr};
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span>datafusion::physical_plan::execution_plan::{Boundedness, EmissionType};
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span>datafusion::physical_plan::{DisplayAs, DisplayFormatType, ExecutionPlan, PlanProperties};
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>datatypes::arrow::datatypes::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>datatypes::schema::SchemaRef;
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span>futures_util::future::try_join_all;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span>meta_client::MetaClientRef;
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">use </span>snafu::ResultExt;
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span>store_api::storage::RegionId;
<a href=#42 id=42 data-nosnippet>42</a>
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">use </span><span class="kw">crate</span>::error;
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::{DatanodeInspectRequest, InformationExtension};
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">pub struct </span>DistributedInformationExtension {
<a href=#47 id=47 data-nosnippet>47</a> meta_client: MetaClientRef,
<a href=#48 id=48 data-nosnippet>48</a> datanode_manager: DatanodeManagerRef,
<a href=#49 id=49 data-nosnippet>49</a>}
<a href=#50 id=50 data-nosnippet>50</a>
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">impl </span>DistributedInformationExtension {
<a href=#52 id=52 data-nosnippet>52</a> <span class="kw">pub fn </span>new(meta_client: MetaClientRef, datanode_manager: DatanodeManagerRef) -&gt; <span class="self">Self </span>{
<a href=#53 id=53 data-nosnippet>53</a> <span class="self">Self </span>{
<a href=#54 id=54 data-nosnippet>54</a> meta_client,
<a href=#55 id=55 data-nosnippet>55</a> datanode_manager,
<a href=#56 id=56 data-nosnippet>56</a> }
<a href=#57 id=57 data-nosnippet>57</a> }
<a href=#58 id=58 data-nosnippet>58</a>
<a href=#59 id=59 data-nosnippet>59</a> <span class="kw">async fn </span>inspect_datanode_stream(
<a href=#60 id=60 data-nosnippet>60</a> meta_client: MetaClientRef,
<a href=#61 id=61 data-nosnippet>61</a> datanode_manager: DatanodeManagerRef,
<a href=#62 id=62 data-nosnippet>62</a> request: DatanodeInspectRequest,
<a href=#63 id=63 data-nosnippet>63</a> ) -&gt; std::result::Result&lt;SendableRecordBatchStream, <span class="kw">crate</span>::error::Error&gt; {
<a href=#64 id=64 data-nosnippet>64</a> <span class="kw">let </span>nodes = meta_client
<a href=#65 id=65 data-nosnippet>65</a> .list_nodes(<span class="prelude-val">Some</span>(Role::Datanode))
<a href=#66 id=66 data-nosnippet>66</a> .<span class="kw">await
<a href=#67 id=67 data-nosnippet>67</a> </span>.map_err(BoxedError::new)
<a href=#68 id=68 data-nosnippet>68</a> .context(<span class="kw">crate</span>::error::ListNodesSnafu)<span class="question-mark">?</span>;
<a href=#69 id=69 data-nosnippet>69</a>
<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">let </span>limit = request.scan.limit;
<a href=#71 id=71 data-nosnippet>71</a> <span class="kw">let </span>plan = request
<a href=#72 id=72 data-nosnippet>72</a> .build_plan()
<a href=#73 id=73 data-nosnippet>73</a> .context(<span class="kw">crate</span>::error::DatafusionSnafu)<span class="question-mark">?</span>;
<a href=#74 id=74 data-nosnippet>74</a>
<a href=#75 id=75 data-nosnippet>75</a> <span class="kw">let </span>streams = try_join_all(nodes.into_iter().map(|node| {
<a href=#76 id=76 data-nosnippet>76</a> <span class="kw">let </span>datanode_manager = datanode_manager.clone();
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">let </span>plan = plan.clone();
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">async move </span>{
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw">let </span>client = datanode_manager.datanode(<span class="kw-2">&amp;</span>node.peer).<span class="kw">await</span>;
<a href=#80 id=80 data-nosnippet>80</a> client
<a href=#81 id=81 data-nosnippet>81</a> .handle_query(QueryRequest {
<a href=#82 id=82 data-nosnippet>82</a> plan,
<a href=#83 id=83 data-nosnippet>83</a> region_id: RegionId::default(),
<a href=#84 id=84 data-nosnippet>84</a> header: <span class="prelude-val">None</span>,
<a href=#85 id=85 data-nosnippet>85</a> })
<a href=#86 id=86 data-nosnippet>86</a> .<span class="kw">await
<a href=#87 id=87 data-nosnippet>87</a> </span>.context(<span class="kw">crate</span>::error::HandleQuerySnafu)
<a href=#88 id=88 data-nosnippet>88</a> }
<a href=#89 id=89 data-nosnippet>89</a> }))
<a href=#90 id=90 data-nosnippet>90</a> .<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#91 id=91 data-nosnippet>91</a>
<a href=#92 id=92 data-nosnippet>92</a> <span class="kw">let </span>chained =
<a href=#93 id=93 data-nosnippet>93</a> ChainedRecordBatchStream::new(streams).context(<span class="kw">crate</span>::error::CreateRecordBatchSnafu)<span class="question-mark">?</span>;
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">match </span>limit {
<a href=#95 id=95 data-nosnippet>95</a> <span class="prelude-val">Some</span>(limit) =&gt; <span class="prelude-val">Ok</span>(Box::pin(LimitedRecordBatchStream::new(
<a href=#96 id=96 data-nosnippet>96</a> Box::pin(chained),
<a href=#97 id=97 data-nosnippet>97</a> limit,
<a href=#98 id=98 data-nosnippet>98</a> ))),
<a href=#99 id=99 data-nosnippet>99</a> <span class="prelude-val">None </span>=&gt; <span class="prelude-val">Ok</span>(Box::pin(chained)),
<a href=#100 id=100 data-nosnippet>100</a> }
<a href=#101 id=101 data-nosnippet>101</a> }
<a href=#102 id=102 data-nosnippet>102</a>}
<a href=#103 id=103 data-nosnippet>103</a>
<a href=#104 id=104 data-nosnippet>104</a><span class="kw">struct </span>DistributedInspectExec {
<a href=#105 id=105 data-nosnippet>105</a> request: DatanodeInspectRequest,
<a href=#106 id=106 data-nosnippet>106</a> meta_client: MetaClientRef,
<a href=#107 id=107 data-nosnippet>107</a> datanode_manager: DatanodeManagerRef,
<a href=#108 id=108 data-nosnippet>108</a> schema: SchemaRef,
<a href=#109 id=109 data-nosnippet>109</a> arrow_schema: ArrowSchemaRef,
<a href=#110 id=110 data-nosnippet>110</a> properties: Arc&lt;PlanProperties&gt;,
<a href=#111 id=111 data-nosnippet>111</a>}
<a href=#112 id=112 data-nosnippet>112</a>
<a href=#113 id=113 data-nosnippet>113</a><span class="kw">impl </span>std::fmt::Debug <span class="kw">for </span>DistributedInspectExec {
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>std::fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; std::fmt::Result {
<a href=#115 id=115 data-nosnippet>115</a> f.debug_struct(<span class="string">"DistributedInspectExec"</span>)
<a href=#116 id=116 data-nosnippet>116</a> .field(<span class="string">"request"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.request)
<a href=#117 id=117 data-nosnippet>117</a> .field(<span class="string">"schema"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.schema)
<a href=#118 id=118 data-nosnippet>118</a> .finish_non_exhaustive()
<a href=#119 id=119 data-nosnippet>119</a> }
<a href=#120 id=120 data-nosnippet>120</a>}
<a href=#121 id=121 data-nosnippet>121</a>
<a href=#122 id=122 data-nosnippet>122</a><span class="kw">impl </span>DistributedInspectExec {
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">fn </span>new(
<a href=#124 id=124 data-nosnippet>124</a> request: DatanodeInspectRequest,
<a href=#125 id=125 data-nosnippet>125</a> schema: SchemaRef,
<a href=#126 id=126 data-nosnippet>126</a> meta_client: MetaClientRef,
<a href=#127 id=127 data-nosnippet>127</a> datanode_manager: DatanodeManagerRef,
<a href=#128 id=128 data-nosnippet>128</a> ) -&gt; <span class="self">Self </span>{
<a href=#129 id=129 data-nosnippet>129</a> <span class="kw">let </span>arrow_schema = schema.arrow_schema().clone();
<a href=#130 id=130 data-nosnippet>130</a> <span class="kw">let </span>properties = Arc::new(PlanProperties::new(
<a href=#131 id=131 data-nosnippet>131</a> EquivalenceProperties::new(arrow_schema.clone()),
<a href=#132 id=132 data-nosnippet>132</a> Partitioning::UnknownPartitioning(<span class="number">1</span>),
<a href=#133 id=133 data-nosnippet>133</a> EmissionType::Incremental,
<a href=#134 id=134 data-nosnippet>134</a> Boundedness::Bounded,
<a href=#135 id=135 data-nosnippet>135</a> ));
<a href=#136 id=136 data-nosnippet>136</a> <span class="self">Self </span>{
<a href=#137 id=137 data-nosnippet>137</a> request,
<a href=#138 id=138 data-nosnippet>138</a> meta_client,
<a href=#139 id=139 data-nosnippet>139</a> datanode_manager,
<a href=#140 id=140 data-nosnippet>140</a> schema,
<a href=#141 id=141 data-nosnippet>141</a> arrow_schema,
<a href=#142 id=142 data-nosnippet>142</a> properties,
<a href=#143 id=143 data-nosnippet>143</a> }
<a href=#144 id=144 data-nosnippet>144</a> }
<a href=#145 id=145 data-nosnippet>145</a>}
<a href=#146 id=146 data-nosnippet>146</a>
<a href=#147 id=147 data-nosnippet>147</a><span class="kw">impl </span>DisplayAs <span class="kw">for </span>DistributedInspectExec {
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">fn </span>fmt_as(<span class="kw-2">&amp;</span><span class="self">self</span>, _t: DisplayFormatType, f: <span class="kw-2">&amp;mut </span>std::fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; std::fmt::Result {
<a href=#149 id=149 data-nosnippet>149</a> <span class="macro">write!</span>(
<a href=#150 id=150 data-nosnippet>150</a> f,
<a href=#151 id=151 data-nosnippet>151</a> <span class="string">"DistributedInspectExec: kind={:?}, scan={}, schema={:?}"</span>,
<a href=#152 id=152 data-nosnippet>152</a> <span class="self">self</span>.request.kind, <span class="self">self</span>.request.scan, <span class="self">self</span>.arrow_schema
<a href=#153 id=153 data-nosnippet>153</a> )
<a href=#154 id=154 data-nosnippet>154</a> }
<a href=#155 id=155 data-nosnippet>155</a>}
<a href=#156 id=156 data-nosnippet>156</a>
<a href=#157 id=157 data-nosnippet>157</a><span class="kw">impl </span>ExecutionPlan <span class="kw">for </span>DistributedInspectExec {
<a href=#158 id=158 data-nosnippet>158</a> <span class="kw">fn </span>name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#159 id=159 data-nosnippet>159</a> <span class="string">"DistributedInspectExec"
<a href=#160 id=160 data-nosnippet>160</a> </span>}
<a href=#161 id=161 data-nosnippet>161</a>
<a href=#162 id=162 data-nosnippet>162</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; ArrowSchemaRef {
<a href=#163 id=163 data-nosnippet>163</a> <span class="self">self</span>.arrow_schema.clone()
<a href=#164 id=164 data-nosnippet>164</a> }
<a href=#165 id=165 data-nosnippet>165</a>
<a href=#166 id=166 data-nosnippet>166</a> <span class="kw">fn </span>properties(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>Arc&lt;PlanProperties&gt; {
<a href=#167 id=167 data-nosnippet>167</a> <span class="kw-2">&amp;</span><span class="self">self</span>.properties
<a href=#168 id=168 data-nosnippet>168</a> }
<a href=#169 id=169 data-nosnippet>169</a>
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw">fn </span>children(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Vec&lt;<span class="kw-2">&amp;</span>Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt; {
<a href=#171 id=171 data-nosnippet>171</a> <span class="macro">vec!</span>[]
<a href=#172 id=172 data-nosnippet>172</a> }
<a href=#173 id=173 data-nosnippet>173</a>
<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">fn </span>apply_expressions(
<a href=#175 id=175 data-nosnippet>175</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#176 id=176 data-nosnippet>176</a> _f: <span class="kw-2">&amp;mut </span><span class="kw">dyn </span>FnMut(<span class="kw-2">&amp;</span>Arc&lt;<span class="kw">dyn </span>PhysicalExpr&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;TreeNodeRecursion&gt;,
<a href=#177 id=177 data-nosnippet>177</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;TreeNodeRecursion&gt; {
<a href=#178 id=178 data-nosnippet>178</a> <span class="prelude-val">Ok</span>(TreeNodeRecursion::Continue)
<a href=#179 id=179 data-nosnippet>179</a> }
<a href=#180 id=180 data-nosnippet>180</a>
<a href=#181 id=181 data-nosnippet>181</a> <span class="kw">fn </span>with_new_children(
<a href=#182 id=182 data-nosnippet>182</a> <span class="self">self</span>: Arc&lt;<span class="self">Self</span>&gt;,
<a href=#183 id=183 data-nosnippet>183</a> children: Vec&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;,
<a href=#184 id=184 data-nosnippet>184</a> ) -&gt; datafusion::error::Result&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt; {
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">if </span>children.is_empty() {
<a href=#186 id=186 data-nosnippet>186</a> <span class="prelude-val">Ok</span>(<span class="self">self</span>)
<a href=#187 id=187 data-nosnippet>187</a> } <span class="kw">else </span>{
<a href=#188 id=188 data-nosnippet>188</a> <span class="prelude-val">Err</span>(datafusion::error::DataFusionError::Internal(
<a href=#189 id=189 data-nosnippet>189</a> <span class="string">"DistributedInspectExec is a leaf execution plan and cannot accept children"
<a href=#190 id=190 data-nosnippet>190</a> </span>.to_string(),
<a href=#191 id=191 data-nosnippet>191</a> ))
<a href=#192 id=192 data-nosnippet>192</a> }
<a href=#193 id=193 data-nosnippet>193</a> }
<a href=#194 id=194 data-nosnippet>194</a>
<a href=#195 id=195 data-nosnippet>195</a> <span class="kw">fn </span>execute(
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#197 id=197 data-nosnippet>197</a> partition: usize,
<a href=#198 id=198 data-nosnippet>198</a> _context: Arc&lt;TaskContext&gt;,
<a href=#199 id=199 data-nosnippet>199</a> ) -&gt; datafusion::error::Result&lt;DfSendableRecordBatchStream&gt; {
<a href=#200 id=200 data-nosnippet>200</a> <span class="kw">if </span>partition != <span class="number">0 </span>{
<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">return </span><span class="prelude-val">Err</span>(datafusion::error::DataFusionError::Execution(<span class="macro">format!</span>(
<a href=#202 id=202 data-nosnippet>202</a> <span class="string">"DistributedInspectExec invalid partition. Expected 0, got {partition}"
<a href=#203 id=203 data-nosnippet>203</a> </span>)));
<a href=#204 id=204 data-nosnippet>204</a> }
<a href=#205 id=205 data-nosnippet>205</a>
<a href=#206 id=206 data-nosnippet>206</a> <span class="kw">let </span>meta_client = <span class="self">self</span>.meta_client.clone();
<a href=#207 id=207 data-nosnippet>207</a> <span class="kw">let </span>datanode_manager = <span class="self">self</span>.datanode_manager.clone();
<a href=#208 id=208 data-nosnippet>208</a> <span class="kw">let </span>request = <span class="self">self</span>.request.clone();
<a href=#209 id=209 data-nosnippet>209</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.clone();
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">let </span>future = <span class="kw">async move </span>{
<a href=#211 id=211 data-nosnippet>211</a> DistributedInformationExtension::inspect_datanode_stream(
<a href=#212 id=212 data-nosnippet>212</a> meta_client,
<a href=#213 id=213 data-nosnippet>213</a> datanode_manager,
<a href=#214 id=214 data-nosnippet>214</a> request,
<a href=#215 id=215 data-nosnippet>215</a> )
<a href=#216 id=216 data-nosnippet>216</a> .<span class="kw">await
<a href=#217 id=217 data-nosnippet>217</a> </span>.map_err(BoxedError::new)
<a href=#218 id=218 data-nosnippet>218</a> .context(common_recordbatch::error::ExternalSnafu)
<a href=#219 id=219 data-nosnippet>219</a> };
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">let </span>stream = AsyncRecordBatchStreamAdapter::new(schema, Box::pin(future));
<a href=#221 id=221 data-nosnippet>221</a> <span class="prelude-val">Ok</span>(Box::pin(DfRecordBatchStreamAdapter::new(Box::pin(stream))))
<a href=#222 id=222 data-nosnippet>222</a> }
<a href=#223 id=223 data-nosnippet>223</a>}
<a href=#224 id=224 data-nosnippet>224</a>
<a href=#225 id=225 data-nosnippet>225</a><span class="attr">#[async_trait::async_trait]
<a href=#226 id=226 data-nosnippet>226</a></span><span class="kw">impl </span>InformationExtension <span class="kw">for </span>DistributedInformationExtension {
<a href=#227 id=227 data-nosnippet>227</a> <span class="kw">type </span>Error = <span class="kw">crate</span>::error::Error;
<a href=#228 id=228 data-nosnippet>228</a>
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">async fn </span>nodes(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Vec&lt;NodeInfo&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#230 id=230 data-nosnippet>230</a> <span class="self">self</span>.meta_client
<a href=#231 id=231 data-nosnippet>231</a> .list_nodes(<span class="prelude-val">None</span>)
<a href=#232 id=232 data-nosnippet>232</a> .<span class="kw">await
<a href=#233 id=233 data-nosnippet>233</a> </span>.map_err(BoxedError::new)
<a href=#234 id=234 data-nosnippet>234</a> .context(error::ListNodesSnafu)
<a href=#235 id=235 data-nosnippet>235</a> }
<a href=#236 id=236 data-nosnippet>236</a>
<a href=#237 id=237 data-nosnippet>237</a> <span class="kw">async fn </span>procedures(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Vec&lt;(String, ProcedureInfo)&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#238 id=238 data-nosnippet>238</a> <span class="kw">let </span>procedures = <span class="self">self
<a href=#239 id=239 data-nosnippet>239</a> </span>.meta_client
<a href=#240 id=240 data-nosnippet>240</a> .list_procedures(<span class="kw-2">&amp;</span>ExecutorContext::default())
<a href=#241 id=241 data-nosnippet>241</a> .<span class="kw">await
<a href=#242 id=242 data-nosnippet>242</a> </span>.map_err(BoxedError::new)
<a href=#243 id=243 data-nosnippet>243</a> .context(error::ListProceduresSnafu)<span class="question-mark">?
<a href=#244 id=244 data-nosnippet>244</a> </span>.procedures;
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw">let </span><span class="kw-2">mut </span>result = Vec::with_capacity(procedures.len());
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">for </span>procedure <span class="kw">in </span>procedures {
<a href=#247 id=247 data-nosnippet>247</a> <span class="kw">let </span>pid = <span class="kw">match </span>procedure.id {
<a href=#248 id=248 data-nosnippet>248</a> <span class="prelude-val">Some</span>(pid) =&gt; pid,
<a href=#249 id=249 data-nosnippet>249</a> <span class="prelude-val">None </span>=&gt; <span class="kw">return </span>error::ProcedureIdNotFoundSnafu {}.fail(),
<a href=#250 id=250 data-nosnippet>250</a> };
<a href=#251 id=251 data-nosnippet>251</a> <span class="kw">let </span>pid = procedure::pb_pid_to_pid(<span class="kw-2">&amp;</span>pid)
<a href=#252 id=252 data-nosnippet>252</a> .map_err(BoxedError::new)
<a href=#253 id=253 data-nosnippet>253</a> .context(error::ConvertProtoDataSnafu)<span class="question-mark">?</span>;
<a href=#254 id=254 data-nosnippet>254</a> <span class="kw">let </span>status = ProcedureStatus::try_from(procedure.status)
<a href=#255 id=255 data-nosnippet>255</a> .map(|v| v.as_str_name())
<a href=#256 id=256 data-nosnippet>256</a> .unwrap_or(<span class="string">"Unknown"</span>)
<a href=#257 id=257 data-nosnippet>257</a> .to_string();
<a href=#258 id=258 data-nosnippet>258</a> <span class="kw">let </span>procedure_info = ProcedureInfo {
<a href=#259 id=259 data-nosnippet>259</a> id: pid,
<a href=#260 id=260 data-nosnippet>260</a> type_name: procedure.type_name,
<a href=#261 id=261 data-nosnippet>261</a> start_time_ms: procedure.start_time_ms,
<a href=#262 id=262 data-nosnippet>262</a> end_time_ms: procedure.end_time_ms,
<a href=#263 id=263 data-nosnippet>263</a> state: ProcedureState::Running,
<a href=#264 id=264 data-nosnippet>264</a> lock_keys: procedure.lock_keys,
<a href=#265 id=265 data-nosnippet>265</a> };
<a href=#266 id=266 data-nosnippet>266</a> result.push((status, procedure_info));
<a href=#267 id=267 data-nosnippet>267</a> }
<a href=#268 id=268 data-nosnippet>268</a>
<a href=#269 id=269 data-nosnippet>269</a> <span class="prelude-val">Ok</span>(result)
<a href=#270 id=270 data-nosnippet>270</a> }
<a href=#271 id=271 data-nosnippet>271</a>
<a href=#272 id=272 data-nosnippet>272</a> <span class="kw">async fn </span>region_stats(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Vec&lt;RegionStat&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#273 id=273 data-nosnippet>273</a> <span class="self">self</span>.meta_client
<a href=#274 id=274 data-nosnippet>274</a> .list_region_stats()
<a href=#275 id=275 data-nosnippet>275</a> .<span class="kw">await
<a href=#276 id=276 data-nosnippet>276</a> </span>.map_err(BoxedError::new)
<a href=#277 id=277 data-nosnippet>277</a> .context(error::ListRegionStatsSnafu)
<a href=#278 id=278 data-nosnippet>278</a> }
<a href=#279 id=279 data-nosnippet>279</a>
<a href=#280 id=280 data-nosnippet>280</a> <span class="kw">async fn </span>flow_stats(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;FlowStat&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#281 id=281 data-nosnippet>281</a> <span class="self">self</span>.meta_client
<a href=#282 id=282 data-nosnippet>282</a> .list_flow_stats()
<a href=#283 id=283 data-nosnippet>283</a> .<span class="kw">await
<a href=#284 id=284 data-nosnippet>284</a> </span>.map_err(BoxedError::new)
<a href=#285 id=285 data-nosnippet>285</a> .context(<span class="kw">crate</span>::error::ListFlowStatsSnafu)
<a href=#286 id=286 data-nosnippet>286</a> }
<a href=#287 id=287 data-nosnippet>287</a>
<a href=#288 id=288 data-nosnippet>288</a> <span class="kw">async fn </span>inspect_datanode(
<a href=#289 id=289 data-nosnippet>289</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#290 id=290 data-nosnippet>290</a> request: DatanodeInspectRequest,
<a href=#291 id=291 data-nosnippet>291</a> ) -&gt; std::result::Result&lt;SendableRecordBatchStream, <span class="self">Self</span>::Error&gt; {
<a href=#292 id=292 data-nosnippet>292</a> <span class="self">Self</span>::inspect_datanode_stream(
<a href=#293 id=293 data-nosnippet>293</a> <span class="self">self</span>.meta_client.clone(),
<a href=#294 id=294 data-nosnippet>294</a> <span class="self">self</span>.datanode_manager.clone(),
<a href=#295 id=295 data-nosnippet>295</a> request,
<a href=#296 id=296 data-nosnippet>296</a> )
<a href=#297 id=297 data-nosnippet>297</a> .<span class="kw">await
<a href=#298 id=298 data-nosnippet>298</a> </span>}
<a href=#299 id=299 data-nosnippet>299</a>
<a href=#300 id=300 data-nosnippet>300</a> <span class="kw">fn </span>inspect_datanode_plan(
<a href=#301 id=301 data-nosnippet>301</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#302 id=302 data-nosnippet>302</a> request: DatanodeInspectRequest,
<a href=#303 id=303 data-nosnippet>303</a> schema: SchemaRef,
<a href=#304 id=304 data-nosnippet>304</a> ) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#305 id=305 data-nosnippet>305</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Arc::new(DistributedInspectExec::new(
<a href=#306 id=306 data-nosnippet>306</a> request,
<a href=#307 id=307 data-nosnippet>307</a> schema,
<a href=#308 id=308 data-nosnippet>308</a> <span class="self">self</span>.meta_client.clone(),
<a href=#309 id=309 data-nosnippet>309</a> <span class="self">self</span>.datanode_manager.clone(),
<a href=#310 id=310 data-nosnippet>310</a> ))))
<a href=#311 id=311 data-nosnippet>311</a> }
<a href=#312 id=312 data-nosnippet>312</a>}
</code></pre></div></section></main></body></html>
+26
View File
@@ -0,0 +1,26 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/kvbackend.rs`."><title>kvbackend.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/</div>kvbackend.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">mod </span>builder;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">mod </span>client;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">mod </span>manager;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">mod </span>table_cache;
<a href=#19 id=19 data-nosnippet>19</a>
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">pub use </span>builder::{
<a href=#21 id=21 data-nosnippet>21</a> CatalogManagerConfigurator, CatalogManagerConfiguratorRef, KvBackendCatalogManagerBuilder,
<a href=#22 id=22 data-nosnippet>22</a>};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">pub use </span>client::{CachedKvBackend, CachedKvBackendBuilder, new_read_only_meta_kv_backend};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">pub use </span>manager::KvBackendCatalogManager;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">pub use </span>table_cache::{TableCache, TableCacheRef, new_table_cache};
</code></pre></div></section></main></body></html>
+145
View File
@@ -0,0 +1,145 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/kvbackend/builder.rs`."><title>builder.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/kvbackend/</div>builder.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::collections::HashMap;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::sync::Arc;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_catalog::consts::DEFAULT_CATALOG_NAME;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::cache::LayeredCacheRegistryRef;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_meta::key::TableMetadataManager;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_meta::key::flow::FlowMetadataManager;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_meta::kv_backend::KvBackendRef;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_procedure::ProcedureManagerRef;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>moka::sync::Cache;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>partition::manager::PartitionRuleManager;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::{
<a href=#29 id=29 data-nosnippet>29</a> InformationExtensionRef, InformationSchemaProvider, InformationSchemaTableFactoryRef,
<a href=#30 id=30 data-nosnippet>30</a>};
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span><span class="kw">crate</span>::kvbackend::KvBackendCatalogManager;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span><span class="kw">crate</span>::kvbackend::manager::{CATALOG_CACHE_MAX_CAPACITY, SystemCatalog};
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span><span class="kw">crate</span>::process_manager::ProcessManagerRef;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::numbers_table_provider::NumbersTableProvider;
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::pg_catalog::PGCatalogProvider;
<a href=#36 id=36 data-nosnippet>36</a>
<a href=#37 id=37 data-nosnippet>37</a><span class="doccomment">/// The configurator that customizes or enhances the [`KvBackendCatalogManagerBuilder`].
<a href=#38 id=38 data-nosnippet>38</a></span><span class="attr">#[async_trait::async_trait]
<a href=#39 id=39 data-nosnippet>39</a></span><span class="kw">pub trait </span>CatalogManagerConfigurator&lt;C&gt;: Send + Sync {
<a href=#40 id=40 data-nosnippet>40</a> <span class="kw">async fn </span>configure(
<a href=#41 id=41 data-nosnippet>41</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#42 id=42 data-nosnippet>42</a> builder: KvBackendCatalogManagerBuilder,
<a href=#43 id=43 data-nosnippet>43</a> ctx: C,
<a href=#44 id=44 data-nosnippet>44</a> ) -&gt; std::result::Result&lt;KvBackendCatalogManagerBuilder, BoxedError&gt;;
<a href=#45 id=45 data-nosnippet>45</a>}
<a href=#46 id=46 data-nosnippet>46</a>
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">pub type </span>CatalogManagerConfiguratorRef&lt;C&gt; = Arc&lt;<span class="kw">dyn </span>CatalogManagerConfigurator&lt;C&gt;&gt;;
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">pub struct </span>KvBackendCatalogManagerBuilder {
<a href=#50 id=50 data-nosnippet>50</a> information_extension: InformationExtensionRef,
<a href=#51 id=51 data-nosnippet>51</a> backend: KvBackendRef,
<a href=#52 id=52 data-nosnippet>52</a> cache_registry: LayeredCacheRegistryRef,
<a href=#53 id=53 data-nosnippet>53</a> procedure_manager: <span class="prelude-ty">Option</span>&lt;ProcedureManagerRef&gt;,
<a href=#54 id=54 data-nosnippet>54</a> process_manager: <span class="prelude-ty">Option</span>&lt;ProcessManagerRef&gt;,
<a href=#55 id=55 data-nosnippet>55</a> extra_information_table_factories: HashMap&lt;String, InformationSchemaTableFactoryRef&gt;,
<a href=#56 id=56 data-nosnippet>56</a>}
<a href=#57 id=57 data-nosnippet>57</a>
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">impl </span>KvBackendCatalogManagerBuilder {
<a href=#59 id=59 data-nosnippet>59</a> <span class="kw">pub fn </span>new(
<a href=#60 id=60 data-nosnippet>60</a> information_extension: InformationExtensionRef,
<a href=#61 id=61 data-nosnippet>61</a> backend: KvBackendRef,
<a href=#62 id=62 data-nosnippet>62</a> cache_registry: LayeredCacheRegistryRef,
<a href=#63 id=63 data-nosnippet>63</a> ) -&gt; <span class="self">Self </span>{
<a href=#64 id=64 data-nosnippet>64</a> <span class="self">Self </span>{
<a href=#65 id=65 data-nosnippet>65</a> information_extension,
<a href=#66 id=66 data-nosnippet>66</a> backend,
<a href=#67 id=67 data-nosnippet>67</a> cache_registry,
<a href=#68 id=68 data-nosnippet>68</a> procedure_manager: <span class="prelude-val">None</span>,
<a href=#69 id=69 data-nosnippet>69</a> process_manager: <span class="prelude-val">None</span>,
<a href=#70 id=70 data-nosnippet>70</a> extra_information_table_factories: HashMap::new(),
<a href=#71 id=71 data-nosnippet>71</a> }
<a href=#72 id=72 data-nosnippet>72</a> }
<a href=#73 id=73 data-nosnippet>73</a>
<a href=#74 id=74 data-nosnippet>74</a> <span class="kw">pub fn </span>with_procedure_manager(<span class="kw-2">mut </span><span class="self">self</span>, procedure_manager: ProcedureManagerRef) -&gt; <span class="self">Self </span>{
<a href=#75 id=75 data-nosnippet>75</a> <span class="self">self</span>.procedure_manager = <span class="prelude-val">Some</span>(procedure_manager);
<a href=#76 id=76 data-nosnippet>76</a> <span class="self">self
<a href=#77 id=77 data-nosnippet>77</a> </span>}
<a href=#78 id=78 data-nosnippet>78</a>
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw">pub fn </span>with_process_manager(<span class="kw-2">mut </span><span class="self">self</span>, process_manager: ProcessManagerRef) -&gt; <span class="self">Self </span>{
<a href=#80 id=80 data-nosnippet>80</a> <span class="self">self</span>.process_manager = <span class="prelude-val">Some</span>(process_manager);
<a href=#81 id=81 data-nosnippet>81</a> <span class="self">self
<a href=#82 id=82 data-nosnippet>82</a> </span>}
<a href=#83 id=83 data-nosnippet>83</a>
<a href=#84 id=84 data-nosnippet>84</a> <span class="doccomment">/// Sets the extra information tables.
<a href=#85 id=85 data-nosnippet>85</a> </span><span class="kw">pub fn </span>with_extra_information_table_factories(
<a href=#86 id=86 data-nosnippet>86</a> <span class="kw-2">mut </span><span class="self">self</span>,
<a href=#87 id=87 data-nosnippet>87</a> factories: HashMap&lt;String, InformationSchemaTableFactoryRef&gt;,
<a href=#88 id=88 data-nosnippet>88</a> ) -&gt; <span class="self">Self </span>{
<a href=#89 id=89 data-nosnippet>89</a> <span class="self">self</span>.extra_information_table_factories = factories;
<a href=#90 id=90 data-nosnippet>90</a> <span class="self">self
<a href=#91 id=91 data-nosnippet>91</a> </span>}
<a href=#92 id=92 data-nosnippet>92</a>
<a href=#93 id=93 data-nosnippet>93</a> <span class="kw">pub fn </span>build(<span class="self">self</span>) -&gt; Arc&lt;KvBackendCatalogManager&gt; {
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">let </span><span class="self">Self </span>{
<a href=#95 id=95 data-nosnippet>95</a> information_extension,
<a href=#96 id=96 data-nosnippet>96</a> backend,
<a href=#97 id=97 data-nosnippet>97</a> cache_registry,
<a href=#98 id=98 data-nosnippet>98</a> procedure_manager,
<a href=#99 id=99 data-nosnippet>99</a> process_manager,
<a href=#100 id=100 data-nosnippet>100</a> extra_information_table_factories,
<a href=#101 id=101 data-nosnippet>101</a> } = <span class="self">self</span>;
<a href=#102 id=102 data-nosnippet>102</a> Arc::new_cyclic(|me| KvBackendCatalogManager {
<a href=#103 id=103 data-nosnippet>103</a> information_extension,
<a href=#104 id=104 data-nosnippet>104</a> entity_graph_provider: Arc::new(std::sync::OnceLock::new()),
<a href=#105 id=105 data-nosnippet>105</a> partition_manager: Arc::new(PartitionRuleManager::new(
<a href=#106 id=106 data-nosnippet>106</a> backend.clone(),
<a href=#107 id=107 data-nosnippet>107</a> cache_registry
<a href=#108 id=108 data-nosnippet>108</a> .get()
<a href=#109 id=109 data-nosnippet>109</a> .expect(<span class="string">"Failed to get table_route_cache"</span>),
<a href=#110 id=110 data-nosnippet>110</a> cache_registry
<a href=#111 id=111 data-nosnippet>111</a> .get()
<a href=#112 id=112 data-nosnippet>112</a> .expect(<span class="string">"Failed to get partition_info_cache"</span>),
<a href=#113 id=113 data-nosnippet>113</a> )),
<a href=#114 id=114 data-nosnippet>114</a> table_metadata_manager: Arc::new(TableMetadataManager::new(backend.clone())),
<a href=#115 id=115 data-nosnippet>115</a> system_catalog: SystemCatalog {
<a href=#116 id=116 data-nosnippet>116</a> catalog_manager: me.clone(),
<a href=#117 id=117 data-nosnippet>117</a> catalog_cache: Cache::new(CATALOG_CACHE_MAX_CAPACITY),
<a href=#118 id=118 data-nosnippet>118</a> pg_catalog_cache: Cache::new(CATALOG_CACHE_MAX_CAPACITY),
<a href=#119 id=119 data-nosnippet>119</a> information_schema_provider: {
<a href=#120 id=120 data-nosnippet>120</a> <span class="kw">let </span>provider = InformationSchemaProvider::new(
<a href=#121 id=121 data-nosnippet>121</a> DEFAULT_CATALOG_NAME.to_string(),
<a href=#122 id=122 data-nosnippet>122</a> me.clone(),
<a href=#123 id=123 data-nosnippet>123</a> Arc::new(FlowMetadataManager::new(backend.clone())),
<a href=#124 id=124 data-nosnippet>124</a> process_manager.clone(),
<a href=#125 id=125 data-nosnippet>125</a> backend.clone(),
<a href=#126 id=126 data-nosnippet>126</a> );
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw">let </span>provider = provider
<a href=#128 id=128 data-nosnippet>128</a> .with_extra_table_factories(extra_information_table_factories.clone());
<a href=#129 id=129 data-nosnippet>129</a> Arc::new(provider)
<a href=#130 id=130 data-nosnippet>130</a> },
<a href=#131 id=131 data-nosnippet>131</a> pg_catalog_provider: Arc::new(PGCatalogProvider::new(
<a href=#132 id=132 data-nosnippet>132</a> DEFAULT_CATALOG_NAME.to_string(),
<a href=#133 id=133 data-nosnippet>133</a> me.clone(),
<a href=#134 id=134 data-nosnippet>134</a> )),
<a href=#135 id=135 data-nosnippet>135</a> numbers_table_provider: NumbersTableProvider,
<a href=#136 id=136 data-nosnippet>136</a> backend,
<a href=#137 id=137 data-nosnippet>137</a> process_manager,
<a href=#138 id=138 data-nosnippet>138</a> extra_information_table_factories,
<a href=#139 id=139 data-nosnippet>139</a> },
<a href=#140 id=140 data-nosnippet>140</a> cache_registry,
<a href=#141 id=141 data-nosnippet>141</a> procedure_manager,
<a href=#142 id=142 data-nosnippet>142</a> })
<a href=#143 id=143 data-nosnippet>143</a> }
<a href=#144 id=144 data-nosnippet>144</a>}
</code></pre></div></section></main></body></html>
+714
View File
@@ -0,0 +1,714 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/kvbackend/client.rs`."><title>client.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/kvbackend/</div>client.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::any::Any;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::fmt::Debug;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>std::sync::atomic::{AtomicUsize, Ordering};
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>std::sync::{Arc, Mutex};
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>std::time::Duration;
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_meta::cache_invalidator::KvCacheInvalidator;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_meta::error::Error::CacheNotGet;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_meta::error::{
<a href=#25 id=25 data-nosnippet>25</a> CacheNotGetSnafu, Error, ExternalSnafu, GetKvCacheSnafu, <span class="prelude-ty">Result</span>, UnsupportedSnafu,
<a href=#26 id=26 data-nosnippet>26</a>};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>common_meta::kv_backend::read_only::ReadOnlyKvBackend;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>common_meta::kv_backend::txn::{Txn, TxnResponse};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>common_meta::kv_backend::{KvBackend, KvBackendRef, TxnService};
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>common_meta::rpc::KeyValue;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>common_meta::rpc::store::{
<a href=#32 id=32 data-nosnippet>32</a> BatchDeleteRequest, BatchDeleteResponse, BatchGetRequest, BatchGetResponse, BatchPutRequest,
<a href=#33 id=33 data-nosnippet>33</a> BatchPutResponse, CompareAndPutRequest, CompareAndPutResponse, DeleteRangeRequest,
<a href=#34 id=34 data-nosnippet>34</a> DeleteRangeResponse, PutRequest, PutResponse, RangeRequest, RangeResponse,
<a href=#35 id=35 data-nosnippet>35</a>};
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>common_telemetry::debug;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>meta_client::client::MetaClient;
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span>moka::future::{Cache, CacheBuilder};
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span>snafu::{OptionExt, ResultExt};
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span><span class="kw">crate</span>::metrics::{
<a href=#42 id=42 data-nosnippet>42</a> METRIC_CATALOG_KV_BATCH_GET, METRIC_CATALOG_KV_GET, METRIC_CATALOG_KV_REMOTE_GET,
<a href=#43 id=43 data-nosnippet>43</a>};
<a href=#44 id=44 data-nosnippet>44</a>
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">const </span>DEFAULT_CACHE_MAX_CAPACITY: u64 = <span class="number">10000</span>;
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">const </span>DEFAULT_CACHE_TTL: Duration = Duration::from_secs(<span class="number">10 </span>* <span class="number">60</span>);
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">const </span>DEFAULT_CACHE_TTI: Duration = Duration::from_secs(<span class="number">5 </span>* <span class="number">60</span>);
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">pub struct </span>CachedKvBackendBuilder {
<a href=#50 id=50 data-nosnippet>50</a> cache_max_capacity: <span class="prelude-ty">Option</span>&lt;u64&gt;,
<a href=#51 id=51 data-nosnippet>51</a> cache_ttl: <span class="prelude-ty">Option</span>&lt;Duration&gt;,
<a href=#52 id=52 data-nosnippet>52</a> cache_tti: <span class="prelude-ty">Option</span>&lt;Duration&gt;,
<a href=#53 id=53 data-nosnippet>53</a> inner: KvBackendRef,
<a href=#54 id=54 data-nosnippet>54</a>}
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">impl </span>CachedKvBackendBuilder {
<a href=#57 id=57 data-nosnippet>57</a> <span class="kw">pub fn </span>new(inner: KvBackendRef) -&gt; <span class="self">Self </span>{
<a href=#58 id=58 data-nosnippet>58</a> <span class="self">Self </span>{
<a href=#59 id=59 data-nosnippet>59</a> cache_max_capacity: <span class="prelude-val">None</span>,
<a href=#60 id=60 data-nosnippet>60</a> cache_ttl: <span class="prelude-val">None</span>,
<a href=#61 id=61 data-nosnippet>61</a> cache_tti: <span class="prelude-val">None</span>,
<a href=#62 id=62 data-nosnippet>62</a> inner,
<a href=#63 id=63 data-nosnippet>63</a> }
<a href=#64 id=64 data-nosnippet>64</a> }
<a href=#65 id=65 data-nosnippet>65</a>
<a href=#66 id=66 data-nosnippet>66</a> <span class="kw">pub fn </span>cache_max_capacity(<span class="kw-2">mut </span><span class="self">self</span>, cache_max_capacity: u64) -&gt; <span class="self">Self </span>{
<a href=#67 id=67 data-nosnippet>67</a> <span class="self">self</span>.cache_max_capacity.replace(cache_max_capacity);
<a href=#68 id=68 data-nosnippet>68</a> <span class="self">self
<a href=#69 id=69 data-nosnippet>69</a> </span>}
<a href=#70 id=70 data-nosnippet>70</a>
<a href=#71 id=71 data-nosnippet>71</a> <span class="kw">pub fn </span>cache_ttl(<span class="kw-2">mut </span><span class="self">self</span>, cache_ttl: Duration) -&gt; <span class="self">Self </span>{
<a href=#72 id=72 data-nosnippet>72</a> <span class="self">self</span>.cache_ttl.replace(cache_ttl);
<a href=#73 id=73 data-nosnippet>73</a> <span class="self">self
<a href=#74 id=74 data-nosnippet>74</a> </span>}
<a href=#75 id=75 data-nosnippet>75</a>
<a href=#76 id=76 data-nosnippet>76</a> <span class="kw">pub fn </span>cache_tti(<span class="kw-2">mut </span><span class="self">self</span>, cache_tti: Duration) -&gt; <span class="self">Self </span>{
<a href=#77 id=77 data-nosnippet>77</a> <span class="self">self</span>.cache_tti.replace(cache_tti);
<a href=#78 id=78 data-nosnippet>78</a> <span class="self">self
<a href=#79 id=79 data-nosnippet>79</a> </span>}
<a href=#80 id=80 data-nosnippet>80</a>
<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">pub fn </span>build(<span class="self">self</span>) -&gt; CachedKvBackend {
<a href=#82 id=82 data-nosnippet>82</a> <span class="kw">let </span>cache_max_capacity = <span class="self">self
<a href=#83 id=83 data-nosnippet>83</a> </span>.cache_max_capacity
<a href=#84 id=84 data-nosnippet>84</a> .unwrap_or(DEFAULT_CACHE_MAX_CAPACITY);
<a href=#85 id=85 data-nosnippet>85</a> <span class="kw">let </span>cache_ttl = <span class="self">self</span>.cache_ttl.unwrap_or(DEFAULT_CACHE_TTL);
<a href=#86 id=86 data-nosnippet>86</a> <span class="kw">let </span>cache_tti = <span class="self">self</span>.cache_tti.unwrap_or(DEFAULT_CACHE_TTI);
<a href=#87 id=87 data-nosnippet>87</a>
<a href=#88 id=88 data-nosnippet>88</a> <span class="kw">let </span>cache = CacheBuilder::new(cache_max_capacity)
<a href=#89 id=89 data-nosnippet>89</a> .time_to_live(cache_ttl)
<a href=#90 id=90 data-nosnippet>90</a> .time_to_idle(cache_tti)
<a href=#91 id=91 data-nosnippet>91</a> .build();
<a href=#92 id=92 data-nosnippet>92</a> <span class="kw">let </span>kv_backend = <span class="self">self</span>.inner;
<a href=#93 id=93 data-nosnippet>93</a> <span class="kw">let </span>name = <span class="macro">format!</span>(<span class="string">"CachedKvBackend({})"</span>, kv_backend.name());
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">let </span>version = AtomicUsize::new(<span class="number">0</span>);
<a href=#95 id=95 data-nosnippet>95</a>
<a href=#96 id=96 data-nosnippet>96</a> CachedKvBackend {
<a href=#97 id=97 data-nosnippet>97</a> kv_backend,
<a href=#98 id=98 data-nosnippet>98</a> cache,
<a href=#99 id=99 data-nosnippet>99</a> name,
<a href=#100 id=100 data-nosnippet>100</a> version,
<a href=#101 id=101 data-nosnippet>101</a> }
<a href=#102 id=102 data-nosnippet>102</a> }
<a href=#103 id=103 data-nosnippet>103</a>}
<a href=#104 id=104 data-nosnippet>104</a>
<a href=#105 id=105 data-nosnippet>105</a><span class="kw">pub type </span>CacheBackend = Cache&lt;Vec&lt;u8&gt;, KeyValue&gt;;
<a href=#106 id=106 data-nosnippet>106</a>
<a href=#107 id=107 data-nosnippet>107</a><span class="doccomment">/// A wrapper of `MetaKvBackend` with cache support.
<a href=#108 id=108 data-nosnippet>108</a>///
<a href=#109 id=109 data-nosnippet>109</a>/// CachedMetaKvBackend is mainly used to read metadata information from Metasrv, and provides
<a href=#110 id=110 data-nosnippet>110</a>/// cache for get and batch_get. One way to trigger cache invalidation of CachedMetaKvBackend:
<a href=#111 id=111 data-nosnippet>111</a>/// when metadata information changes, Metasrv will broadcast a metadata invalidation request.
<a href=#112 id=112 data-nosnippet>112</a>///
<a href=#113 id=113 data-nosnippet>113</a>/// Therefore, it is recommended to use CachedMetaKvBackend to only read metadata related
<a href=#114 id=114 data-nosnippet>114</a>/// information. Note: If you read other information, you may read expired data, which depends on
<a href=#115 id=115 data-nosnippet>115</a>/// TTL and TTI for cache.
<a href=#116 id=116 data-nosnippet>116</a></span><span class="kw">pub struct </span>CachedKvBackend {
<a href=#117 id=117 data-nosnippet>117</a> kv_backend: KvBackendRef,
<a href=#118 id=118 data-nosnippet>118</a> cache: CacheBackend,
<a href=#119 id=119 data-nosnippet>119</a> name: String,
<a href=#120 id=120 data-nosnippet>120</a> version: AtomicUsize,
<a href=#121 id=121 data-nosnippet>121</a>}
<a href=#122 id=122 data-nosnippet>122</a>
<a href=#123 id=123 data-nosnippet>123</a><span class="attr">#[async_trait::async_trait]
<a href=#124 id=124 data-nosnippet>124</a></span><span class="kw">impl </span>TxnService <span class="kw">for </span>CachedKvBackend {
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw">type </span>Error = Error;
<a href=#126 id=126 data-nosnippet>126</a>
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw">async fn </span>txn(<span class="kw-2">&amp;</span><span class="self">self</span>, txn: Txn) -&gt; std::result::Result&lt;TxnResponse, <span class="self">Self</span>::Error&gt; {
<a href=#128 id=128 data-nosnippet>128</a> <span class="comment">// TODO(hl): txn of CachedKvBackend simply pass through to inner backend without invalidating caches.
<a href=#129 id=129 data-nosnippet>129</a> </span><span class="self">self</span>.kv_backend.txn(txn).<span class="kw">await
<a href=#130 id=130 data-nosnippet>130</a> </span>}
<a href=#131 id=131 data-nosnippet>131</a>
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">fn </span>max_txn_ops(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<a href=#133 id=133 data-nosnippet>133</a> <span class="self">self</span>.kv_backend.max_txn_ops()
<a href=#134 id=134 data-nosnippet>134</a> }
<a href=#135 id=135 data-nosnippet>135</a>}
<a href=#136 id=136 data-nosnippet>136</a>
<a href=#137 id=137 data-nosnippet>137</a><span class="attr">#[async_trait::async_trait]
<a href=#138 id=138 data-nosnippet>138</a></span><span class="kw">impl </span>KvBackend <span class="kw">for </span>CachedKvBackend {
<a href=#139 id=139 data-nosnippet>139</a> <span class="kw">fn </span>name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#140 id=140 data-nosnippet>140</a> <span class="kw-2">&amp;</span><span class="self">self</span>.name
<a href=#141 id=141 data-nosnippet>141</a> }
<a href=#142 id=142 data-nosnippet>142</a>
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>Any {
<a href=#144 id=144 data-nosnippet>144</a> <span class="self">self
<a href=#145 id=145 data-nosnippet>145</a> </span>}
<a href=#146 id=146 data-nosnippet>146</a>
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">async fn </span>range(<span class="kw-2">&amp;</span><span class="self">self</span>, req: RangeRequest) -&gt; <span class="prelude-ty">Result</span>&lt;RangeResponse&gt; {
<a href=#148 id=148 data-nosnippet>148</a> <span class="self">self</span>.kv_backend.range(req).<span class="kw">await
<a href=#149 id=149 data-nosnippet>149</a> </span>}
<a href=#150 id=150 data-nosnippet>150</a>
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">async fn </span>put(<span class="kw-2">&amp;</span><span class="self">self</span>, req: PutRequest) -&gt; <span class="prelude-ty">Result</span>&lt;PutResponse&gt; {
<a href=#152 id=152 data-nosnippet>152</a> <span class="kw">let </span>key = <span class="kw-2">&amp;</span>req.key.clone();
<a href=#153 id=153 data-nosnippet>153</a>
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">let </span>ret = <span class="self">self</span>.kv_backend.put(req).<span class="kw">await</span>;
<a href=#155 id=155 data-nosnippet>155</a>
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">if </span>ret.is_ok() {
<a href=#157 id=157 data-nosnippet>157</a> <span class="self">self</span>.invalidate_key(key).<span class="kw">await</span>;
<a href=#158 id=158 data-nosnippet>158</a> }
<a href=#159 id=159 data-nosnippet>159</a>
<a href=#160 id=160 data-nosnippet>160</a> ret
<a href=#161 id=161 data-nosnippet>161</a> }
<a href=#162 id=162 data-nosnippet>162</a>
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">async fn </span>batch_put(<span class="kw-2">&amp;</span><span class="self">self</span>, req: BatchPutRequest) -&gt; <span class="prelude-ty">Result</span>&lt;BatchPutResponse&gt; {
<a href=#164 id=164 data-nosnippet>164</a> <span class="kw">let </span>keys = req
<a href=#165 id=165 data-nosnippet>165</a> .kvs
<a href=#166 id=166 data-nosnippet>166</a> .iter()
<a href=#167 id=167 data-nosnippet>167</a> .map(|kv| kv.key().to_vec())
<a href=#168 id=168 data-nosnippet>168</a> .collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;();
<a href=#169 id=169 data-nosnippet>169</a>
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw">let </span>resp = <span class="self">self</span>.kv_backend.batch_put(req).<span class="kw">await</span>;
<a href=#171 id=171 data-nosnippet>171</a>
<a href=#172 id=172 data-nosnippet>172</a> <span class="kw">if </span>resp.is_ok() {
<a href=#173 id=173 data-nosnippet>173</a> <span class="kw">for </span>key <span class="kw">in </span>keys {
<a href=#174 id=174 data-nosnippet>174</a> <span class="self">self</span>.invalidate_key(<span class="kw-2">&amp;</span>key).<span class="kw">await</span>;
<a href=#175 id=175 data-nosnippet>175</a> }
<a href=#176 id=176 data-nosnippet>176</a> }
<a href=#177 id=177 data-nosnippet>177</a>
<a href=#178 id=178 data-nosnippet>178</a> resp
<a href=#179 id=179 data-nosnippet>179</a> }
<a href=#180 id=180 data-nosnippet>180</a>
<a href=#181 id=181 data-nosnippet>181</a> <span class="kw">async fn </span>batch_get(<span class="kw-2">&amp;</span><span class="self">self</span>, req: BatchGetRequest) -&gt; <span class="prelude-ty">Result</span>&lt;BatchGetResponse&gt; {
<a href=#182 id=182 data-nosnippet>182</a> <span class="kw">let </span>_timer = METRIC_CATALOG_KV_BATCH_GET.start_timer();
<a href=#183 id=183 data-nosnippet>183</a>
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">let </span><span class="kw-2">mut </span>kvs = Vec::with_capacity(req.keys.len());
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">let </span><span class="kw-2">mut </span>miss_keys = Vec::with_capacity(req.keys.len());
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">for </span>key <span class="kw">in </span>req.keys {
<a href=#188 id=188 data-nosnippet>188</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(val) = <span class="self">self</span>.cache.get(<span class="kw-2">&amp;</span>key).<span class="kw">await </span>{
<a href=#189 id=189 data-nosnippet>189</a> kvs.push(val);
<a href=#190 id=190 data-nosnippet>190</a> } <span class="kw">else </span>{
<a href=#191 id=191 data-nosnippet>191</a> miss_keys.push(key);
<a href=#192 id=192 data-nosnippet>192</a> }
<a href=#193 id=193 data-nosnippet>193</a> }
<a href=#194 id=194 data-nosnippet>194</a>
<a href=#195 id=195 data-nosnippet>195</a> <span class="kw">if </span>miss_keys.is_empty() {
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(BatchGetResponse { kvs });
<a href=#197 id=197 data-nosnippet>197</a> }
<a href=#198 id=198 data-nosnippet>198</a>
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">let </span>batch_get_req = BatchGetRequest::new().with_keys(miss_keys.clone());
<a href=#200 id=200 data-nosnippet>200</a>
<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">let </span>pre_version = <span class="self">self</span>.version();
<a href=#202 id=202 data-nosnippet>202</a>
<a href=#203 id=203 data-nosnippet>203</a> <span class="kw">let </span>unhit_kvs = <span class="self">self</span>.kv_backend.batch_get(batch_get_req).<span class="kw">await</span><span class="question-mark">?</span>.kvs;
<a href=#204 id=204 data-nosnippet>204</a>
<a href=#205 id=205 data-nosnippet>205</a> <span class="kw">for </span>kv <span class="kw">in </span>unhit_kvs.iter() {
<a href=#206 id=206 data-nosnippet>206</a> <span class="self">self</span>.cache.insert(kv.key().to_vec(), kv.clone()).<span class="kw">await</span>;
<a href=#207 id=207 data-nosnippet>207</a> }
<a href=#208 id=208 data-nosnippet>208</a>
<a href=#209 id=209 data-nosnippet>209</a> <span class="kw">if </span>!<span class="self">self</span>.validate_version(pre_version) {
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">for </span>key <span class="kw">in </span>miss_keys.iter() {
<a href=#211 id=211 data-nosnippet>211</a> <span class="self">self</span>.cache.invalidate(key).<span class="kw">await</span>;
<a href=#212 id=212 data-nosnippet>212</a> }
<a href=#213 id=213 data-nosnippet>213</a> }
<a href=#214 id=214 data-nosnippet>214</a>
<a href=#215 id=215 data-nosnippet>215</a> kvs.extend(unhit_kvs);
<a href=#216 id=216 data-nosnippet>216</a>
<a href=#217 id=217 data-nosnippet>217</a> <span class="prelude-val">Ok</span>(BatchGetResponse { kvs })
<a href=#218 id=218 data-nosnippet>218</a> }
<a href=#219 id=219 data-nosnippet>219</a>
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">async fn </span>compare_and_put(<span class="kw-2">&amp;</span><span class="self">self</span>, req: CompareAndPutRequest) -&gt; <span class="prelude-ty">Result</span>&lt;CompareAndPutResponse&gt; {
<a href=#221 id=221 data-nosnippet>221</a> <span class="kw">let </span>key = <span class="kw-2">&amp;</span>req.key.clone();
<a href=#222 id=222 data-nosnippet>222</a>
<a href=#223 id=223 data-nosnippet>223</a> <span class="kw">let </span>ret = <span class="self">self</span>.kv_backend.compare_and_put(req).<span class="kw">await</span>;
<a href=#224 id=224 data-nosnippet>224</a>
<a href=#225 id=225 data-nosnippet>225</a> <span class="kw">if </span>ret.is_ok() {
<a href=#226 id=226 data-nosnippet>226</a> <span class="self">self</span>.invalidate_key(key).<span class="kw">await</span>;
<a href=#227 id=227 data-nosnippet>227</a> }
<a href=#228 id=228 data-nosnippet>228</a>
<a href=#229 id=229 data-nosnippet>229</a> ret
<a href=#230 id=230 data-nosnippet>230</a> }
<a href=#231 id=231 data-nosnippet>231</a>
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">async fn </span>delete_range(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw-2">mut </span>req: DeleteRangeRequest) -&gt; <span class="prelude-ty">Result</span>&lt;DeleteRangeResponse&gt; {
<a href=#233 id=233 data-nosnippet>233</a> <span class="kw">let </span>prev_kv = req.prev_kv;
<a href=#234 id=234 data-nosnippet>234</a>
<a href=#235 id=235 data-nosnippet>235</a> req.prev_kv = <span class="bool-val">true</span>;
<a href=#236 id=236 data-nosnippet>236</a> <span class="kw">let </span>resp = <span class="self">self</span>.kv_backend.delete_range(req).<span class="kw">await</span>;
<a href=#237 id=237 data-nosnippet>237</a> <span class="kw">match </span>resp {
<a href=#238 id=238 data-nosnippet>238</a> <span class="prelude-val">Ok</span>(<span class="kw-2">mut </span>resp) =&gt; {
<a href=#239 id=239 data-nosnippet>239</a> <span class="kw">for </span>prev_kv <span class="kw">in </span>resp.prev_kvs.iter() {
<a href=#240 id=240 data-nosnippet>240</a> <span class="self">self</span>.invalidate_key(prev_kv.key()).<span class="kw">await</span>;
<a href=#241 id=241 data-nosnippet>241</a> }
<a href=#242 id=242 data-nosnippet>242</a>
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">if </span>!prev_kv {
<a href=#244 id=244 data-nosnippet>244</a> resp.prev_kvs = <span class="macro">vec!</span>[];
<a href=#245 id=245 data-nosnippet>245</a> }
<a href=#246 id=246 data-nosnippet>246</a> <span class="prelude-val">Ok</span>(resp)
<a href=#247 id=247 data-nosnippet>247</a> }
<a href=#248 id=248 data-nosnippet>248</a> <span class="prelude-val">Err</span>(e) =&gt; <span class="prelude-val">Err</span>(e),
<a href=#249 id=249 data-nosnippet>249</a> }
<a href=#250 id=250 data-nosnippet>250</a> }
<a href=#251 id=251 data-nosnippet>251</a>
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw">async fn </span>batch_delete(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw-2">mut </span>req: BatchDeleteRequest) -&gt; <span class="prelude-ty">Result</span>&lt;BatchDeleteResponse&gt; {
<a href=#253 id=253 data-nosnippet>253</a> <span class="kw">let </span>prev_kv = req.prev_kv;
<a href=#254 id=254 data-nosnippet>254</a>
<a href=#255 id=255 data-nosnippet>255</a> req.prev_kv = <span class="bool-val">true</span>;
<a href=#256 id=256 data-nosnippet>256</a> <span class="kw">let </span>resp = <span class="self">self</span>.kv_backend.batch_delete(req).<span class="kw">await</span>;
<a href=#257 id=257 data-nosnippet>257</a> <span class="kw">match </span>resp {
<a href=#258 id=258 data-nosnippet>258</a> <span class="prelude-val">Ok</span>(<span class="kw-2">mut </span>resp) =&gt; {
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">for </span>prev_kv <span class="kw">in </span>resp.prev_kvs.iter() {
<a href=#260 id=260 data-nosnippet>260</a> <span class="self">self</span>.invalidate_key(prev_kv.key()).<span class="kw">await</span>;
<a href=#261 id=261 data-nosnippet>261</a> }
<a href=#262 id=262 data-nosnippet>262</a>
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">if </span>!prev_kv {
<a href=#264 id=264 data-nosnippet>264</a> resp.prev_kvs = <span class="macro">vec!</span>[];
<a href=#265 id=265 data-nosnippet>265</a> }
<a href=#266 id=266 data-nosnippet>266</a> <span class="prelude-val">Ok</span>(resp)
<a href=#267 id=267 data-nosnippet>267</a> }
<a href=#268 id=268 data-nosnippet>268</a> <span class="prelude-val">Err</span>(e) =&gt; <span class="prelude-val">Err</span>(e),
<a href=#269 id=269 data-nosnippet>269</a> }
<a href=#270 id=270 data-nosnippet>270</a> }
<a href=#271 id=271 data-nosnippet>271</a>
<a href=#272 id=272 data-nosnippet>272</a> <span class="kw">async fn </span>get(<span class="kw-2">&amp;</span><span class="self">self</span>, key: <span class="kw-2">&amp;</span>[u8]) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;KeyValue&gt;&gt; {
<a href=#273 id=273 data-nosnippet>273</a> <span class="kw">let </span>_timer = METRIC_CATALOG_KV_GET.start_timer();
<a href=#274 id=274 data-nosnippet>274</a>
<a href=#275 id=275 data-nosnippet>275</a> <span class="kw">let </span>pre_version = Arc::new(Mutex::new(<span class="prelude-val">None</span>));
<a href=#276 id=276 data-nosnippet>276</a>
<a href=#277 id=277 data-nosnippet>277</a> <span class="kw">let </span>init = <span class="kw">async </span>{
<a href=#278 id=278 data-nosnippet>278</a> <span class="kw">let </span>version_clone = pre_version.clone();
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">let </span>_timer = METRIC_CATALOG_KV_REMOTE_GET.start_timer();
<a href=#280 id=280 data-nosnippet>280</a>
<a href=#281 id=281 data-nosnippet>281</a> version_clone.lock().unwrap().replace(<span class="self">self</span>.version());
<a href=#282 id=282 data-nosnippet>282</a>
<a href=#283 id=283 data-nosnippet>283</a> <span class="self">self</span>.kv_backend.get(key).<span class="kw">await</span>.map(|val| {
<a href=#284 id=284 data-nosnippet>284</a> val.with_context(|| CacheNotGetSnafu {
<a href=#285 id=285 data-nosnippet>285</a> key: String::from_utf8_lossy(key),
<a href=#286 id=286 data-nosnippet>286</a> })
<a href=#287 id=287 data-nosnippet>287</a> })<span class="question-mark">?
<a href=#288 id=288 data-nosnippet>288</a> </span>};
<a href=#289 id=289 data-nosnippet>289</a>
<a href=#290 id=290 data-nosnippet>290</a> <span class="comment">// currently moka doesn't have `optionally_try_get_with_by_ref`
<a href=#291 id=291 data-nosnippet>291</a> // TODO(fys): change to moka method when available
<a href=#292 id=292 data-nosnippet>292</a> // https://github.com/moka-rs/moka/issues/254
<a href=#293 id=293 data-nosnippet>293</a> </span><span class="kw">let </span>ret = <span class="kw">match </span><span class="self">self</span>.cache.try_get_with_by_ref(key, init).<span class="kw">await </span>{
<a href=#294 id=294 data-nosnippet>294</a> <span class="prelude-val">Ok</span>(val) =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(val)),
<a href=#295 id=295 data-nosnippet>295</a> <span class="prelude-val">Err</span>(e) =&gt; <span class="kw">match </span>e.as_ref() {
<a href=#296 id=296 data-nosnippet>296</a> CacheNotGet { .. } =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>),
<a href=#297 id=297 data-nosnippet>297</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">Err</span>(e),
<a href=#298 id=298 data-nosnippet>298</a> },
<a href=#299 id=299 data-nosnippet>299</a> }
<a href=#300 id=300 data-nosnippet>300</a> .map_err(|e| {
<a href=#301 id=301 data-nosnippet>301</a> GetKvCacheSnafu {
<a href=#302 id=302 data-nosnippet>302</a> err_msg: e.to_string(),
<a href=#303 id=303 data-nosnippet>303</a> }
<a href=#304 id=304 data-nosnippet>304</a> .build()
<a href=#305 id=305 data-nosnippet>305</a> });
<a href=#306 id=306 data-nosnippet>306</a>
<a href=#307 id=307 data-nosnippet>307</a> <span class="comment">// "cache.invalidate_key" and "cache.try_get_with_by_ref" are not mutually exclusive. So we need
<a href=#308 id=308 data-nosnippet>308</a> // to use the version mechanism to prevent expired data from being put into the cache.
<a href=#309 id=309 data-nosnippet>309</a> </span><span class="kw">if </span>pre_version
<a href=#310 id=310 data-nosnippet>310</a> .lock()
<a href=#311 id=311 data-nosnippet>311</a> .unwrap()
<a href=#312 id=312 data-nosnippet>312</a> .as_ref()
<a href=#313 id=313 data-nosnippet>313</a> .is_some_and(|v| !<span class="self">self</span>.validate_version(<span class="kw-2">*</span>v))
<a href=#314 id=314 data-nosnippet>314</a> {
<a href=#315 id=315 data-nosnippet>315</a> <span class="self">self</span>.cache.invalidate(key).<span class="kw">await</span>;
<a href=#316 id=316 data-nosnippet>316</a> }
<a href=#317 id=317 data-nosnippet>317</a>
<a href=#318 id=318 data-nosnippet>318</a> ret
<a href=#319 id=319 data-nosnippet>319</a> }
<a href=#320 id=320 data-nosnippet>320</a>}
<a href=#321 id=321 data-nosnippet>321</a>
<a href=#322 id=322 data-nosnippet>322</a><span class="attr">#[async_trait::async_trait]
<a href=#323 id=323 data-nosnippet>323</a></span><span class="kw">impl </span>KvCacheInvalidator <span class="kw">for </span>CachedKvBackend {
<a href=#324 id=324 data-nosnippet>324</a> <span class="kw">async fn </span>invalidate_key(<span class="kw-2">&amp;</span><span class="self">self</span>, key: <span class="kw-2">&amp;</span>[u8]) {
<a href=#325 id=325 data-nosnippet>325</a> <span class="self">self</span>.create_new_version();
<a href=#326 id=326 data-nosnippet>326</a> <span class="self">self</span>.cache.invalidate(key).<span class="kw">await</span>;
<a href=#327 id=327 data-nosnippet>327</a> <span class="macro">debug!</span>(<span class="string">"invalidated cache key: {}"</span>, String::from_utf8_lossy(key));
<a href=#328 id=328 data-nosnippet>328</a> }
<a href=#329 id=329 data-nosnippet>329</a>}
<a href=#330 id=330 data-nosnippet>330</a>
<a href=#331 id=331 data-nosnippet>331</a><span class="kw">impl </span>CachedKvBackend {
<a href=#332 id=332 data-nosnippet>332</a> <span class="comment">// only for test
<a href=#333 id=333 data-nosnippet>333</a> </span><span class="attr">#[cfg(test)]
<a href=#334 id=334 data-nosnippet>334</a> </span><span class="kw">fn </span>wrap(kv_backend: KvBackendRef) -&gt; <span class="self">Self </span>{
<a href=#335 id=335 data-nosnippet>335</a> <span class="kw">let </span>cache = CacheBuilder::new(DEFAULT_CACHE_MAX_CAPACITY)
<a href=#336 id=336 data-nosnippet>336</a> .time_to_live(DEFAULT_CACHE_TTL)
<a href=#337 id=337 data-nosnippet>337</a> .time_to_idle(DEFAULT_CACHE_TTI)
<a href=#338 id=338 data-nosnippet>338</a> .build();
<a href=#339 id=339 data-nosnippet>339</a>
<a href=#340 id=340 data-nosnippet>340</a> <span class="kw">let </span>name = <span class="macro">format!</span>(<span class="string">"CachedKvBackend({})"</span>, kv_backend.name());
<a href=#341 id=341 data-nosnippet>341</a> <span class="self">Self </span>{
<a href=#342 id=342 data-nosnippet>342</a> kv_backend,
<a href=#343 id=343 data-nosnippet>343</a> cache,
<a href=#344 id=344 data-nosnippet>344</a> name,
<a href=#345 id=345 data-nosnippet>345</a> version: AtomicUsize::new(<span class="number">0</span>),
<a href=#346 id=346 data-nosnippet>346</a> }
<a href=#347 id=347 data-nosnippet>347</a> }
<a href=#348 id=348 data-nosnippet>348</a>
<a href=#349 id=349 data-nosnippet>349</a> <span class="kw">pub fn </span>cache(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>CacheBackend {
<a href=#350 id=350 data-nosnippet>350</a> <span class="kw-2">&amp;</span><span class="self">self</span>.cache
<a href=#351 id=351 data-nosnippet>351</a> }
<a href=#352 id=352 data-nosnippet>352</a>
<a href=#353 id=353 data-nosnippet>353</a> <span class="kw">fn </span>version(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<a href=#354 id=354 data-nosnippet>354</a> <span class="self">self</span>.version.load(Ordering::Relaxed)
<a href=#355 id=355 data-nosnippet>355</a> }
<a href=#356 id=356 data-nosnippet>356</a>
<a href=#357 id=357 data-nosnippet>357</a> <span class="kw">fn </span>validate_version(<span class="kw-2">&amp;</span><span class="self">self</span>, pre_version: usize) -&gt; bool {
<a href=#358 id=358 data-nosnippet>358</a> <span class="self">self</span>.version() == pre_version
<a href=#359 id=359 data-nosnippet>359</a> }
<a href=#360 id=360 data-nosnippet>360</a>
<a href=#361 id=361 data-nosnippet>361</a> <span class="kw">fn </span>create_new_version(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<a href=#362 id=362 data-nosnippet>362</a> <span class="self">self</span>.version.fetch_add(<span class="number">1</span>, Ordering::Relaxed) + <span class="number">1
<a href=#363 id=363 data-nosnippet>363</a> </span>}
<a href=#364 id=364 data-nosnippet>364</a>}
<a href=#365 id=365 data-nosnippet>365</a>
<a href=#366 id=366 data-nosnippet>366</a><span class="attr">#[derive(Debug)]
<a href=#367 id=367 data-nosnippet>367</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>MetaKvBackend {
<a href=#368 id=368 data-nosnippet>368</a> client: Arc&lt;MetaClient&gt;,
<a href=#369 id=369 data-nosnippet>369</a>}
<a href=#370 id=370 data-nosnippet>370</a>
<a href=#371 id=371 data-nosnippet>371</a><span class="kw">impl </span>MetaKvBackend {
<a href=#372 id=372 data-nosnippet>372</a> <span class="doccomment">/// Constructs a [MetaKvBackend].
<a href=#373 id=373 data-nosnippet>373</a> </span><span class="kw">fn </span>new(client: Arc&lt;MetaClient&gt;) -&gt; MetaKvBackend {
<a href=#374 id=374 data-nosnippet>374</a> MetaKvBackend { client }
<a href=#375 id=375 data-nosnippet>375</a> }
<a href=#376 id=376 data-nosnippet>376</a>}
<a href=#377 id=377 data-nosnippet>377</a>
<a href=#378 id=378 data-nosnippet>378</a><span class="kw">pub fn </span>new_read_only_meta_kv_backend(client: Arc&lt;MetaClient&gt;) -&gt; KvBackendRef {
<a href=#379 id=379 data-nosnippet>379</a> Arc::new(ReadOnlyKvBackend::new(Arc::new(MetaKvBackend::new(client))))
<a href=#380 id=380 data-nosnippet>380</a>}
<a href=#381 id=381 data-nosnippet>381</a>
<a href=#382 id=382 data-nosnippet>382</a><span class="attr">#[async_trait::async_trait]
<a href=#383 id=383 data-nosnippet>383</a></span><span class="kw">impl </span>TxnService <span class="kw">for </span>MetaKvBackend {
<a href=#384 id=384 data-nosnippet>384</a> <span class="kw">type </span>Error = Error;
<a href=#385 id=385 data-nosnippet>385</a>
<a href=#386 id=386 data-nosnippet>386</a> <span class="kw">async fn </span>txn(<span class="kw-2">&amp;</span><span class="self">self</span>, _txn: Txn) -&gt; <span class="prelude-ty">Result</span>&lt;TxnResponse&gt; {
<a href=#387 id=387 data-nosnippet>387</a> UnsupportedSnafu {
<a href=#388 id=388 data-nosnippet>388</a> operation: <span class="string">"MetaKvBackend txn"</span>,
<a href=#389 id=389 data-nosnippet>389</a> }
<a href=#390 id=390 data-nosnippet>390</a> .fail()
<a href=#391 id=391 data-nosnippet>391</a> }
<a href=#392 id=392 data-nosnippet>392</a>
<a href=#393 id=393 data-nosnippet>393</a> <span class="kw">fn </span>max_txn_ops(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<a href=#394 id=394 data-nosnippet>394</a> usize::MAX
<a href=#395 id=395 data-nosnippet>395</a> }
<a href=#396 id=396 data-nosnippet>396</a>}
<a href=#397 id=397 data-nosnippet>397</a>
<a href=#398 id=398 data-nosnippet>398</a><span class="doccomment">/// Implement `KvBackend` trait for `MetaKvBackend` instead of opendal's `Accessor` since
<a href=#399 id=399 data-nosnippet>399</a>/// `MetaClient`'s range method can return both keys and values, which can reduce IO overhead
<a href=#400 id=400 data-nosnippet>400</a>/// comparing to `Accessor`'s list and get method.
<a href=#401 id=401 data-nosnippet>401</a></span><span class="attr">#[async_trait::async_trait]
<a href=#402 id=402 data-nosnippet>402</a></span><span class="kw">impl </span>KvBackend <span class="kw">for </span>MetaKvBackend {
<a href=#403 id=403 data-nosnippet>403</a> <span class="kw">fn </span>name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#404 id=404 data-nosnippet>404</a> <span class="string">"MetaKvBackend"
<a href=#405 id=405 data-nosnippet>405</a> </span>}
<a href=#406 id=406 data-nosnippet>406</a>
<a href=#407 id=407 data-nosnippet>407</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>Any {
<a href=#408 id=408 data-nosnippet>408</a> <span class="self">self
<a href=#409 id=409 data-nosnippet>409</a> </span>}
<a href=#410 id=410 data-nosnippet>410</a>
<a href=#411 id=411 data-nosnippet>411</a> <span class="kw">async fn </span>range(<span class="kw-2">&amp;</span><span class="self">self</span>, req: RangeRequest) -&gt; <span class="prelude-ty">Result</span>&lt;RangeResponse&gt; {
<a href=#412 id=412 data-nosnippet>412</a> <span class="self">self</span>.client
<a href=#413 id=413 data-nosnippet>413</a> .range(req)
<a href=#414 id=414 data-nosnippet>414</a> .<span class="kw">await
<a href=#415 id=415 data-nosnippet>415</a> </span>.map_err(BoxedError::new)
<a href=#416 id=416 data-nosnippet>416</a> .context(ExternalSnafu)
<a href=#417 id=417 data-nosnippet>417</a> }
<a href=#418 id=418 data-nosnippet>418</a>
<a href=#419 id=419 data-nosnippet>419</a> <span class="kw">async fn </span>put(<span class="kw-2">&amp;</span><span class="self">self</span>, req: PutRequest) -&gt; <span class="prelude-ty">Result</span>&lt;PutResponse&gt; {
<a href=#420 id=420 data-nosnippet>420</a> <span class="self">self</span>.client
<a href=#421 id=421 data-nosnippet>421</a> .put(req)
<a href=#422 id=422 data-nosnippet>422</a> .<span class="kw">await
<a href=#423 id=423 data-nosnippet>423</a> </span>.map_err(BoxedError::new)
<a href=#424 id=424 data-nosnippet>424</a> .context(ExternalSnafu)
<a href=#425 id=425 data-nosnippet>425</a> }
<a href=#426 id=426 data-nosnippet>426</a>
<a href=#427 id=427 data-nosnippet>427</a> <span class="kw">async fn </span>batch_put(<span class="kw-2">&amp;</span><span class="self">self</span>, req: BatchPutRequest) -&gt; <span class="prelude-ty">Result</span>&lt;BatchPutResponse&gt; {
<a href=#428 id=428 data-nosnippet>428</a> <span class="self">self</span>.client
<a href=#429 id=429 data-nosnippet>429</a> .batch_put(req)
<a href=#430 id=430 data-nosnippet>430</a> .<span class="kw">await
<a href=#431 id=431 data-nosnippet>431</a> </span>.map_err(BoxedError::new)
<a href=#432 id=432 data-nosnippet>432</a> .context(ExternalSnafu)
<a href=#433 id=433 data-nosnippet>433</a> }
<a href=#434 id=434 data-nosnippet>434</a>
<a href=#435 id=435 data-nosnippet>435</a> <span class="kw">async fn </span>batch_get(<span class="kw-2">&amp;</span><span class="self">self</span>, req: BatchGetRequest) -&gt; <span class="prelude-ty">Result</span>&lt;BatchGetResponse&gt; {
<a href=#436 id=436 data-nosnippet>436</a> <span class="self">self</span>.client
<a href=#437 id=437 data-nosnippet>437</a> .batch_get(req)
<a href=#438 id=438 data-nosnippet>438</a> .<span class="kw">await
<a href=#439 id=439 data-nosnippet>439</a> </span>.map_err(BoxedError::new)
<a href=#440 id=440 data-nosnippet>440</a> .context(ExternalSnafu)
<a href=#441 id=441 data-nosnippet>441</a> }
<a href=#442 id=442 data-nosnippet>442</a>
<a href=#443 id=443 data-nosnippet>443</a> <span class="kw">async fn </span>compare_and_put(
<a href=#444 id=444 data-nosnippet>444</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#445 id=445 data-nosnippet>445</a> request: CompareAndPutRequest,
<a href=#446 id=446 data-nosnippet>446</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;CompareAndPutResponse&gt; {
<a href=#447 id=447 data-nosnippet>447</a> <span class="self">self</span>.client
<a href=#448 id=448 data-nosnippet>448</a> .compare_and_put(request)
<a href=#449 id=449 data-nosnippet>449</a> .<span class="kw">await
<a href=#450 id=450 data-nosnippet>450</a> </span>.map_err(BoxedError::new)
<a href=#451 id=451 data-nosnippet>451</a> .context(ExternalSnafu)
<a href=#452 id=452 data-nosnippet>452</a> }
<a href=#453 id=453 data-nosnippet>453</a>
<a href=#454 id=454 data-nosnippet>454</a> <span class="kw">async fn </span>delete_range(<span class="kw-2">&amp;</span><span class="self">self</span>, req: DeleteRangeRequest) -&gt; <span class="prelude-ty">Result</span>&lt;DeleteRangeResponse&gt; {
<a href=#455 id=455 data-nosnippet>455</a> <span class="self">self</span>.client
<a href=#456 id=456 data-nosnippet>456</a> .delete_range(req)
<a href=#457 id=457 data-nosnippet>457</a> .<span class="kw">await
<a href=#458 id=458 data-nosnippet>458</a> </span>.map_err(BoxedError::new)
<a href=#459 id=459 data-nosnippet>459</a> .context(ExternalSnafu)
<a href=#460 id=460 data-nosnippet>460</a> }
<a href=#461 id=461 data-nosnippet>461</a>
<a href=#462 id=462 data-nosnippet>462</a> <span class="kw">async fn </span>batch_delete(<span class="kw-2">&amp;</span><span class="self">self</span>, req: BatchDeleteRequest) -&gt; <span class="prelude-ty">Result</span>&lt;BatchDeleteResponse&gt; {
<a href=#463 id=463 data-nosnippet>463</a> <span class="self">self</span>.client
<a href=#464 id=464 data-nosnippet>464</a> .batch_delete(req)
<a href=#465 id=465 data-nosnippet>465</a> .<span class="kw">await
<a href=#466 id=466 data-nosnippet>466</a> </span>.map_err(BoxedError::new)
<a href=#467 id=467 data-nosnippet>467</a> .context(ExternalSnafu)
<a href=#468 id=468 data-nosnippet>468</a> }
<a href=#469 id=469 data-nosnippet>469</a>
<a href=#470 id=470 data-nosnippet>470</a> <span class="kw">async fn </span>get(<span class="kw-2">&amp;</span><span class="self">self</span>, key: <span class="kw-2">&amp;</span>[u8]) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;KeyValue&gt;&gt; {
<a href=#471 id=471 data-nosnippet>471</a> <span class="kw">let </span><span class="kw-2">mut </span>response = <span class="self">self
<a href=#472 id=472 data-nosnippet>472</a> </span>.client
<a href=#473 id=473 data-nosnippet>473</a> .range(RangeRequest::new().with_key(key))
<a href=#474 id=474 data-nosnippet>474</a> .<span class="kw">await
<a href=#475 id=475 data-nosnippet>475</a> </span>.map_err(BoxedError::new)
<a href=#476 id=476 data-nosnippet>476</a> .context(ExternalSnafu)<span class="question-mark">?</span>;
<a href=#477 id=477 data-nosnippet>477</a> <span class="prelude-val">Ok</span>(response.take_kvs().get_mut(<span class="number">0</span>).map(|kv| KeyValue {
<a href=#478 id=478 data-nosnippet>478</a> key: kv.take_key(),
<a href=#479 id=479 data-nosnippet>479</a> value: kv.take_value(),
<a href=#480 id=480 data-nosnippet>480</a> }))
<a href=#481 id=481 data-nosnippet>481</a> }
<a href=#482 id=482 data-nosnippet>482</a>}
<a href=#483 id=483 data-nosnippet>483</a>
<a href=#484 id=484 data-nosnippet>484</a><span class="attr">#[cfg(test)]
<a href=#485 id=485 data-nosnippet>485</a></span><span class="kw">mod </span>tests {
<a href=#486 id=486 data-nosnippet>486</a> <span class="kw">use </span>std::any::Any;
<a href=#487 id=487 data-nosnippet>487</a> <span class="kw">use </span>std::sync::Arc;
<a href=#488 id=488 data-nosnippet>488</a> <span class="kw">use </span>std::sync::atomic::{AtomicU32, Ordering};
<a href=#489 id=489 data-nosnippet>489</a>
<a href=#490 id=490 data-nosnippet>490</a> <span class="kw">use </span>async_trait::async_trait;
<a href=#491 id=491 data-nosnippet>491</a> <span class="kw">use </span>common_meta::kv_backend::memory::MemoryKvBackend;
<a href=#492 id=492 data-nosnippet>492</a> <span class="kw">use </span>common_meta::kv_backend::read_only::ReadOnlyKvBackend;
<a href=#493 id=493 data-nosnippet>493</a> <span class="kw">use </span>common_meta::kv_backend::txn::{Txn, TxnOp};
<a href=#494 id=494 data-nosnippet>494</a> <span class="kw">use </span>common_meta::kv_backend::{KvBackend, TxnService};
<a href=#495 id=495 data-nosnippet>495</a> <span class="kw">use </span>common_meta::rpc::KeyValue;
<a href=#496 id=496 data-nosnippet>496</a> <span class="kw">use </span>common_meta::rpc::store::{
<a href=#497 id=497 data-nosnippet>497</a> BatchDeleteRequest, BatchDeleteResponse, BatchGetRequest, BatchGetResponse,
<a href=#498 id=498 data-nosnippet>498</a> BatchPutRequest, BatchPutResponse, DeleteRangeRequest, DeleteRangeResponse, PutRequest,
<a href=#499 id=499 data-nosnippet>499</a> PutResponse, RangeRequest, RangeResponse,
<a href=#500 id=500 data-nosnippet>500</a> };
<a href=#501 id=501 data-nosnippet>501</a> <span class="kw">use </span>dashmap::DashMap;
<a href=#502 id=502 data-nosnippet>502</a> <span class="kw">use </span>meta_client::client::MetaClientBuilder;
<a href=#503 id=503 data-nosnippet>503</a>
<a href=#504 id=504 data-nosnippet>504</a> <span class="kw">use </span>super::{CachedKvBackend, new_read_only_meta_kv_backend};
<a href=#505 id=505 data-nosnippet>505</a>
<a href=#506 id=506 data-nosnippet>506</a> <span class="attr">#[derive(Default)]
<a href=#507 id=507 data-nosnippet>507</a> </span><span class="kw">pub struct </span>SimpleKvBackend {
<a href=#508 id=508 data-nosnippet>508</a> inner_map: DashMap&lt;Vec&lt;u8&gt;, Vec&lt;u8&gt;&gt;,
<a href=#509 id=509 data-nosnippet>509</a> get_execute_times: Arc&lt;AtomicU32&gt;,
<a href=#510 id=510 data-nosnippet>510</a> batch_get_execute_times: Arc&lt;AtomicU32&gt;,
<a href=#511 id=511 data-nosnippet>511</a> }
<a href=#512 id=512 data-nosnippet>512</a>
<a href=#513 id=513 data-nosnippet>513</a> <span class="kw">impl </span>TxnService <span class="kw">for </span>SimpleKvBackend {
<a href=#514 id=514 data-nosnippet>514</a> <span class="kw">type </span>Error = common_meta::error::Error;
<a href=#515 id=515 data-nosnippet>515</a> }
<a href=#516 id=516 data-nosnippet>516</a>
<a href=#517 id=517 data-nosnippet>517</a> <span class="attr">#[async_trait]
<a href=#518 id=518 data-nosnippet>518</a> </span><span class="kw">impl </span>KvBackend <span class="kw">for </span>SimpleKvBackend {
<a href=#519 id=519 data-nosnippet>519</a> <span class="kw">fn </span>name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#520 id=520 data-nosnippet>520</a> <span class="string">"SimpleKvBackend"
<a href=#521 id=521 data-nosnippet>521</a> </span>}
<a href=#522 id=522 data-nosnippet>522</a>
<a href=#523 id=523 data-nosnippet>523</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>Any {
<a href=#524 id=524 data-nosnippet>524</a> <span class="self">self
<a href=#525 id=525 data-nosnippet>525</a> </span>}
<a href=#526 id=526 data-nosnippet>526</a>
<a href=#527 id=527 data-nosnippet>527</a> <span class="kw">async fn </span>batch_get(<span class="kw-2">&amp;</span><span class="self">self</span>, req: BatchGetRequest) -&gt; <span class="prelude-ty">Result</span>&lt;BatchGetResponse, <span class="self">Self</span>::Error&gt; {
<a href=#528 id=528 data-nosnippet>528</a> <span class="self">self</span>.batch_get_execute_times.fetch_add(<span class="number">1</span>, Ordering::SeqCst);
<a href=#529 id=529 data-nosnippet>529</a> <span class="kw">let </span><span class="kw-2">mut </span>kvs = Vec::with_capacity(req.keys.len());
<a href=#530 id=530 data-nosnippet>530</a> <span class="kw">for </span>key <span class="kw">in </span>req.keys.iter() {
<a href=#531 id=531 data-nosnippet>531</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(kv) = <span class="self">self</span>.get(key).<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#532 id=532 data-nosnippet>532</a> kvs.push(kv);
<a href=#533 id=533 data-nosnippet>533</a> }
<a href=#534 id=534 data-nosnippet>534</a> }
<a href=#535 id=535 data-nosnippet>535</a> <span class="prelude-val">Ok</span>(BatchGetResponse { kvs })
<a href=#536 id=536 data-nosnippet>536</a> }
<a href=#537 id=537 data-nosnippet>537</a>
<a href=#538 id=538 data-nosnippet>538</a> <span class="kw">async fn </span>put(<span class="kw-2">&amp;</span><span class="self">self</span>, req: PutRequest) -&gt; <span class="prelude-ty">Result</span>&lt;PutResponse, <span class="self">Self</span>::Error&gt; {
<a href=#539 id=539 data-nosnippet>539</a> <span class="self">self</span>.inner_map.insert(req.key, req.value);
<a href=#540 id=540 data-nosnippet>540</a> <span class="comment">// always return None as prev_kv, since we don't use it in this test.
<a href=#541 id=541 data-nosnippet>541</a> </span><span class="prelude-val">Ok</span>(PutResponse { prev_kv: <span class="prelude-val">None </span>})
<a href=#542 id=542 data-nosnippet>542</a> }
<a href=#543 id=543 data-nosnippet>543</a>
<a href=#544 id=544 data-nosnippet>544</a> <span class="kw">async fn </span>get(<span class="kw-2">&amp;</span><span class="self">self</span>, key: <span class="kw-2">&amp;</span>[u8]) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;KeyValue&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#545 id=545 data-nosnippet>545</a> <span class="self">self</span>.get_execute_times
<a href=#546 id=546 data-nosnippet>546</a> .fetch_add(<span class="number">1</span>, std::sync::atomic::Ordering::SeqCst);
<a href=#547 id=547 data-nosnippet>547</a> <span class="prelude-val">Ok</span>(<span class="self">self</span>.inner_map.get(key).map(|v| KeyValue {
<a href=#548 id=548 data-nosnippet>548</a> key: key.to_vec(),
<a href=#549 id=549 data-nosnippet>549</a> value: v.value().clone(),
<a href=#550 id=550 data-nosnippet>550</a> }))
<a href=#551 id=551 data-nosnippet>551</a> }
<a href=#552 id=552 data-nosnippet>552</a>
<a href=#553 id=553 data-nosnippet>553</a> <span class="kw">async fn </span>range(<span class="kw-2">&amp;</span><span class="self">self</span>, _req: RangeRequest) -&gt; <span class="prelude-ty">Result</span>&lt;RangeResponse, <span class="self">Self</span>::Error&gt; {
<a href=#554 id=554 data-nosnippet>554</a> <span class="macro">unimplemented!</span>()
<a href=#555 id=555 data-nosnippet>555</a> }
<a href=#556 id=556 data-nosnippet>556</a>
<a href=#557 id=557 data-nosnippet>557</a> <span class="kw">async fn </span>batch_put(<span class="kw-2">&amp;</span><span class="self">self</span>, _req: BatchPutRequest) -&gt; <span class="prelude-ty">Result</span>&lt;BatchPutResponse, <span class="self">Self</span>::Error&gt; {
<a href=#558 id=558 data-nosnippet>558</a> <span class="macro">unimplemented!</span>()
<a href=#559 id=559 data-nosnippet>559</a> }
<a href=#560 id=560 data-nosnippet>560</a>
<a href=#561 id=561 data-nosnippet>561</a> <span class="kw">async fn </span>delete_range(
<a href=#562 id=562 data-nosnippet>562</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#563 id=563 data-nosnippet>563</a> _req: DeleteRangeRequest,
<a href=#564 id=564 data-nosnippet>564</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;DeleteRangeResponse, <span class="self">Self</span>::Error&gt; {
<a href=#565 id=565 data-nosnippet>565</a> <span class="macro">unimplemented!</span>()
<a href=#566 id=566 data-nosnippet>566</a> }
<a href=#567 id=567 data-nosnippet>567</a>
<a href=#568 id=568 data-nosnippet>568</a> <span class="kw">async fn </span>batch_delete(
<a href=#569 id=569 data-nosnippet>569</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#570 id=570 data-nosnippet>570</a> _req: BatchDeleteRequest,
<a href=#571 id=571 data-nosnippet>571</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;BatchDeleteResponse, <span class="self">Self</span>::Error&gt; {
<a href=#572 id=572 data-nosnippet>572</a> <span class="macro">unimplemented!</span>()
<a href=#573 id=573 data-nosnippet>573</a> }
<a href=#574 id=574 data-nosnippet>574</a> }
<a href=#575 id=575 data-nosnippet>575</a>
<a href=#576 id=576 data-nosnippet>576</a> <span class="attr">#[tokio::test]
<a href=#577 id=577 data-nosnippet>577</a> </span><span class="kw">async fn </span>test_cached_kv_backend() {
<a href=#578 id=578 data-nosnippet>578</a> <span class="kw">let </span>simple_kv = Arc::new(SimpleKvBackend::default());
<a href=#579 id=579 data-nosnippet>579</a> <span class="kw">let </span>get_execute_times = simple_kv.get_execute_times.clone();
<a href=#580 id=580 data-nosnippet>580</a> <span class="kw">let </span>batch_get_execute_times = simple_kv.batch_get_execute_times.clone();
<a href=#581 id=581 data-nosnippet>581</a> <span class="kw">let </span>cached_kv = CachedKvBackend::wrap(simple_kv);
<a href=#582 id=582 data-nosnippet>582</a>
<a href=#583 id=583 data-nosnippet>583</a> add_some_vals(<span class="kw-2">&amp;</span>cached_kv).<span class="kw">await</span>;
<a href=#584 id=584 data-nosnippet>584</a>
<a href=#585 id=585 data-nosnippet>585</a> <span class="kw">let </span>batch_get_req = BatchGetRequest {
<a href=#586 id=586 data-nosnippet>586</a> keys: <span class="macro">vec!</span>[<span class="string">b"k1"</span>.to_vec(), <span class="string">b"k2"</span>.to_vec()],
<a href=#587 id=587 data-nosnippet>587</a> };
<a href=#588 id=588 data-nosnippet>588</a>
<a href=#589 id=589 data-nosnippet>589</a> <span class="macro">assert_eq!</span>(get_execute_times.load(Ordering::SeqCst), <span class="number">0</span>);
<a href=#590 id=590 data-nosnippet>590</a>
<a href=#591 id=591 data-nosnippet>591</a> <span class="kw">for _ in </span><span class="number">0</span>..<span class="number">10 </span>{
<a href=#592 id=592 data-nosnippet>592</a> <span class="kw">let </span>batch_get_resp = cached_kv.batch_get(batch_get_req.clone()).<span class="kw">await</span>.unwrap();
<a href=#593 id=593 data-nosnippet>593</a>
<a href=#594 id=594 data-nosnippet>594</a> <span class="macro">assert_eq!</span>(batch_get_resp.kvs.len(), <span class="number">2</span>);
<a href=#595 id=595 data-nosnippet>595</a> <span class="macro">assert_eq!</span>(get_execute_times.load(Ordering::SeqCst), <span class="number">2</span>);
<a href=#596 id=596 data-nosnippet>596</a> <span class="macro">assert_eq!</span>(batch_get_execute_times.load(Ordering::SeqCst), <span class="number">1</span>);
<a href=#597 id=597 data-nosnippet>597</a> }
<a href=#598 id=598 data-nosnippet>598</a>
<a href=#599 id=599 data-nosnippet>599</a> <span class="kw">let </span>batch_get_req = BatchGetRequest {
<a href=#600 id=600 data-nosnippet>600</a> keys: <span class="macro">vec!</span>[<span class="string">b"k1"</span>.to_vec(), <span class="string">b"k2"</span>.to_vec(), <span class="string">b"k3"</span>.to_vec()],
<a href=#601 id=601 data-nosnippet>601</a> };
<a href=#602 id=602 data-nosnippet>602</a>
<a href=#603 id=603 data-nosnippet>603</a> <span class="kw">let </span>_batch_get_resp = cached_kv.batch_get(batch_get_req.clone()).<span class="kw">await</span>.unwrap();
<a href=#604 id=604 data-nosnippet>604</a>
<a href=#605 id=605 data-nosnippet>605</a> <span class="macro">assert_eq!</span>(get_execute_times.load(Ordering::SeqCst), <span class="number">3</span>);
<a href=#606 id=606 data-nosnippet>606</a> <span class="macro">assert_eq!</span>(batch_get_execute_times.load(Ordering::SeqCst), <span class="number">2</span>);
<a href=#607 id=607 data-nosnippet>607</a>
<a href=#608 id=608 data-nosnippet>608</a> <span class="kw">for _ in </span><span class="number">0</span>..<span class="number">10 </span>{
<a href=#609 id=609 data-nosnippet>609</a> <span class="kw">let </span>batch_get_resp = cached_kv.batch_get(batch_get_req.clone()).<span class="kw">await</span>.unwrap();
<a href=#610 id=610 data-nosnippet>610</a>
<a href=#611 id=611 data-nosnippet>611</a> <span class="macro">assert_eq!</span>(batch_get_resp.kvs.len(), <span class="number">3</span>);
<a href=#612 id=612 data-nosnippet>612</a> <span class="macro">assert_eq!</span>(get_execute_times.load(Ordering::SeqCst), <span class="number">3</span>);
<a href=#613 id=613 data-nosnippet>613</a> <span class="macro">assert_eq!</span>(batch_get_execute_times.load(Ordering::SeqCst), <span class="number">2</span>);
<a href=#614 id=614 data-nosnippet>614</a> }
<a href=#615 id=615 data-nosnippet>615</a> }
<a href=#616 id=616 data-nosnippet>616</a>
<a href=#617 id=617 data-nosnippet>617</a> <span class="attr">#[tokio::test]
<a href=#618 id=618 data-nosnippet>618</a> </span><span class="kw">async fn </span>test_cached_kv_backend_empty_batch_get() {
<a href=#619 id=619 data-nosnippet>619</a> <span class="kw">let </span>simple_kv = Arc::new(SimpleKvBackend::default());
<a href=#620 id=620 data-nosnippet>620</a> <span class="kw">let </span>cached_kv = CachedKvBackend::wrap(simple_kv.clone());
<a href=#621 id=621 data-nosnippet>621</a>
<a href=#622 id=622 data-nosnippet>622</a> <span class="kw">let </span>response = cached_kv.batch_get(BatchGetRequest::new()).<span class="kw">await</span>.unwrap();
<a href=#623 id=623 data-nosnippet>623</a>
<a href=#624 id=624 data-nosnippet>624</a> <span class="macro">assert!</span>(response.kvs.is_empty());
<a href=#625 id=625 data-nosnippet>625</a> <span class="macro">assert_eq!</span>(simple_kv.batch_get_execute_times.load(Ordering::SeqCst), <span class="number">0</span>);
<a href=#626 id=626 data-nosnippet>626</a> <span class="macro">assert_eq!</span>(simple_kv.get_execute_times.load(Ordering::SeqCst), <span class="number">0</span>);
<a href=#627 id=627 data-nosnippet>627</a> }
<a href=#628 id=628 data-nosnippet>628</a>
<a href=#629 id=629 data-nosnippet>629</a> <span class="attr">#[tokio::test]
<a href=#630 id=630 data-nosnippet>630</a> </span><span class="kw">async fn </span>test_cached_kv_backend_rejects_writes_with_read_only_inner() {
<a href=#631 id=631 data-nosnippet>631</a> <span class="kw">let </span>inner = Arc::new(MemoryKvBackend::&lt;common_meta::error::Error&gt;::new());
<a href=#632 id=632 data-nosnippet>632</a> <span class="kw">let </span>cached_kv = CachedKvBackend::wrap(Arc::new(ReadOnlyKvBackend::new(inner)));
<a href=#633 id=633 data-nosnippet>633</a>
<a href=#634 id=634 data-nosnippet>634</a> <span class="kw">let </span>err = cached_kv
<a href=#635 id=635 data-nosnippet>635</a> .put(PutRequest {
<a href=#636 id=636 data-nosnippet>636</a> key: <span class="string">b"k1"</span>.to_vec(),
<a href=#637 id=637 data-nosnippet>637</a> value: <span class="string">b"v1"</span>.to_vec(),
<a href=#638 id=638 data-nosnippet>638</a> prev_kv: <span class="bool-val">false</span>,
<a href=#639 id=639 data-nosnippet>639</a> })
<a href=#640 id=640 data-nosnippet>640</a> .<span class="kw">await
<a href=#641 id=641 data-nosnippet>641</a> </span>.unwrap_err();
<a href=#642 id=642 data-nosnippet>642</a>
<a href=#643 id=643 data-nosnippet>643</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(
<a href=#644 id=644 data-nosnippet>644</a> err,
<a href=#645 id=645 data-nosnippet>645</a> common_meta::error::Error::ReadOnlyKvBackend { .. }
<a href=#646 id=646 data-nosnippet>646</a> ));
<a href=#647 id=647 data-nosnippet>647</a> }
<a href=#648 id=648 data-nosnippet>648</a>
<a href=#649 id=649 data-nosnippet>649</a> <span class="attr">#[tokio::test]
<a href=#650 id=650 data-nosnippet>650</a> </span><span class="kw">async fn </span>test_read_only_meta_kv_backend_rejects_writes() {
<a href=#651 id=651 data-nosnippet>651</a> <span class="kw">let </span>meta_client = Arc::new(MetaClientBuilder::frontend_default_options().build());
<a href=#652 id=652 data-nosnippet>652</a> <span class="kw">let </span>backend = new_read_only_meta_kv_backend(meta_client);
<a href=#653 id=653 data-nosnippet>653</a>
<a href=#654 id=654 data-nosnippet>654</a> <span class="kw">let </span>err = backend
<a href=#655 id=655 data-nosnippet>655</a> .put(PutRequest {
<a href=#656 id=656 data-nosnippet>656</a> key: <span class="string">b"k1"</span>.to_vec(),
<a href=#657 id=657 data-nosnippet>657</a> value: <span class="string">b"v1"</span>.to_vec(),
<a href=#658 id=658 data-nosnippet>658</a> prev_kv: <span class="bool-val">false</span>,
<a href=#659 id=659 data-nosnippet>659</a> })
<a href=#660 id=660 data-nosnippet>660</a> .<span class="kw">await
<a href=#661 id=661 data-nosnippet>661</a> </span>.unwrap_err();
<a href=#662 id=662 data-nosnippet>662</a>
<a href=#663 id=663 data-nosnippet>663</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(
<a href=#664 id=664 data-nosnippet>664</a> err,
<a href=#665 id=665 data-nosnippet>665</a> common_meta::error::Error::ReadOnlyKvBackend { .. }
<a href=#666 id=666 data-nosnippet>666</a> ));
<a href=#667 id=667 data-nosnippet>667</a> }
<a href=#668 id=668 data-nosnippet>668</a>
<a href=#669 id=669 data-nosnippet>669</a> <span class="attr">#[tokio::test]
<a href=#670 id=670 data-nosnippet>670</a> </span><span class="kw">async fn </span>test_read_only_meta_kv_backend_does_not_emulate_txn() {
<a href=#671 id=671 data-nosnippet>671</a> <span class="kw">let </span>meta_client = Arc::new(MetaClientBuilder::frontend_default_options().build());
<a href=#672 id=672 data-nosnippet>672</a> <span class="kw">let </span>backend = new_read_only_meta_kv_backend(meta_client);
<a href=#673 id=673 data-nosnippet>673</a>
<a href=#674 id=674 data-nosnippet>674</a> <span class="kw">let </span>result = backend
<a href=#675 id=675 data-nosnippet>675</a> .txn(Txn::new().and_then(<span class="macro">vec!</span>[TxnOp::Get(<span class="string">b"k1"</span>.to_vec())]))
<a href=#676 id=676 data-nosnippet>676</a> .<span class="kw">await</span>;
<a href=#677 id=677 data-nosnippet>677</a> <span class="kw">let </span>err = <span class="kw">match </span>result {
<a href=#678 id=678 data-nosnippet>678</a> <span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; <span class="macro">panic!</span>(<span class="string">"expected unsupported txn error"</span>),
<a href=#679 id=679 data-nosnippet>679</a> <span class="prelude-val">Err</span>(err) =&gt; err,
<a href=#680 id=680 data-nosnippet>680</a> };
<a href=#681 id=681 data-nosnippet>681</a>
<a href=#682 id=682 data-nosnippet>682</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(err, common_meta::error::Error::Unsupported { .. }));
<a href=#683 id=683 data-nosnippet>683</a> }
<a href=#684 id=684 data-nosnippet>684</a>
<a href=#685 id=685 data-nosnippet>685</a> <span class="kw">async fn </span>add_some_vals(kv_backend: <span class="kw-2">&amp;</span><span class="kw">impl </span>KvBackend) {
<a href=#686 id=686 data-nosnippet>686</a> kv_backend
<a href=#687 id=687 data-nosnippet>687</a> .put(PutRequest {
<a href=#688 id=688 data-nosnippet>688</a> key: <span class="string">b"k1"</span>.to_vec(),
<a href=#689 id=689 data-nosnippet>689</a> value: <span class="string">b"v1"</span>.to_vec(),
<a href=#690 id=690 data-nosnippet>690</a> prev_kv: <span class="bool-val">false</span>,
<a href=#691 id=691 data-nosnippet>691</a> })
<a href=#692 id=692 data-nosnippet>692</a> .<span class="kw">await
<a href=#693 id=693 data-nosnippet>693</a> </span>.unwrap();
<a href=#694 id=694 data-nosnippet>694</a>
<a href=#695 id=695 data-nosnippet>695</a> kv_backend
<a href=#696 id=696 data-nosnippet>696</a> .put(PutRequest {
<a href=#697 id=697 data-nosnippet>697</a> key: <span class="string">b"k2"</span>.to_vec(),
<a href=#698 id=698 data-nosnippet>698</a> value: <span class="string">b"v2"</span>.to_vec(),
<a href=#699 id=699 data-nosnippet>699</a> prev_kv: <span class="bool-val">false</span>,
<a href=#700 id=700 data-nosnippet>700</a> })
<a href=#701 id=701 data-nosnippet>701</a> .<span class="kw">await
<a href=#702 id=702 data-nosnippet>702</a> </span>.unwrap();
<a href=#703 id=703 data-nosnippet>703</a>
<a href=#704 id=704 data-nosnippet>704</a> kv_backend
<a href=#705 id=705 data-nosnippet>705</a> .put(PutRequest {
<a href=#706 id=706 data-nosnippet>706</a> key: <span class="string">b"k3"</span>.to_vec(),
<a href=#707 id=707 data-nosnippet>707</a> value: <span class="string">b"v3"</span>.to_vec(),
<a href=#708 id=708 data-nosnippet>708</a> prev_kv: <span class="bool-val">false</span>,
<a href=#709 id=709 data-nosnippet>709</a> })
<a href=#710 id=710 data-nosnippet>710</a> .<span class="kw">await
<a href=#711 id=711 data-nosnippet>711</a> </span>.unwrap();
<a href=#712 id=712 data-nosnippet>712</a> }
<a href=#713 id=713 data-nosnippet>713</a>}
</code></pre></div></section></main></body></html>
+783
View File
@@ -0,0 +1,783 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/kvbackend/manager.rs`."><title>manager.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/kvbackend/</div>manager.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::any::Any;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::collections::BTreeSet;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>std::sync::{Arc, OnceLock, Weak};
<a href=#18 id=18 data-nosnippet>18</a>
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>async_stream::try_stream;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_catalog::consts::{
<a href=#21 id=21 data-nosnippet>21</a> DEFAULT_CATALOG_NAME, DEFAULT_PRIVATE_SCHEMA_NAME, DEFAULT_SCHEMA_NAME,
<a href=#22 id=22 data-nosnippet>22</a> INFORMATION_SCHEMA_NAME, PG_CATALOG_NAME,
<a href=#23 id=23 data-nosnippet>23</a>};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>common_meta::cache::{
<a href=#26 id=26 data-nosnippet>26</a> LayeredCacheRegistryRef, TableInfoCacheRef, TableNameCacheRef, TableRoute, TableRouteCacheRef,
<a href=#27 id=27 data-nosnippet>27</a> ViewInfoCacheRef,
<a href=#28 id=28 data-nosnippet>28</a>};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>common_meta::key::TableMetadataManagerRef;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>common_meta::key::catalog_name::CatalogNameKey;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>common_meta::key::flow::FlowMetadataManager;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>common_meta::key::schema_name::SchemaNameKey;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>common_meta::key::table_info::TableInfoValue;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span>common_meta::key::table_name::TableNameKey;
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span>common_meta::kv_backend::KvBackendRef;
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>common_procedure::ProcedureManagerRef;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>futures_util::stream::BoxStream;
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span>futures_util::{StreamExt, TryStreamExt};
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span>moka::sync::Cache;
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">use </span>partition::manager::PartitionRuleManagerRef;
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span>session::context::{Channel, QueryContext};
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span>snafu::prelude::<span class="kw-2">*</span>;
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">use </span>store_api::metric_engine_consts::METRIC_ENGINE_NAME;
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">use </span>table::TableRef;
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">use </span>table::dist_table::DistTable;
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">use </span>table::metadata::{TableId, TableInfoRef};
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">use </span>table::table::PartitionRules;
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">use </span>table::table_name::TableName;
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">use </span>tokio::sync::Semaphore;
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">use </span>tokio_stream::wrappers::ReceiverStream;
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#54 id=54 data-nosnippet>54</a> CacheNotFoundSnafu, GetTableCacheSnafu, ListCatalogsSnafu, ListSchemasSnafu, ListTablesSnafu,
<a href=#55 id=55 data-nosnippet>55</a> <span class="prelude-ty">Result</span>, TableMetadataManagerSnafu,
<a href=#56 id=56 data-nosnippet>56</a>};
<a href=#57 id=57 data-nosnippet>57</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::{
<a href=#58 id=58 data-nosnippet>58</a> InformationExtensionRef, InformationSchemaProvider, InformationSchemaTableFactoryRef,
<a href=#59 id=59 data-nosnippet>59</a>};
<a href=#60 id=60 data-nosnippet>60</a><span class="kw">use </span><span class="kw">crate</span>::kvbackend::TableCacheRef;
<a href=#61 id=61 data-nosnippet>61</a><span class="kw">use </span><span class="kw">crate</span>::process_manager::ProcessManagerRef;
<a href=#62 id=62 data-nosnippet>62</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::SystemSchemaProvider;
<a href=#63 id=63 data-nosnippet>63</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::numbers_table_provider::NumbersTableProvider;
<a href=#64 id=64 data-nosnippet>64</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::pg_catalog::PGCatalogProvider;
<a href=#65 id=65 data-nosnippet>65</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::semantic_graph::{EntityGraphProviderRef, SemanticGraphTableProvider};
<a href=#66 id=66 data-nosnippet>66</a>
<a href=#67 id=67 data-nosnippet>67</a><span class="doccomment">/// Access all existing catalog, schema and tables.
<a href=#68 id=68 data-nosnippet>68</a>///
<a href=#69 id=69 data-nosnippet>69</a>/// The result comes from two source, all the user tables are presented in
<a href=#70 id=70 data-nosnippet>70</a>/// a kv-backend which persists the metadata of a table. And system tables
<a href=#71 id=71 data-nosnippet>71</a>/// comes from `SystemCatalog`, which is static and read-only.
<a href=#72 id=72 data-nosnippet>72</a></span><span class="attr">#[derive(Clone)]
<a href=#73 id=73 data-nosnippet>73</a></span><span class="kw">pub struct </span>KvBackendCatalogManager {
<a href=#74 id=74 data-nosnippet>74</a> <span class="doccomment">/// Provides the extension methods for the `information_schema` tables
<a href=#75 id=75 data-nosnippet>75</a> </span><span class="kw">pub</span>(<span class="kw">super</span>) information_extension: InformationExtensionRef,
<a href=#76 id=76 data-nosnippet>76</a> <span class="doccomment">/// Backs the computed entity-graph tables (`semantic_entities` /
<a href=#77 id=77 data-nosnippet>77</a> /// `semantic_relationships`). Set once, after the query engine is built, to
<a href=#78 id=78 data-nosnippet>78</a> /// break the `catalog -&gt; query` cycle; `None` until then. `Arc` so the cell
<a href=#79 id=79 data-nosnippet>79</a> /// stays shared across `Clone`s of the manager (a plain `OnceLock` would
<a href=#80 id=80 data-nosnippet>80</a> /// fork on clone).
<a href=#81 id=81 data-nosnippet>81</a> </span><span class="kw">pub</span>(<span class="kw">super</span>) entity_graph_provider: Arc&lt;OnceLock&lt;EntityGraphProviderRef&gt;&gt;,
<a href=#82 id=82 data-nosnippet>82</a> <span class="doccomment">/// Manages partition rules.
<a href=#83 id=83 data-nosnippet>83</a> </span><span class="kw">pub</span>(<span class="kw">super</span>) partition_manager: PartitionRuleManagerRef,
<a href=#84 id=84 data-nosnippet>84</a> <span class="doccomment">/// Manages table metadata.
<a href=#85 id=85 data-nosnippet>85</a> </span><span class="kw">pub</span>(<span class="kw">super</span>) table_metadata_manager: TableMetadataManagerRef,
<a href=#86 id=86 data-nosnippet>86</a> <span class="doccomment">/// A sub-CatalogManager that handles system tables
<a href=#87 id=87 data-nosnippet>87</a> </span><span class="kw">pub</span>(<span class="kw">super</span>) system_catalog: SystemCatalog,
<a href=#88 id=88 data-nosnippet>88</a> <span class="doccomment">/// Cache registry for all caches.
<a href=#89 id=89 data-nosnippet>89</a> </span><span class="kw">pub</span>(<span class="kw">super</span>) cache_registry: LayeredCacheRegistryRef,
<a href=#90 id=90 data-nosnippet>90</a> <span class="doccomment">/// Only available in `Standalone` mode.
<a href=#91 id=91 data-nosnippet>91</a> </span><span class="kw">pub</span>(<span class="kw">super</span>) procedure_manager: <span class="prelude-ty">Option</span>&lt;ProcedureManagerRef&gt;,
<a href=#92 id=92 data-nosnippet>92</a>}
<a href=#93 id=93 data-nosnippet>93</a>
<a href=#94 id=94 data-nosnippet>94</a><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">const </span>CATALOG_CACHE_MAX_CAPACITY: u64 = <span class="number">128</span>;
<a href=#95 id=95 data-nosnippet>95</a>
<a href=#96 id=96 data-nosnippet>96</a><span class="kw">impl </span>KvBackendCatalogManager {
<a href=#97 id=97 data-nosnippet>97</a> <span class="kw">pub fn </span>view_info_cache(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;ViewInfoCacheRef&gt; {
<a href=#98 id=98 data-nosnippet>98</a> <span class="self">self</span>.cache_registry.get().context(CacheNotFoundSnafu {
<a href=#99 id=99 data-nosnippet>99</a> name: <span class="string">"view_info_cache"</span>,
<a href=#100 id=100 data-nosnippet>100</a> })
<a href=#101 id=101 data-nosnippet>101</a> }
<a href=#102 id=102 data-nosnippet>102</a>
<a href=#103 id=103 data-nosnippet>103</a> <span class="doccomment">/// Returns the [`InformationExtension`].
<a href=#104 id=104 data-nosnippet>104</a> </span><span class="kw">pub fn </span>information_extension(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationExtensionRef {
<a href=#105 id=105 data-nosnippet>105</a> <span class="self">self</span>.information_extension.clone()
<a href=#106 id=106 data-nosnippet>106</a> }
<a href=#107 id=107 data-nosnippet>107</a>
<a href=#108 id=108 data-nosnippet>108</a> <span class="doccomment">/// Returns the entity-graph provider, or `None` if it has not been injected
<a href=#109 id=109 data-nosnippet>109</a> /// yet (before the query engine is built). The computed graph tables stream
<a href=#110 id=110 data-nosnippet>110</a> /// empty until it is set.
<a href=#111 id=111 data-nosnippet>111</a> </span><span class="kw">pub fn </span>entity_graph_provider(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;EntityGraphProviderRef&gt; {
<a href=#112 id=112 data-nosnippet>112</a> <span class="self">self</span>.entity_graph_provider.get().cloned()
<a href=#113 id=113 data-nosnippet>113</a> }
<a href=#114 id=114 data-nosnippet>114</a>
<a href=#115 id=115 data-nosnippet>115</a> <span class="doccomment">/// Injects the entity-graph provider once the query engine exists. A second
<a href=#116 id=116 data-nosnippet>116</a> /// call is a no-op (the first binding wins).
<a href=#117 id=117 data-nosnippet>117</a> </span><span class="kw">pub fn </span>set_entity_graph_provider(<span class="kw-2">&amp;</span><span class="self">self</span>, provider: EntityGraphProviderRef) {
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">let _ </span>= <span class="self">self</span>.entity_graph_provider.set(provider);
<a href=#119 id=119 data-nosnippet>119</a> }
<a href=#120 id=120 data-nosnippet>120</a>
<a href=#121 id=121 data-nosnippet>121</a> <span class="kw">pub fn </span>partition_manager(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; PartitionRuleManagerRef {
<a href=#122 id=122 data-nosnippet>122</a> <span class="self">self</span>.partition_manager.clone()
<a href=#123 id=123 data-nosnippet>123</a> }
<a href=#124 id=124 data-nosnippet>124</a>
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw">pub fn </span>table_metadata_manager_ref(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>TableMetadataManagerRef {
<a href=#126 id=126 data-nosnippet>126</a> <span class="kw-2">&amp;</span><span class="self">self</span>.table_metadata_manager
<a href=#127 id=127 data-nosnippet>127</a> }
<a href=#128 id=128 data-nosnippet>128</a>
<a href=#129 id=129 data-nosnippet>129</a> <span class="kw">pub fn </span>procedure_manager(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;ProcedureManagerRef&gt; {
<a href=#130 id=130 data-nosnippet>130</a> <span class="self">self</span>.procedure_manager.clone()
<a href=#131 id=131 data-nosnippet>131</a> }
<a href=#132 id=132 data-nosnippet>132</a>
<a href=#133 id=133 data-nosnippet>133</a> <span class="comment">// Override logical table's partition key indices with physical table's.
<a href=#134 id=134 data-nosnippet>134</a> </span><span class="kw">async fn </span>override_logical_table_partition_key_indices(
<a href=#135 id=135 data-nosnippet>135</a> table_route_cache: <span class="kw-2">&amp;</span>TableRouteCacheRef,
<a href=#136 id=136 data-nosnippet>136</a> table_info_cache: <span class="kw-2">&amp;</span>TableInfoCacheRef,
<a href=#137 id=137 data-nosnippet>137</a> table: TableRef,
<a href=#138 id=138 data-nosnippet>138</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;TableRef&gt; {
<a href=#139 id=139 data-nosnippet>139</a> <span class="comment">// If the table is not a metric table, return the table directly.
<a href=#140 id=140 data-nosnippet>140</a> </span><span class="kw">if </span>table.table_info().meta.engine != METRIC_ENGINE_NAME {
<a href=#141 id=141 data-nosnippet>141</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(table);
<a href=#142 id=142 data-nosnippet>142</a> }
<a href=#143 id=143 data-nosnippet>143</a>
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table_route_value) = table_route_cache
<a href=#145 id=145 data-nosnippet>145</a> .get(table.table_info().table_id())
<a href=#146 id=146 data-nosnippet>146</a> .<span class="kw">await
<a href=#147 id=147 data-nosnippet>147</a> </span>.context(TableMetadataManagerSnafu)<span class="question-mark">?
<a href=#148 id=148 data-nosnippet>148</a> </span>&amp;&amp; <span class="kw">let </span>TableRoute::Logical(logical_route) = <span class="kw-2">&amp;*</span>table_route_value
<a href=#149 id=149 data-nosnippet>149</a> &amp;&amp; <span class="kw">let </span><span class="prelude-val">Some</span>(physical_table_info) = table_info_cache
<a href=#150 id=150 data-nosnippet>150</a> .get(logical_route.physical_table_id())
<a href=#151 id=151 data-nosnippet>151</a> .<span class="kw">await
<a href=#152 id=152 data-nosnippet>152</a> </span>.context(TableMetadataManagerSnafu)<span class="question-mark">?
<a href=#153 id=153 data-nosnippet>153</a> </span>{
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">let </span><span class="kw-2">mut </span>new_table_info = (<span class="kw-2">*</span>table.table_info()).clone();
<a href=#155 id=155 data-nosnippet>155</a>
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">let </span><span class="kw-2">mut </span>phy_part_cols_not_in_logical_table = <span class="macro">vec!</span>[];
<a href=#157 id=157 data-nosnippet>157</a>
<a href=#158 id=158 data-nosnippet>158</a> <span class="comment">// Remap partition key indices from physical table to logical table
<a href=#159 id=159 data-nosnippet>159</a> </span>new_table_info.meta.partition_key_indices = physical_table_info
<a href=#160 id=160 data-nosnippet>160</a> .meta
<a href=#161 id=161 data-nosnippet>161</a> .partition_key_indices
<a href=#162 id=162 data-nosnippet>162</a> .iter()
<a href=#163 id=163 data-nosnippet>163</a> .filter_map(|<span class="kw-2">&amp;</span>physical_index| {
<a href=#164 id=164 data-nosnippet>164</a> <span class="comment">// Get the column name from the physical table using the physical index
<a href=#165 id=165 data-nosnippet>165</a> </span>physical_table_info
<a href=#166 id=166 data-nosnippet>166</a> .meta
<a href=#167 id=167 data-nosnippet>167</a> .schema
<a href=#168 id=168 data-nosnippet>168</a> .column_schemas()
<a href=#169 id=169 data-nosnippet>169</a> .get(physical_index)
<a href=#170 id=170 data-nosnippet>170</a> .and_then(|physical_column| {
<a href=#171 id=171 data-nosnippet>171</a> <span class="comment">// Find the corresponding index in the logical table schema
<a href=#172 id=172 data-nosnippet>172</a> </span><span class="kw">let </span>idx = new_table_info
<a href=#173 id=173 data-nosnippet>173</a> .meta
<a href=#174 id=174 data-nosnippet>174</a> .schema
<a href=#175 id=175 data-nosnippet>175</a> .column_index_by_name(physical_column.name.as_str());
<a href=#176 id=176 data-nosnippet>176</a> <span class="kw">if </span>idx.is_none() {
<a href=#177 id=177 data-nosnippet>177</a> <span class="comment">// not all part columns in physical table that are also in logical table
<a href=#178 id=178 data-nosnippet>178</a> </span>phy_part_cols_not_in_logical_table
<a href=#179 id=179 data-nosnippet>179</a> .push(physical_column.name.clone());
<a href=#180 id=180 data-nosnippet>180</a> }
<a href=#181 id=181 data-nosnippet>181</a>
<a href=#182 id=182 data-nosnippet>182</a> idx
<a href=#183 id=183 data-nosnippet>183</a> })
<a href=#184 id=184 data-nosnippet>184</a> })
<a href=#185 id=185 data-nosnippet>185</a> .collect();
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">let </span>partition_rules = <span class="kw">if </span>!phy_part_cols_not_in_logical_table.is_empty() {
<a href=#188 id=188 data-nosnippet>188</a> <span class="prelude-val">Some</span>(PartitionRules {
<a href=#189 id=189 data-nosnippet>189</a> extra_phy_cols_not_in_logical_table: phy_part_cols_not_in_logical_table,
<a href=#190 id=190 data-nosnippet>190</a> })
<a href=#191 id=191 data-nosnippet>191</a> } <span class="kw">else </span>{
<a href=#192 id=192 data-nosnippet>192</a> <span class="prelude-val">None
<a href=#193 id=193 data-nosnippet>193</a> </span>};
<a href=#194 id=194 data-nosnippet>194</a>
<a href=#195 id=195 data-nosnippet>195</a> <span class="kw">let </span>new_table = DistTable::table_partitioned(Arc::new(new_table_info), partition_rules);
<a href=#196 id=196 data-nosnippet>196</a>
<a href=#197 id=197 data-nosnippet>197</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(new_table);
<a href=#198 id=198 data-nosnippet>198</a> }
<a href=#199 id=199 data-nosnippet>199</a>
<a href=#200 id=200 data-nosnippet>200</a> <span class="prelude-val">Ok</span>(table)
<a href=#201 id=201 data-nosnippet>201</a> }
<a href=#202 id=202 data-nosnippet>202</a>}
<a href=#203 id=203 data-nosnippet>203</a>
<a href=#204 id=204 data-nosnippet>204</a><span class="attr">#[async_trait::async_trait]
<a href=#205 id=205 data-nosnippet>205</a></span><span class="kw">impl </span>CatalogManager <span class="kw">for </span>KvBackendCatalogManager {
<a href=#206 id=206 data-nosnippet>206</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>Any {
<a href=#207 id=207 data-nosnippet>207</a> <span class="self">self
<a href=#208 id=208 data-nosnippet>208</a> </span>}
<a href=#209 id=209 data-nosnippet>209</a>
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">async fn </span>catalog_names(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt; {
<a href=#211 id=211 data-nosnippet>211</a> <span class="kw">let </span>stream = <span class="self">self
<a href=#212 id=212 data-nosnippet>212</a> </span>.table_metadata_manager
<a href=#213 id=213 data-nosnippet>213</a> .catalog_manager()
<a href=#214 id=214 data-nosnippet>214</a> .catalog_names();
<a href=#215 id=215 data-nosnippet>215</a>
<a href=#216 id=216 data-nosnippet>216</a> <span class="kw">let </span>keys = stream
<a href=#217 id=217 data-nosnippet>217</a> .try_collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;()
<a href=#218 id=218 data-nosnippet>218</a> .<span class="kw">await
<a href=#219 id=219 data-nosnippet>219</a> </span>.map_err(BoxedError::new)
<a href=#220 id=220 data-nosnippet>220</a> .context(ListCatalogsSnafu)<span class="question-mark">?</span>;
<a href=#221 id=221 data-nosnippet>221</a>
<a href=#222 id=222 data-nosnippet>222</a> <span class="prelude-val">Ok</span>(keys)
<a href=#223 id=223 data-nosnippet>223</a> }
<a href=#224 id=224 data-nosnippet>224</a>
<a href=#225 id=225 data-nosnippet>225</a> <span class="kw">async fn </span>schema_names(
<a href=#226 id=226 data-nosnippet>226</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#227 id=227 data-nosnippet>227</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#228 id=228 data-nosnippet>228</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#229 id=229 data-nosnippet>229</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt; {
<a href=#230 id=230 data-nosnippet>230</a> <span class="kw">let </span>stream = <span class="self">self
<a href=#231 id=231 data-nosnippet>231</a> </span>.table_metadata_manager
<a href=#232 id=232 data-nosnippet>232</a> .schema_manager()
<a href=#233 id=233 data-nosnippet>233</a> .schema_names(catalog);
<a href=#234 id=234 data-nosnippet>234</a> <span class="kw">let </span><span class="kw-2">mut </span>keys = stream
<a href=#235 id=235 data-nosnippet>235</a> .try_collect::&lt;BTreeSet&lt;<span class="kw">_</span>&gt;&gt;()
<a href=#236 id=236 data-nosnippet>236</a> .<span class="kw">await
<a href=#237 id=237 data-nosnippet>237</a> </span>.map_err(BoxedError::new)
<a href=#238 id=238 data-nosnippet>238</a> .context(ListSchemasSnafu { catalog })<span class="question-mark">?</span>;
<a href=#239 id=239 data-nosnippet>239</a>
<a href=#240 id=240 data-nosnippet>240</a> keys.extend(<span class="self">self</span>.system_catalog.schema_names(query_ctx));
<a href=#241 id=241 data-nosnippet>241</a>
<a href=#242 id=242 data-nosnippet>242</a> <span class="prelude-val">Ok</span>(keys.into_iter().collect())
<a href=#243 id=243 data-nosnippet>243</a> }
<a href=#244 id=244 data-nosnippet>244</a>
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw">async fn </span>table_names(
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#247 id=247 data-nosnippet>247</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#248 id=248 data-nosnippet>248</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#249 id=249 data-nosnippet>249</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#250 id=250 data-nosnippet>250</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt; {
<a href=#251 id=251 data-nosnippet>251</a> <span class="kw">let </span><span class="kw-2">mut </span>tables = <span class="self">self
<a href=#252 id=252 data-nosnippet>252</a> </span>.table_metadata_manager
<a href=#253 id=253 data-nosnippet>253</a> .table_name_manager()
<a href=#254 id=254 data-nosnippet>254</a> .tables(catalog, schema)
<a href=#255 id=255 data-nosnippet>255</a> .map_ok(|(table_name, <span class="kw">_</span>)| table_name)
<a href=#256 id=256 data-nosnippet>256</a> .try_collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;()
<a href=#257 id=257 data-nosnippet>257</a> .<span class="kw">await
<a href=#258 id=258 data-nosnippet>258</a> </span>.map_err(BoxedError::new)
<a href=#259 id=259 data-nosnippet>259</a> .context(ListTablesSnafu { catalog, schema })<span class="question-mark">?</span>;
<a href=#260 id=260 data-nosnippet>260</a>
<a href=#261 id=261 data-nosnippet>261</a> tables.extend(<span class="self">self</span>.system_catalog.table_names(schema, query_ctx));
<a href=#262 id=262 data-nosnippet>262</a> <span class="prelude-val">Ok</span>(tables)
<a href=#263 id=263 data-nosnippet>263</a> }
<a href=#264 id=264 data-nosnippet>264</a>
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">async fn </span>catalog_exists(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;bool&gt; {
<a href=#266 id=266 data-nosnippet>266</a> <span class="self">self</span>.table_metadata_manager
<a href=#267 id=267 data-nosnippet>267</a> .catalog_manager()
<a href=#268 id=268 data-nosnippet>268</a> .exists(CatalogNameKey::new(catalog))
<a href=#269 id=269 data-nosnippet>269</a> .<span class="kw">await
<a href=#270 id=270 data-nosnippet>270</a> </span>.context(TableMetadataManagerSnafu)
<a href=#271 id=271 data-nosnippet>271</a> }
<a href=#272 id=272 data-nosnippet>272</a>
<a href=#273 id=273 data-nosnippet>273</a> <span class="kw">async fn </span>schema_exists(
<a href=#274 id=274 data-nosnippet>274</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#275 id=275 data-nosnippet>275</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#276 id=276 data-nosnippet>276</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#277 id=277 data-nosnippet>277</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#278 id=278 data-nosnippet>278</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;bool&gt; {
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">if </span><span class="self">self</span>.system_catalog.schema_exists(schema, query_ctx) {
<a href=#280 id=280 data-nosnippet>280</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="bool-val">true</span>);
<a href=#281 id=281 data-nosnippet>281</a> }
<a href=#282 id=282 data-nosnippet>282</a>
<a href=#283 id=283 data-nosnippet>283</a> <span class="self">self</span>.table_metadata_manager
<a href=#284 id=284 data-nosnippet>284</a> .schema_manager()
<a href=#285 id=285 data-nosnippet>285</a> .exists(SchemaNameKey::new(catalog, schema))
<a href=#286 id=286 data-nosnippet>286</a> .<span class="kw">await
<a href=#287 id=287 data-nosnippet>287</a> </span>.context(TableMetadataManagerSnafu)
<a href=#288 id=288 data-nosnippet>288</a> }
<a href=#289 id=289 data-nosnippet>289</a>
<a href=#290 id=290 data-nosnippet>290</a> <span class="kw">async fn </span>table_exists(
<a href=#291 id=291 data-nosnippet>291</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#292 id=292 data-nosnippet>292</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#293 id=293 data-nosnippet>293</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#294 id=294 data-nosnippet>294</a> table: <span class="kw-2">&amp;</span>str,
<a href=#295 id=295 data-nosnippet>295</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#296 id=296 data-nosnippet>296</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;bool&gt; {
<a href=#297 id=297 data-nosnippet>297</a> <span class="kw">if </span><span class="self">self</span>.system_catalog.table_exists(schema, table, query_ctx) {
<a href=#298 id=298 data-nosnippet>298</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="bool-val">true</span>);
<a href=#299 id=299 data-nosnippet>299</a> }
<a href=#300 id=300 data-nosnippet>300</a>
<a href=#301 id=301 data-nosnippet>301</a> <span class="kw">let </span>key = TableNameKey::new(catalog, schema, table);
<a href=#302 id=302 data-nosnippet>302</a> <span class="self">self</span>.table_metadata_manager
<a href=#303 id=303 data-nosnippet>303</a> .table_name_manager()
<a href=#304 id=304 data-nosnippet>304</a> .get(key)
<a href=#305 id=305 data-nosnippet>305</a> .<span class="kw">await
<a href=#306 id=306 data-nosnippet>306</a> </span>.context(TableMetadataManagerSnafu)
<a href=#307 id=307 data-nosnippet>307</a> .map(|x| x.is_some())
<a href=#308 id=308 data-nosnippet>308</a> }
<a href=#309 id=309 data-nosnippet>309</a>
<a href=#310 id=310 data-nosnippet>310</a> <span class="kw">async fn </span>table(
<a href=#311 id=311 data-nosnippet>311</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#312 id=312 data-nosnippet>312</a> catalog_name: <span class="kw-2">&amp;</span>str,
<a href=#313 id=313 data-nosnippet>313</a> schema_name: <span class="kw-2">&amp;</span>str,
<a href=#314 id=314 data-nosnippet>314</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#315 id=315 data-nosnippet>315</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#316 id=316 data-nosnippet>316</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;TableRef&gt;&gt; {
<a href=#317 id=317 data-nosnippet>317</a> <span class="kw">let </span>channel = query_ctx.map_or(Channel::Unknown, |ctx| ctx.channel());
<a href=#318 id=318 data-nosnippet>318</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table) =
<a href=#319 id=319 data-nosnippet>319</a> <span class="self">self</span>.system_catalog
<a href=#320 id=320 data-nosnippet>320</a> .table(catalog_name, schema_name, table_name, query_ctx)
<a href=#321 id=321 data-nosnippet>321</a> {
<a href=#322 id=322 data-nosnippet>322</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(table));
<a href=#323 id=323 data-nosnippet>323</a> }
<a href=#324 id=324 data-nosnippet>324</a>
<a href=#325 id=325 data-nosnippet>325</a> <span class="kw">let </span>table_cache: TableCacheRef = <span class="self">self</span>.cache_registry.get().context(CacheNotFoundSnafu {
<a href=#326 id=326 data-nosnippet>326</a> name: <span class="string">"table_cache"</span>,
<a href=#327 id=327 data-nosnippet>327</a> })<span class="question-mark">?</span>;
<a href=#328 id=328 data-nosnippet>328</a>
<a href=#329 id=329 data-nosnippet>329</a> <span class="kw">let </span>table = table_cache
<a href=#330 id=330 data-nosnippet>330</a> .get_by_ref(<span class="kw-2">&amp;</span>TableName {
<a href=#331 id=331 data-nosnippet>331</a> catalog_name: catalog_name.to_string(),
<a href=#332 id=332 data-nosnippet>332</a> schema_name: schema_name.to_string(),
<a href=#333 id=333 data-nosnippet>333</a> table_name: table_name.to_string(),
<a href=#334 id=334 data-nosnippet>334</a> })
<a href=#335 id=335 data-nosnippet>335</a> .<span class="kw">await
<a href=#336 id=336 data-nosnippet>336</a> </span>.context(GetTableCacheSnafu)<span class="question-mark">?</span>;
<a href=#337 id=337 data-nosnippet>337</a>
<a href=#338 id=338 data-nosnippet>338</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table) = table {
<a href=#339 id=339 data-nosnippet>339</a> <span class="kw">let </span>table_route_cache: TableRouteCacheRef =
<a href=#340 id=340 data-nosnippet>340</a> <span class="self">self</span>.cache_registry.get().context(CacheNotFoundSnafu {
<a href=#341 id=341 data-nosnippet>341</a> name: <span class="string">"table_route_cache"</span>,
<a href=#342 id=342 data-nosnippet>342</a> })<span class="question-mark">?</span>;
<a href=#343 id=343 data-nosnippet>343</a> <span class="kw">let </span>table_info_cache: TableInfoCacheRef =
<a href=#344 id=344 data-nosnippet>344</a> <span class="self">self</span>.cache_registry.get().context(CacheNotFoundSnafu {
<a href=#345 id=345 data-nosnippet>345</a> name: <span class="string">"table_info_cache"</span>,
<a href=#346 id=346 data-nosnippet>346</a> })<span class="question-mark">?</span>;
<a href=#347 id=347 data-nosnippet>347</a> <span class="kw">return </span><span class="self">Self</span>::override_logical_table_partition_key_indices(
<a href=#348 id=348 data-nosnippet>348</a> <span class="kw-2">&amp;</span>table_route_cache,
<a href=#349 id=349 data-nosnippet>349</a> <span class="kw-2">&amp;</span>table_info_cache,
<a href=#350 id=350 data-nosnippet>350</a> table,
<a href=#351 id=351 data-nosnippet>351</a> )
<a href=#352 id=352 data-nosnippet>352</a> .<span class="kw">await
<a href=#353 id=353 data-nosnippet>353</a> </span>.map(<span class="prelude-val">Some</span>);
<a href=#354 id=354 data-nosnippet>354</a> }
<a href=#355 id=355 data-nosnippet>355</a>
<a href=#356 id=356 data-nosnippet>356</a> <span class="kw">if </span>channel == Channel::Postgres {
<a href=#357 id=357 data-nosnippet>357</a> <span class="comment">// falldown to pg_catalog
<a href=#358 id=358 data-nosnippet>358</a> </span><span class="kw">if let </span><span class="prelude-val">Some</span>(table) =
<a href=#359 id=359 data-nosnippet>359</a> <span class="self">self</span>.system_catalog
<a href=#360 id=360 data-nosnippet>360</a> .table(catalog_name, PG_CATALOG_NAME, table_name, query_ctx)
<a href=#361 id=361 data-nosnippet>361</a> {
<a href=#362 id=362 data-nosnippet>362</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(table));
<a href=#363 id=363 data-nosnippet>363</a> }
<a href=#364 id=364 data-nosnippet>364</a> }
<a href=#365 id=365 data-nosnippet>365</a>
<a href=#366 id=366 data-nosnippet>366</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
<a href=#367 id=367 data-nosnippet>367</a> }
<a href=#368 id=368 data-nosnippet>368</a>
<a href=#369 id=369 data-nosnippet>369</a> <span class="kw">async fn </span>table_id(
<a href=#370 id=370 data-nosnippet>370</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#371 id=371 data-nosnippet>371</a> catalog_name: <span class="kw-2">&amp;</span>str,
<a href=#372 id=372 data-nosnippet>372</a> schema_name: <span class="kw-2">&amp;</span>str,
<a href=#373 id=373 data-nosnippet>373</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#374 id=374 data-nosnippet>374</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#375 id=375 data-nosnippet>375</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;TableId&gt;&gt; {
<a href=#376 id=376 data-nosnippet>376</a> <span class="kw">let </span>channel = query_ctx.map_or(Channel::Unknown, |ctx| ctx.channel());
<a href=#377 id=377 data-nosnippet>377</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table) =
<a href=#378 id=378 data-nosnippet>378</a> <span class="self">self</span>.system_catalog
<a href=#379 id=379 data-nosnippet>379</a> .table(catalog_name, schema_name, table_name, query_ctx)
<a href=#380 id=380 data-nosnippet>380</a> {
<a href=#381 id=381 data-nosnippet>381</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(table.table_info().table_id()));
<a href=#382 id=382 data-nosnippet>382</a> }
<a href=#383 id=383 data-nosnippet>383</a>
<a href=#384 id=384 data-nosnippet>384</a> <span class="kw">let </span>table_cache: TableNameCacheRef =
<a href=#385 id=385 data-nosnippet>385</a> <span class="self">self</span>.cache_registry.get().context(CacheNotFoundSnafu {
<a href=#386 id=386 data-nosnippet>386</a> name: <span class="string">"table_name_cache"</span>,
<a href=#387 id=387 data-nosnippet>387</a> })<span class="question-mark">?</span>;
<a href=#388 id=388 data-nosnippet>388</a>
<a href=#389 id=389 data-nosnippet>389</a> <span class="kw">let </span>table = table_cache
<a href=#390 id=390 data-nosnippet>390</a> .get_by_ref(<span class="kw-2">&amp;</span>TableName {
<a href=#391 id=391 data-nosnippet>391</a> catalog_name: catalog_name.to_string(),
<a href=#392 id=392 data-nosnippet>392</a> schema_name: schema_name.to_string(),
<a href=#393 id=393 data-nosnippet>393</a> table_name: table_name.to_string(),
<a href=#394 id=394 data-nosnippet>394</a> })
<a href=#395 id=395 data-nosnippet>395</a> .<span class="kw">await
<a href=#396 id=396 data-nosnippet>396</a> </span>.context(GetTableCacheSnafu)<span class="question-mark">?</span>;
<a href=#397 id=397 data-nosnippet>397</a>
<a href=#398 id=398 data-nosnippet>398</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table) = table {
<a href=#399 id=399 data-nosnippet>399</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(table));
<a href=#400 id=400 data-nosnippet>400</a> }
<a href=#401 id=401 data-nosnippet>401</a>
<a href=#402 id=402 data-nosnippet>402</a> <span class="kw">if </span>channel == Channel::Postgres {
<a href=#403 id=403 data-nosnippet>403</a> <span class="comment">// falldown to pg_catalog
<a href=#404 id=404 data-nosnippet>404</a> </span><span class="kw">if let </span><span class="prelude-val">Some</span>(table) =
<a href=#405 id=405 data-nosnippet>405</a> <span class="self">self</span>.system_catalog
<a href=#406 id=406 data-nosnippet>406</a> .table(catalog_name, PG_CATALOG_NAME, table_name, query_ctx)
<a href=#407 id=407 data-nosnippet>407</a> {
<a href=#408 id=408 data-nosnippet>408</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(table.table_info().table_id()));
<a href=#409 id=409 data-nosnippet>409</a> }
<a href=#410 id=410 data-nosnippet>410</a> }
<a href=#411 id=411 data-nosnippet>411</a>
<a href=#412 id=412 data-nosnippet>412</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
<a href=#413 id=413 data-nosnippet>413</a> }
<a href=#414 id=414 data-nosnippet>414</a>
<a href=#415 id=415 data-nosnippet>415</a> <span class="kw">async fn </span>table_info_by_id(<span class="kw-2">&amp;</span><span class="self">self</span>, table_id: TableId) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;TableInfoRef&gt;&gt; {
<a href=#416 id=416 data-nosnippet>416</a> <span class="kw">let </span>table_info_cache: TableInfoCacheRef =
<a href=#417 id=417 data-nosnippet>417</a> <span class="self">self</span>.cache_registry.get().context(CacheNotFoundSnafu {
<a href=#418 id=418 data-nosnippet>418</a> name: <span class="string">"table_info_cache"</span>,
<a href=#419 id=419 data-nosnippet>419</a> })<span class="question-mark">?</span>;
<a href=#420 id=420 data-nosnippet>420</a> table_info_cache
<a href=#421 id=421 data-nosnippet>421</a> .get_by_ref(<span class="kw-2">&amp;</span>table_id)
<a href=#422 id=422 data-nosnippet>422</a> .<span class="kw">await
<a href=#423 id=423 data-nosnippet>423</a> </span>.context(GetTableCacheSnafu)
<a href=#424 id=424 data-nosnippet>424</a> }
<a href=#425 id=425 data-nosnippet>425</a>
<a href=#426 id=426 data-nosnippet>426</a> <span class="kw">async fn </span>tables_by_ids(
<a href=#427 id=427 data-nosnippet>427</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#428 id=428 data-nosnippet>428</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#429 id=429 data-nosnippet>429</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#430 id=430 data-nosnippet>430</a> table_ids: <span class="kw-2">&amp;</span>[TableId],
<a href=#431 id=431 data-nosnippet>431</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;TableRef&gt;&gt; {
<a href=#432 id=432 data-nosnippet>432</a> <span class="kw">let </span>table_info_values = <span class="self">self
<a href=#433 id=433 data-nosnippet>433</a> </span>.table_metadata_manager
<a href=#434 id=434 data-nosnippet>434</a> .table_info_manager()
<a href=#435 id=435 data-nosnippet>435</a> .batch_get(table_ids)
<a href=#436 id=436 data-nosnippet>436</a> .<span class="kw">await
<a href=#437 id=437 data-nosnippet>437</a> </span>.context(TableMetadataManagerSnafu)<span class="question-mark">?</span>;
<a href=#438 id=438 data-nosnippet>438</a>
<a href=#439 id=439 data-nosnippet>439</a> <span class="kw">let </span>tables = table_info_values
<a href=#440 id=440 data-nosnippet>440</a> .into_values()
<a href=#441 id=441 data-nosnippet>441</a> .filter(|t| t.table_info.catalog_name == catalog &amp;&amp; t.table_info.schema_name == schema)
<a href=#442 id=442 data-nosnippet>442</a> .map(build_table)
<a href=#443 id=443 data-nosnippet>443</a> .collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;();
<a href=#444 id=444 data-nosnippet>444</a>
<a href=#445 id=445 data-nosnippet>445</a> <span class="prelude-val">Ok</span>(tables)
<a href=#446 id=446 data-nosnippet>446</a> }
<a href=#447 id=447 data-nosnippet>447</a>
<a href=#448 id=448 data-nosnippet>448</a> <span class="kw">fn </span>tables&lt;<span class="lifetime">'a</span>&gt;(
<a href=#449 id=449 data-nosnippet>449</a> <span class="kw-2">&amp;</span><span class="lifetime">'a </span><span class="self">self</span>,
<a href=#450 id=450 data-nosnippet>450</a> catalog: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str,
<a href=#451 id=451 data-nosnippet>451</a> schema: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str,
<a href=#452 id=452 data-nosnippet>452</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span><span class="lifetime">'a </span>QueryContext&gt;,
<a href=#453 id=453 data-nosnippet>453</a> ) -&gt; BoxStream&lt;<span class="lifetime">'a</span>, <span class="prelude-ty">Result</span>&lt;TableRef&gt;&gt; {
<a href=#454 id=454 data-nosnippet>454</a> <span class="kw">let </span>sys_tables = <span class="macro">try_stream!</span>({
<a href=#455 id=455 data-nosnippet>455</a> <span class="comment">// System tables
<a href=#456 id=456 data-nosnippet>456</a> </span><span class="kw">let </span>sys_table_names = <span class="self">self</span>.system_catalog.table_names(schema, query_ctx);
<a href=#457 id=457 data-nosnippet>457</a> <span class="kw">for </span>table_name <span class="kw">in </span>sys_table_names {
<a href=#458 id=458 data-nosnippet>458</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table) =
<a href=#459 id=459 data-nosnippet>459</a> <span class="self">self</span>.system_catalog
<a href=#460 id=460 data-nosnippet>460</a> .table(catalog, schema, <span class="kw-2">&amp;</span>table_name, query_ctx)
<a href=#461 id=461 data-nosnippet>461</a> {
<a href=#462 id=462 data-nosnippet>462</a> <span class="kw">yield </span>table;
<a href=#463 id=463 data-nosnippet>463</a> }
<a href=#464 id=464 data-nosnippet>464</a> }
<a href=#465 id=465 data-nosnippet>465</a> });
<a href=#466 id=466 data-nosnippet>466</a>
<a href=#467 id=467 data-nosnippet>467</a> <span class="kw">const </span>BATCH_SIZE: usize = <span class="number">128</span>;
<a href=#468 id=468 data-nosnippet>468</a> <span class="kw">const </span>CONCURRENCY: usize = <span class="number">8</span>;
<a href=#469 id=469 data-nosnippet>469</a>
<a href=#470 id=470 data-nosnippet>470</a> <span class="kw">let </span>(tx, rx) = tokio::sync::mpsc::channel(<span class="number">64</span>);
<a href=#471 id=471 data-nosnippet>471</a> <span class="kw">let </span>metadata_manager = <span class="self">self</span>.table_metadata_manager.clone();
<a href=#472 id=472 data-nosnippet>472</a> <span class="kw">let </span>catalog = catalog.to_string();
<a href=#473 id=473 data-nosnippet>473</a> <span class="kw">let </span>schema = schema.to_string();
<a href=#474 id=474 data-nosnippet>474</a> <span class="kw">let </span>semaphore = Arc::new(Semaphore::new(CONCURRENCY));
<a href=#475 id=475 data-nosnippet>475</a> <span class="kw">let </span>table_route_cache: <span class="prelude-ty">Result</span>&lt;TableRouteCacheRef&gt; =
<a href=#476 id=476 data-nosnippet>476</a> <span class="self">self</span>.cache_registry.get().context(CacheNotFoundSnafu {
<a href=#477 id=477 data-nosnippet>477</a> name: <span class="string">"table_route_cache"</span>,
<a href=#478 id=478 data-nosnippet>478</a> });
<a href=#479 id=479 data-nosnippet>479</a> <span class="kw">let </span>table_info_cache: <span class="prelude-ty">Result</span>&lt;TableInfoCacheRef&gt; =
<a href=#480 id=480 data-nosnippet>480</a> <span class="self">self</span>.cache_registry.get().context(CacheNotFoundSnafu {
<a href=#481 id=481 data-nosnippet>481</a> name: <span class="string">"table_info_cache"</span>,
<a href=#482 id=482 data-nosnippet>482</a> });
<a href=#483 id=483 data-nosnippet>483</a>
<a href=#484 id=484 data-nosnippet>484</a> common_runtime::spawn_global(<span class="kw">async move </span>{
<a href=#485 id=485 data-nosnippet>485</a> <span class="kw">let </span>table_route_cache = <span class="kw">match </span>table_route_cache {
<a href=#486 id=486 data-nosnippet>486</a> <span class="prelude-val">Ok</span>(table_route_cache) =&gt; table_route_cache,
<a href=#487 id=487 data-nosnippet>487</a> <span class="prelude-val">Err</span>(e) =&gt; {
<a href=#488 id=488 data-nosnippet>488</a> <span class="kw">let _ </span>= tx.send(<span class="prelude-val">Err</span>(e)).<span class="kw">await</span>;
<a href=#489 id=489 data-nosnippet>489</a> <span class="kw">return</span>;
<a href=#490 id=490 data-nosnippet>490</a> }
<a href=#491 id=491 data-nosnippet>491</a> };
<a href=#492 id=492 data-nosnippet>492</a> <span class="kw">let </span>table_info_cache = <span class="kw">match </span>table_info_cache {
<a href=#493 id=493 data-nosnippet>493</a> <span class="prelude-val">Ok</span>(table_info_cache) =&gt; table_info_cache,
<a href=#494 id=494 data-nosnippet>494</a> <span class="prelude-val">Err</span>(e) =&gt; {
<a href=#495 id=495 data-nosnippet>495</a> <span class="kw">let _ </span>= tx.send(<span class="prelude-val">Err</span>(e)).<span class="kw">await</span>;
<a href=#496 id=496 data-nosnippet>496</a> <span class="kw">return</span>;
<a href=#497 id=497 data-nosnippet>497</a> }
<a href=#498 id=498 data-nosnippet>498</a> };
<a href=#499 id=499 data-nosnippet>499</a>
<a href=#500 id=500 data-nosnippet>500</a> <span class="kw">let </span>table_id_stream = metadata_manager
<a href=#501 id=501 data-nosnippet>501</a> .table_name_manager()
<a href=#502 id=502 data-nosnippet>502</a> .tables(<span class="kw-2">&amp;</span>catalog, <span class="kw-2">&amp;</span>schema)
<a href=#503 id=503 data-nosnippet>503</a> .map_ok(|(<span class="kw">_</span>, v)| v.table_id());
<a href=#504 id=504 data-nosnippet>504</a> <span class="comment">// Split table ids into chunks
<a href=#505 id=505 data-nosnippet>505</a> </span><span class="kw">let </span><span class="kw-2">mut </span>table_id_chunks = table_id_stream.ready_chunks(BATCH_SIZE);
<a href=#506 id=506 data-nosnippet>506</a>
<a href=#507 id=507 data-nosnippet>507</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(table_ids) = table_id_chunks.next().<span class="kw">await </span>{
<a href=#508 id=508 data-nosnippet>508</a> <span class="kw">let </span>table_ids = <span class="kw">match </span>table_ids
<a href=#509 id=509 data-nosnippet>509</a> .into_iter()
<a href=#510 id=510 data-nosnippet>510</a> .collect::&lt;std::result::Result&lt;Vec&lt;<span class="kw">_</span>&gt;, <span class="kw">_</span>&gt;&gt;()
<a href=#511 id=511 data-nosnippet>511</a> .map_err(BoxedError::new)
<a href=#512 id=512 data-nosnippet>512</a> .context(ListTablesSnafu {
<a href=#513 id=513 data-nosnippet>513</a> catalog: <span class="kw-2">&amp;</span>catalog,
<a href=#514 id=514 data-nosnippet>514</a> schema: <span class="kw-2">&amp;</span>schema,
<a href=#515 id=515 data-nosnippet>515</a> }) {
<a href=#516 id=516 data-nosnippet>516</a> <span class="prelude-val">Ok</span>(table_ids) =&gt; table_ids,
<a href=#517 id=517 data-nosnippet>517</a> <span class="prelude-val">Err</span>(e) =&gt; {
<a href=#518 id=518 data-nosnippet>518</a> <span class="kw">let _ </span>= tx.send(<span class="prelude-val">Err</span>(e)).<span class="kw">await</span>;
<a href=#519 id=519 data-nosnippet>519</a> <span class="kw">return</span>;
<a href=#520 id=520 data-nosnippet>520</a> }
<a href=#521 id=521 data-nosnippet>521</a> };
<a href=#522 id=522 data-nosnippet>522</a>
<a href=#523 id=523 data-nosnippet>523</a> <span class="kw">let </span>metadata_manager = metadata_manager.clone();
<a href=#524 id=524 data-nosnippet>524</a> <span class="kw">let </span>tx = tx.clone();
<a href=#525 id=525 data-nosnippet>525</a> <span class="kw">let </span>semaphore = semaphore.clone();
<a href=#526 id=526 data-nosnippet>526</a> <span class="kw">let </span>table_route_cache = table_route_cache.clone();
<a href=#527 id=527 data-nosnippet>527</a> <span class="kw">let </span>table_info_cache = table_info_cache.clone();
<a href=#528 id=528 data-nosnippet>528</a> common_runtime::spawn_global(<span class="kw">async move </span>{
<a href=#529 id=529 data-nosnippet>529</a> <span class="comment">// we don't explicitly close the semaphore so just ignore the potential error.
<a href=#530 id=530 data-nosnippet>530</a> </span><span class="kw">let _ </span>= semaphore.acquire().<span class="kw">await</span>;
<a href=#531 id=531 data-nosnippet>531</a> <span class="kw">let </span>table_info_values = <span class="kw">match </span>metadata_manager
<a href=#532 id=532 data-nosnippet>532</a> .table_info_manager()
<a href=#533 id=533 data-nosnippet>533</a> .batch_get(<span class="kw-2">&amp;</span>table_ids)
<a href=#534 id=534 data-nosnippet>534</a> .<span class="kw">await
<a href=#535 id=535 data-nosnippet>535</a> </span>.context(TableMetadataManagerSnafu)
<a href=#536 id=536 data-nosnippet>536</a> {
<a href=#537 id=537 data-nosnippet>537</a> <span class="prelude-val">Ok</span>(table_info_values) =&gt; table_info_values,
<a href=#538 id=538 data-nosnippet>538</a> <span class="prelude-val">Err</span>(e) =&gt; {
<a href=#539 id=539 data-nosnippet>539</a> <span class="kw">let _ </span>= tx.send(<span class="prelude-val">Err</span>(e)).<span class="kw">await</span>;
<a href=#540 id=540 data-nosnippet>540</a> <span class="kw">return</span>;
<a href=#541 id=541 data-nosnippet>541</a> }
<a href=#542 id=542 data-nosnippet>542</a> };
<a href=#543 id=543 data-nosnippet>543</a>
<a href=#544 id=544 data-nosnippet>544</a> <span class="kw">for </span>table <span class="kw">in </span>table_info_values.into_values().map(build_table) {
<a href=#545 id=545 data-nosnippet>545</a> <span class="kw">let </span>table = <span class="self">Self</span>::override_logical_table_partition_key_indices(
<a href=#546 id=546 data-nosnippet>546</a> <span class="kw-2">&amp;</span>table_route_cache,
<a href=#547 id=547 data-nosnippet>547</a> <span class="kw-2">&amp;</span>table_info_cache,
<a href=#548 id=548 data-nosnippet>548</a> table,
<a href=#549 id=549 data-nosnippet>549</a> )
<a href=#550 id=550 data-nosnippet>550</a> .<span class="kw">await</span>;
<a href=#551 id=551 data-nosnippet>551</a> <span class="kw">if </span>tx.send(table).<span class="kw">await</span>.is_err() {
<a href=#552 id=552 data-nosnippet>552</a> <span class="kw">return</span>;
<a href=#553 id=553 data-nosnippet>553</a> }
<a href=#554 id=554 data-nosnippet>554</a> }
<a href=#555 id=555 data-nosnippet>555</a> });
<a href=#556 id=556 data-nosnippet>556</a> }
<a href=#557 id=557 data-nosnippet>557</a> });
<a href=#558 id=558 data-nosnippet>558</a>
<a href=#559 id=559 data-nosnippet>559</a> <span class="kw">let </span>user_tables = ReceiverStream::new(rx);
<a href=#560 id=560 data-nosnippet>560</a> Box::pin(sys_tables.chain(user_tables))
<a href=#561 id=561 data-nosnippet>561</a> }
<a href=#562 id=562 data-nosnippet>562</a>}
<a href=#563 id=563 data-nosnippet>563</a>
<a href=#564 id=564 data-nosnippet>564</a><span class="kw">fn </span>build_table(table_info_value: TableInfoValue) -&gt; TableRef {
<a href=#565 id=565 data-nosnippet>565</a> <span class="kw">let </span>table_info = table_info_value.table_info;
<a href=#566 id=566 data-nosnippet>566</a> DistTable::table(Arc::new(table_info))
<a href=#567 id=567 data-nosnippet>567</a>}
<a href=#568 id=568 data-nosnippet>568</a>
<a href=#569 id=569 data-nosnippet>569</a><span class="comment">// TODO: This struct can hold a static map of all system tables when
<a href=#570 id=570 data-nosnippet>570</a>// the upper layer (e.g., procedure) can inform the catalog manager
<a href=#571 id=571 data-nosnippet>571</a>// a new catalog is created.
<a href=#572 id=572 data-nosnippet>572</a></span><span class="doccomment">/// Existing system tables:
<a href=#573 id=573 data-nosnippet>573</a>/// - public.numbers
<a href=#574 id=574 data-nosnippet>574</a>/// - information_schema.{tables}
<a href=#575 id=575 data-nosnippet>575</a>/// - pg_catalog.{tables}
<a href=#576 id=576 data-nosnippet>576</a></span><span class="attr">#[derive(Clone)]
<a href=#577 id=577 data-nosnippet>577</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>SystemCatalog {
<a href=#578 id=578 data-nosnippet>578</a> <span class="kw">pub</span>(<span class="kw">super</span>) catalog_manager: Weak&lt;KvBackendCatalogManager&gt;,
<a href=#579 id=579 data-nosnippet>579</a> <span class="kw">pub</span>(<span class="kw">super</span>) catalog_cache: Cache&lt;String, Arc&lt;InformationSchemaProvider&gt;&gt;,
<a href=#580 id=580 data-nosnippet>580</a> <span class="kw">pub</span>(<span class="kw">super</span>) pg_catalog_cache: Cache&lt;String, Arc&lt;PGCatalogProvider&gt;&gt;,
<a href=#581 id=581 data-nosnippet>581</a>
<a href=#582 id=582 data-nosnippet>582</a> <span class="comment">// system_schema_provider for default catalog
<a href=#583 id=583 data-nosnippet>583</a> </span><span class="kw">pub</span>(<span class="kw">super</span>) information_schema_provider: Arc&lt;InformationSchemaProvider&gt;,
<a href=#584 id=584 data-nosnippet>584</a> <span class="kw">pub</span>(<span class="kw">super</span>) pg_catalog_provider: Arc&lt;PGCatalogProvider&gt;,
<a href=#585 id=585 data-nosnippet>585</a> <span class="kw">pub</span>(<span class="kw">super</span>) numbers_table_provider: NumbersTableProvider,
<a href=#586 id=586 data-nosnippet>586</a> <span class="kw">pub</span>(<span class="kw">super</span>) backend: KvBackendRef,
<a href=#587 id=587 data-nosnippet>587</a> <span class="kw">pub</span>(<span class="kw">super</span>) process_manager: <span class="prelude-ty">Option</span>&lt;ProcessManagerRef&gt;,
<a href=#588 id=588 data-nosnippet>588</a> <span class="kw">pub</span>(<span class="kw">super</span>) extra_information_table_factories:
<a href=#589 id=589 data-nosnippet>589</a> std::collections::HashMap&lt;String, InformationSchemaTableFactoryRef&gt;,
<a href=#590 id=590 data-nosnippet>590</a>}
<a href=#591 id=591 data-nosnippet>591</a>
<a href=#592 id=592 data-nosnippet>592</a><span class="kw">impl </span>SystemCatalog {
<a href=#593 id=593 data-nosnippet>593</a> <span class="kw">fn </span>schema_names(<span class="kw-2">&amp;</span><span class="self">self</span>, query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;) -&gt; Vec&lt;String&gt; {
<a href=#594 id=594 data-nosnippet>594</a> <span class="kw">let </span>channel = query_ctx.map_or(Channel::Unknown, |ctx| ctx.channel());
<a href=#595 id=595 data-nosnippet>595</a> <span class="kw">match </span>channel {
<a href=#596 id=596 data-nosnippet>596</a> <span class="comment">// pg_catalog only visible under postgres protocol
<a href=#597 id=597 data-nosnippet>597</a> </span>Channel::Postgres =&gt; <span class="macro">vec!</span>[
<a href=#598 id=598 data-nosnippet>598</a> INFORMATION_SCHEMA_NAME.to_string(),
<a href=#599 id=599 data-nosnippet>599</a> PG_CATALOG_NAME.to_string(),
<a href=#600 id=600 data-nosnippet>600</a> ],
<a href=#601 id=601 data-nosnippet>601</a> <span class="kw">_ </span>=&gt; {
<a href=#602 id=602 data-nosnippet>602</a> <span class="macro">vec!</span>[INFORMATION_SCHEMA_NAME.to_string()]
<a href=#603 id=603 data-nosnippet>603</a> }
<a href=#604 id=604 data-nosnippet>604</a> }
<a href=#605 id=605 data-nosnippet>605</a> }
<a href=#606 id=606 data-nosnippet>606</a>
<a href=#607 id=607 data-nosnippet>607</a> <span class="kw">fn </span>table_names(<span class="kw-2">&amp;</span><span class="self">self</span>, schema: <span class="kw-2">&amp;</span>str, query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;) -&gt; Vec&lt;String&gt; {
<a href=#608 id=608 data-nosnippet>608</a> <span class="kw">let </span>channel = query_ctx.map_or(Channel::Unknown, |ctx| ctx.channel());
<a href=#609 id=609 data-nosnippet>609</a> <span class="kw">match </span>schema {
<a href=#610 id=610 data-nosnippet>610</a> INFORMATION_SCHEMA_NAME =&gt; <span class="self">self</span>.information_schema_provider.table_names(),
<a href=#611 id=611 data-nosnippet>611</a> PG_CATALOG_NAME <span class="kw">if </span>channel == Channel::Postgres =&gt; {
<a href=#612 id=612 data-nosnippet>612</a> <span class="self">self</span>.pg_catalog_provider.table_names()
<a href=#613 id=613 data-nosnippet>613</a> }
<a href=#614 id=614 data-nosnippet>614</a> DEFAULT_SCHEMA_NAME =&gt; <span class="self">self</span>.numbers_table_provider.table_names(),
<a href=#615 id=615 data-nosnippet>615</a> <span class="comment">// Computed entity-graph tables overlay the physical tables of
<a href=#616 id=616 data-nosnippet>616</a> // `greptime_private` (the caller appends these to the physical list).
<a href=#617 id=617 data-nosnippet>617</a> </span>DEFAULT_PRIVATE_SCHEMA_NAME =&gt; SemanticGraphTableProvider::table_names(),
<a href=#618 id=618 data-nosnippet>618</a> <span class="kw">_ </span>=&gt; <span class="macro">vec!</span>[],
<a href=#619 id=619 data-nosnippet>619</a> }
<a href=#620 id=620 data-nosnippet>620</a> }
<a href=#621 id=621 data-nosnippet>621</a>
<a href=#622 id=622 data-nosnippet>622</a> <span class="kw">fn </span>schema_exists(<span class="kw-2">&amp;</span><span class="self">self</span>, schema: <span class="kw-2">&amp;</span>str, query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;) -&gt; bool {
<a href=#623 id=623 data-nosnippet>623</a> <span class="kw">let </span>channel = query_ctx.map_or(Channel::Unknown, |ctx| ctx.channel());
<a href=#624 id=624 data-nosnippet>624</a> <span class="kw">match </span>channel {
<a href=#625 id=625 data-nosnippet>625</a> Channel::Postgres =&gt; schema == PG_CATALOG_NAME || schema == INFORMATION_SCHEMA_NAME,
<a href=#626 id=626 data-nosnippet>626</a> <span class="kw">_ </span>=&gt; schema == INFORMATION_SCHEMA_NAME,
<a href=#627 id=627 data-nosnippet>627</a> }
<a href=#628 id=628 data-nosnippet>628</a> }
<a href=#629 id=629 data-nosnippet>629</a>
<a href=#630 id=630 data-nosnippet>630</a> <span class="kw">fn </span>table_exists(<span class="kw-2">&amp;</span><span class="self">self</span>, schema: <span class="kw-2">&amp;</span>str, table: <span class="kw-2">&amp;</span>str, query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;) -&gt; bool {
<a href=#631 id=631 data-nosnippet>631</a> <span class="kw">let </span>channel = query_ctx.map_or(Channel::Unknown, |ctx| ctx.channel());
<a href=#632 id=632 data-nosnippet>632</a> <span class="kw">if </span>schema == INFORMATION_SCHEMA_NAME {
<a href=#633 id=633 data-nosnippet>633</a> <span class="self">self</span>.information_schema_provider.table(table).is_some()
<a href=#634 id=634 data-nosnippet>634</a> } <span class="kw">else if </span>schema == DEFAULT_SCHEMA_NAME {
<a href=#635 id=635 data-nosnippet>635</a> <span class="self">self</span>.numbers_table_provider.table_exists(table)
<a href=#636 id=636 data-nosnippet>636</a> } <span class="kw">else if </span>schema == PG_CATALOG_NAME &amp;&amp; channel == Channel::Postgres {
<a href=#637 id=637 data-nosnippet>637</a> <span class="self">self</span>.pg_catalog_provider.table(table).is_some()
<a href=#638 id=638 data-nosnippet>638</a> } <span class="kw">else if </span>schema == DEFAULT_PRIVATE_SCHEMA_NAME {
<a href=#639 id=639 data-nosnippet>639</a> SemanticGraphTableProvider::table_exists(table)
<a href=#640 id=640 data-nosnippet>640</a> } <span class="kw">else </span>{
<a href=#641 id=641 data-nosnippet>641</a> <span class="bool-val">false
<a href=#642 id=642 data-nosnippet>642</a> </span>}
<a href=#643 id=643 data-nosnippet>643</a> }
<a href=#644 id=644 data-nosnippet>644</a>
<a href=#645 id=645 data-nosnippet>645</a> <span class="kw">fn </span>table(
<a href=#646 id=646 data-nosnippet>646</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#647 id=647 data-nosnippet>647</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#648 id=648 data-nosnippet>648</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#649 id=649 data-nosnippet>649</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#650 id=650 data-nosnippet>650</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#651 id=651 data-nosnippet>651</a> ) -&gt; <span class="prelude-ty">Option</span>&lt;TableRef&gt; {
<a href=#652 id=652 data-nosnippet>652</a> <span class="kw">let </span>channel = query_ctx.map_or(Channel::Unknown, |ctx| ctx.channel());
<a href=#653 id=653 data-nosnippet>653</a> <span class="kw">if </span>schema == INFORMATION_SCHEMA_NAME {
<a href=#654 id=654 data-nosnippet>654</a> <span class="kw">let </span>information_schema_provider =
<a href=#655 id=655 data-nosnippet>655</a> <span class="self">self</span>.catalog_cache.get_with_by_ref(catalog, <span class="kw">move </span>|| {
<a href=#656 id=656 data-nosnippet>656</a> <span class="kw">let </span>provider = InformationSchemaProvider::new(
<a href=#657 id=657 data-nosnippet>657</a> catalog.to_string(),
<a href=#658 id=658 data-nosnippet>658</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#659 id=659 data-nosnippet>659</a> Arc::new(FlowMetadataManager::new(<span class="self">self</span>.backend.clone())),
<a href=#660 id=660 data-nosnippet>660</a> <span class="self">self</span>.process_manager.clone(),
<a href=#661 id=661 data-nosnippet>661</a> <span class="self">self</span>.backend.clone(),
<a href=#662 id=662 data-nosnippet>662</a> );
<a href=#663 id=663 data-nosnippet>663</a> <span class="kw">let </span>provider = provider
<a href=#664 id=664 data-nosnippet>664</a> .with_extra_table_factories(<span class="self">self</span>.extra_information_table_factories.clone());
<a href=#665 id=665 data-nosnippet>665</a> Arc::new(provider)
<a href=#666 id=666 data-nosnippet>666</a> });
<a href=#667 id=667 data-nosnippet>667</a> information_schema_provider.table(table_name)
<a href=#668 id=668 data-nosnippet>668</a> } <span class="kw">else if </span>schema == PG_CATALOG_NAME &amp;&amp; channel == Channel::Postgres {
<a href=#669 id=669 data-nosnippet>669</a> <span class="kw">if </span>catalog == DEFAULT_CATALOG_NAME {
<a href=#670 id=670 data-nosnippet>670</a> <span class="self">self</span>.pg_catalog_provider.table(table_name)
<a href=#671 id=671 data-nosnippet>671</a> } <span class="kw">else </span>{
<a href=#672 id=672 data-nosnippet>672</a> <span class="kw">let </span>pg_catalog_provider =
<a href=#673 id=673 data-nosnippet>673</a> <span class="self">self</span>.pg_catalog_cache.get_with_by_ref(catalog, <span class="kw">move </span>|| {
<a href=#674 id=674 data-nosnippet>674</a> Arc::new(PGCatalogProvider::new(
<a href=#675 id=675 data-nosnippet>675</a> catalog.to_string(),
<a href=#676 id=676 data-nosnippet>676</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#677 id=677 data-nosnippet>677</a> ))
<a href=#678 id=678 data-nosnippet>678</a> });
<a href=#679 id=679 data-nosnippet>679</a> pg_catalog_provider.table(table_name)
<a href=#680 id=680 data-nosnippet>680</a> }
<a href=#681 id=681 data-nosnippet>681</a> } <span class="kw">else if </span>schema == DEFAULT_SCHEMA_NAME {
<a href=#682 id=682 data-nosnippet>682</a> <span class="self">self</span>.numbers_table_provider.table(table_name)
<a href=#683 id=683 data-nosnippet>683</a> } <span class="kw">else if </span>schema == DEFAULT_PRIVATE_SCHEMA_NAME
<a href=#684 id=684 data-nosnippet>684</a> &amp;&amp; SemanticGraphTableProvider::table_exists(table_name)
<a href=#685 id=685 data-nosnippet>685</a> {
<a href=#686 id=686 data-nosnippet>686</a> <span class="comment">// Constructed on demand (the provider is a name + a weak ref); the
<a href=#687 id=687 data-nosnippet>687</a> // system catalog is consulted before physical resolution, so the
<a href=#688 id=688 data-nosnippet>688</a> // computed tables shadow same-named physical tables by design.
<a href=#689 id=689 data-nosnippet>689</a> </span>SemanticGraphTableProvider::new(
<a href=#690 id=690 data-nosnippet>690</a> catalog.to_string(),
<a href=#691 id=691 data-nosnippet>691</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#692 id=692 data-nosnippet>692</a> query_ctx.cloned().map(Arc::new),
<a href=#693 id=693 data-nosnippet>693</a> )
<a href=#694 id=694 data-nosnippet>694</a> .table(table_name)
<a href=#695 id=695 data-nosnippet>695</a> } <span class="kw">else </span>{
<a href=#696 id=696 data-nosnippet>696</a> <span class="prelude-val">None
<a href=#697 id=697 data-nosnippet>697</a> </span>}
<a href=#698 id=698 data-nosnippet>698</a> }
<a href=#699 id=699 data-nosnippet>699</a>}
<a href=#700 id=700 data-nosnippet>700</a>
<a href=#701 id=701 data-nosnippet>701</a><span class="attr">#[cfg(test)]
<a href=#702 id=702 data-nosnippet>702</a></span><span class="kw">mod </span>tests {
<a href=#703 id=703 data-nosnippet>703</a> <span class="kw">use </span>std::sync::atomic::{AtomicUsize, Ordering};
<a href=#704 id=704 data-nosnippet>704</a>
<a href=#705 id=705 data-nosnippet>705</a> <span class="kw">use </span>common_meta::cache::{CacheContainer, Initializer};
<a href=#706 id=706 data-nosnippet>706</a> <span class="kw">use </span>common_meta::key::table_route::LogicalTableRouteValue;
<a href=#707 id=707 data-nosnippet>707</a> <span class="kw">use </span>moka::future::Cache <span class="kw">as </span>FutureCache;
<a href=#708 id=708 data-nosnippet>708</a> <span class="kw">use </span>table::metadata::TableInfo;
<a href=#709 id=709 data-nosnippet>709</a>
<a href=#710 id=710 data-nosnippet>710</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#711 id=711 data-nosnippet>711</a>
<a href=#712 id=712 data-nosnippet>712</a> <span class="kw">fn </span>metric_table_info(
<a href=#713 id=713 data-nosnippet>713</a> table_id: TableId,
<a href=#714 id=714 data-nosnippet>714</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#715 id=715 data-nosnippet>715</a> partition_key_indices: Vec&lt;usize&gt;,
<a href=#716 id=716 data-nosnippet>716</a> ) -&gt; TableInfo {
<a href=#717 id=717 data-nosnippet>717</a> <span class="kw">let </span><span class="kw-2">mut </span>table_info =
<a href=#718 id=718 data-nosnippet>718</a> common_meta::ddl::test_util::create_table::test_create_table_task(table_name, table_id)
<a href=#719 id=719 data-nosnippet>719</a> .table_info;
<a href=#720 id=720 data-nosnippet>720</a> table_info.meta.engine = METRIC_ENGINE_NAME.to_string();
<a href=#721 id=721 data-nosnippet>721</a> table_info.meta.partition_key_indices = partition_key_indices;
<a href=#722 id=722 data-nosnippet>722</a> table_info
<a href=#723 id=723 data-nosnippet>723</a> }
<a href=#724 id=724 data-nosnippet>724</a>
<a href=#725 id=725 data-nosnippet>725</a> <span class="attr">#[tokio::test]
<a href=#726 id=726 data-nosnippet>726</a> </span><span class="kw">async fn </span>test_logical_table_uses_cached_physical_table_info() {
<a href=#727 id=727 data-nosnippet>727</a> <span class="kw">const </span>LOGICAL_TABLE_ID: TableId = <span class="number">1</span>;
<a href=#728 id=728 data-nosnippet>728</a> <span class="kw">const </span>PHYSICAL_TABLE_ID: TableId = <span class="number">2</span>;
<a href=#729 id=729 data-nosnippet>729</a>
<a href=#730 id=730 data-nosnippet>730</a> <span class="kw">let </span>route = Arc::new(TableRoute::Logical(Arc::new(LogicalTableRouteValue::new(
<a href=#731 id=731 data-nosnippet>731</a> PHYSICAL_TABLE_ID,
<a href=#732 id=732 data-nosnippet>732</a> ))));
<a href=#733 id=733 data-nosnippet>733</a> <span class="kw">let </span>route_initializer: Initializer&lt;TableId, Arc&lt;TableRoute&gt;&gt; = Arc::new(<span class="kw">move </span>|<span class="kw">_</span>| {
<a href=#734 id=734 data-nosnippet>734</a> <span class="kw">let </span>route = route.clone();
<a href=#735 id=735 data-nosnippet>735</a> Box::pin(<span class="kw">async move </span>{ <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(route)) })
<a href=#736 id=736 data-nosnippet>736</a> });
<a href=#737 id=737 data-nosnippet>737</a> <span class="kw">let </span>table_route_cache = Arc::new(CacheContainer::new(
<a href=#738 id=738 data-nosnippet>738</a> <span class="string">"test_table_route_cache"</span>.to_string(),
<a href=#739 id=739 data-nosnippet>739</a> FutureCache::new(<span class="number">16</span>),
<a href=#740 id=740 data-nosnippet>740</a> Box::new(|<span class="kw">_</span>, <span class="kw">_</span>| Box::pin(<span class="kw">async </span>{ <span class="prelude-val">Ok</span>(()) })),
<a href=#741 id=741 data-nosnippet>741</a> route_initializer,
<a href=#742 id=742 data-nosnippet>742</a> |<span class="kw">_</span>| <span class="bool-val">true</span>,
<a href=#743 id=743 data-nosnippet>743</a> ));
<a href=#744 id=744 data-nosnippet>744</a>
<a href=#745 id=745 data-nosnippet>745</a> <span class="kw">let </span>load_count = Arc::new(AtomicUsize::new(<span class="number">0</span>));
<a href=#746 id=746 data-nosnippet>746</a> <span class="kw">let </span>physical_table_info =
<a href=#747 id=747 data-nosnippet>747</a> Arc::new(metric_table_info(PHYSICAL_TABLE_ID, <span class="string">"physical"</span>, <span class="macro">vec!</span>[<span class="number">1</span>]));
<a href=#748 id=748 data-nosnippet>748</a> <span class="kw">let </span>table_info_initializer: Initializer&lt;TableId, Arc&lt;TableInfo&gt;&gt; = {
<a href=#749 id=749 data-nosnippet>749</a> <span class="kw">let </span>load_count = load_count.clone();
<a href=#750 id=750 data-nosnippet>750</a> <span class="kw">let </span>table_info = physical_table_info.clone();
<a href=#751 id=751 data-nosnippet>751</a> Arc::new(<span class="kw">move </span>|<span class="kw">_</span>| {
<a href=#752 id=752 data-nosnippet>752</a> load_count.fetch_add(<span class="number">1</span>, Ordering::Relaxed);
<a href=#753 id=753 data-nosnippet>753</a> <span class="kw">let </span>table_info = table_info.clone();
<a href=#754 id=754 data-nosnippet>754</a> Box::pin(<span class="kw">async move </span>{ <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(table_info)) })
<a href=#755 id=755 data-nosnippet>755</a> })
<a href=#756 id=756 data-nosnippet>756</a> };
<a href=#757 id=757 data-nosnippet>757</a> <span class="kw">let </span>table_info_cache = Arc::new(CacheContainer::new(
<a href=#758 id=758 data-nosnippet>758</a> <span class="string">"test_table_info_cache"</span>.to_string(),
<a href=#759 id=759 data-nosnippet>759</a> FutureCache::new(<span class="number">16</span>),
<a href=#760 id=760 data-nosnippet>760</a> Box::new(|<span class="kw">_</span>, <span class="kw">_</span>| Box::pin(<span class="kw">async </span>{ <span class="prelude-val">Ok</span>(()) })),
<a href=#761 id=761 data-nosnippet>761</a> table_info_initializer,
<a href=#762 id=762 data-nosnippet>762</a> |<span class="kw">_</span>| <span class="bool-val">true</span>,
<a href=#763 id=763 data-nosnippet>763</a> ));
<a href=#764 id=764 data-nosnippet>764</a>
<a href=#765 id=765 data-nosnippet>765</a> <span class="kw">let </span>logical_table = DistTable::table(Arc::new(metric_table_info(
<a href=#766 id=766 data-nosnippet>766</a> LOGICAL_TABLE_ID,
<a href=#767 id=767 data-nosnippet>767</a> <span class="string">"logical"</span>,
<a href=#768 id=768 data-nosnippet>768</a> <span class="macro">vec!</span>[],
<a href=#769 id=769 data-nosnippet>769</a> )));
<a href=#770 id=770 data-nosnippet>770</a> <span class="kw">for _ in </span><span class="number">0</span>..<span class="number">2 </span>{
<a href=#771 id=771 data-nosnippet>771</a> <span class="kw">let </span>table = KvBackendCatalogManager::override_logical_table_partition_key_indices(
<a href=#772 id=772 data-nosnippet>772</a> <span class="kw-2">&amp;</span>table_route_cache,
<a href=#773 id=773 data-nosnippet>773</a> <span class="kw-2">&amp;</span>table_info_cache,
<a href=#774 id=774 data-nosnippet>774</a> logical_table.clone(),
<a href=#775 id=775 data-nosnippet>775</a> )
<a href=#776 id=776 data-nosnippet>776</a> .<span class="kw">await
<a href=#777 id=777 data-nosnippet>777</a> </span>.unwrap();
<a href=#778 id=778 data-nosnippet>778</a> <span class="macro">assert_eq!</span>(table.table_info().meta.partition_key_indices, <span class="macro">vec!</span>[<span class="number">1</span>]);
<a href=#779 id=779 data-nosnippet>779</a> }
<a href=#780 id=780 data-nosnippet>780</a> <span class="macro">assert_eq!</span>(load_count.load(Ordering::Relaxed), <span class="number">1</span>);
<a href=#781 id=781 data-nosnippet>781</a> }
<a href=#782 id=782 data-nosnippet>782</a>}
</code></pre></div></section></main></body></html>
+92
View File
@@ -0,0 +1,92 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/kvbackend/table_cache.rs`."><title>table_cache.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/kvbackend/</div>table_cache.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::Arc;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_meta::cache::{
<a href=#18 id=18 data-nosnippet>18</a> CacheContainer, InitStrategy, Initializer, TableInfoCacheRef, TableNameCacheRef,
<a href=#19 id=19 data-nosnippet>19</a>};
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::error::{<span class="prelude-ty">Result </span><span class="kw">as </span>MetaResult, ValueNotExistSnafu};
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_meta::instruction::CacheIdent;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>futures::future::BoxFuture;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>moka::future::Cache;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>snafu::OptionExt;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>table::TableRef;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>table::dist_table::DistTable;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>table::table_name::TableName;
<a href=#28 id=28 data-nosnippet>28</a>
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">pub type </span>TableCacheRef = Arc&lt;TableCache&gt;;
<a href=#30 id=30 data-nosnippet>30</a>
<a href=#31 id=31 data-nosnippet>31</a><span class="doccomment">/// [TableCache] caches the [TableName] to [TableRef] mapping.
<a href=#32 id=32 data-nosnippet>32</a></span><span class="kw">pub type </span>TableCache = CacheContainer&lt;TableName, TableRef, CacheIdent&gt;;
<a href=#33 id=33 data-nosnippet>33</a>
<a href=#34 id=34 data-nosnippet>34</a><span class="doccomment">/// Constructs a [TableCache].
<a href=#35 id=35 data-nosnippet>35</a></span><span class="kw">pub fn </span>new_table_cache(
<a href=#36 id=36 data-nosnippet>36</a> name: String,
<a href=#37 id=37 data-nosnippet>37</a> cache: Cache&lt;TableName, TableRef&gt;,
<a href=#38 id=38 data-nosnippet>38</a> table_info_cache: TableInfoCacheRef,
<a href=#39 id=39 data-nosnippet>39</a> table_name_cache: TableNameCacheRef,
<a href=#40 id=40 data-nosnippet>40</a>) -&gt; TableCache {
<a href=#41 id=41 data-nosnippet>41</a> <span class="kw">let </span>init = init_factory(table_info_cache, table_name_cache);
<a href=#42 id=42 data-nosnippet>42</a>
<a href=#43 id=43 data-nosnippet>43</a> CacheContainer::with_strategy(
<a href=#44 id=44 data-nosnippet>44</a> name,
<a href=#45 id=45 data-nosnippet>45</a> cache,
<a href=#46 id=46 data-nosnippet>46</a> Box::new(invalidator),
<a href=#47 id=47 data-nosnippet>47</a> init,
<a href=#48 id=48 data-nosnippet>48</a> filter,
<a href=#49 id=49 data-nosnippet>49</a> InitStrategy::VersionChecked,
<a href=#50 id=50 data-nosnippet>50</a> )
<a href=#51 id=51 data-nosnippet>51</a>}
<a href=#52 id=52 data-nosnippet>52</a>
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">fn </span>init_factory(
<a href=#54 id=54 data-nosnippet>54</a> table_info_cache: TableInfoCacheRef,
<a href=#55 id=55 data-nosnippet>55</a> table_name_cache: TableNameCacheRef,
<a href=#56 id=56 data-nosnippet>56</a>) -&gt; Initializer&lt;TableName, TableRef&gt; {
<a href=#57 id=57 data-nosnippet>57</a> Arc::new(<span class="kw">move </span>|table_name| {
<a href=#58 id=58 data-nosnippet>58</a> <span class="kw">let </span>table_info_cache = table_info_cache.clone();
<a href=#59 id=59 data-nosnippet>59</a> <span class="kw">let </span>table_name_cache = table_name_cache.clone();
<a href=#60 id=60 data-nosnippet>60</a> Box::pin(<span class="kw">async move </span>{
<a href=#61 id=61 data-nosnippet>61</a> <span class="kw">let </span>table_id = table_name_cache
<a href=#62 id=62 data-nosnippet>62</a> .get_by_ref(table_name)
<a href=#63 id=63 data-nosnippet>63</a> .<span class="kw">await</span><span class="question-mark">?
<a href=#64 id=64 data-nosnippet>64</a> </span>.context(ValueNotExistSnafu)<span class="question-mark">?</span>;
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">let </span>table_info = table_info_cache
<a href=#66 id=66 data-nosnippet>66</a> .get_by_ref(<span class="kw-2">&amp;</span>table_id)
<a href=#67 id=67 data-nosnippet>67</a> .<span class="kw">await</span><span class="question-mark">?
<a href=#68 id=68 data-nosnippet>68</a> </span>.context(ValueNotExistSnafu)<span class="question-mark">?</span>;
<a href=#69 id=69 data-nosnippet>69</a>
<a href=#70 id=70 data-nosnippet>70</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(DistTable::table(table_info)))
<a href=#71 id=71 data-nosnippet>71</a> })
<a href=#72 id=72 data-nosnippet>72</a> })
<a href=#73 id=73 data-nosnippet>73</a>}
<a href=#74 id=74 data-nosnippet>74</a>
<a href=#75 id=75 data-nosnippet>75</a><span class="kw">fn </span>invalidator&lt;<span class="lifetime">'a</span>&gt;(
<a href=#76 id=76 data-nosnippet>76</a> cache: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>Cache&lt;TableName, TableRef&gt;,
<a href=#77 id=77 data-nosnippet>77</a> idents: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>[<span class="kw-2">&amp;</span>CacheIdent],
<a href=#78 id=78 data-nosnippet>78</a>) -&gt; BoxFuture&lt;<span class="lifetime">'a</span>, MetaResult&lt;()&gt;&gt; {
<a href=#79 id=79 data-nosnippet>79</a> Box::pin(<span class="kw">async move </span>{
<a href=#80 id=80 data-nosnippet>80</a> <span class="kw">for </span>ident <span class="kw">in </span>idents {
<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">if let </span>CacheIdent::TableName(table_name) = ident {
<a href=#82 id=82 data-nosnippet>82</a> cache.invalidate(table_name).<span class="kw">await
<a href=#83 id=83 data-nosnippet>83</a> </span>}
<a href=#84 id=84 data-nosnippet>84</a> }
<a href=#85 id=85 data-nosnippet>85</a> <span class="prelude-val">Ok</span>(())
<a href=#86 id=86 data-nosnippet>86</a> })
<a href=#87 id=87 data-nosnippet>87</a>}
<a href=#88 id=88 data-nosnippet>88</a>
<a href=#89 id=89 data-nosnippet>89</a><span class="kw">fn </span>filter(ident: <span class="kw-2">&amp;</span>CacheIdent) -&gt; bool {
<a href=#90 id=90 data-nosnippet>90</a> <span class="macro">matches!</span>(ident, CacheIdent::TableName(<span class="kw">_</span>))
<a href=#91 id=91 data-nosnippet>91</a>}
</code></pre></div></section></main></body></html>
+198
View File
@@ -0,0 +1,198 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::any::Any;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::fmt::{Debug, Formatter};
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>std::sync::Arc;
<a href=#18 id=18 data-nosnippet>18</a>
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>api::v1::CreateTableExpr;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_catalog::consts::system_schema_name;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>futures::future::BoxFuture;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>futures_util::stream::BoxStream;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>session::context::QueryContext;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>table::TableRef;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>table::metadata::{TableId, TableInfoRef};
<a href=#26 id=26 data-nosnippet>26</a>
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span><span class="kw">crate</span>::error::Result;
<a href=#28 id=28 data-nosnippet>28</a>
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">pub mod </span>error;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">pub mod </span>information_extension;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">pub mod </span>kvbackend;
<a href=#32 id=32 data-nosnippet>32</a><span class="attr">#[cfg(any(test, feature = <span class="string">"testing"</span>))]
<a href=#33 id=33 data-nosnippet>33</a></span><span class="kw">pub mod </span>memory;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">mod </span>metrics;
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">pub mod </span>system_schema;
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">pub mod </span>information_schema {
<a href=#37 id=37 data-nosnippet>37</a> <span class="comment">// TODO(j0hn50n133): re-export to make it compatible with the legacy code, migrate to the new path later
<a href=#38 id=38 data-nosnippet>38</a> </span><span class="kw">pub use </span><span class="kw">crate</span>::system_schema::information_schema::<span class="kw-2">*</span>;
<a href=#39 id=39 data-nosnippet>39</a>}
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">pub mod </span>process_manager;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">pub mod </span>table_source;
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="attr">#[async_trait::async_trait]
<a href=#45 id=45 data-nosnippet>45</a></span><span class="kw">pub trait </span>CatalogManager: Send + Sync {
<a href=#46 id=46 data-nosnippet>46</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>Any;
<a href=#47 id=47 data-nosnippet>47</a>
<a href=#48 id=48 data-nosnippet>48</a> <span class="kw">async fn </span>catalog_names(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt;;
<a href=#49 id=49 data-nosnippet>49</a>
<a href=#50 id=50 data-nosnippet>50</a> <span class="kw">async fn </span>schema_names(
<a href=#51 id=51 data-nosnippet>51</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#52 id=52 data-nosnippet>52</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#53 id=53 data-nosnippet>53</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#54 id=54 data-nosnippet>54</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt;;
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a> <span class="kw">async fn </span>table_names(
<a href=#57 id=57 data-nosnippet>57</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#58 id=58 data-nosnippet>58</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#59 id=59 data-nosnippet>59</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#60 id=60 data-nosnippet>60</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#61 id=61 data-nosnippet>61</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt;;
<a href=#62 id=62 data-nosnippet>62</a>
<a href=#63 id=63 data-nosnippet>63</a> <span class="kw">async fn </span>catalog_exists(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;bool&gt;;
<a href=#64 id=64 data-nosnippet>64</a>
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">async fn </span>schema_exists(
<a href=#66 id=66 data-nosnippet>66</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#67 id=67 data-nosnippet>67</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#68 id=68 data-nosnippet>68</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#69 id=69 data-nosnippet>69</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#70 id=70 data-nosnippet>70</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;bool&gt;;
<a href=#71 id=71 data-nosnippet>71</a>
<a href=#72 id=72 data-nosnippet>72</a> <span class="kw">async fn </span>table_exists(
<a href=#73 id=73 data-nosnippet>73</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#74 id=74 data-nosnippet>74</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#75 id=75 data-nosnippet>75</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#76 id=76 data-nosnippet>76</a> table: <span class="kw-2">&amp;</span>str,
<a href=#77 id=77 data-nosnippet>77</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#78 id=78 data-nosnippet>78</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;bool&gt;;
<a href=#79 id=79 data-nosnippet>79</a>
<a href=#80 id=80 data-nosnippet>80</a> <span class="doccomment">/// Returns the table by catalog, schema and table name.
<a href=#81 id=81 data-nosnippet>81</a> </span><span class="kw">async fn </span>table(
<a href=#82 id=82 data-nosnippet>82</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#83 id=83 data-nosnippet>83</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#84 id=84 data-nosnippet>84</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#85 id=85 data-nosnippet>85</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#86 id=86 data-nosnippet>86</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#87 id=87 data-nosnippet>87</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;TableRef&gt;&gt;;
<a href=#88 id=88 data-nosnippet>88</a>
<a href=#89 id=89 data-nosnippet>89</a> <span class="doccomment">/// Returns the table id of provided table ident.
<a href=#90 id=90 data-nosnippet>90</a> </span><span class="kw">async fn </span>table_id(
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#92 id=92 data-nosnippet>92</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#93 id=93 data-nosnippet>93</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#94 id=94 data-nosnippet>94</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#95 id=95 data-nosnippet>95</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>QueryContext&gt;,
<a href=#96 id=96 data-nosnippet>96</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;TableId&gt;&gt; {
<a href=#97 id=97 data-nosnippet>97</a> <span class="prelude-val">Ok</span>(<span class="self">self
<a href=#98 id=98 data-nosnippet>98</a> </span>.table(catalog, schema, table_name, query_ctx)
<a href=#99 id=99 data-nosnippet>99</a> .<span class="kw">await</span><span class="question-mark">?
<a href=#100 id=100 data-nosnippet>100</a> </span>.map(|t| t.table_info().ident.table_id))
<a href=#101 id=101 data-nosnippet>101</a> }
<a href=#102 id=102 data-nosnippet>102</a>
<a href=#103 id=103 data-nosnippet>103</a> <span class="doccomment">/// Returns the table of provided id.
<a href=#104 id=104 data-nosnippet>104</a> </span><span class="kw">async fn </span>table_info_by_id(<span class="kw-2">&amp;</span><span class="self">self</span>, table_id: TableId) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;TableInfoRef&gt;&gt;;
<a href=#105 id=105 data-nosnippet>105</a>
<a href=#106 id=106 data-nosnippet>106</a> <span class="doccomment">/// Returns the tables by table ids.
<a href=#107 id=107 data-nosnippet>107</a> </span><span class="kw">async fn </span>tables_by_ids(
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#109 id=109 data-nosnippet>109</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#110 id=110 data-nosnippet>110</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#111 id=111 data-nosnippet>111</a> table_ids: <span class="kw-2">&amp;</span>[TableId],
<a href=#112 id=112 data-nosnippet>112</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;TableRef&gt;&gt;;
<a href=#113 id=113 data-nosnippet>113</a>
<a href=#114 id=114 data-nosnippet>114</a> <span class="doccomment">/// Returns all tables with a stream by catalog and schema.
<a href=#115 id=115 data-nosnippet>115</a> </span><span class="kw">fn </span>tables&lt;<span class="lifetime">'a</span>&gt;(
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw-2">&amp;</span><span class="lifetime">'a </span><span class="self">self</span>,
<a href=#117 id=117 data-nosnippet>117</a> catalog: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str,
<a href=#118 id=118 data-nosnippet>118</a> schema: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str,
<a href=#119 id=119 data-nosnippet>119</a> query_ctx: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span><span class="lifetime">'a </span>QueryContext&gt;,
<a href=#120 id=120 data-nosnippet>120</a> ) -&gt; BoxStream&lt;<span class="lifetime">'a</span>, <span class="prelude-ty">Result</span>&lt;TableRef&gt;&gt;;
<a href=#121 id=121 data-nosnippet>121</a>
<a href=#122 id=122 data-nosnippet>122</a> <span class="doccomment">/// Check if `schema` is a reserved schema name
<a href=#123 id=123 data-nosnippet>123</a> </span><span class="kw">fn </span>is_reserved_schema_name(<span class="kw-2">&amp;</span><span class="self">self</span>, schema: <span class="kw-2">&amp;</span>str) -&gt; bool {
<a href=#124 id=124 data-nosnippet>124</a> <span class="comment">// We have to check whether a schema name is reserved before create schema.
<a href=#125 id=125 data-nosnippet>125</a> // We need this rather than use schema_exists directly because `pg_catalog` is
<a href=#126 id=126 data-nosnippet>126</a> // only visible via postgres protocol. So if we don't check, a mysql client may
<a href=#127 id=127 data-nosnippet>127</a> // create a schema named `pg_catalog` which is somehow malformed.
<a href=#128 id=128 data-nosnippet>128</a> //
<a href=#129 id=129 data-nosnippet>129</a> // Case-insensitive, otherwise `CREATE DATABASE "INFORMATION_SCHEMA"` keeps its
<a href=#130 id=130 data-nosnippet>130</a> // case and creates a schema shadowed by the system one.
<a href=#131 id=131 data-nosnippet>131</a> </span>system_schema_name(schema).is_some()
<a href=#132 id=132 data-nosnippet>132</a> }
<a href=#133 id=133 data-nosnippet>133</a>}
<a href=#134 id=134 data-nosnippet>134</a>
<a href=#135 id=135 data-nosnippet>135</a><span class="kw">pub type </span>CatalogManagerRef = Arc&lt;<span class="kw">dyn </span>CatalogManager&gt;;
<a href=#136 id=136 data-nosnippet>136</a>
<a href=#137 id=137 data-nosnippet>137</a><span class="doccomment">/// Hook called after system table opening.
<a href=#138 id=138 data-nosnippet>138</a></span><span class="kw">pub type </span>OpenSystemTableHook =
<a href=#139 id=139 data-nosnippet>139</a> Box&lt;<span class="kw">dyn </span>Fn(TableRef) -&gt; BoxFuture&lt;<span class="lifetime">'static</span>, <span class="prelude-ty">Result</span>&lt;()&gt;&gt; + Send + Sync&gt;;
<a href=#140 id=140 data-nosnippet>140</a>
<a href=#141 id=141 data-nosnippet>141</a><span class="doccomment">/// Register system table request:
<a href=#142 id=142 data-nosnippet>142</a>/// - When system table is already created and registered, the hook will be called
<a href=#143 id=143 data-nosnippet>143</a>/// with table ref after opening the system table
<a href=#144 id=144 data-nosnippet>144</a>/// - When system table is not exists, create and register the table by `create_table_expr` and calls `open_hook` with the created table.
<a href=#145 id=145 data-nosnippet>145</a></span><span class="kw">pub struct </span>RegisterSystemTableRequest {
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">pub </span>create_table_expr: CreateTableExpr,
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">pub </span>open_hook: <span class="prelude-ty">Option</span>&lt;OpenSystemTableHook&gt;,
<a href=#148 id=148 data-nosnippet>148</a>}
<a href=#149 id=149 data-nosnippet>149</a>
<a href=#150 id=150 data-nosnippet>150</a><span class="attr">#[derive(Clone)]
<a href=#151 id=151 data-nosnippet>151</a></span><span class="kw">pub struct </span>RegisterTableRequest {
<a href=#152 id=152 data-nosnippet>152</a> <span class="kw">pub </span>catalog: String,
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">pub </span>schema: String,
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">pub </span>table_name: String,
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">pub </span>table_id: TableId,
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">pub </span>table: TableRef,
<a href=#157 id=157 data-nosnippet>157</a>}
<a href=#158 id=158 data-nosnippet>158</a>
<a href=#159 id=159 data-nosnippet>159</a><span class="kw">impl </span>Debug <span class="kw">for </span>RegisterTableRequest {
<a href=#160 id=160 data-nosnippet>160</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; std::fmt::Result {
<a href=#161 id=161 data-nosnippet>161</a> f.debug_struct(<span class="string">"RegisterTableRequest"</span>)
<a href=#162 id=162 data-nosnippet>162</a> .field(<span class="string">"catalog"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.catalog)
<a href=#163 id=163 data-nosnippet>163</a> .field(<span class="string">"schema"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.schema)
<a href=#164 id=164 data-nosnippet>164</a> .field(<span class="string">"table_name"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.table_name)
<a href=#165 id=165 data-nosnippet>165</a> .field(<span class="string">"table_id"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.table_id)
<a href=#166 id=166 data-nosnippet>166</a> .field(<span class="string">"table"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.table.table_info())
<a href=#167 id=167 data-nosnippet>167</a> .finish()
<a href=#168 id=168 data-nosnippet>168</a> }
<a href=#169 id=169 data-nosnippet>169</a>}
<a href=#170 id=170 data-nosnippet>170</a>
<a href=#171 id=171 data-nosnippet>171</a><span class="attr">#[derive(Debug, Clone)]
<a href=#172 id=172 data-nosnippet>172</a></span><span class="kw">pub struct </span>RenameTableRequest {
<a href=#173 id=173 data-nosnippet>173</a> <span class="kw">pub </span>catalog: String,
<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">pub </span>schema: String,
<a href=#175 id=175 data-nosnippet>175</a> <span class="kw">pub </span>table_name: String,
<a href=#176 id=176 data-nosnippet>176</a> <span class="kw">pub </span>new_table_name: String,
<a href=#177 id=177 data-nosnippet>177</a> <span class="kw">pub </span>table_id: TableId,
<a href=#178 id=178 data-nosnippet>178</a>}
<a href=#179 id=179 data-nosnippet>179</a>
<a href=#180 id=180 data-nosnippet>180</a><span class="attr">#[derive(Debug, Clone)]
<a href=#181 id=181 data-nosnippet>181</a></span><span class="kw">pub struct </span>DeregisterTableRequest {
<a href=#182 id=182 data-nosnippet>182</a> <span class="kw">pub </span>catalog: String,
<a href=#183 id=183 data-nosnippet>183</a> <span class="kw">pub </span>schema: String,
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">pub </span>table_name: String,
<a href=#185 id=185 data-nosnippet>185</a>}
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a><span class="attr">#[derive(Debug, Clone)]
<a href=#188 id=188 data-nosnippet>188</a></span><span class="kw">pub struct </span>DeregisterSchemaRequest {
<a href=#189 id=189 data-nosnippet>189</a> <span class="kw">pub </span>catalog: String,
<a href=#190 id=190 data-nosnippet>190</a> <span class="kw">pub </span>schema: String,
<a href=#191 id=191 data-nosnippet>191</a>}
<a href=#192 id=192 data-nosnippet>192</a>
<a href=#193 id=193 data-nosnippet>193</a><span class="attr">#[derive(Debug, Clone)]
<a href=#194 id=194 data-nosnippet>194</a></span><span class="kw">pub struct </span>RegisterSchemaRequest {
<a href=#195 id=195 data-nosnippet>195</a> <span class="kw">pub </span>catalog: String,
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">pub </span>schema: String,
<a href=#197 id=197 data-nosnippet>197</a>}
</code></pre></div></section></main></body></html>
+52
View File
@@ -0,0 +1,52 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/metrics.rs`."><title>metrics.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/</div>metrics.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>lazy_static::lazy_static;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>prometheus::<span class="kw-2">*</span>;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="macro">lazy_static!</span> {
<a href=#19 id=19 data-nosnippet>19</a> <span class="kw">pub static </span><span class="kw-2">ref </span>METRIC_CATALOG_MANAGER_CATALOG_COUNT: IntGauge =
<a href=#20 id=20 data-nosnippet>20</a> <span class="macro">register_int_gauge!</span>(<span class="string">"greptime_catalog_catalog_count"</span>, <span class="string">"catalog catalog count"</span>).unwrap();
<a href=#21 id=21 data-nosnippet>21</a> <span class="kw">pub static </span><span class="kw-2">ref </span>METRIC_CATALOG_MANAGER_SCHEMA_COUNT: IntGauge =
<a href=#22 id=22 data-nosnippet>22</a> <span class="macro">register_int_gauge!</span>(<span class="string">"greptime_catalog_schema_count"</span>, <span class="string">"catalog schema count"</span>).unwrap();
<a href=#23 id=23 data-nosnippet>23</a> <span class="kw">pub static </span><span class="kw-2">ref </span>METRIC_CATALOG_MANAGER_TABLE_COUNT: IntGaugeVec = <span class="macro">register_int_gauge_vec!</span>(
<a href=#24 id=24 data-nosnippet>24</a> <span class="string">"greptime_catalog_table_count"</span>,
<a href=#25 id=25 data-nosnippet>25</a> <span class="string">"catalog table count"</span>,
<a href=#26 id=26 data-nosnippet>26</a> <span class="kw-2">&amp;</span>[<span class="string">"db"</span>]
<a href=#27 id=27 data-nosnippet>27</a> )
<a href=#28 id=28 data-nosnippet>28</a> .unwrap();
<a href=#29 id=29 data-nosnippet>29</a> <span class="kw">pub static </span><span class="kw-2">ref </span>METRIC_CATALOG_KV_REMOTE_GET: Histogram =
<a href=#30 id=30 data-nosnippet>30</a> <span class="macro">register_histogram!</span>(<span class="string">"greptime_catalog_kv_get_remote"</span>, <span class="string">"catalog kv get remote"</span>).unwrap();
<a href=#31 id=31 data-nosnippet>31</a> <span class="kw">pub static </span><span class="kw-2">ref </span>METRIC_CATALOG_KV_GET: Histogram =
<a href=#32 id=32 data-nosnippet>32</a> <span class="macro">register_histogram!</span>(<span class="string">"greptime_catalog_kv_get"</span>, <span class="string">"catalog kv get"</span>).unwrap();
<a href=#33 id=33 data-nosnippet>33</a> <span class="kw">pub static </span><span class="kw-2">ref </span>METRIC_CATALOG_KV_BATCH_GET: Histogram =
<a href=#34 id=34 data-nosnippet>34</a> <span class="macro">register_histogram!</span>(<span class="string">"greptime_catalog_kv_batch_get"</span>, <span class="string">"catalog kv batch get"</span>).unwrap();
<a href=#35 id=35 data-nosnippet>35</a>
<a href=#36 id=36 data-nosnippet>36</a> <span class="doccomment">/// Count of running process in each catalog.
<a href=#37 id=37 data-nosnippet>37</a> </span><span class="kw">pub static </span><span class="kw-2">ref </span>PROCESS_LIST_COUNT: IntGaugeVec = <span class="macro">register_int_gauge_vec!</span>(
<a href=#38 id=38 data-nosnippet>38</a> <span class="string">"greptime_process_list_count"</span>,
<a href=#39 id=39 data-nosnippet>39</a> <span class="string">"Running process count per catalog"</span>,
<a href=#40 id=40 data-nosnippet>40</a> <span class="kw-2">&amp;</span>[<span class="string">"catalog"</span>]
<a href=#41 id=41 data-nosnippet>41</a> )
<a href=#42 id=42 data-nosnippet>42</a> .unwrap();
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a> <span class="doccomment">/// Count of killed process in each catalog.
<a href=#45 id=45 data-nosnippet>45</a> </span><span class="kw">pub static </span><span class="kw-2">ref </span>PROCESS_KILL_COUNT: IntCounterVec = <span class="macro">register_int_counter_vec!</span>(
<a href=#46 id=46 data-nosnippet>46</a> <span class="string">"greptime_process_kill_count"</span>,
<a href=#47 id=47 data-nosnippet>47</a> <span class="string">"Completed kill process requests count"</span>,
<a href=#48 id=48 data-nosnippet>48</a> <span class="kw-2">&amp;</span>[<span class="string">"catalog"</span>]
<a href=#49 id=49 data-nosnippet>49</a> )
<a href=#50 id=50 data-nosnippet>50</a> .unwrap();
<a href=#51 id=51 data-nosnippet>51</a>}
</code></pre></div></section></main></body></html>
+774
View File
@@ -0,0 +1,774 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/process_manager.rs`."><title>process_manager.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/</div>process_manager.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::collections::HashMap;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::collections::hash_map::Entry;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>std::fmt::{Debug, Display, Formatter};
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>std::sync::atomic::{AtomicU32, Ordering};
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>std::sync::{Arc, RwLock};
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>std::time::{Duration, Instant, UNIX_EPOCH};
<a href=#21 id=21 data-nosnippet>21</a>
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>api::v1::frontend::{KillProcessRequest, ListProcessRequest, ProcessInfo};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_base::cancellation::CancellationHandle;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_event_recorder::EventRecorderRef;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>common_frontend::selector::{FrontendSelector, MetaClientSelector};
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>common_frontend::slow_query_event::SlowQueryEvent;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>common_telemetry::logging::SlowQueriesRecordType;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>common_telemetry::{debug, info, slow, warn};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>common_time::util::current_time_millis;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>meta_client::MetaClientRef;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>promql_parser::parser::EvalStmt;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>rand::random;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>snafu::{OptionExt, ResultExt, ensure};
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span>sql::statements::statement::Statement;
<a href=#35 id=35 data-nosnippet>35</a>
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span><span class="kw">crate</span>::error;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span><span class="kw">crate</span>::metrics::{PROCESS_KILL_COUNT, PROCESS_LIST_COUNT};
<a href=#38 id=38 data-nosnippet>38</a>
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">pub type </span>ProcessId = u32;
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">pub type </span>ProcessManagerRef = Arc&lt;ProcessManager&gt;;
<a href=#41 id=41 data-nosnippet>41</a>
<a href=#42 id=42 data-nosnippet>42</a><span class="doccomment">/// Query process manager.
<a href=#43 id=43 data-nosnippet>43</a></span><span class="kw">pub struct </span>ProcessManager {
<a href=#44 id=44 data-nosnippet>44</a> <span class="doccomment">/// Local frontend server address,
<a href=#45 id=45 data-nosnippet>45</a> </span>server_addr: String,
<a href=#46 id=46 data-nosnippet>46</a> <span class="doccomment">/// Next process id for local queries.
<a href=#47 id=47 data-nosnippet>47</a> </span>next_id: AtomicU32,
<a href=#48 id=48 data-nosnippet>48</a> <span class="doccomment">/// Running process per catalog.
<a href=#49 id=49 data-nosnippet>49</a> </span>catalogs: RwLock&lt;HashMap&lt;String, HashMap&lt;ProcessId, CancellableProcess&gt;&gt;&gt;,
<a href=#50 id=50 data-nosnippet>50</a> <span class="doccomment">/// Frontend selector to locate frontend nodes.
<a href=#51 id=51 data-nosnippet>51</a> </span>frontend_selector: <span class="prelude-ty">Option</span>&lt;MetaClientSelector&gt;,
<a href=#52 id=52 data-nosnippet>52</a>}
<a href=#53 id=53 data-nosnippet>53</a>
<a href=#54 id=54 data-nosnippet>54</a><span class="doccomment">/// Represents a parsed query statement, functionally equivalent to [query::parser::QueryStatement].
<a href=#55 id=55 data-nosnippet>55</a>/// This enum is defined here to avoid cyclic dependencies with the query parser module.
<a href=#56 id=56 data-nosnippet>56</a></span><span class="attr">#[derive(Debug, Clone)]
<a href=#57 id=57 data-nosnippet>57</a></span><span class="kw">pub enum </span>QueryStatement {
<a href=#58 id=58 data-nosnippet>58</a> Sql(Statement),
<a href=#59 id=59 data-nosnippet>59</a> <span class="comment">// The optional string is the alias of the PromQL query.
<a href=#60 id=60 data-nosnippet>60</a> </span>Promql(EvalStmt, <span class="prelude-ty">Option</span>&lt;String&gt;),
<a href=#61 id=61 data-nosnippet>61</a> <span class="doccomment">/// Logical plan with original query string
<a href=#62 id=62 data-nosnippet>62</a> </span>Plan(String),
<a href=#63 id=63 data-nosnippet>63</a>}
<a href=#64 id=64 data-nosnippet>64</a>
<a href=#65 id=65 data-nosnippet>65</a><span class="kw">impl </span>Display <span class="kw">for </span>QueryStatement {
<a href=#66 id=66 data-nosnippet>66</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; std::fmt::Result {
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#68 id=68 data-nosnippet>68</a> QueryStatement::Sql(stmt) =&gt; <span class="macro">write!</span>(f, <span class="string">"{}"</span>, stmt),
<a href=#69 id=69 data-nosnippet>69</a> QueryStatement::Promql(eval_stmt, alias) =&gt; {
<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(alias) = alias {
<a href=#71 id=71 data-nosnippet>71</a> <span class="macro">write!</span>(f, <span class="string">"{} AS {}"</span>, eval_stmt, alias)
<a href=#72 id=72 data-nosnippet>72</a> } <span class="kw">else </span>{
<a href=#73 id=73 data-nosnippet>73</a> <span class="macro">write!</span>(f, <span class="string">"{}"</span>, eval_stmt)
<a href=#74 id=74 data-nosnippet>74</a> }
<a href=#75 id=75 data-nosnippet>75</a> }
<a href=#76 id=76 data-nosnippet>76</a> QueryStatement::Plan(query) =&gt; <span class="macro">write!</span>(f, <span class="string">"{}"</span>, query),
<a href=#77 id=77 data-nosnippet>77</a> }
<a href=#78 id=78 data-nosnippet>78</a> }
<a href=#79 id=79 data-nosnippet>79</a>}
<a href=#80 id=80 data-nosnippet>80</a>
<a href=#81 id=81 data-nosnippet>81</a><span class="kw">impl </span>ProcessManager {
<a href=#82 id=82 data-nosnippet>82</a> <span class="doccomment">/// Create a [ProcessManager] instance with server address and kv client.
<a href=#83 id=83 data-nosnippet>83</a> </span><span class="kw">pub fn </span>new(server_addr: String, meta_client: <span class="prelude-ty">Option</span>&lt;MetaClientRef&gt;) -&gt; <span class="self">Self </span>{
<a href=#84 id=84 data-nosnippet>84</a> <span class="kw">let </span>frontend_selector = meta_client.map(MetaClientSelector::new);
<a href=#85 id=85 data-nosnippet>85</a> <span class="self">Self </span>{
<a href=#86 id=86 data-nosnippet>86</a> server_addr,
<a href=#87 id=87 data-nosnippet>87</a> next_id: Default::default(),
<a href=#88 id=88 data-nosnippet>88</a> catalogs: Default::default(),
<a href=#89 id=89 data-nosnippet>89</a> frontend_selector,
<a href=#90 id=90 data-nosnippet>90</a> }
<a href=#91 id=91 data-nosnippet>91</a> }
<a href=#92 id=92 data-nosnippet>92</a>}
<a href=#93 id=93 data-nosnippet>93</a>
<a href=#94 id=94 data-nosnippet>94</a><span class="kw">impl </span>ProcessManager {
<a href=#95 id=95 data-nosnippet>95</a> <span class="doccomment">/// Registers a submitted query. Use the provided id if present.
<a href=#96 id=96 data-nosnippet>96</a> </span><span class="attr">#[must_use]
<a href=#97 id=97 data-nosnippet>97</a> </span><span class="kw">pub fn </span>register_query(
<a href=#98 id=98 data-nosnippet>98</a> <span class="self">self</span>: <span class="kw-2">&amp;</span>Arc&lt;<span class="self">Self</span>&gt;,
<a href=#99 id=99 data-nosnippet>99</a> catalog: String,
<a href=#100 id=100 data-nosnippet>100</a> schemas: Vec&lt;String&gt;,
<a href=#101 id=101 data-nosnippet>101</a> query: String,
<a href=#102 id=102 data-nosnippet>102</a> client: String,
<a href=#103 id=103 data-nosnippet>103</a> query_id: <span class="prelude-ty">Option</span>&lt;ProcessId&gt;,
<a href=#104 id=104 data-nosnippet>104</a> _slow_query_timer: <span class="prelude-ty">Option</span>&lt;SlowQueryTimer&gt;,
<a href=#105 id=105 data-nosnippet>105</a> ) -&gt; Ticket {
<a href=#106 id=106 data-nosnippet>106</a> <span class="kw">let </span>id = query_id.unwrap_or_else(|| <span class="self">self</span>.next_id.fetch_add(<span class="number">1</span>, Ordering::Relaxed));
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">let </span>process = ProcessInfo {
<a href=#108 id=108 data-nosnippet>108</a> id,
<a href=#109 id=109 data-nosnippet>109</a> catalog: catalog.clone(),
<a href=#110 id=110 data-nosnippet>110</a> schemas,
<a href=#111 id=111 data-nosnippet>111</a> query,
<a href=#112 id=112 data-nosnippet>112</a> start_timestamp: current_time_millis(),
<a href=#113 id=113 data-nosnippet>113</a> client,
<a href=#114 id=114 data-nosnippet>114</a> frontend: <span class="self">self</span>.server_addr.clone(),
<a href=#115 id=115 data-nosnippet>115</a> };
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw">let </span>cancellation_handle = Arc::new(CancellationHandle::default());
<a href=#117 id=117 data-nosnippet>117</a> <span class="kw">let </span>cancellable_process = CancellableProcess::new(cancellation_handle.clone(), process);
<a href=#118 id=118 data-nosnippet>118</a>
<a href=#119 id=119 data-nosnippet>119</a> <span class="self">self</span>.catalogs
<a href=#120 id=120 data-nosnippet>120</a> .write()
<a href=#121 id=121 data-nosnippet>121</a> .unwrap()
<a href=#122 id=122 data-nosnippet>122</a> .entry(catalog.clone())
<a href=#123 id=123 data-nosnippet>123</a> .or_default()
<a href=#124 id=124 data-nosnippet>124</a> .insert(id, cancellable_process);
<a href=#125 id=125 data-nosnippet>125</a>
<a href=#126 id=126 data-nosnippet>126</a> Ticket {
<a href=#127 id=127 data-nosnippet>127</a> catalog,
<a href=#128 id=128 data-nosnippet>128</a> manager: <span class="self">self</span>.clone(),
<a href=#129 id=129 data-nosnippet>129</a> id,
<a href=#130 id=130 data-nosnippet>130</a> cancellation_handle,
<a href=#131 id=131 data-nosnippet>131</a> _slow_query_timer,
<a href=#132 id=132 data-nosnippet>132</a> }
<a href=#133 id=133 data-nosnippet>133</a> }
<a href=#134 id=134 data-nosnippet>134</a>
<a href=#135 id=135 data-nosnippet>135</a> <span class="doccomment">/// Generates the next process id.
<a href=#136 id=136 data-nosnippet>136</a> </span><span class="kw">pub fn </span>next_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; u32 {
<a href=#137 id=137 data-nosnippet>137</a> <span class="self">self</span>.next_id.fetch_add(<span class="number">1</span>, Ordering::Relaxed)
<a href=#138 id=138 data-nosnippet>138</a> }
<a href=#139 id=139 data-nosnippet>139</a>
<a href=#140 id=140 data-nosnippet>140</a> <span class="doccomment">/// De-register a query from process list.
<a href=#141 id=141 data-nosnippet>141</a> </span><span class="kw">pub fn </span>deregister_query(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog: String, id: ProcessId) {
<a href=#142 id=142 data-nosnippet>142</a> <span class="kw">if let </span>Entry::Occupied(<span class="kw-2">mut </span>o) = <span class="self">self</span>.catalogs.write().unwrap().entry(catalog) {
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">let </span>process = o.get_mut().remove(<span class="kw-2">&amp;</span>id);
<a href=#144 id=144 data-nosnippet>144</a> <span class="macro">debug!</span>(<span class="string">"Deregister process: {:?}"</span>, process);
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">if </span>o.get().is_empty() {
<a href=#146 id=146 data-nosnippet>146</a> o.remove();
<a href=#147 id=147 data-nosnippet>147</a> }
<a href=#148 id=148 data-nosnippet>148</a> }
<a href=#149 id=149 data-nosnippet>149</a> }
<a href=#150 id=150 data-nosnippet>150</a>
<a href=#151 id=151 data-nosnippet>151</a> <span class="doccomment">/// List local running processes in given catalog.
<a href=#152 id=152 data-nosnippet>152</a> </span><span class="kw">pub fn </span>local_processes(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt;) -&gt; error::Result&lt;Vec&lt;ProcessInfo&gt;&gt; {
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">let </span>catalogs = <span class="self">self</span>.catalogs.read().unwrap();
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">let </span>result = <span class="kw">if let </span><span class="prelude-val">Some</span>(catalog) = catalog {
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(catalogs) = catalogs.get(catalog) {
<a href=#156 id=156 data-nosnippet>156</a> catalogs.values().map(|p| p.process.clone()).collect()
<a href=#157 id=157 data-nosnippet>157</a> } <span class="kw">else </span>{
<a href=#158 id=158 data-nosnippet>158</a> <span class="macro">vec!</span>[]
<a href=#159 id=159 data-nosnippet>159</a> }
<a href=#160 id=160 data-nosnippet>160</a> } <span class="kw">else </span>{
<a href=#161 id=161 data-nosnippet>161</a> catalogs
<a href=#162 id=162 data-nosnippet>162</a> .values()
<a href=#163 id=163 data-nosnippet>163</a> .flat_map(|v| v.values().map(|p| p.process.clone()))
<a href=#164 id=164 data-nosnippet>164</a> .collect()
<a href=#165 id=165 data-nosnippet>165</a> };
<a href=#166 id=166 data-nosnippet>166</a> <span class="prelude-val">Ok</span>(result)
<a href=#167 id=167 data-nosnippet>167</a> }
<a href=#168 id=168 data-nosnippet>168</a>
<a href=#169 id=169 data-nosnippet>169</a> <span class="kw">pub async fn </span>list_all_processes(
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#171 id=171 data-nosnippet>171</a> catalog: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt;,
<a href=#172 id=172 data-nosnippet>172</a> ) -&gt; error::Result&lt;Vec&lt;ProcessInfo&gt;&gt; {
<a href=#173 id=173 data-nosnippet>173</a> <span class="kw">let </span><span class="kw-2">mut </span>processes = <span class="macro">vec!</span>[];
<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(remote_frontend_selector) = <span class="self">self</span>.frontend_selector.as_ref() {
<a href=#175 id=175 data-nosnippet>175</a> <span class="kw">let </span>frontends = remote_frontend_selector
<a href=#176 id=176 data-nosnippet>176</a> .select(|peer| peer.addr != <span class="self">self</span>.server_addr)
<a href=#177 id=177 data-nosnippet>177</a> .<span class="kw">await
<a href=#178 id=178 data-nosnippet>178</a> </span>.context(error::InvokeFrontendSnafu)<span class="question-mark">?</span>;
<a href=#179 id=179 data-nosnippet>179</a> <span class="kw">for </span><span class="kw-2">mut </span>f <span class="kw">in </span>frontends {
<a href=#180 id=180 data-nosnippet>180</a> <span class="kw">let </span>result = f
<a href=#181 id=181 data-nosnippet>181</a> .list_process(ListProcessRequest {
<a href=#182 id=182 data-nosnippet>182</a> catalog: catalog.unwrap_or_default().to_string(),
<a href=#183 id=183 data-nosnippet>183</a> })
<a href=#184 id=184 data-nosnippet>184</a> .<span class="kw">await
<a href=#185 id=185 data-nosnippet>185</a> </span>.context(error::InvokeFrontendSnafu);
<a href=#186 id=186 data-nosnippet>186</a> <span class="kw">match </span>result {
<a href=#187 id=187 data-nosnippet>187</a> <span class="prelude-val">Ok</span>(resp) =&gt; {
<a href=#188 id=188 data-nosnippet>188</a> processes.extend(resp.processes);
<a href=#189 id=189 data-nosnippet>189</a> }
<a href=#190 id=190 data-nosnippet>190</a> <span class="prelude-val">Err</span>(e) =&gt; {
<a href=#191 id=191 data-nosnippet>191</a> <span class="macro">warn!</span>(e; <span class="string">"Skipping failing node: {:?}"</span>, f)
<a href=#192 id=192 data-nosnippet>192</a> }
<a href=#193 id=193 data-nosnippet>193</a> }
<a href=#194 id=194 data-nosnippet>194</a> }
<a href=#195 id=195 data-nosnippet>195</a> }
<a href=#196 id=196 data-nosnippet>196</a> processes.extend(<span class="self">self</span>.local_processes(catalog)<span class="question-mark">?</span>);
<a href=#197 id=197 data-nosnippet>197</a> <span class="prelude-val">Ok</span>(processes)
<a href=#198 id=198 data-nosnippet>198</a> }
<a href=#199 id=199 data-nosnippet>199</a>
<a href=#200 id=200 data-nosnippet>200</a> <span class="doccomment">/// Kills query with provided catalog and id.
<a href=#201 id=201 data-nosnippet>201</a> </span><span class="kw">pub async fn </span>kill_process(
<a href=#202 id=202 data-nosnippet>202</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#203 id=203 data-nosnippet>203</a> server_addr: String,
<a href=#204 id=204 data-nosnippet>204</a> catalog: String,
<a href=#205 id=205 data-nosnippet>205</a> id: ProcessId,
<a href=#206 id=206 data-nosnippet>206</a> ) -&gt; error::Result&lt;bool&gt; {
<a href=#207 id=207 data-nosnippet>207</a> <span class="kw">if </span>server_addr == <span class="self">self</span>.server_addr {
<a href=#208 id=208 data-nosnippet>208</a> <span class="self">self</span>.kill_local_process(catalog, id).<span class="kw">await
<a href=#209 id=209 data-nosnippet>209</a> </span>} <span class="kw">else </span>{
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">let </span><span class="kw-2">mut </span>nodes = <span class="self">self
<a href=#211 id=211 data-nosnippet>211</a> </span>.frontend_selector
<a href=#212 id=212 data-nosnippet>212</a> .as_ref()
<a href=#213 id=213 data-nosnippet>213</a> .context(error::MetaClientMissingSnafu)<span class="question-mark">?
<a href=#214 id=214 data-nosnippet>214</a> </span>.select(|peer| peer.addr == server_addr)
<a href=#215 id=215 data-nosnippet>215</a> .<span class="kw">await
<a href=#216 id=216 data-nosnippet>216</a> </span>.context(error::InvokeFrontendSnafu)<span class="question-mark">?</span>;
<a href=#217 id=217 data-nosnippet>217</a> <span class="macro">ensure!</span>(
<a href=#218 id=218 data-nosnippet>218</a> !nodes.is_empty(),
<a href=#219 id=219 data-nosnippet>219</a> error::FrontendNotFoundSnafu { addr: server_addr }
<a href=#220 id=220 data-nosnippet>220</a> );
<a href=#221 id=221 data-nosnippet>221</a>
<a href=#222 id=222 data-nosnippet>222</a> <span class="kw">let </span>request = KillProcessRequest {
<a href=#223 id=223 data-nosnippet>223</a> server_addr,
<a href=#224 id=224 data-nosnippet>224</a> catalog,
<a href=#225 id=225 data-nosnippet>225</a> process_id: id,
<a href=#226 id=226 data-nosnippet>226</a> };
<a href=#227 id=227 data-nosnippet>227</a> nodes[<span class="number">0</span>]
<a href=#228 id=228 data-nosnippet>228</a> .kill_process(request)
<a href=#229 id=229 data-nosnippet>229</a> .<span class="kw">await
<a href=#230 id=230 data-nosnippet>230</a> </span>.context(error::InvokeFrontendSnafu)<span class="question-mark">?</span>;
<a href=#231 id=231 data-nosnippet>231</a> <span class="prelude-val">Ok</span>(<span class="bool-val">true</span>)
<a href=#232 id=232 data-nosnippet>232</a> }
<a href=#233 id=233 data-nosnippet>233</a> }
<a href=#234 id=234 data-nosnippet>234</a>
<a href=#235 id=235 data-nosnippet>235</a> <span class="doccomment">/// Kills local query with provided catalog and id.
<a href=#236 id=236 data-nosnippet>236</a> </span><span class="kw">pub async fn </span>kill_local_process(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog: String, id: ProcessId) -&gt; error::Result&lt;bool&gt; {
<a href=#237 id=237 data-nosnippet>237</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(catalogs) = <span class="self">self</span>.catalogs.write().unwrap().get_mut(<span class="kw-2">&amp;</span>catalog) {
<a href=#238 id=238 data-nosnippet>238</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(process) = catalogs.remove(<span class="kw-2">&amp;</span>id) {
<a href=#239 id=239 data-nosnippet>239</a> process.handle.cancel();
<a href=#240 id=240 data-nosnippet>240</a> <span class="macro">info!</span>(
<a href=#241 id=241 data-nosnippet>241</a> <span class="string">"Killed process, catalog: {}, id: {:?}"</span>,
<a href=#242 id=242 data-nosnippet>242</a> process.process.catalog, process.process.id
<a href=#243 id=243 data-nosnippet>243</a> );
<a href=#244 id=244 data-nosnippet>244</a> PROCESS_KILL_COUNT.with_label_values(<span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span>catalog]).inc();
<a href=#245 id=245 data-nosnippet>245</a> <span class="prelude-val">Ok</span>(<span class="bool-val">true</span>)
<a href=#246 id=246 data-nosnippet>246</a> } <span class="kw">else </span>{
<a href=#247 id=247 data-nosnippet>247</a> <span class="macro">debug!</span>(<span class="string">"Failed to kill process, id not found: {}"</span>, id);
<a href=#248 id=248 data-nosnippet>248</a> <span class="prelude-val">Ok</span>(<span class="bool-val">false</span>)
<a href=#249 id=249 data-nosnippet>249</a> }
<a href=#250 id=250 data-nosnippet>250</a> } <span class="kw">else </span>{
<a href=#251 id=251 data-nosnippet>251</a> <span class="macro">debug!</span>(<span class="string">"Failed to kill process, catalog not found: {}"</span>, catalog);
<a href=#252 id=252 data-nosnippet>252</a> <span class="prelude-val">Ok</span>(<span class="bool-val">false</span>)
<a href=#253 id=253 data-nosnippet>253</a> }
<a href=#254 id=254 data-nosnippet>254</a> }
<a href=#255 id=255 data-nosnippet>255</a>}
<a href=#256 id=256 data-nosnippet>256</a>
<a href=#257 id=257 data-nosnippet>257</a><span class="kw">pub struct </span>Ticket {
<a href=#258 id=258 data-nosnippet>258</a> <span class="kw">pub</span>(<span class="kw">crate</span>) catalog: String,
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">pub</span>(<span class="kw">crate</span>) manager: ProcessManagerRef,
<a href=#260 id=260 data-nosnippet>260</a> <span class="kw">pub</span>(<span class="kw">crate</span>) id: ProcessId,
<a href=#261 id=261 data-nosnippet>261</a> <span class="kw">pub </span>cancellation_handle: Arc&lt;CancellationHandle&gt;,
<a href=#262 id=262 data-nosnippet>262</a>
<a href=#263 id=263 data-nosnippet>263</a> <span class="comment">// Keep the handle of the slow query timer to ensure it will trigger the event recording when dropped.
<a href=#264 id=264 data-nosnippet>264</a> </span>_slow_query_timer: <span class="prelude-ty">Option</span>&lt;SlowQueryTimer&gt;,
<a href=#265 id=265 data-nosnippet>265</a>}
<a href=#266 id=266 data-nosnippet>266</a>
<a href=#267 id=267 data-nosnippet>267</a><span class="kw">impl </span>Drop <span class="kw">for </span>Ticket {
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#269 id=269 data-nosnippet>269</a> <span class="self">self</span>.manager
<a href=#270 id=270 data-nosnippet>270</a> .deregister_query(std::mem::take(<span class="kw-2">&amp;mut </span><span class="self">self</span>.catalog), <span class="self">self</span>.id);
<a href=#271 id=271 data-nosnippet>271</a> }
<a href=#272 id=272 data-nosnippet>272</a>}
<a href=#273 id=273 data-nosnippet>273</a>
<a href=#274 id=274 data-nosnippet>274</a><span class="kw">struct </span>CancellableProcess {
<a href=#275 id=275 data-nosnippet>275</a> handle: Arc&lt;CancellationHandle&gt;,
<a href=#276 id=276 data-nosnippet>276</a> process: ProcessInfo,
<a href=#277 id=277 data-nosnippet>277</a>}
<a href=#278 id=278 data-nosnippet>278</a>
<a href=#279 id=279 data-nosnippet>279</a><span class="kw">impl </span>Drop <span class="kw">for </span>CancellableProcess {
<a href=#280 id=280 data-nosnippet>280</a> <span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#281 id=281 data-nosnippet>281</a> PROCESS_LIST_COUNT
<a href=#282 id=282 data-nosnippet>282</a> .with_label_values(<span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span><span class="self">self</span>.process.catalog])
<a href=#283 id=283 data-nosnippet>283</a> .dec();
<a href=#284 id=284 data-nosnippet>284</a> }
<a href=#285 id=285 data-nosnippet>285</a>}
<a href=#286 id=286 data-nosnippet>286</a>
<a href=#287 id=287 data-nosnippet>287</a><span class="kw">impl </span>CancellableProcess {
<a href=#288 id=288 data-nosnippet>288</a> <span class="kw">fn </span>new(handle: Arc&lt;CancellationHandle&gt;, process: ProcessInfo) -&gt; <span class="self">Self </span>{
<a href=#289 id=289 data-nosnippet>289</a> PROCESS_LIST_COUNT
<a href=#290 id=290 data-nosnippet>290</a> .with_label_values(<span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span>process.catalog])
<a href=#291 id=291 data-nosnippet>291</a> .inc();
<a href=#292 id=292 data-nosnippet>292</a> <span class="self">Self </span>{ handle, process }
<a href=#293 id=293 data-nosnippet>293</a> }
<a href=#294 id=294 data-nosnippet>294</a>}
<a href=#295 id=295 data-nosnippet>295</a>
<a href=#296 id=296 data-nosnippet>296</a><span class="kw">impl </span>Debug <span class="kw">for </span>CancellableProcess {
<a href=#297 id=297 data-nosnippet>297</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; std::fmt::Result {
<a href=#298 id=298 data-nosnippet>298</a> f.debug_struct(<span class="string">"CancellableProcess"</span>)
<a href=#299 id=299 data-nosnippet>299</a> .field(<span class="string">"cancelled"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.handle.is_cancelled())
<a href=#300 id=300 data-nosnippet>300</a> .field(<span class="string">"process"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.process)
<a href=#301 id=301 data-nosnippet>301</a> .finish()
<a href=#302 id=302 data-nosnippet>302</a> }
<a href=#303 id=303 data-nosnippet>303</a>}
<a href=#304 id=304 data-nosnippet>304</a>
<a href=#305 id=305 data-nosnippet>305</a><span class="doccomment">/// SlowQueryTimer is used to log slow query when it's dropped.
<a href=#306 id=306 data-nosnippet>306</a>/// In drop(), it will check if the query is slow and send the slow query event to the handler.
<a href=#307 id=307 data-nosnippet>307</a></span><span class="kw">pub struct </span>SlowQueryTimer {
<a href=#308 id=308 data-nosnippet>308</a> start: Instant,
<a href=#309 id=309 data-nosnippet>309</a> stmt: QueryStatement,
<a href=#310 id=310 data-nosnippet>310</a> schema_name: String,
<a href=#311 id=311 data-nosnippet>311</a> threshold: Duration,
<a href=#312 id=312 data-nosnippet>312</a> sample_ratio: f64,
<a href=#313 id=313 data-nosnippet>313</a> record_type: SlowQueriesRecordType,
<a href=#314 id=314 data-nosnippet>314</a> recorder: EventRecorderRef,
<a href=#315 id=315 data-nosnippet>315</a> record_state: Arc&lt;RwLock&lt;SlowQueryRecordState&gt;&gt;,
<a href=#316 id=316 data-nosnippet>316</a>}
<a href=#317 id=317 data-nosnippet>317</a>
<a href=#318 id=318 data-nosnippet>318</a><span class="attr">#[derive(Default)]
<a href=#319 id=319 data-nosnippet>319</a></span><span class="kw">struct </span>SlowQueryRecordState {
<a href=#320 id=320 data-nosnippet>320</a> force_record: bool,
<a href=#321 id=321 data-nosnippet>321</a> payload: serde_json::Value,
<a href=#322 id=322 data-nosnippet>322</a>}
<a href=#323 id=323 data-nosnippet>323</a>
<a href=#324 id=324 data-nosnippet>324</a><span class="doccomment">/// A handle to attach diagnostics to a slow query and force it to be recorded.
<a href=#325 id=325 data-nosnippet>325</a></span><span class="attr">#[derive(Clone)]
<a href=#326 id=326 data-nosnippet>326</a></span><span class="kw">pub struct </span>SlowQueryRecorder {
<a href=#327 id=327 data-nosnippet>327</a> record_state: Arc&lt;RwLock&lt;SlowQueryRecordState&gt;&gt;,
<a href=#328 id=328 data-nosnippet>328</a>}
<a href=#329 id=329 data-nosnippet>329</a>
<a href=#330 id=330 data-nosnippet>330</a><span class="kw">impl </span>SlowQueryRecorder {
<a href=#331 id=331 data-nosnippet>331</a> <span class="doccomment">/// Attaches the payload and marks the query to bypass the threshold and sampling checks.
<a href=#332 id=332 data-nosnippet>332</a> </span><span class="kw">pub fn </span>force_record_with_payload(<span class="kw-2">&amp;</span><span class="self">self</span>, payload: serde_json::Value) {
<a href=#333 id=333 data-nosnippet>333</a> <span class="kw">let </span><span class="kw-2">mut </span>state = <span class="self">self</span>.record_state.write().unwrap();
<a href=#334 id=334 data-nosnippet>334</a> state.payload = payload;
<a href=#335 id=335 data-nosnippet>335</a> state.force_record = <span class="bool-val">true</span>;
<a href=#336 id=336 data-nosnippet>336</a> }
<a href=#337 id=337 data-nosnippet>337</a>}
<a href=#338 id=338 data-nosnippet>338</a>
<a href=#339 id=339 data-nosnippet>339</a><span class="kw">impl </span>SlowQueryTimer {
<a href=#340 id=340 data-nosnippet>340</a> <span class="kw">pub fn </span>new(
<a href=#341 id=341 data-nosnippet>341</a> stmt: QueryStatement,
<a href=#342 id=342 data-nosnippet>342</a> schema_name: String,
<a href=#343 id=343 data-nosnippet>343</a> threshold: Duration,
<a href=#344 id=344 data-nosnippet>344</a> sample_ratio: f64,
<a href=#345 id=345 data-nosnippet>345</a> record_type: SlowQueriesRecordType,
<a href=#346 id=346 data-nosnippet>346</a> recorder: EventRecorderRef,
<a href=#347 id=347 data-nosnippet>347</a> ) -&gt; <span class="self">Self </span>{
<a href=#348 id=348 data-nosnippet>348</a> <span class="self">Self </span>{
<a href=#349 id=349 data-nosnippet>349</a> start: Instant::now(),
<a href=#350 id=350 data-nosnippet>350</a> stmt,
<a href=#351 id=351 data-nosnippet>351</a> schema_name,
<a href=#352 id=352 data-nosnippet>352</a> threshold,
<a href=#353 id=353 data-nosnippet>353</a> sample_ratio,
<a href=#354 id=354 data-nosnippet>354</a> record_type,
<a href=#355 id=355 data-nosnippet>355</a> recorder,
<a href=#356 id=356 data-nosnippet>356</a> record_state: Arc::default(),
<a href=#357 id=357 data-nosnippet>357</a> }
<a href=#358 id=358 data-nosnippet>358</a> }
<a href=#359 id=359 data-nosnippet>359</a>
<a href=#360 id=360 data-nosnippet>360</a> <span class="doccomment">/// Returns a handle that can attach diagnostics and force this query to be recorded.
<a href=#361 id=361 data-nosnippet>361</a> </span><span class="kw">pub fn </span>recorder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SlowQueryRecorder {
<a href=#362 id=362 data-nosnippet>362</a> SlowQueryRecorder {
<a href=#363 id=363 data-nosnippet>363</a> record_state: <span class="self">self</span>.record_state.clone(),
<a href=#364 id=364 data-nosnippet>364</a> }
<a href=#365 id=365 data-nosnippet>365</a> }
<a href=#366 id=366 data-nosnippet>366</a>}
<a href=#367 id=367 data-nosnippet>367</a>
<a href=#368 id=368 data-nosnippet>368</a><span class="kw">impl </span>SlowQueryTimer {
<a href=#369 id=369 data-nosnippet>369</a> <span class="kw">fn </span>send_slow_query_event(<span class="kw-2">&amp;</span><span class="self">self</span>, elapsed: Duration, payload: serde_json::Value) {
<a href=#370 id=370 data-nosnippet>370</a> <span class="kw">let </span><span class="kw-2">mut </span>slow_query_event = SlowQueryEvent {
<a href=#371 id=371 data-nosnippet>371</a> cost: elapsed.as_millis() <span class="kw">as </span>u64,
<a href=#372 id=372 data-nosnippet>372</a> threshold: <span class="self">self</span>.threshold.as_millis() <span class="kw">as </span>u64,
<a href=#373 id=373 data-nosnippet>373</a> query: <span class="string">""</span>.to_string(),
<a href=#374 id=374 data-nosnippet>374</a> schema_name: <span class="self">self</span>.schema_name.clone(),
<a href=#375 id=375 data-nosnippet>375</a>
<a href=#376 id=376 data-nosnippet>376</a> <span class="comment">// The following fields are only used for PromQL queries.
<a href=#377 id=377 data-nosnippet>377</a> </span>is_promql: <span class="bool-val">false</span>,
<a href=#378 id=378 data-nosnippet>378</a> promql_range: <span class="prelude-val">None</span>,
<a href=#379 id=379 data-nosnippet>379</a> promql_step: <span class="prelude-val">None</span>,
<a href=#380 id=380 data-nosnippet>380</a> promql_start: <span class="prelude-val">None</span>,
<a href=#381 id=381 data-nosnippet>381</a> promql_end: <span class="prelude-val">None</span>,
<a href=#382 id=382 data-nosnippet>382</a> payload,
<a href=#383 id=383 data-nosnippet>383</a> };
<a href=#384 id=384 data-nosnippet>384</a>
<a href=#385 id=385 data-nosnippet>385</a> <span class="kw">match </span><span class="kw-2">&amp;</span><span class="self">self</span>.stmt {
<a href=#386 id=386 data-nosnippet>386</a> QueryStatement::Promql(stmt, _alias) =&gt; {
<a href=#387 id=387 data-nosnippet>387</a> slow_query_event.is_promql = <span class="bool-val">true</span>;
<a href=#388 id=388 data-nosnippet>388</a> slow_query_event.query = <span class="self">self</span>.stmt.to_string();
<a href=#389 id=389 data-nosnippet>389</a> slow_query_event.promql_step = <span class="prelude-val">Some</span>(stmt.interval.as_millis() <span class="kw">as </span>u64);
<a href=#390 id=390 data-nosnippet>390</a>
<a href=#391 id=391 data-nosnippet>391</a> <span class="kw">let </span>start = stmt
<a href=#392 id=392 data-nosnippet>392</a> .start
<a href=#393 id=393 data-nosnippet>393</a> .duration_since(UNIX_EPOCH)
<a href=#394 id=394 data-nosnippet>394</a> .unwrap_or_default()
<a href=#395 id=395 data-nosnippet>395</a> .as_millis() <span class="kw">as </span>i64;
<a href=#396 id=396 data-nosnippet>396</a>
<a href=#397 id=397 data-nosnippet>397</a> <span class="kw">let </span>end = stmt
<a href=#398 id=398 data-nosnippet>398</a> .end
<a href=#399 id=399 data-nosnippet>399</a> .duration_since(UNIX_EPOCH)
<a href=#400 id=400 data-nosnippet>400</a> .unwrap_or_default()
<a href=#401 id=401 data-nosnippet>401</a> .as_millis() <span class="kw">as </span>i64;
<a href=#402 id=402 data-nosnippet>402</a>
<a href=#403 id=403 data-nosnippet>403</a> slow_query_event.promql_range = <span class="prelude-val">Some</span>((end - start) <span class="kw">as </span>u64);
<a href=#404 id=404 data-nosnippet>404</a> slow_query_event.promql_start = <span class="prelude-val">Some</span>(start);
<a href=#405 id=405 data-nosnippet>405</a> slow_query_event.promql_end = <span class="prelude-val">Some</span>(end);
<a href=#406 id=406 data-nosnippet>406</a> }
<a href=#407 id=407 data-nosnippet>407</a> QueryStatement::Sql(stmt) =&gt; {
<a href=#408 id=408 data-nosnippet>408</a> slow_query_event.query = stmt.to_string();
<a href=#409 id=409 data-nosnippet>409</a> }
<a href=#410 id=410 data-nosnippet>410</a> QueryStatement::Plan(query) =&gt; {
<a href=#411 id=411 data-nosnippet>411</a> slow_query_event.query = query.clone();
<a href=#412 id=412 data-nosnippet>412</a> }
<a href=#413 id=413 data-nosnippet>413</a> }
<a href=#414 id=414 data-nosnippet>414</a>
<a href=#415 id=415 data-nosnippet>415</a> <span class="kw">match </span><span class="self">self</span>.record_type {
<a href=#416 id=416 data-nosnippet>416</a> <span class="comment">// Send the slow query event to the event recorder to persist it as the system table.
<a href=#417 id=417 data-nosnippet>417</a> </span>SlowQueriesRecordType::SystemTable =&gt; {
<a href=#418 id=418 data-nosnippet>418</a> <span class="self">self</span>.recorder.record(Box::new(slow_query_event));
<a href=#419 id=419 data-nosnippet>419</a> }
<a href=#420 id=420 data-nosnippet>420</a> <span class="comment">// Record the slow query in a specific logs file.
<a href=#421 id=421 data-nosnippet>421</a> </span>SlowQueriesRecordType::Log =&gt; {
<a href=#422 id=422 data-nosnippet>422</a> <span class="macro">slow!</span>(
<a href=#423 id=423 data-nosnippet>423</a> cost = slow_query_event.cost,
<a href=#424 id=424 data-nosnippet>424</a> threshold = slow_query_event.threshold,
<a href=#425 id=425 data-nosnippet>425</a> query = slow_query_event.query,
<a href=#426 id=426 data-nosnippet>426</a> schema_name = slow_query_event.schema_name,
<a href=#427 id=427 data-nosnippet>427</a> is_promql = slow_query_event.is_promql,
<a href=#428 id=428 data-nosnippet>428</a> promql_range = slow_query_event.promql_range,
<a href=#429 id=429 data-nosnippet>429</a> promql_step = slow_query_event.promql_step,
<a href=#430 id=430 data-nosnippet>430</a> promql_start = slow_query_event.promql_start,
<a href=#431 id=431 data-nosnippet>431</a> promql_end = slow_query_event.promql_end,
<a href=#432 id=432 data-nosnippet>432</a> payload = slow_query_event.payload.to_string(),
<a href=#433 id=433 data-nosnippet>433</a> );
<a href=#434 id=434 data-nosnippet>434</a> }
<a href=#435 id=435 data-nosnippet>435</a> }
<a href=#436 id=436 data-nosnippet>436</a> }
<a href=#437 id=437 data-nosnippet>437</a>}
<a href=#438 id=438 data-nosnippet>438</a>
<a href=#439 id=439 data-nosnippet>439</a><span class="kw">impl </span>Drop <span class="kw">for </span>SlowQueryTimer {
<a href=#440 id=440 data-nosnippet>440</a> <span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#441 id=441 data-nosnippet>441</a> <span class="kw">let </span>elapsed = <span class="self">self</span>.start.elapsed();
<a href=#442 id=442 data-nosnippet>442</a> <span class="kw">let </span>(force_record, payload) = {
<a href=#443 id=443 data-nosnippet>443</a> <span class="kw">let </span>state = <span class="self">self</span>.record_state.read().unwrap();
<a href=#444 id=444 data-nosnippet>444</a> (state.force_record, state.payload.clone())
<a href=#445 id=445 data-nosnippet>445</a> };
<a href=#446 id=446 data-nosnippet>446</a>
<a href=#447 id=447 data-nosnippet>447</a> <span class="kw">if </span>force_record
<a href=#448 id=448 data-nosnippet>448</a> || (elapsed &gt; <span class="self">self</span>.threshold
<a href=#449 id=449 data-nosnippet>449</a> &amp;&amp; (<span class="self">self</span>.sample_ratio &gt;= <span class="number">1.0 </span>|| random::&lt;f64&gt;() &lt;= <span class="self">self</span>.sample_ratio))
<a href=#450 id=450 data-nosnippet>450</a> {
<a href=#451 id=451 data-nosnippet>451</a> <span class="self">self</span>.send_slow_query_event(elapsed, payload);
<a href=#452 id=452 data-nosnippet>452</a> }
<a href=#453 id=453 data-nosnippet>453</a> }
<a href=#454 id=454 data-nosnippet>454</a>}
<a href=#455 id=455 data-nosnippet>455</a>
<a href=#456 id=456 data-nosnippet>456</a><span class="attr">#[cfg(test)]
<a href=#457 id=457 data-nosnippet>457</a></span><span class="kw">mod </span>tests {
<a href=#458 id=458 data-nosnippet>458</a> <span class="kw">use </span>std::sync::{Arc, Mutex};
<a href=#459 id=459 data-nosnippet>459</a> <span class="kw">use </span>std::time::Duration;
<a href=#460 id=460 data-nosnippet>460</a>
<a href=#461 id=461 data-nosnippet>461</a> <span class="kw">use </span>common_event_recorder::{Event, EventRecorder, EventTypeFilter, EventTypeFilterRef};
<a href=#462 id=462 data-nosnippet>462</a> <span class="kw">use </span>common_frontend::slow_query_event::SlowQueryEvent;
<a href=#463 id=463 data-nosnippet>463</a> <span class="kw">use </span>common_telemetry::logging::SlowQueriesRecordType;
<a href=#464 id=464 data-nosnippet>464</a> <span class="kw">use </span>serde_json::Value;
<a href=#465 id=465 data-nosnippet>465</a>
<a href=#466 id=466 data-nosnippet>466</a> <span class="kw">use </span><span class="kw">crate</span>::process_manager::{ProcessManager, QueryStatement, SlowQueryTimer};
<a href=#467 id=467 data-nosnippet>467</a>
<a href=#468 id=468 data-nosnippet>468</a> <span class="attr">#[derive(Debug, Default)]
<a href=#469 id=469 data-nosnippet>469</a> </span><span class="kw">struct </span>RecordingEventRecorder {
<a href=#470 id=470 data-nosnippet>470</a> events: Mutex&lt;Vec&lt;(String, Value)&gt;&gt;,
<a href=#471 id=471 data-nosnippet>471</a> }
<a href=#472 id=472 data-nosnippet>472</a>
<a href=#473 id=473 data-nosnippet>473</a> <span class="kw">impl </span>EventRecorder <span class="kw">for </span>RecordingEventRecorder {
<a href=#474 id=474 data-nosnippet>474</a> <span class="kw">fn </span>record(<span class="kw-2">&amp;</span><span class="self">self</span>, event: Box&lt;<span class="kw">dyn </span>Event&gt;) {
<a href=#475 id=475 data-nosnippet>475</a> <span class="kw">let </span>event = event
<a href=#476 id=476 data-nosnippet>476</a> .as_any()
<a href=#477 id=477 data-nosnippet>477</a> .downcast_ref::&lt;SlowQueryEvent&gt;()
<a href=#478 id=478 data-nosnippet>478</a> .expect(<span class="string">"expected a slow query event"</span>);
<a href=#479 id=479 data-nosnippet>479</a> <span class="self">self</span>.events
<a href=#480 id=480 data-nosnippet>480</a> .lock()
<a href=#481 id=481 data-nosnippet>481</a> .unwrap()
<a href=#482 id=482 data-nosnippet>482</a> .push((event.query.clone(), event.payload.clone()));
<a href=#483 id=483 data-nosnippet>483</a> }
<a href=#484 id=484 data-nosnippet>484</a>
<a href=#485 id=485 data-nosnippet>485</a> <span class="kw">fn </span>event_type_filter(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; EventTypeFilterRef {
<a href=#486 id=486 data-nosnippet>486</a> Arc::new(EventTypeFilter::All)
<a href=#487 id=487 data-nosnippet>487</a> }
<a href=#488 id=488 data-nosnippet>488</a>
<a href=#489 id=489 data-nosnippet>489</a> <span class="kw">fn </span>close(<span class="kw-2">&amp;</span><span class="self">self</span>) {}
<a href=#490 id=490 data-nosnippet>490</a> }
<a href=#491 id=491 data-nosnippet>491</a>
<a href=#492 id=492 data-nosnippet>492</a> <span class="attr">#[test]
<a href=#493 id=493 data-nosnippet>493</a> </span><span class="kw">fn </span>test_forced_slow_query_bypasses_threshold_and_sampling() {
<a href=#494 id=494 data-nosnippet>494</a> <span class="kw">let </span>event_recorder = Arc::new(RecordingEventRecorder::default());
<a href=#495 id=495 data-nosnippet>495</a> <span class="kw">let </span>timer = SlowQueryTimer::new(
<a href=#496 id=496 data-nosnippet>496</a> QueryStatement::Plan(<span class="string">"EXPLAIN ANALYZE VERBOSE SELECT 1"</span>.to_string()),
<a href=#497 id=497 data-nosnippet>497</a> <span class="string">"public"</span>.to_string(),
<a href=#498 id=498 data-nosnippet>498</a> Duration::from_secs(<span class="number">3600</span>),
<a href=#499 id=499 data-nosnippet>499</a> <span class="number">0.0</span>,
<a href=#500 id=500 data-nosnippet>500</a> SlowQueriesRecordType::SystemTable,
<a href=#501 id=501 data-nosnippet>501</a> event_recorder.clone(),
<a href=#502 id=502 data-nosnippet>502</a> );
<a href=#503 id=503 data-nosnippet>503</a> <span class="kw">let </span>payload = <span class="macro">serde_json::json!</span>({
<a href=#504 id=504 data-nosnippet>504</a> <span class="string">"timed_out"</span>: <span class="bool-val">true</span>,
<a href=#505 id=505 data-nosnippet>505</a> <span class="string">"metrics"</span>: [{<span class="string">"stage"</span>: <span class="number">0</span>}],
<a href=#506 id=506 data-nosnippet>506</a> });
<a href=#507 id=507 data-nosnippet>507</a> timer.recorder().force_record_with_payload(payload.clone());
<a href=#508 id=508 data-nosnippet>508</a>
<a href=#509 id=509 data-nosnippet>509</a> drop(timer);
<a href=#510 id=510 data-nosnippet>510</a>
<a href=#511 id=511 data-nosnippet>511</a> <span class="kw">let </span>events = event_recorder.events.lock().unwrap();
<a href=#512 id=512 data-nosnippet>512</a> <span class="macro">assert_eq!</span>(events.len(), <span class="number">1</span>);
<a href=#513 id=513 data-nosnippet>513</a> <span class="macro">assert_eq!</span>(events[<span class="number">0</span>].<span class="number">0</span>, <span class="string">"EXPLAIN ANALYZE VERBOSE SELECT 1"</span>);
<a href=#514 id=514 data-nosnippet>514</a> <span class="macro">assert_eq!</span>(events[<span class="number">0</span>].<span class="number">1</span>, payload);
<a href=#515 id=515 data-nosnippet>515</a> }
<a href=#516 id=516 data-nosnippet>516</a>
<a href=#517 id=517 data-nosnippet>517</a> <span class="attr">#[test]
<a href=#518 id=518 data-nosnippet>518</a> </span><span class="kw">fn </span>test_unforced_fast_query_is_not_recorded() {
<a href=#519 id=519 data-nosnippet>519</a> <span class="kw">let </span>event_recorder = Arc::new(RecordingEventRecorder::default());
<a href=#520 id=520 data-nosnippet>520</a> <span class="kw">let </span>timer = SlowQueryTimer::new(
<a href=#521 id=521 data-nosnippet>521</a> QueryStatement::Plan(<span class="string">"SELECT 1"</span>.to_string()),
<a href=#522 id=522 data-nosnippet>522</a> <span class="string">"public"</span>.to_string(),
<a href=#523 id=523 data-nosnippet>523</a> Duration::from_secs(<span class="number">3600</span>),
<a href=#524 id=524 data-nosnippet>524</a> <span class="number">0.0</span>,
<a href=#525 id=525 data-nosnippet>525</a> SlowQueriesRecordType::SystemTable,
<a href=#526 id=526 data-nosnippet>526</a> event_recorder.clone(),
<a href=#527 id=527 data-nosnippet>527</a> );
<a href=#528 id=528 data-nosnippet>528</a>
<a href=#529 id=529 data-nosnippet>529</a> drop(timer);
<a href=#530 id=530 data-nosnippet>530</a>
<a href=#531 id=531 data-nosnippet>531</a> <span class="macro">assert!</span>(event_recorder.events.lock().unwrap().is_empty());
<a href=#532 id=532 data-nosnippet>532</a> }
<a href=#533 id=533 data-nosnippet>533</a>
<a href=#534 id=534 data-nosnippet>534</a> <span class="attr">#[tokio::test]
<a href=#535 id=535 data-nosnippet>535</a> </span><span class="kw">async fn </span>test_register_query() {
<a href=#536 id=536 data-nosnippet>536</a> <span class="kw">let </span>process_manager = Arc::new(ProcessManager::new(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#537 id=537 data-nosnippet>537</a> <span class="kw">let </span>ticket = process_manager.clone().register_query(
<a href=#538 id=538 data-nosnippet>538</a> <span class="string">"public"</span>.to_string(),
<a href=#539 id=539 data-nosnippet>539</a> <span class="macro">vec!</span>[<span class="string">"test"</span>.to_string()],
<a href=#540 id=540 data-nosnippet>540</a> <span class="string">"SELECT * FROM table"</span>.to_string(),
<a href=#541 id=541 data-nosnippet>541</a> <span class="string">""</span>.to_string(),
<a href=#542 id=542 data-nosnippet>542</a> <span class="prelude-val">None</span>,
<a href=#543 id=543 data-nosnippet>543</a> <span class="prelude-val">None</span>,
<a href=#544 id=544 data-nosnippet>544</a> );
<a href=#545 id=545 data-nosnippet>545</a>
<a href=#546 id=546 data-nosnippet>546</a> <span class="kw">let </span>running_processes = process_manager.local_processes(<span class="prelude-val">None</span>).unwrap();
<a href=#547 id=547 data-nosnippet>547</a> <span class="macro">assert_eq!</span>(running_processes.len(), <span class="number">1</span>);
<a href=#548 id=548 data-nosnippet>548</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>running_processes[<span class="number">0</span>].frontend, <span class="string">"127.0.0.1:8000"</span>);
<a href=#549 id=549 data-nosnippet>549</a> <span class="macro">assert_eq!</span>(running_processes[<span class="number">0</span>].id, ticket.id);
<a href=#550 id=550 data-nosnippet>550</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>running_processes[<span class="number">0</span>].query, <span class="string">"SELECT * FROM table"</span>);
<a href=#551 id=551 data-nosnippet>551</a>
<a href=#552 id=552 data-nosnippet>552</a> drop(ticket);
<a href=#553 id=553 data-nosnippet>553</a> <span class="macro">assert_eq!</span>(process_manager.local_processes(<span class="prelude-val">None</span>).unwrap().len(), <span class="number">0</span>);
<a href=#554 id=554 data-nosnippet>554</a> }
<a href=#555 id=555 data-nosnippet>555</a>
<a href=#556 id=556 data-nosnippet>556</a> <span class="attr">#[tokio::test]
<a href=#557 id=557 data-nosnippet>557</a> </span><span class="kw">async fn </span>test_register_query_with_custom_id() {
<a href=#558 id=558 data-nosnippet>558</a> <span class="kw">let </span>process_manager = Arc::new(ProcessManager::new(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#559 id=559 data-nosnippet>559</a> <span class="kw">let </span>custom_id = <span class="number">12345</span>;
<a href=#560 id=560 data-nosnippet>560</a>
<a href=#561 id=561 data-nosnippet>561</a> <span class="kw">let </span>ticket = process_manager.clone().register_query(
<a href=#562 id=562 data-nosnippet>562</a> <span class="string">"public"</span>.to_string(),
<a href=#563 id=563 data-nosnippet>563</a> <span class="macro">vec!</span>[<span class="string">"test"</span>.to_string()],
<a href=#564 id=564 data-nosnippet>564</a> <span class="string">"SELECT * FROM table"</span>.to_string(),
<a href=#565 id=565 data-nosnippet>565</a> <span class="string">"client1"</span>.to_string(),
<a href=#566 id=566 data-nosnippet>566</a> <span class="prelude-val">Some</span>(custom_id),
<a href=#567 id=567 data-nosnippet>567</a> <span class="prelude-val">None</span>,
<a href=#568 id=568 data-nosnippet>568</a> );
<a href=#569 id=569 data-nosnippet>569</a>
<a href=#570 id=570 data-nosnippet>570</a> <span class="macro">assert_eq!</span>(ticket.id, custom_id);
<a href=#571 id=571 data-nosnippet>571</a>
<a href=#572 id=572 data-nosnippet>572</a> <span class="kw">let </span>running_processes = process_manager.local_processes(<span class="prelude-val">None</span>).unwrap();
<a href=#573 id=573 data-nosnippet>573</a> <span class="macro">assert_eq!</span>(running_processes.len(), <span class="number">1</span>);
<a href=#574 id=574 data-nosnippet>574</a> <span class="macro">assert_eq!</span>(running_processes[<span class="number">0</span>].id, custom_id);
<a href=#575 id=575 data-nosnippet>575</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>running_processes[<span class="number">0</span>].client, <span class="string">"client1"</span>);
<a href=#576 id=576 data-nosnippet>576</a> }
<a href=#577 id=577 data-nosnippet>577</a>
<a href=#578 id=578 data-nosnippet>578</a> <span class="attr">#[tokio::test]
<a href=#579 id=579 data-nosnippet>579</a> </span><span class="kw">async fn </span>test_multiple_queries_same_catalog() {
<a href=#580 id=580 data-nosnippet>580</a> <span class="kw">let </span>process_manager = Arc::new(ProcessManager::new(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#581 id=581 data-nosnippet>581</a>
<a href=#582 id=582 data-nosnippet>582</a> <span class="kw">let </span>ticket1 = process_manager.clone().register_query(
<a href=#583 id=583 data-nosnippet>583</a> <span class="string">"public"</span>.to_string(),
<a href=#584 id=584 data-nosnippet>584</a> <span class="macro">vec!</span>[<span class="string">"schema1"</span>.to_string()],
<a href=#585 id=585 data-nosnippet>585</a> <span class="string">"SELECT * FROM table1"</span>.to_string(),
<a href=#586 id=586 data-nosnippet>586</a> <span class="string">"client1"</span>.to_string(),
<a href=#587 id=587 data-nosnippet>587</a> <span class="prelude-val">None</span>,
<a href=#588 id=588 data-nosnippet>588</a> <span class="prelude-val">None</span>,
<a href=#589 id=589 data-nosnippet>589</a> );
<a href=#590 id=590 data-nosnippet>590</a>
<a href=#591 id=591 data-nosnippet>591</a> <span class="kw">let </span>ticket2 = process_manager.clone().register_query(
<a href=#592 id=592 data-nosnippet>592</a> <span class="string">"public"</span>.to_string(),
<a href=#593 id=593 data-nosnippet>593</a> <span class="macro">vec!</span>[<span class="string">"schema2"</span>.to_string()],
<a href=#594 id=594 data-nosnippet>594</a> <span class="string">"SELECT * FROM table2"</span>.to_string(),
<a href=#595 id=595 data-nosnippet>595</a> <span class="string">"client2"</span>.to_string(),
<a href=#596 id=596 data-nosnippet>596</a> <span class="prelude-val">None</span>,
<a href=#597 id=597 data-nosnippet>597</a> <span class="prelude-val">None</span>,
<a href=#598 id=598 data-nosnippet>598</a> );
<a href=#599 id=599 data-nosnippet>599</a>
<a href=#600 id=600 data-nosnippet>600</a> <span class="kw">let </span>running_processes = process_manager.local_processes(<span class="prelude-val">Some</span>(<span class="string">"public"</span>)).unwrap();
<a href=#601 id=601 data-nosnippet>601</a> <span class="macro">assert_eq!</span>(running_processes.len(), <span class="number">2</span>);
<a href=#602 id=602 data-nosnippet>602</a>
<a href=#603 id=603 data-nosnippet>603</a> <span class="comment">// Verify both processes are present
<a href=#604 id=604 data-nosnippet>604</a> </span><span class="kw">let </span>ids: Vec&lt;u32&gt; = running_processes.iter().map(|p| p.id).collect();
<a href=#605 id=605 data-nosnippet>605</a> <span class="macro">assert!</span>(ids.contains(<span class="kw-2">&amp;</span>ticket1.id));
<a href=#606 id=606 data-nosnippet>606</a> <span class="macro">assert!</span>(ids.contains(<span class="kw-2">&amp;</span>ticket2.id));
<a href=#607 id=607 data-nosnippet>607</a> }
<a href=#608 id=608 data-nosnippet>608</a>
<a href=#609 id=609 data-nosnippet>609</a> <span class="attr">#[tokio::test]
<a href=#610 id=610 data-nosnippet>610</a> </span><span class="kw">async fn </span>test_multiple_catalogs() {
<a href=#611 id=611 data-nosnippet>611</a> <span class="kw">let </span>process_manager = Arc::new(ProcessManager::new(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#612 id=612 data-nosnippet>612</a>
<a href=#613 id=613 data-nosnippet>613</a> <span class="kw">let </span>_ticket1 = process_manager.clone().register_query(
<a href=#614 id=614 data-nosnippet>614</a> <span class="string">"catalog1"</span>.to_string(),
<a href=#615 id=615 data-nosnippet>615</a> <span class="macro">vec!</span>[<span class="string">"schema1"</span>.to_string()],
<a href=#616 id=616 data-nosnippet>616</a> <span class="string">"SELECT * FROM table1"</span>.to_string(),
<a href=#617 id=617 data-nosnippet>617</a> <span class="string">"client1"</span>.to_string(),
<a href=#618 id=618 data-nosnippet>618</a> <span class="prelude-val">None</span>,
<a href=#619 id=619 data-nosnippet>619</a> <span class="prelude-val">None</span>,
<a href=#620 id=620 data-nosnippet>620</a> );
<a href=#621 id=621 data-nosnippet>621</a>
<a href=#622 id=622 data-nosnippet>622</a> <span class="kw">let </span>_ticket2 = process_manager.clone().register_query(
<a href=#623 id=623 data-nosnippet>623</a> <span class="string">"catalog2"</span>.to_string(),
<a href=#624 id=624 data-nosnippet>624</a> <span class="macro">vec!</span>[<span class="string">"schema2"</span>.to_string()],
<a href=#625 id=625 data-nosnippet>625</a> <span class="string">"SELECT * FROM table2"</span>.to_string(),
<a href=#626 id=626 data-nosnippet>626</a> <span class="string">"client2"</span>.to_string(),
<a href=#627 id=627 data-nosnippet>627</a> <span class="prelude-val">None</span>,
<a href=#628 id=628 data-nosnippet>628</a> <span class="prelude-val">None</span>,
<a href=#629 id=629 data-nosnippet>629</a> );
<a href=#630 id=630 data-nosnippet>630</a>
<a href=#631 id=631 data-nosnippet>631</a> <span class="comment">// Test listing processes for specific catalog
<a href=#632 id=632 data-nosnippet>632</a> </span><span class="kw">let </span>catalog1_processes = process_manager.local_processes(<span class="prelude-val">Some</span>(<span class="string">"catalog1"</span>)).unwrap();
<a href=#633 id=633 data-nosnippet>633</a> <span class="macro">assert_eq!</span>(catalog1_processes.len(), <span class="number">1</span>);
<a href=#634 id=634 data-nosnippet>634</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>catalog1_processes[<span class="number">0</span>].catalog, <span class="string">"catalog1"</span>);
<a href=#635 id=635 data-nosnippet>635</a>
<a href=#636 id=636 data-nosnippet>636</a> <span class="kw">let </span>catalog2_processes = process_manager.local_processes(<span class="prelude-val">Some</span>(<span class="string">"catalog2"</span>)).unwrap();
<a href=#637 id=637 data-nosnippet>637</a> <span class="macro">assert_eq!</span>(catalog2_processes.len(), <span class="number">1</span>);
<a href=#638 id=638 data-nosnippet>638</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>catalog2_processes[<span class="number">0</span>].catalog, <span class="string">"catalog2"</span>);
<a href=#639 id=639 data-nosnippet>639</a>
<a href=#640 id=640 data-nosnippet>640</a> <span class="comment">// Test listing all processes
<a href=#641 id=641 data-nosnippet>641</a> </span><span class="kw">let </span>all_processes = process_manager.local_processes(<span class="prelude-val">None</span>).unwrap();
<a href=#642 id=642 data-nosnippet>642</a> <span class="macro">assert_eq!</span>(all_processes.len(), <span class="number">2</span>);
<a href=#643 id=643 data-nosnippet>643</a> }
<a href=#644 id=644 data-nosnippet>644</a>
<a href=#645 id=645 data-nosnippet>645</a> <span class="attr">#[tokio::test]
<a href=#646 id=646 data-nosnippet>646</a> </span><span class="kw">async fn </span>test_deregister_query() {
<a href=#647 id=647 data-nosnippet>647</a> <span class="kw">let </span>process_manager = Arc::new(ProcessManager::new(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#648 id=648 data-nosnippet>648</a>
<a href=#649 id=649 data-nosnippet>649</a> <span class="kw">let </span>ticket = process_manager.clone().register_query(
<a href=#650 id=650 data-nosnippet>650</a> <span class="string">"public"</span>.to_string(),
<a href=#651 id=651 data-nosnippet>651</a> <span class="macro">vec!</span>[<span class="string">"test"</span>.to_string()],
<a href=#652 id=652 data-nosnippet>652</a> <span class="string">"SELECT * FROM table"</span>.to_string(),
<a href=#653 id=653 data-nosnippet>653</a> <span class="string">"client1"</span>.to_string(),
<a href=#654 id=654 data-nosnippet>654</a> <span class="prelude-val">None</span>,
<a href=#655 id=655 data-nosnippet>655</a> <span class="prelude-val">None</span>,
<a href=#656 id=656 data-nosnippet>656</a> );
<a href=#657 id=657 data-nosnippet>657</a> <span class="macro">assert_eq!</span>(process_manager.local_processes(<span class="prelude-val">None</span>).unwrap().len(), <span class="number">1</span>);
<a href=#658 id=658 data-nosnippet>658</a> process_manager.deregister_query(<span class="string">"public"</span>.to_string(), ticket.id);
<a href=#659 id=659 data-nosnippet>659</a> <span class="macro">assert_eq!</span>(process_manager.local_processes(<span class="prelude-val">None</span>).unwrap().len(), <span class="number">0</span>);
<a href=#660 id=660 data-nosnippet>660</a> }
<a href=#661 id=661 data-nosnippet>661</a>
<a href=#662 id=662 data-nosnippet>662</a> <span class="attr">#[tokio::test]
<a href=#663 id=663 data-nosnippet>663</a> </span><span class="kw">async fn </span>test_cancellation_handle() {
<a href=#664 id=664 data-nosnippet>664</a> <span class="kw">let </span>process_manager = Arc::new(ProcessManager::new(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#665 id=665 data-nosnippet>665</a>
<a href=#666 id=666 data-nosnippet>666</a> <span class="kw">let </span>ticket = process_manager.clone().register_query(
<a href=#667 id=667 data-nosnippet>667</a> <span class="string">"public"</span>.to_string(),
<a href=#668 id=668 data-nosnippet>668</a> <span class="macro">vec!</span>[<span class="string">"test"</span>.to_string()],
<a href=#669 id=669 data-nosnippet>669</a> <span class="string">"SELECT * FROM table"</span>.to_string(),
<a href=#670 id=670 data-nosnippet>670</a> <span class="string">"client1"</span>.to_string(),
<a href=#671 id=671 data-nosnippet>671</a> <span class="prelude-val">None</span>,
<a href=#672 id=672 data-nosnippet>672</a> <span class="prelude-val">None</span>,
<a href=#673 id=673 data-nosnippet>673</a> );
<a href=#674 id=674 data-nosnippet>674</a>
<a href=#675 id=675 data-nosnippet>675</a> <span class="macro">assert!</span>(!ticket.cancellation_handle.is_cancelled());
<a href=#676 id=676 data-nosnippet>676</a> ticket.cancellation_handle.cancel();
<a href=#677 id=677 data-nosnippet>677</a> <span class="macro">assert!</span>(ticket.cancellation_handle.is_cancelled());
<a href=#678 id=678 data-nosnippet>678</a> }
<a href=#679 id=679 data-nosnippet>679</a>
<a href=#680 id=680 data-nosnippet>680</a> <span class="attr">#[tokio::test]
<a href=#681 id=681 data-nosnippet>681</a> </span><span class="kw">async fn </span>test_kill_local_process() {
<a href=#682 id=682 data-nosnippet>682</a> <span class="kw">let </span>process_manager = Arc::new(ProcessManager::new(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#683 id=683 data-nosnippet>683</a>
<a href=#684 id=684 data-nosnippet>684</a> <span class="kw">let </span>ticket = process_manager.clone().register_query(
<a href=#685 id=685 data-nosnippet>685</a> <span class="string">"public"</span>.to_string(),
<a href=#686 id=686 data-nosnippet>686</a> <span class="macro">vec!</span>[<span class="string">"test"</span>.to_string()],
<a href=#687 id=687 data-nosnippet>687</a> <span class="string">"SELECT * FROM table"</span>.to_string(),
<a href=#688 id=688 data-nosnippet>688</a> <span class="string">"client1"</span>.to_string(),
<a href=#689 id=689 data-nosnippet>689</a> <span class="prelude-val">None</span>,
<a href=#690 id=690 data-nosnippet>690</a> <span class="prelude-val">None</span>,
<a href=#691 id=691 data-nosnippet>691</a> );
<a href=#692 id=692 data-nosnippet>692</a> <span class="macro">assert!</span>(!ticket.cancellation_handle.is_cancelled());
<a href=#693 id=693 data-nosnippet>693</a> <span class="kw">let </span>killed = process_manager
<a href=#694 id=694 data-nosnippet>694</a> .kill_process(
<a href=#695 id=695 data-nosnippet>695</a> <span class="string">"127.0.0.1:8000"</span>.to_string(),
<a href=#696 id=696 data-nosnippet>696</a> <span class="string">"public"</span>.to_string(),
<a href=#697 id=697 data-nosnippet>697</a> ticket.id,
<a href=#698 id=698 data-nosnippet>698</a> )
<a href=#699 id=699 data-nosnippet>699</a> .<span class="kw">await
<a href=#700 id=700 data-nosnippet>700</a> </span>.unwrap();
<a href=#701 id=701 data-nosnippet>701</a>
<a href=#702 id=702 data-nosnippet>702</a> <span class="macro">assert!</span>(killed);
<a href=#703 id=703 data-nosnippet>703</a> <span class="macro">assert_eq!</span>(process_manager.local_processes(<span class="prelude-val">None</span>).unwrap().len(), <span class="number">0</span>);
<a href=#704 id=704 data-nosnippet>704</a> }
<a href=#705 id=705 data-nosnippet>705</a>
<a href=#706 id=706 data-nosnippet>706</a> <span class="attr">#[tokio::test]
<a href=#707 id=707 data-nosnippet>707</a> </span><span class="kw">async fn </span>test_kill_nonexistent_process() {
<a href=#708 id=708 data-nosnippet>708</a> <span class="kw">let </span>process_manager = Arc::new(ProcessManager::new(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#709 id=709 data-nosnippet>709</a> <span class="kw">let </span>killed = process_manager
<a href=#710 id=710 data-nosnippet>710</a> .kill_process(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="string">"public"</span>.to_string(), <span class="number">999</span>)
<a href=#711 id=711 data-nosnippet>711</a> .<span class="kw">await
<a href=#712 id=712 data-nosnippet>712</a> </span>.unwrap();
<a href=#713 id=713 data-nosnippet>713</a> <span class="macro">assert!</span>(!killed);
<a href=#714 id=714 data-nosnippet>714</a> }
<a href=#715 id=715 data-nosnippet>715</a>
<a href=#716 id=716 data-nosnippet>716</a> <span class="attr">#[tokio::test]
<a href=#717 id=717 data-nosnippet>717</a> </span><span class="kw">async fn </span>test_kill_process_nonexistent_catalog() {
<a href=#718 id=718 data-nosnippet>718</a> <span class="kw">let </span>process_manager = Arc::new(ProcessManager::new(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#719 id=719 data-nosnippet>719</a> <span class="kw">let </span>killed = process_manager
<a href=#720 id=720 data-nosnippet>720</a> .kill_process(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="string">"nonexistent"</span>.to_string(), <span class="number">1</span>)
<a href=#721 id=721 data-nosnippet>721</a> .<span class="kw">await
<a href=#722 id=722 data-nosnippet>722</a> </span>.unwrap();
<a href=#723 id=723 data-nosnippet>723</a> <span class="macro">assert!</span>(!killed);
<a href=#724 id=724 data-nosnippet>724</a> }
<a href=#725 id=725 data-nosnippet>725</a>
<a href=#726 id=726 data-nosnippet>726</a> <span class="attr">#[tokio::test]
<a href=#727 id=727 data-nosnippet>727</a> </span><span class="kw">async fn </span>test_process_info_fields() {
<a href=#728 id=728 data-nosnippet>728</a> <span class="kw">let </span>process_manager = Arc::new(ProcessManager::new(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#729 id=729 data-nosnippet>729</a>
<a href=#730 id=730 data-nosnippet>730</a> <span class="kw">let </span>_ticket = process_manager.clone().register_query(
<a href=#731 id=731 data-nosnippet>731</a> <span class="string">"test_catalog"</span>.to_string(),
<a href=#732 id=732 data-nosnippet>732</a> <span class="macro">vec!</span>[<span class="string">"schema1"</span>.to_string(), <span class="string">"schema2"</span>.to_string()],
<a href=#733 id=733 data-nosnippet>733</a> <span class="string">"SELECT COUNT(*) FROM users WHERE age &gt; 18"</span>.to_string(),
<a href=#734 id=734 data-nosnippet>734</a> <span class="string">"test_client"</span>.to_string(),
<a href=#735 id=735 data-nosnippet>735</a> <span class="prelude-val">Some</span>(<span class="number">42</span>),
<a href=#736 id=736 data-nosnippet>736</a> <span class="prelude-val">None</span>,
<a href=#737 id=737 data-nosnippet>737</a> );
<a href=#738 id=738 data-nosnippet>738</a>
<a href=#739 id=739 data-nosnippet>739</a> <span class="kw">let </span>processes = process_manager.local_processes(<span class="prelude-val">None</span>).unwrap();
<a href=#740 id=740 data-nosnippet>740</a> <span class="macro">assert_eq!</span>(processes.len(), <span class="number">1</span>);
<a href=#741 id=741 data-nosnippet>741</a>
<a href=#742 id=742 data-nosnippet>742</a> <span class="kw">let </span>process = <span class="kw-2">&amp;</span>processes[<span class="number">0</span>];
<a href=#743 id=743 data-nosnippet>743</a> <span class="macro">assert_eq!</span>(process.id, <span class="number">42</span>);
<a href=#744 id=744 data-nosnippet>744</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>process.catalog, <span class="string">"test_catalog"</span>);
<a href=#745 id=745 data-nosnippet>745</a> <span class="macro">assert_eq!</span>(process.schemas, <span class="macro">vec!</span>[<span class="string">"schema1"</span>, <span class="string">"schema2"</span>]);
<a href=#746 id=746 data-nosnippet>746</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>process.query, <span class="string">"SELECT COUNT(*) FROM users WHERE age &gt; 18"</span>);
<a href=#747 id=747 data-nosnippet>747</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>process.client, <span class="string">"test_client"</span>);
<a href=#748 id=748 data-nosnippet>748</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>process.frontend, <span class="string">"127.0.0.1:8000"</span>);
<a href=#749 id=749 data-nosnippet>749</a> <span class="macro">assert!</span>(process.start_timestamp &gt; <span class="number">0</span>);
<a href=#750 id=750 data-nosnippet>750</a> }
<a href=#751 id=751 data-nosnippet>751</a>
<a href=#752 id=752 data-nosnippet>752</a> <span class="attr">#[tokio::test]
<a href=#753 id=753 data-nosnippet>753</a> </span><span class="kw">async fn </span>test_ticket_drop_deregisters_process() {
<a href=#754 id=754 data-nosnippet>754</a> <span class="kw">let </span>process_manager = Arc::new(ProcessManager::new(<span class="string">"127.0.0.1:8000"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#755 id=755 data-nosnippet>755</a>
<a href=#756 id=756 data-nosnippet>756</a> {
<a href=#757 id=757 data-nosnippet>757</a> <span class="kw">let </span>_ticket = process_manager.clone().register_query(
<a href=#758 id=758 data-nosnippet>758</a> <span class="string">"public"</span>.to_string(),
<a href=#759 id=759 data-nosnippet>759</a> <span class="macro">vec!</span>[<span class="string">"test"</span>.to_string()],
<a href=#760 id=760 data-nosnippet>760</a> <span class="string">"SELECT * FROM table"</span>.to_string(),
<a href=#761 id=761 data-nosnippet>761</a> <span class="string">"client1"</span>.to_string(),
<a href=#762 id=762 data-nosnippet>762</a> <span class="prelude-val">None</span>,
<a href=#763 id=763 data-nosnippet>763</a> <span class="prelude-val">None</span>,
<a href=#764 id=764 data-nosnippet>764</a> );
<a href=#765 id=765 data-nosnippet>765</a>
<a href=#766 id=766 data-nosnippet>766</a> <span class="comment">// Process should be registered
<a href=#767 id=767 data-nosnippet>767</a> </span><span class="macro">assert_eq!</span>(process_manager.local_processes(<span class="prelude-val">None</span>).unwrap().len(), <span class="number">1</span>);
<a href=#768 id=768 data-nosnippet>768</a> } <span class="comment">// ticket goes out of scope here
<a href=#769 id=769 data-nosnippet>769</a>
<a href=#770 id=770 data-nosnippet>770</a> // Process should be automatically deregistered
<a href=#771 id=771 data-nosnippet>771</a> </span><span class="macro">assert_eq!</span>(process_manager.local_processes(<span class="prelude-val">None</span>).unwrap().len(), <span class="number">0</span>);
<a href=#772 id=772 data-nosnippet>772</a> }
<a href=#773 id=773 data-nosnippet>773</a>}
</code></pre></div></section></main></body></html>
+190
View File
@@ -0,0 +1,190 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema.rs`."><title>system_schema.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/</div>system_schema.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">pub mod </span>information_schema;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">mod </span>memory_table;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">pub mod </span>numbers_table_provider;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">pub mod </span>pg_catalog;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">pub mod </span>predicate;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">pub mod </span>semantic_graph;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">mod </span>utils;
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>std::collections::HashMap;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>std::sync::Arc;
<a href=#25 id=25 data-nosnippet>25</a>
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>common_recordbatch::{RecordBatchStreamWrapper, SendableRecordBatchStream};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>common_telemetry::tracing::Span;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datafusion::physical_plan::ExecutionPlan;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datatypes::schema::SchemaRef;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>futures_util::StreamExt;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>snafu::ResultExt;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>store_api::data_source::DataSource;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span>store_api::storage::ScanRequest;
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span>table::error::{SchemaConversionSnafu, TablesRecordBatchSnafu};
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>table::metadata::{
<a href=#37 id=37 data-nosnippet>37</a> FilterPushDownType, TableId, TableInfoBuilder, TableInfoRef, TableMetaBuilder, TableType,
<a href=#38 id=38 data-nosnippet>38</a>};
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span>table::{Table, TableRef};
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span><span class="kw">crate</span>::error::Result;
<a href=#42 id=42 data-nosnippet>42</a>
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">pub trait </span>SystemSchemaProvider {
<a href=#44 id=44 data-nosnippet>44</a> <span class="doccomment">/// Returns a map of [TableRef] in information schema.
<a href=#45 id=45 data-nosnippet>45</a> </span><span class="kw">fn </span>tables(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>HashMap&lt;String, TableRef&gt;;
<a href=#46 id=46 data-nosnippet>46</a>
<a href=#47 id=47 data-nosnippet>47</a> <span class="doccomment">/// Returns the [TableRef] by table name.
<a href=#48 id=48 data-nosnippet>48</a> </span><span class="kw">fn </span>table(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;TableRef&gt; {
<a href=#49 id=49 data-nosnippet>49</a> <span class="self">self</span>.tables().get(name).cloned()
<a href=#50 id=50 data-nosnippet>50</a> }
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a> <span class="doccomment">/// Returns table names in the order of table id.
<a href=#53 id=53 data-nosnippet>53</a> </span><span class="kw">fn </span>table_names(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Vec&lt;String&gt; {
<a href=#54 id=54 data-nosnippet>54</a> <span class="kw">let </span><span class="kw-2">mut </span>tables = <span class="self">self</span>.tables().values().clone().collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;();
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a> tables.sort_by(|t1, t2| {
<a href=#57 id=57 data-nosnippet>57</a> t1.table_info()
<a href=#58 id=58 data-nosnippet>58</a> .table_id()
<a href=#59 id=59 data-nosnippet>59</a> .partial_cmp(<span class="kw-2">&amp;</span>t2.table_info().table_id())
<a href=#60 id=60 data-nosnippet>60</a> .unwrap()
<a href=#61 id=61 data-nosnippet>61</a> });
<a href=#62 id=62 data-nosnippet>62</a> tables
<a href=#63 id=63 data-nosnippet>63</a> .into_iter()
<a href=#64 id=64 data-nosnippet>64</a> .map(|t| t.table_info().name.clone())
<a href=#65 id=65 data-nosnippet>65</a> .collect()
<a href=#66 id=66 data-nosnippet>66</a> }
<a href=#67 id=67 data-nosnippet>67</a>}
<a href=#68 id=68 data-nosnippet>68</a>
<a href=#69 id=69 data-nosnippet>69</a><span class="kw">trait </span>SystemSchemaProviderInner {
<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">fn </span>catalog_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str;
<a href=#71 id=71 data-nosnippet>71</a> <span class="kw">fn </span>schema_name() -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str;
<a href=#72 id=72 data-nosnippet>72</a> <span class="kw">fn </span>build_table(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;TableRef&gt; {
<a href=#73 id=73 data-nosnippet>73</a> <span class="self">self</span>.system_table(name).map(|table| {
<a href=#74 id=74 data-nosnippet>74</a> <span class="kw">let </span>table_info = <span class="self">Self</span>::table_info(<span class="self">self</span>.catalog_name().to_string(), <span class="kw-2">&amp;</span>table);
<a href=#75 id=75 data-nosnippet>75</a> <span class="kw">let </span>filter_pushdown = FilterPushDownType::Inexact;
<a href=#76 id=76 data-nosnippet>76</a> <span class="kw">let </span>data_source = Arc::new(SystemTableDataSource::new(table));
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">let </span>table = Table::new(table_info, filter_pushdown, data_source);
<a href=#78 id=78 data-nosnippet>78</a> Arc::new(table)
<a href=#79 id=79 data-nosnippet>79</a> })
<a href=#80 id=80 data-nosnippet>80</a> }
<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">fn </span>system_table(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;SystemTableRef&gt;;
<a href=#82 id=82 data-nosnippet>82</a>
<a href=#83 id=83 data-nosnippet>83</a> <span class="kw">fn </span>table_info(catalog_name: String, table: <span class="kw-2">&amp;</span>SystemTableRef) -&gt; TableInfoRef {
<a href=#84 id=84 data-nosnippet>84</a> <span class="kw">let </span>table_meta = TableMetaBuilder::empty()
<a href=#85 id=85 data-nosnippet>85</a> .schema(table.schema())
<a href=#86 id=86 data-nosnippet>86</a> .primary_key_indices(<span class="macro">vec!</span>[])
<a href=#87 id=87 data-nosnippet>87</a> .next_column_id(<span class="number">0</span>)
<a href=#88 id=88 data-nosnippet>88</a> .build()
<a href=#89 id=89 data-nosnippet>89</a> .unwrap();
<a href=#90 id=90 data-nosnippet>90</a> <span class="kw">let </span>table_info = TableInfoBuilder::default()
<a href=#91 id=91 data-nosnippet>91</a> .table_id(table.table_id())
<a href=#92 id=92 data-nosnippet>92</a> .name(table.table_name().to_string())
<a href=#93 id=93 data-nosnippet>93</a> .catalog_name(catalog_name)
<a href=#94 id=94 data-nosnippet>94</a> .schema_name(<span class="self">Self</span>::schema_name().to_string())
<a href=#95 id=95 data-nosnippet>95</a> .meta(table_meta)
<a href=#96 id=96 data-nosnippet>96</a> .table_type(table.table_type())
<a href=#97 id=97 data-nosnippet>97</a> .build()
<a href=#98 id=98 data-nosnippet>98</a> .unwrap();
<a href=#99 id=99 data-nosnippet>99</a> Arc::new(table_info)
<a href=#100 id=100 data-nosnippet>100</a> }
<a href=#101 id=101 data-nosnippet>101</a>}
<a href=#102 id=102 data-nosnippet>102</a>
<a href=#103 id=103 data-nosnippet>103</a><span class="kw">pub trait </span>SystemTable {
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId;
<a href=#105 id=105 data-nosnippet>105</a>
<a href=#106 id=106 data-nosnippet>106</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str;
<a href=#107 id=107 data-nosnippet>107</a>
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef;
<a href=#109 id=109 data-nosnippet>109</a>
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt;;
<a href=#111 id=111 data-nosnippet>111</a>
<a href=#112 id=112 data-nosnippet>112</a> <span class="kw">fn </span>scan_plan(<span class="kw-2">&amp;</span><span class="self">self</span>, _request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;&gt; {
<a href=#113 id=113 data-nosnippet>113</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
<a href=#114 id=114 data-nosnippet>114</a> }
<a href=#115 id=115 data-nosnippet>115</a>
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw">fn </span>table_type(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableType {
<a href=#117 id=117 data-nosnippet>117</a> TableType::Temporary
<a href=#118 id=118 data-nosnippet>118</a> }
<a href=#119 id=119 data-nosnippet>119</a>}
<a href=#120 id=120 data-nosnippet>120</a>
<a href=#121 id=121 data-nosnippet>121</a><span class="kw">pub type </span>SystemTableRef = Arc&lt;<span class="kw">dyn </span>SystemTable + Send + Sync&gt;;
<a href=#122 id=122 data-nosnippet>122</a>
<a href=#123 id=123 data-nosnippet>123</a><span class="kw">struct </span>SystemTableDataSource {
<a href=#124 id=124 data-nosnippet>124</a> table: SystemTableRef,
<a href=#125 id=125 data-nosnippet>125</a>}
<a href=#126 id=126 data-nosnippet>126</a>
<a href=#127 id=127 data-nosnippet>127</a><span class="kw">impl </span>SystemTableDataSource {
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw">fn </span>new(table: SystemTableRef) -&gt; <span class="self">Self </span>{
<a href=#129 id=129 data-nosnippet>129</a> <span class="self">Self </span>{ table }
<a href=#130 id=130 data-nosnippet>130</a> }
<a href=#131 id=131 data-nosnippet>131</a>
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">fn </span>try_project(<span class="kw-2">&amp;</span><span class="self">self</span>, projection: <span class="kw-2">&amp;</span>[usize]) -&gt; std::result::Result&lt;SchemaRef, BoxedError&gt; {
<a href=#133 id=133 data-nosnippet>133</a> <span class="kw">let </span>schema = <span class="self">self
<a href=#134 id=134 data-nosnippet>134</a> </span>.table
<a href=#135 id=135 data-nosnippet>135</a> .schema()
<a href=#136 id=136 data-nosnippet>136</a> .try_project(projection)
<a href=#137 id=137 data-nosnippet>137</a> .context(SchemaConversionSnafu)
<a href=#138 id=138 data-nosnippet>138</a> .map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#139 id=139 data-nosnippet>139</a> <span class="prelude-val">Ok</span>(Arc::new(schema))
<a href=#140 id=140 data-nosnippet>140</a> }
<a href=#141 id=141 data-nosnippet>141</a>}
<a href=#142 id=142 data-nosnippet>142</a>
<a href=#143 id=143 data-nosnippet>143</a><span class="kw">impl </span>DataSource <span class="kw">for </span>SystemTableDataSource {
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">fn </span>get_stream(
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#146 id=146 data-nosnippet>146</a> request: ScanRequest,
<a href=#147 id=147 data-nosnippet>147</a> ) -&gt; std::result::Result&lt;SendableRecordBatchStream, BoxedError&gt; {
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">let </span>projection = request.projection.clone();
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">let </span>projected_schema = <span class="kw">match </span>request.projection.as_ref() {
<a href=#150 id=150 data-nosnippet>150</a> <span class="prelude-val">Some</span>(projection) =&gt; <span class="self">self</span>.try_project(projection)<span class="question-mark">?</span>,
<a href=#151 id=151 data-nosnippet>151</a> <span class="prelude-val">None </span>=&gt; <span class="self">self</span>.table.schema(),
<a href=#152 id=152 data-nosnippet>152</a> };
<a href=#153 id=153 data-nosnippet>153</a>
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">let </span>stream = <span class="self">self
<a href=#155 id=155 data-nosnippet>155</a> </span>.table
<a href=#156 id=156 data-nosnippet>156</a> .to_stream(request)
<a href=#157 id=157 data-nosnippet>157</a> .map_err(BoxedError::new)
<a href=#158 id=158 data-nosnippet>158</a> .context(TablesRecordBatchSnafu)
<a href=#159 id=159 data-nosnippet>159</a> .map_err(BoxedError::new)<span class="question-mark">?
<a href=#160 id=160 data-nosnippet>160</a> </span>.map(<span class="kw">move </span>|batch| <span class="kw">match </span>(<span class="kw-2">&amp;</span>projection, batch) {
<a href=#161 id=161 data-nosnippet>161</a> <span class="comment">// Some tables (e.g., inspect tables) already honor projection in their inner stream;
<a href=#162 id=162 data-nosnippet>162</a> // others ignore it and return full rows. We will only apply projection here if the
<a href=#163 id=163 data-nosnippet>163</a> // inner batch width doesn't match the projection size.
<a href=#164 id=164 data-nosnippet>164</a> </span>(<span class="prelude-val">Some</span>(p), <span class="prelude-val">Ok</span>(b)) <span class="kw">if </span>b.num_columns() != p.len() =&gt; b.try_project(p),
<a href=#165 id=165 data-nosnippet>165</a> (<span class="kw">_</span>, res) =&gt; res,
<a href=#166 id=166 data-nosnippet>166</a> });
<a href=#167 id=167 data-nosnippet>167</a>
<a href=#168 id=168 data-nosnippet>168</a> <span class="kw">let </span>stream = RecordBatchStreamWrapper {
<a href=#169 id=169 data-nosnippet>169</a> schema: projected_schema,
<a href=#170 id=170 data-nosnippet>170</a> stream: Box::pin(stream),
<a href=#171 id=171 data-nosnippet>171</a> output_ordering: <span class="prelude-val">None</span>,
<a href=#172 id=172 data-nosnippet>172</a> metrics: Default::default(),
<a href=#173 id=173 data-nosnippet>173</a> span: Span::current(),
<a href=#174 id=174 data-nosnippet>174</a> };
<a href=#175 id=175 data-nosnippet>175</a>
<a href=#176 id=176 data-nosnippet>176</a> <span class="prelude-val">Ok</span>(Box::pin(stream))
<a href=#177 id=177 data-nosnippet>177</a> }
<a href=#178 id=178 data-nosnippet>178</a>
<a href=#179 id=179 data-nosnippet>179</a> <span class="kw">fn </span>get_physical_plan(
<a href=#180 id=180 data-nosnippet>180</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#181 id=181 data-nosnippet>181</a> request: ScanRequest,
<a href=#182 id=182 data-nosnippet>182</a> ) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;, BoxedError&gt; {
<a href=#183 id=183 data-nosnippet>183</a> <span class="self">self</span>.table
<a href=#184 id=184 data-nosnippet>184</a> .scan_plan(request)
<a href=#185 id=185 data-nosnippet>185</a> .map_err(BoxedError::new)
<a href=#186 id=186 data-nosnippet>186</a> .context(TablesRecordBatchSnafu)
<a href=#187 id=187 data-nosnippet>187</a> .map_err(BoxedError::new)
<a href=#188 id=188 data-nosnippet>188</a> }
<a href=#189 id=189 data-nosnippet>189</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,622 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema.rs`."><title>information_schema.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/</div>information_schema.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">mod </span>cluster_info;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">pub mod </span>columns;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">pub mod </span>flow_statistics;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">pub mod </span>flows;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">mod </span>information_memory_table;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">pub mod </span>key_column_usage;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">mod </span>partitions;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">mod </span>procedure_info;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">pub mod </span>process_list;
<a href=#24 id=24 data-nosnippet>24</a><span class="attr">#[cfg(feature = <span class="string">"enterprise"</span>)]
<a href=#25 id=25 data-nosnippet>25</a></span><span class="kw">mod </span>recycle_bin;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">mod </span>region_info;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">pub mod </span>region_peers;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">mod </span>region_statistics;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">pub mod </span>schemata;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">mod </span>ssts;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">pub mod </span>statistics;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">mod </span>table_constraints;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">mod </span>table_names;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">mod </span>table_semantics;
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">pub mod </span>tables;
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">mod </span>views;
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a><span class="attr">#[cfg(all(test, feature = <span class="string">"enterprise"</span>))]
<a href=#39 id=39 data-nosnippet>39</a></span><span class="kw">mod </span>recycle_bin_test;
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span>std::collections::HashMap;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">use </span>common_catalog::consts::{<span class="self">self</span>, DEFAULT_CATALOG_NAME, INFORMATION_SCHEMA_NAME};
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">use </span>common_error::ext::ErrorExt;
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">use </span>common_meta::cluster::NodeInfo;
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">use </span>common_meta::datanode::RegionStat;
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">use </span>common_meta::key::flow::FlowMetadataManager;
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">use </span>common_meta::key::flow::flow_state::FlowStat;
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">use </span>common_meta::kv_backend::KvBackendRef;
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">use </span>common_procedure::ProcedureInfo;
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">use </span>common_recordbatch::SendableRecordBatchStream;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">use </span>datafusion::error::DataFusionError;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">use </span>datafusion::logical_expr::LogicalPlan;
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">use </span>datafusion::physical_plan::ExecutionPlan;
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">use </span>datatypes::schema::SchemaRef;
<a href=#57 id=57 data-nosnippet>57</a><span class="kw">use </span>lazy_static::lazy_static;
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">use </span>paste::paste;
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">use </span>process_list::InformationSchemaProcessList;
<a href=#60 id=60 data-nosnippet>60</a><span class="kw">use </span>region_info::InformationSchemaRegionInfo;
<a href=#61 id=61 data-nosnippet>61</a><span class="kw">use </span>store_api::metric_engine_consts::{
<a href=#62 id=62 data-nosnippet>62</a> MEMTABLE_PARTITION_TREE_PRIMARY_KEY_ENCODING, PRIMARY_KEY_ENCODING,
<a href=#63 id=63 data-nosnippet>63</a>};
<a href=#64 id=64 data-nosnippet>64</a><span class="kw">use </span>store_api::region_info::RegionInfoEntry;
<a href=#65 id=65 data-nosnippet>65</a><span class="kw">use </span>store_api::sst_entry::{ManifestSstEntry, PuffinIndexMetaEntry, StorageSstEntry};
<a href=#66 id=66 data-nosnippet>66</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#67 id=67 data-nosnippet>67</a><span class="kw">use </span>table::TableRef;
<a href=#68 id=68 data-nosnippet>68</a><span class="kw">use </span>table::metadata::TableType;
<a href=#69 id=69 data-nosnippet>69</a><span class="kw">pub use </span>table_names::<span class="kw-2">*</span>;
<a href=#70 id=70 data-nosnippet>70</a><span class="kw">use </span>views::InformationSchemaViews;
<a href=#71 id=71 data-nosnippet>71</a>
<a href=#72 id=72 data-nosnippet>72</a><span class="kw">use </span><span class="self">self</span>::columns::InformationSchemaColumns;
<a href=#73 id=73 data-nosnippet>73</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#74 id=74 data-nosnippet>74</a><span class="kw">use </span><span class="kw">crate</span>::error::{Error, <span class="prelude-ty">Result</span>};
<a href=#75 id=75 data-nosnippet>75</a><span class="kw">use </span><span class="kw">crate</span>::process_manager::ProcessManagerRef;
<a href=#76 id=76 data-nosnippet>76</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::cluster_info::InformationSchemaClusterInfo;
<a href=#77 id=77 data-nosnippet>77</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::flow_statistics::InformationSchemaFlowStatistics;
<a href=#78 id=78 data-nosnippet>78</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::flows::InformationSchemaFlows;
<a href=#79 id=79 data-nosnippet>79</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::information_memory_table::get_schema_columns;
<a href=#80 id=80 data-nosnippet>80</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::key_column_usage::InformationSchemaKeyColumnUsage;
<a href=#81 id=81 data-nosnippet>81</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::partitions::InformationSchemaPartitions;
<a href=#82 id=82 data-nosnippet>82</a><span class="attr">#[cfg(feature = <span class="string">"enterprise"</span>)]
<a href=#83 id=83 data-nosnippet>83</a></span><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::recycle_bin::InformationSchemaRecycleBin;
<a href=#84 id=84 data-nosnippet>84</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::region_peers::InformationSchemaRegionPeers;
<a href=#85 id=85 data-nosnippet>85</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::schemata::InformationSchemaSchemata;
<a href=#86 id=86 data-nosnippet>86</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::ssts::{
<a href=#87 id=87 data-nosnippet>87</a> InformationSchemaSstsIndexMeta, InformationSchemaSstsManifest, InformationSchemaSstsStorage,
<a href=#88 id=88 data-nosnippet>88</a>};
<a href=#89 id=89 data-nosnippet>89</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::statistics::InformationSchemaStatistics;
<a href=#90 id=90 data-nosnippet>90</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::table_constraints::InformationSchemaTableConstraints;
<a href=#91 id=91 data-nosnippet>91</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::table_semantics::InformationSchemaTableSemantics;
<a href=#92 id=92 data-nosnippet>92</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::tables::InformationSchemaTables;
<a href=#93 id=93 data-nosnippet>93</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::memory_table::MemoryTable;
<a href=#94 id=94 data-nosnippet>94</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">use </span><span class="kw">crate</span>::system_schema::predicate::Predicates;
<a href=#95 id=95 data-nosnippet>95</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::{
<a href=#96 id=96 data-nosnippet>96</a> SystemSchemaProvider, SystemSchemaProviderInner, SystemTable, SystemTableRef,
<a href=#97 id=97 data-nosnippet>97</a>};
<a href=#98 id=98 data-nosnippet>98</a>
<a href=#99 id=99 data-nosnippet>99</a><span class="kw">const </span>DENSE_PRIMARY_KEY_ENCODING: <span class="kw-2">&amp;</span>str = <span class="string">"dense"</span>;
<a href=#100 id=100 data-nosnippet>100</a><span class="kw">const </span>SPARSE_PRIMARY_KEY_ENCODING: <span class="kw-2">&amp;</span>str = <span class="string">"sparse"</span>;
<a href=#101 id=101 data-nosnippet>101</a>
<a href=#102 id=102 data-nosnippet>102</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>primary_key_encoding_index_type(options: <span class="kw-2">&amp;</span>HashMap&lt;String, String&gt;) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#103 id=103 data-nosnippet>103</a> options
<a href=#104 id=104 data-nosnippet>104</a> .get(PRIMARY_KEY_ENCODING)
<a href=#105 id=105 data-nosnippet>105</a> .or_else(|| options.get(MEMTABLE_PARTITION_TREE_PRIMARY_KEY_ENCODING))
<a href=#106 id=106 data-nosnippet>106</a> .map(|value| {
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">if </span>value.eq_ignore_ascii_case(SPARSE_PRIMARY_KEY_ENCODING) {
<a href=#108 id=108 data-nosnippet>108</a> SPARSE_PRIMARY_KEY_ENCODING
<a href=#109 id=109 data-nosnippet>109</a> } <span class="kw">else </span>{
<a href=#110 id=110 data-nosnippet>110</a> DENSE_PRIMARY_KEY_ENCODING
<a href=#111 id=111 data-nosnippet>111</a> }
<a href=#112 id=112 data-nosnippet>112</a> })
<a href=#113 id=113 data-nosnippet>113</a> .unwrap_or(DENSE_PRIMARY_KEY_ENCODING)
<a href=#114 id=114 data-nosnippet>114</a>}
<a href=#115 id=115 data-nosnippet>115</a>
<a href=#116 id=116 data-nosnippet>116</a><span class="macro">lazy_static!</span> {
<a href=#117 id=117 data-nosnippet>117</a> <span class="comment">// Memory tables in `information_schema`.
<a href=#118 id=118 data-nosnippet>118</a> </span><span class="kw">static </span><span class="kw-2">ref </span>MEMORY_TABLES: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>[<span class="kw-2">&amp;</span><span class="lifetime">'static </span>str] = <span class="kw-2">&amp;</span>[
<a href=#119 id=119 data-nosnippet>119</a> ENGINES,
<a href=#120 id=120 data-nosnippet>120</a> COLUMN_PRIVILEGES,
<a href=#121 id=121 data-nosnippet>121</a> COLUMN_STATISTICS,
<a href=#122 id=122 data-nosnippet>122</a> CHARACTER_SETS,
<a href=#123 id=123 data-nosnippet>123</a> COLLATIONS,
<a href=#124 id=124 data-nosnippet>124</a> COLLATION_CHARACTER_SET_APPLICABILITY,
<a href=#125 id=125 data-nosnippet>125</a> CHECK_CONSTRAINTS,
<a href=#126 id=126 data-nosnippet>126</a> EVENTS,
<a href=#127 id=127 data-nosnippet>127</a> FILES,
<a href=#128 id=128 data-nosnippet>128</a> OPTIMIZER_TRACE,
<a href=#129 id=129 data-nosnippet>129</a> PARAMETERS,
<a href=#130 id=130 data-nosnippet>130</a> PROFILING,
<a href=#131 id=131 data-nosnippet>131</a> REFERENTIAL_CONSTRAINTS,
<a href=#132 id=132 data-nosnippet>132</a> ROUTINES,
<a href=#133 id=133 data-nosnippet>133</a> SCHEMA_PRIVILEGES,
<a href=#134 id=134 data-nosnippet>134</a> TABLE_PRIVILEGES,
<a href=#135 id=135 data-nosnippet>135</a> GLOBAL_STATUS,
<a href=#136 id=136 data-nosnippet>136</a> SESSION_STATUS,
<a href=#137 id=137 data-nosnippet>137</a> PARTITIONS,
<a href=#138 id=138 data-nosnippet>138</a> PLUGINS,
<a href=#139 id=139 data-nosnippet>139</a> USER_PRIVILEGES,
<a href=#140 id=140 data-nosnippet>140</a> PROCESSLIST,
<a href=#141 id=141 data-nosnippet>141</a> ];
<a href=#142 id=142 data-nosnippet>142</a>}
<a href=#143 id=143 data-nosnippet>143</a>
<a href=#144 id=144 data-nosnippet>144</a><span class="macro">macro_rules!</span> setup_memory_table {
<a href=#145 id=145 data-nosnippet>145</a> (<span class="macro-nonterminal">$name</span>: expr) =&gt; {
<a href=#146 id=146 data-nosnippet>146</a> <span class="macro">paste!</span> {
<a href=#147 id=147 data-nosnippet>147</a> {
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">let </span>(schema, columns) = get_schema_columns(<span class="macro-nonterminal">$name</span>);
<a href=#149 id=149 data-nosnippet>149</a> <span class="prelude-val">Some</span>(Arc::new(MemoryTable::new(
<a href=#150 id=150 data-nosnippet>150</a> consts::[&lt;INFORMATION_SCHEMA_ <span class="macro-nonterminal">$name </span>_TABLE_ID&gt;],
<a href=#151 id=151 data-nosnippet>151</a> <span class="macro-nonterminal">$name</span>,
<a href=#152 id=152 data-nosnippet>152</a> schema,
<a href=#153 id=153 data-nosnippet>153</a> columns
<a href=#154 id=154 data-nosnippet>154</a> )) <span class="kw">as _</span>)
<a href=#155 id=155 data-nosnippet>155</a> }
<a href=#156 id=156 data-nosnippet>156</a> }
<a href=#157 id=157 data-nosnippet>157</a> };
<a href=#158 id=158 data-nosnippet>158</a>}
<a href=#159 id=159 data-nosnippet>159</a>
<a href=#160 id=160 data-nosnippet>160</a><span class="kw">pub struct </span>MakeInformationTableRequest {
<a href=#161 id=161 data-nosnippet>161</a> <span class="kw">pub </span>catalog_name: String,
<a href=#162 id=162 data-nosnippet>162</a> <span class="kw">pub </span>catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">pub </span>kv_backend: KvBackendRef,
<a href=#164 id=164 data-nosnippet>164</a>}
<a href=#165 id=165 data-nosnippet>165</a>
<a href=#166 id=166 data-nosnippet>166</a><span class="doccomment">/// A factory trait for making information schema tables.
<a href=#167 id=167 data-nosnippet>167</a>///
<a href=#168 id=168 data-nosnippet>168</a>/// This trait allows for extensibility of the information schema by providing
<a href=#169 id=169 data-nosnippet>169</a>/// a way to dynamically create custom information schema tables.
<a href=#170 id=170 data-nosnippet>170</a></span><span class="kw">pub trait </span>InformationSchemaTableFactory {
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">fn </span>make_information_table(<span class="kw-2">&amp;</span><span class="self">self</span>, req: MakeInformationTableRequest) -&gt; SystemTableRef;
<a href=#172 id=172 data-nosnippet>172</a>}
<a href=#173 id=173 data-nosnippet>173</a>
<a href=#174 id=174 data-nosnippet>174</a><span class="kw">pub type </span>InformationSchemaTableFactoryRef = Arc&lt;<span class="kw">dyn </span>InformationSchemaTableFactory + Send + Sync&gt;;
<a href=#175 id=175 data-nosnippet>175</a>
<a href=#176 id=176 data-nosnippet>176</a><span class="doccomment">/// The `information_schema` tables info provider.
<a href=#177 id=177 data-nosnippet>177</a></span><span class="kw">pub struct </span>InformationSchemaProvider {
<a href=#178 id=178 data-nosnippet>178</a> catalog_name: String,
<a href=#179 id=179 data-nosnippet>179</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#180 id=180 data-nosnippet>180</a> process_manager: <span class="prelude-ty">Option</span>&lt;ProcessManagerRef&gt;,
<a href=#181 id=181 data-nosnippet>181</a> flow_metadata_manager: Arc&lt;FlowMetadataManager&gt;,
<a href=#182 id=182 data-nosnippet>182</a> tables: HashMap&lt;String, TableRef&gt;,
<a href=#183 id=183 data-nosnippet>183</a> kv_backend: KvBackendRef,
<a href=#184 id=184 data-nosnippet>184</a> extra_table_factories: HashMap&lt;String, InformationSchemaTableFactoryRef&gt;,
<a href=#185 id=185 data-nosnippet>185</a>}
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a><span class="kw">impl </span>SystemSchemaProvider <span class="kw">for </span>InformationSchemaProvider {
<a href=#188 id=188 data-nosnippet>188</a> <span class="kw">fn </span>tables(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>HashMap&lt;String, TableRef&gt; {
<a href=#189 id=189 data-nosnippet>189</a> <span class="macro">assert!</span>(!<span class="self">self</span>.tables.is_empty());
<a href=#190 id=190 data-nosnippet>190</a>
<a href=#191 id=191 data-nosnippet>191</a> <span class="kw-2">&amp;</span><span class="self">self</span>.tables
<a href=#192 id=192 data-nosnippet>192</a> }
<a href=#193 id=193 data-nosnippet>193</a>}
<a href=#194 id=194 data-nosnippet>194</a>
<a href=#195 id=195 data-nosnippet>195</a><span class="kw">impl </span>SystemSchemaProviderInner <span class="kw">for </span>InformationSchemaProvider {
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">fn </span>catalog_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#197 id=197 data-nosnippet>197</a> <span class="kw-2">&amp;</span><span class="self">self</span>.catalog_name
<a href=#198 id=198 data-nosnippet>198</a> }
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">fn </span>schema_name() -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#200 id=200 data-nosnippet>200</a> INFORMATION_SCHEMA_NAME
<a href=#201 id=201 data-nosnippet>201</a> }
<a href=#202 id=202 data-nosnippet>202</a>
<a href=#203 id=203 data-nosnippet>203</a> <span class="kw">fn </span>system_table(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;SystemTableRef&gt; {
<a href=#204 id=204 data-nosnippet>204</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(factory) = <span class="self">self</span>.extra_table_factories.get(name) {
<a href=#205 id=205 data-nosnippet>205</a> <span class="kw">let </span>req = MakeInformationTableRequest {
<a href=#206 id=206 data-nosnippet>206</a> catalog_name: <span class="self">self</span>.catalog_name.clone(),
<a href=#207 id=207 data-nosnippet>207</a> catalog_manager: <span class="self">self</span>.catalog_manager.clone(),
<a href=#208 id=208 data-nosnippet>208</a> kv_backend: <span class="self">self</span>.kv_backend.clone(),
<a href=#209 id=209 data-nosnippet>209</a> };
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">return </span><span class="prelude-val">Some</span>(factory.make_information_table(req));
<a href=#211 id=211 data-nosnippet>211</a> }
<a href=#212 id=212 data-nosnippet>212</a>
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">match </span>name.to_ascii_lowercase().as_str() {
<a href=#214 id=214 data-nosnippet>214</a> TABLES =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaTables::new(
<a href=#215 id=215 data-nosnippet>215</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#216 id=216 data-nosnippet>216</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#217 id=217 data-nosnippet>217</a> )) <span class="kw">as _</span>),
<a href=#218 id=218 data-nosnippet>218</a> COLUMNS =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaColumns::new(
<a href=#219 id=219 data-nosnippet>219</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#220 id=220 data-nosnippet>220</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#221 id=221 data-nosnippet>221</a> )) <span class="kw">as _</span>),
<a href=#222 id=222 data-nosnippet>222</a> ENGINES =&gt; <span class="macro">setup_memory_table!</span>(ENGINES),
<a href=#223 id=223 data-nosnippet>223</a> COLUMN_PRIVILEGES =&gt; <span class="macro">setup_memory_table!</span>(COLUMN_PRIVILEGES),
<a href=#224 id=224 data-nosnippet>224</a> COLUMN_STATISTICS =&gt; <span class="macro">setup_memory_table!</span>(COLUMN_STATISTICS),
<a href=#225 id=225 data-nosnippet>225</a> BUILD_INFO =&gt; <span class="macro">setup_memory_table!</span>(BUILD_INFO),
<a href=#226 id=226 data-nosnippet>226</a> CHARACTER_SETS =&gt; <span class="macro">setup_memory_table!</span>(CHARACTER_SETS),
<a href=#227 id=227 data-nosnippet>227</a> COLLATIONS =&gt; <span class="macro">setup_memory_table!</span>(COLLATIONS),
<a href=#228 id=228 data-nosnippet>228</a> COLLATION_CHARACTER_SET_APPLICABILITY =&gt; {
<a href=#229 id=229 data-nosnippet>229</a> <span class="macro">setup_memory_table!</span>(COLLATION_CHARACTER_SET_APPLICABILITY)
<a href=#230 id=230 data-nosnippet>230</a> }
<a href=#231 id=231 data-nosnippet>231</a> CHECK_CONSTRAINTS =&gt; <span class="macro">setup_memory_table!</span>(CHECK_CONSTRAINTS),
<a href=#232 id=232 data-nosnippet>232</a> EVENTS =&gt; <span class="macro">setup_memory_table!</span>(EVENTS),
<a href=#233 id=233 data-nosnippet>233</a> FILES =&gt; <span class="macro">setup_memory_table!</span>(FILES),
<a href=#234 id=234 data-nosnippet>234</a> OPTIMIZER_TRACE =&gt; <span class="macro">setup_memory_table!</span>(OPTIMIZER_TRACE),
<a href=#235 id=235 data-nosnippet>235</a> PARAMETERS =&gt; <span class="macro">setup_memory_table!</span>(PARAMETERS),
<a href=#236 id=236 data-nosnippet>236</a> PROFILING =&gt; <span class="macro">setup_memory_table!</span>(PROFILING),
<a href=#237 id=237 data-nosnippet>237</a> REFERENTIAL_CONSTRAINTS =&gt; <span class="macro">setup_memory_table!</span>(REFERENTIAL_CONSTRAINTS),
<a href=#238 id=238 data-nosnippet>238</a> ROUTINES =&gt; <span class="macro">setup_memory_table!</span>(ROUTINES),
<a href=#239 id=239 data-nosnippet>239</a> SCHEMA_PRIVILEGES =&gt; <span class="macro">setup_memory_table!</span>(SCHEMA_PRIVILEGES),
<a href=#240 id=240 data-nosnippet>240</a> TABLE_PRIVILEGES =&gt; <span class="macro">setup_memory_table!</span>(TABLE_PRIVILEGES),
<a href=#241 id=241 data-nosnippet>241</a> GLOBAL_STATUS =&gt; <span class="macro">setup_memory_table!</span>(GLOBAL_STATUS),
<a href=#242 id=242 data-nosnippet>242</a> SESSION_STATUS =&gt; <span class="macro">setup_memory_table!</span>(SESSION_STATUS),
<a href=#243 id=243 data-nosnippet>243</a> PLUGINS =&gt; <span class="macro">setup_memory_table!</span>(PLUGINS),
<a href=#244 id=244 data-nosnippet>244</a> USER_PRIVILEGES =&gt; <span class="macro">setup_memory_table!</span>(USER_PRIVILEGES),
<a href=#245 id=245 data-nosnippet>245</a> PROCESSLIST =&gt; <span class="macro">setup_memory_table!</span>(PROCESSLIST),
<a href=#246 id=246 data-nosnippet>246</a> KEY_COLUMN_USAGE =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaKeyColumnUsage::new(
<a href=#247 id=247 data-nosnippet>247</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#248 id=248 data-nosnippet>248</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#249 id=249 data-nosnippet>249</a> )) <span class="kw">as _</span>),
<a href=#250 id=250 data-nosnippet>250</a> SCHEMATA =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaSchemata::new(
<a href=#251 id=251 data-nosnippet>251</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#252 id=252 data-nosnippet>252</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#253 id=253 data-nosnippet>253</a> )) <span class="kw">as _</span>),
<a href=#254 id=254 data-nosnippet>254</a> PARTITIONS =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaPartitions::new(
<a href=#255 id=255 data-nosnippet>255</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#256 id=256 data-nosnippet>256</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#257 id=257 data-nosnippet>257</a> )) <span class="kw">as _</span>),
<a href=#258 id=258 data-nosnippet>258</a> REGION_PEERS =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaRegionPeers::new(
<a href=#259 id=259 data-nosnippet>259</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#260 id=260 data-nosnippet>260</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#261 id=261 data-nosnippet>261</a> )) <span class="kw">as _</span>),
<a href=#262 id=262 data-nosnippet>262</a> TABLE_CONSTRAINTS =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaTableConstraints::new(
<a href=#263 id=263 data-nosnippet>263</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#264 id=264 data-nosnippet>264</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#265 id=265 data-nosnippet>265</a> )) <span class="kw">as _</span>),
<a href=#266 id=266 data-nosnippet>266</a> STATISTICS =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaStatistics::new(
<a href=#267 id=267 data-nosnippet>267</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#268 id=268 data-nosnippet>268</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#269 id=269 data-nosnippet>269</a> )) <span class="kw">as _</span>),
<a href=#270 id=270 data-nosnippet>270</a> CLUSTER_INFO =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaClusterInfo::new(
<a href=#271 id=271 data-nosnippet>271</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#272 id=272 data-nosnippet>272</a> )) <span class="kw">as _</span>),
<a href=#273 id=273 data-nosnippet>273</a> VIEWS =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaViews::new(
<a href=#274 id=274 data-nosnippet>274</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#275 id=275 data-nosnippet>275</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#276 id=276 data-nosnippet>276</a> )) <span class="kw">as _</span>),
<a href=#277 id=277 data-nosnippet>277</a> FLOWS =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaFlows::new(
<a href=#278 id=278 data-nosnippet>278</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#279 id=279 data-nosnippet>279</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#280 id=280 data-nosnippet>280</a> <span class="self">self</span>.flow_metadata_manager.clone(),
<a href=#281 id=281 data-nosnippet>281</a> )) <span class="kw">as _</span>),
<a href=#282 id=282 data-nosnippet>282</a> FLOW_STATISTICS =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaFlowStatistics::new(
<a href=#283 id=283 data-nosnippet>283</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#284 id=284 data-nosnippet>284</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#285 id=285 data-nosnippet>285</a> <span class="self">self</span>.flow_metadata_manager.clone(),
<a href=#286 id=286 data-nosnippet>286</a> )) <span class="kw">as _</span>),
<a href=#287 id=287 data-nosnippet>287</a> PROCEDURE_INFO =&gt; <span class="prelude-val">Some</span>(
<a href=#288 id=288 data-nosnippet>288</a> Arc::new(procedure_info::InformationSchemaProcedureInfo::new(
<a href=#289 id=289 data-nosnippet>289</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#290 id=290 data-nosnippet>290</a> )) <span class="kw">as _</span>,
<a href=#291 id=291 data-nosnippet>291</a> ),
<a href=#292 id=292 data-nosnippet>292</a> <span class="attr">#[cfg(feature = <span class="string">"enterprise"</span>)]
<a href=#293 id=293 data-nosnippet>293</a> </span>RECYCLE_BIN =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaRecycleBin::new(
<a href=#294 id=294 data-nosnippet>294</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#295 id=295 data-nosnippet>295</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#296 id=296 data-nosnippet>296</a> )) <span class="kw">as _</span>),
<a href=#297 id=297 data-nosnippet>297</a> REGION_STATISTICS =&gt; <span class="prelude-val">Some</span>(Arc::new(
<a href=#298 id=298 data-nosnippet>298</a> region_statistics::InformationSchemaRegionStatistics::new(
<a href=#299 id=299 data-nosnippet>299</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#300 id=300 data-nosnippet>300</a> ),
<a href=#301 id=301 data-nosnippet>301</a> ) <span class="kw">as _</span>),
<a href=#302 id=302 data-nosnippet>302</a> REGION_INFO =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaRegionInfo::new(
<a href=#303 id=303 data-nosnippet>303</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#304 id=304 data-nosnippet>304</a> )) <span class="kw">as _</span>),
<a href=#305 id=305 data-nosnippet>305</a> PROCESS_LIST =&gt; <span class="self">self
<a href=#306 id=306 data-nosnippet>306</a> </span>.process_manager
<a href=#307 id=307 data-nosnippet>307</a> .as_ref()
<a href=#308 id=308 data-nosnippet>308</a> .map(|p| Arc::new(InformationSchemaProcessList::new(p.clone())) <span class="kw">as _</span>),
<a href=#309 id=309 data-nosnippet>309</a> SSTS_MANIFEST =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaSstsManifest::new(
<a href=#310 id=310 data-nosnippet>310</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#311 id=311 data-nosnippet>311</a> )) <span class="kw">as _</span>),
<a href=#312 id=312 data-nosnippet>312</a> SSTS_STORAGE =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaSstsStorage::new(
<a href=#313 id=313 data-nosnippet>313</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#314 id=314 data-nosnippet>314</a> )) <span class="kw">as _</span>),
<a href=#315 id=315 data-nosnippet>315</a> SSTS_INDEX_META =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaSstsIndexMeta::new(
<a href=#316 id=316 data-nosnippet>316</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#317 id=317 data-nosnippet>317</a> )) <span class="kw">as _</span>),
<a href=#318 id=318 data-nosnippet>318</a> TABLE_SEMANTICS =&gt; <span class="prelude-val">Some</span>(Arc::new(InformationSchemaTableSemantics::new(
<a href=#319 id=319 data-nosnippet>319</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#320 id=320 data-nosnippet>320</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#321 id=321 data-nosnippet>321</a> )) <span class="kw">as _</span>),
<a href=#322 id=322 data-nosnippet>322</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
<a href=#323 id=323 data-nosnippet>323</a> }
<a href=#324 id=324 data-nosnippet>324</a> }
<a href=#325 id=325 data-nosnippet>325</a>}
<a href=#326 id=326 data-nosnippet>326</a>
<a href=#327 id=327 data-nosnippet>327</a><span class="kw">impl </span>InformationSchemaProvider {
<a href=#328 id=328 data-nosnippet>328</a> <span class="kw">pub fn </span>new(
<a href=#329 id=329 data-nosnippet>329</a> catalog_name: String,
<a href=#330 id=330 data-nosnippet>330</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#331 id=331 data-nosnippet>331</a> flow_metadata_manager: Arc&lt;FlowMetadataManager&gt;,
<a href=#332 id=332 data-nosnippet>332</a> process_manager: <span class="prelude-ty">Option</span>&lt;ProcessManagerRef&gt;,
<a href=#333 id=333 data-nosnippet>333</a> kv_backend: KvBackendRef,
<a href=#334 id=334 data-nosnippet>334</a> ) -&gt; <span class="self">Self </span>{
<a href=#335 id=335 data-nosnippet>335</a> <span class="kw">let </span><span class="kw-2">mut </span>provider = <span class="self">Self </span>{
<a href=#336 id=336 data-nosnippet>336</a> catalog_name,
<a href=#337 id=337 data-nosnippet>337</a> catalog_manager,
<a href=#338 id=338 data-nosnippet>338</a> flow_metadata_manager,
<a href=#339 id=339 data-nosnippet>339</a> process_manager,
<a href=#340 id=340 data-nosnippet>340</a> tables: HashMap::new(),
<a href=#341 id=341 data-nosnippet>341</a> kv_backend,
<a href=#342 id=342 data-nosnippet>342</a> extra_table_factories: HashMap::new(),
<a href=#343 id=343 data-nosnippet>343</a> };
<a href=#344 id=344 data-nosnippet>344</a>
<a href=#345 id=345 data-nosnippet>345</a> provider.build_tables();
<a href=#346 id=346 data-nosnippet>346</a>
<a href=#347 id=347 data-nosnippet>347</a> provider
<a href=#348 id=348 data-nosnippet>348</a> }
<a href=#349 id=349 data-nosnippet>349</a>
<a href=#350 id=350 data-nosnippet>350</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>with_extra_table_factories(
<a href=#351 id=351 data-nosnippet>351</a> <span class="kw-2">mut </span><span class="self">self</span>,
<a href=#352 id=352 data-nosnippet>352</a> factories: HashMap&lt;String, InformationSchemaTableFactoryRef&gt;,
<a href=#353 id=353 data-nosnippet>353</a> ) -&gt; <span class="self">Self </span>{
<a href=#354 id=354 data-nosnippet>354</a> <span class="self">self</span>.extra_table_factories = factories;
<a href=#355 id=355 data-nosnippet>355</a> <span class="self">self</span>.build_tables();
<a href=#356 id=356 data-nosnippet>356</a> <span class="self">self
<a href=#357 id=357 data-nosnippet>357</a> </span>}
<a href=#358 id=358 data-nosnippet>358</a>
<a href=#359 id=359 data-nosnippet>359</a> <span class="kw">fn </span>build_tables(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#360 id=360 data-nosnippet>360</a> <span class="kw">let </span><span class="kw-2">mut </span>tables = HashMap::new();
<a href=#361 id=361 data-nosnippet>361</a>
<a href=#362 id=362 data-nosnippet>362</a> <span class="comment">// SECURITY NOTE:
<a href=#363 id=363 data-nosnippet>363</a> // Carefully consider the tables that may expose sensitive cluster configurations,
<a href=#364 id=364 data-nosnippet>364</a> // authentication details, and other critical information.
<a href=#365 id=365 data-nosnippet>365</a> // Only put these tables under `greptime` catalog to prevent info leak.
<a href=#366 id=366 data-nosnippet>366</a> </span><span class="kw">if </span><span class="self">self</span>.catalog_name == DEFAULT_CATALOG_NAME {
<a href=#367 id=367 data-nosnippet>367</a> tables.insert(
<a href=#368 id=368 data-nosnippet>368</a> BUILD_INFO.to_string(),
<a href=#369 id=369 data-nosnippet>369</a> <span class="self">self</span>.build_table(BUILD_INFO).unwrap(),
<a href=#370 id=370 data-nosnippet>370</a> );
<a href=#371 id=371 data-nosnippet>371</a> tables.insert(
<a href=#372 id=372 data-nosnippet>372</a> REGION_PEERS.to_string(),
<a href=#373 id=373 data-nosnippet>373</a> <span class="self">self</span>.build_table(REGION_PEERS).unwrap(),
<a href=#374 id=374 data-nosnippet>374</a> );
<a href=#375 id=375 data-nosnippet>375</a> tables.insert(
<a href=#376 id=376 data-nosnippet>376</a> CLUSTER_INFO.to_string(),
<a href=#377 id=377 data-nosnippet>377</a> <span class="self">self</span>.build_table(CLUSTER_INFO).unwrap(),
<a href=#378 id=378 data-nosnippet>378</a> );
<a href=#379 id=379 data-nosnippet>379</a> tables.insert(
<a href=#380 id=380 data-nosnippet>380</a> PROCEDURE_INFO.to_string(),
<a href=#381 id=381 data-nosnippet>381</a> <span class="self">self</span>.build_table(PROCEDURE_INFO).unwrap(),
<a href=#382 id=382 data-nosnippet>382</a> );
<a href=#383 id=383 data-nosnippet>383</a> tables.insert(
<a href=#384 id=384 data-nosnippet>384</a> REGION_STATISTICS.to_string(),
<a href=#385 id=385 data-nosnippet>385</a> <span class="self">self</span>.build_table(REGION_STATISTICS).unwrap(),
<a href=#386 id=386 data-nosnippet>386</a> );
<a href=#387 id=387 data-nosnippet>387</a> tables.insert(
<a href=#388 id=388 data-nosnippet>388</a> REGION_INFO.to_string(),
<a href=#389 id=389 data-nosnippet>389</a> <span class="self">self</span>.build_table(REGION_INFO).unwrap(),
<a href=#390 id=390 data-nosnippet>390</a> );
<a href=#391 id=391 data-nosnippet>391</a> tables.insert(
<a href=#392 id=392 data-nosnippet>392</a> SSTS_MANIFEST.to_string(),
<a href=#393 id=393 data-nosnippet>393</a> <span class="self">self</span>.build_table(SSTS_MANIFEST).unwrap(),
<a href=#394 id=394 data-nosnippet>394</a> );
<a href=#395 id=395 data-nosnippet>395</a> tables.insert(
<a href=#396 id=396 data-nosnippet>396</a> SSTS_STORAGE.to_string(),
<a href=#397 id=397 data-nosnippet>397</a> <span class="self">self</span>.build_table(SSTS_STORAGE).unwrap(),
<a href=#398 id=398 data-nosnippet>398</a> );
<a href=#399 id=399 data-nosnippet>399</a> tables.insert(
<a href=#400 id=400 data-nosnippet>400</a> SSTS_INDEX_META.to_string(),
<a href=#401 id=401 data-nosnippet>401</a> <span class="self">self</span>.build_table(SSTS_INDEX_META).unwrap(),
<a href=#402 id=402 data-nosnippet>402</a> );
<a href=#403 id=403 data-nosnippet>403</a> }
<a href=#404 id=404 data-nosnippet>404</a>
<a href=#405 id=405 data-nosnippet>405</a> tables.insert(TABLES.to_string(), <span class="self">self</span>.build_table(TABLES).unwrap());
<a href=#406 id=406 data-nosnippet>406</a> tables.insert(VIEWS.to_string(), <span class="self">self</span>.build_table(VIEWS).unwrap());
<a href=#407 id=407 data-nosnippet>407</a> tables.insert(SCHEMATA.to_string(), <span class="self">self</span>.build_table(SCHEMATA).unwrap());
<a href=#408 id=408 data-nosnippet>408</a> tables.insert(COLUMNS.to_string(), <span class="self">self</span>.build_table(COLUMNS).unwrap());
<a href=#409 id=409 data-nosnippet>409</a> tables.insert(
<a href=#410 id=410 data-nosnippet>410</a> KEY_COLUMN_USAGE.to_string(),
<a href=#411 id=411 data-nosnippet>411</a> <span class="self">self</span>.build_table(KEY_COLUMN_USAGE).unwrap(),
<a href=#412 id=412 data-nosnippet>412</a> );
<a href=#413 id=413 data-nosnippet>413</a> tables.insert(
<a href=#414 id=414 data-nosnippet>414</a> TABLE_CONSTRAINTS.to_string(),
<a href=#415 id=415 data-nosnippet>415</a> <span class="self">self</span>.build_table(TABLE_CONSTRAINTS).unwrap(),
<a href=#416 id=416 data-nosnippet>416</a> );
<a href=#417 id=417 data-nosnippet>417</a> tables.insert(
<a href=#418 id=418 data-nosnippet>418</a> STATISTICS.to_string(),
<a href=#419 id=419 data-nosnippet>419</a> <span class="self">self</span>.build_table(STATISTICS).unwrap(),
<a href=#420 id=420 data-nosnippet>420</a> );
<a href=#421 id=421 data-nosnippet>421</a> tables.insert(FLOWS.to_string(), <span class="self">self</span>.build_table(FLOWS).unwrap());
<a href=#422 id=422 data-nosnippet>422</a> tables.insert(
<a href=#423 id=423 data-nosnippet>423</a> FLOW_STATISTICS.to_string(),
<a href=#424 id=424 data-nosnippet>424</a> <span class="self">self</span>.build_table(FLOW_STATISTICS).unwrap(),
<a href=#425 id=425 data-nosnippet>425</a> );
<a href=#426 id=426 data-nosnippet>426</a> <span class="attr">#[cfg(feature = <span class="string">"enterprise"</span>)]
<a href=#427 id=427 data-nosnippet>427</a> </span>tables.insert(
<a href=#428 id=428 data-nosnippet>428</a> RECYCLE_BIN.to_string(),
<a href=#429 id=429 data-nosnippet>429</a> <span class="self">self</span>.build_table(RECYCLE_BIN).unwrap(),
<a href=#430 id=430 data-nosnippet>430</a> );
<a href=#431 id=431 data-nosnippet>431</a> tables.insert(
<a href=#432 id=432 data-nosnippet>432</a> TABLE_SEMANTICS.to_string(),
<a href=#433 id=433 data-nosnippet>433</a> <span class="self">self</span>.build_table(TABLE_SEMANTICS).unwrap(),
<a href=#434 id=434 data-nosnippet>434</a> );
<a href=#435 id=435 data-nosnippet>435</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(process_list) = <span class="self">self</span>.build_table(PROCESS_LIST) {
<a href=#436 id=436 data-nosnippet>436</a> tables.insert(PROCESS_LIST.to_string(), process_list);
<a href=#437 id=437 data-nosnippet>437</a> }
<a href=#438 id=438 data-nosnippet>438</a> <span class="kw">for </span>name <span class="kw">in </span><span class="self">self</span>.extra_table_factories.keys() {
<a href=#439 id=439 data-nosnippet>439</a> tables.insert(name.clone(), <span class="self">self</span>.build_table(name).expect(name));
<a href=#440 id=440 data-nosnippet>440</a> }
<a href=#441 id=441 data-nosnippet>441</a> <span class="comment">// Add memory tables
<a href=#442 id=442 data-nosnippet>442</a> </span><span class="kw">for </span>name <span class="kw">in </span>MEMORY_TABLES.iter() {
<a href=#443 id=443 data-nosnippet>443</a> tables.insert((<span class="kw-2">*</span>name).to_string(), <span class="self">self</span>.build_table(name).expect(name));
<a href=#444 id=444 data-nosnippet>444</a> }
<a href=#445 id=445 data-nosnippet>445</a> <span class="self">self</span>.tables = tables;
<a href=#446 id=446 data-nosnippet>446</a> }
<a href=#447 id=447 data-nosnippet>447</a>}
<a href=#448 id=448 data-nosnippet>448</a>
<a href=#449 id=449 data-nosnippet>449</a><span class="kw">pub trait </span>InformationTable {
<a href=#450 id=450 data-nosnippet>450</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId;
<a href=#451 id=451 data-nosnippet>451</a>
<a href=#452 id=452 data-nosnippet>452</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str;
<a href=#453 id=453 data-nosnippet>453</a>
<a href=#454 id=454 data-nosnippet>454</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef;
<a href=#455 id=455 data-nosnippet>455</a>
<a href=#456 id=456 data-nosnippet>456</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt;;
<a href=#457 id=457 data-nosnippet>457</a>
<a href=#458 id=458 data-nosnippet>458</a> <span class="kw">fn </span>scan_plan(<span class="kw-2">&amp;</span><span class="self">self</span>, _request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;&gt; {
<a href=#459 id=459 data-nosnippet>459</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
<a href=#460 id=460 data-nosnippet>460</a> }
<a href=#461 id=461 data-nosnippet>461</a>
<a href=#462 id=462 data-nosnippet>462</a> <span class="kw">fn </span>table_type(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableType {
<a href=#463 id=463 data-nosnippet>463</a> TableType::Temporary
<a href=#464 id=464 data-nosnippet>464</a> }
<a href=#465 id=465 data-nosnippet>465</a>}
<a href=#466 id=466 data-nosnippet>466</a>
<a href=#467 id=467 data-nosnippet>467</a><span class="comment">// Provide compatibility for legacy `information_schema` code.
<a href=#468 id=468 data-nosnippet>468</a></span><span class="kw">impl</span>&lt;T&gt; SystemTable <span class="kw">for </span>T
<a href=#469 id=469 data-nosnippet>469</a><span class="kw">where
<a href=#470 id=470 data-nosnippet>470</a> </span>T: InformationTable,
<a href=#471 id=471 data-nosnippet>471</a>{
<a href=#472 id=472 data-nosnippet>472</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#473 id=473 data-nosnippet>473</a> InformationTable::table_id(<span class="self">self</span>)
<a href=#474 id=474 data-nosnippet>474</a> }
<a href=#475 id=475 data-nosnippet>475</a>
<a href=#476 id=476 data-nosnippet>476</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#477 id=477 data-nosnippet>477</a> InformationTable::table_name(<span class="self">self</span>)
<a href=#478 id=478 data-nosnippet>478</a> }
<a href=#479 id=479 data-nosnippet>479</a>
<a href=#480 id=480 data-nosnippet>480</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#481 id=481 data-nosnippet>481</a> InformationTable::schema(<span class="self">self</span>)
<a href=#482 id=482 data-nosnippet>482</a> }
<a href=#483 id=483 data-nosnippet>483</a>
<a href=#484 id=484 data-nosnippet>484</a> <span class="kw">fn </span>table_type(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableType {
<a href=#485 id=485 data-nosnippet>485</a> InformationTable::table_type(<span class="self">self</span>)
<a href=#486 id=486 data-nosnippet>486</a> }
<a href=#487 id=487 data-nosnippet>487</a>
<a href=#488 id=488 data-nosnippet>488</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#489 id=489 data-nosnippet>489</a> InformationTable::to_stream(<span class="self">self</span>, request)
<a href=#490 id=490 data-nosnippet>490</a> }
<a href=#491 id=491 data-nosnippet>491</a>
<a href=#492 id=492 data-nosnippet>492</a> <span class="kw">fn </span>scan_plan(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;&gt; {
<a href=#493 id=493 data-nosnippet>493</a> InformationTable::scan_plan(<span class="self">self</span>, request)
<a href=#494 id=494 data-nosnippet>494</a> }
<a href=#495 id=495 data-nosnippet>495</a>}
<a href=#496 id=496 data-nosnippet>496</a>
<a href=#497 id=497 data-nosnippet>497</a><span class="kw">pub type </span>InformationExtensionRef = Arc&lt;<span class="kw">dyn </span>InformationExtension&lt;Error = Error&gt; + Send + Sync&gt;;
<a href=#498 id=498 data-nosnippet>498</a>
<a href=#499 id=499 data-nosnippet>499</a><span class="doccomment">/// The `InformationExtension` trait provides the extension methods for the `information_schema` tables.
<a href=#500 id=500 data-nosnippet>500</a></span><span class="attr">#[async_trait::async_trait]
<a href=#501 id=501 data-nosnippet>501</a></span><span class="kw">pub trait </span>InformationExtension {
<a href=#502 id=502 data-nosnippet>502</a> <span class="kw">type </span>Error: ErrorExt;
<a href=#503 id=503 data-nosnippet>503</a>
<a href=#504 id=504 data-nosnippet>504</a> <span class="doccomment">/// Gets the nodes information.
<a href=#505 id=505 data-nosnippet>505</a> </span><span class="kw">async fn </span>nodes(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Vec&lt;NodeInfo&gt;, <span class="self">Self</span>::Error&gt;;
<a href=#506 id=506 data-nosnippet>506</a>
<a href=#507 id=507 data-nosnippet>507</a> <span class="doccomment">/// Gets the procedures information.
<a href=#508 id=508 data-nosnippet>508</a> </span><span class="kw">async fn </span>procedures(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Vec&lt;(String, ProcedureInfo)&gt;, <span class="self">Self</span>::Error&gt;;
<a href=#509 id=509 data-nosnippet>509</a>
<a href=#510 id=510 data-nosnippet>510</a> <span class="doccomment">/// Gets the region statistics.
<a href=#511 id=511 data-nosnippet>511</a> </span><span class="kw">async fn </span>region_stats(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Vec&lt;RegionStat&gt;, <span class="self">Self</span>::Error&gt;;
<a href=#512 id=512 data-nosnippet>512</a>
<a href=#513 id=513 data-nosnippet>513</a> <span class="doccomment">/// Get the flow statistics. If no flownode is available, return `None`.
<a href=#514 id=514 data-nosnippet>514</a> </span><span class="kw">async fn </span>flow_stats(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;FlowStat&gt;, <span class="self">Self</span>::Error&gt;;
<a href=#515 id=515 data-nosnippet>515</a>
<a href=#516 id=516 data-nosnippet>516</a> <span class="doccomment">/// Inspects the datanode.
<a href=#517 id=517 data-nosnippet>517</a> </span><span class="kw">async fn </span>inspect_datanode(
<a href=#518 id=518 data-nosnippet>518</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#519 id=519 data-nosnippet>519</a> request: DatanodeInspectRequest,
<a href=#520 id=520 data-nosnippet>520</a> ) -&gt; std::result::Result&lt;SendableRecordBatchStream, <span class="self">Self</span>::Error&gt;;
<a href=#521 id=521 data-nosnippet>521</a>
<a href=#522 id=522 data-nosnippet>522</a> <span class="doccomment">/// Builds a physical plan for datanode inspect if the extension can expose
<a href=#523 id=523 data-nosnippet>523</a> /// the distributed fan-in semantics to DataFusion.
<a href=#524 id=524 data-nosnippet>524</a> </span><span class="kw">fn </span>inspect_datanode_plan(
<a href=#525 id=525 data-nosnippet>525</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#526 id=526 data-nosnippet>526</a> _request: DatanodeInspectRequest,
<a href=#527 id=527 data-nosnippet>527</a> _schema: SchemaRef,
<a href=#528 id=528 data-nosnippet>528</a> ) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#529 id=529 data-nosnippet>529</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
<a href=#530 id=530 data-nosnippet>530</a> }
<a href=#531 id=531 data-nosnippet>531</a>}
<a href=#532 id=532 data-nosnippet>532</a>
<a href=#533 id=533 data-nosnippet>533</a><span class="doccomment">/// The request to inspect the datanode.
<a href=#534 id=534 data-nosnippet>534</a></span><span class="attr">#[derive(Debug, Clone, PartialEq)]
<a href=#535 id=535 data-nosnippet>535</a></span><span class="kw">pub struct </span>DatanodeInspectRequest {
<a href=#536 id=536 data-nosnippet>536</a> <span class="doccomment">/// Kind to fetch from datanode.
<a href=#537 id=537 data-nosnippet>537</a> </span><span class="kw">pub </span>kind: DatanodeInspectKind,
<a href=#538 id=538 data-nosnippet>538</a>
<a href=#539 id=539 data-nosnippet>539</a> <span class="doccomment">/// Pushdown scan configuration (projection/predicate/limit) for the returned stream.
<a href=#540 id=540 data-nosnippet>540</a> /// This allows server-side filtering to reduce I/O and network costs.
<a href=#541 id=541 data-nosnippet>541</a> </span><span class="kw">pub </span>scan: ScanRequest,
<a href=#542 id=542 data-nosnippet>542</a>}
<a href=#543 id=543 data-nosnippet>543</a>
<a href=#544 id=544 data-nosnippet>544</a><span class="doccomment">/// The kind of the datanode inspect request.
<a href=#545 id=545 data-nosnippet>545</a></span><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq)]
<a href=#546 id=546 data-nosnippet>546</a></span><span class="kw">pub enum </span>DatanodeInspectKind {
<a href=#547 id=547 data-nosnippet>547</a> <span class="doccomment">/// List SST entries recorded in manifest
<a href=#548 id=548 data-nosnippet>548</a> </span>SstManifest,
<a href=#549 id=549 data-nosnippet>549</a> <span class="doccomment">/// List SST entries discovered in storage layer
<a href=#550 id=550 data-nosnippet>550</a> </span>SstStorage,
<a href=#551 id=551 data-nosnippet>551</a> <span class="doccomment">/// List index metadata collected from manifest
<a href=#552 id=552 data-nosnippet>552</a> </span>SstIndexMeta,
<a href=#553 id=553 data-nosnippet>553</a> <span class="doccomment">/// List region runtime and manifest info
<a href=#554 id=554 data-nosnippet>554</a> </span>RegionInfo,
<a href=#555 id=555 data-nosnippet>555</a>}
<a href=#556 id=556 data-nosnippet>556</a>
<a href=#557 id=557 data-nosnippet>557</a><span class="kw">impl </span>DatanodeInspectRequest {
<a href=#558 id=558 data-nosnippet>558</a> <span class="doccomment">/// Builds a logical plan for the datanode inspect request.
<a href=#559 id=559 data-nosnippet>559</a> </span><span class="kw">pub fn </span>build_plan(<span class="self">self</span>) -&gt; std::result::Result&lt;LogicalPlan, DataFusionError&gt; {
<a href=#560 id=560 data-nosnippet>560</a> <span class="kw">match </span><span class="self">self</span>.kind {
<a href=#561 id=561 data-nosnippet>561</a> DatanodeInspectKind::SstManifest =&gt; ManifestSstEntry::build_plan(<span class="self">self</span>.scan),
<a href=#562 id=562 data-nosnippet>562</a> DatanodeInspectKind::SstStorage =&gt; StorageSstEntry::build_plan(<span class="self">self</span>.scan),
<a href=#563 id=563 data-nosnippet>563</a> DatanodeInspectKind::SstIndexMeta =&gt; PuffinIndexMetaEntry::build_plan(<span class="self">self</span>.scan),
<a href=#564 id=564 data-nosnippet>564</a> DatanodeInspectKind::RegionInfo =&gt; RegionInfoEntry::build_plan(<span class="self">self</span>.scan),
<a href=#565 id=565 data-nosnippet>565</a> }
<a href=#566 id=566 data-nosnippet>566</a> }
<a href=#567 id=567 data-nosnippet>567</a>}
<a href=#568 id=568 data-nosnippet>568</a><span class="kw">pub struct </span>NoopInformationExtension;
<a href=#569 id=569 data-nosnippet>569</a>
<a href=#570 id=570 data-nosnippet>570</a><span class="attr">#[async_trait::async_trait]
<a href=#571 id=571 data-nosnippet>571</a></span><span class="kw">impl </span>InformationExtension <span class="kw">for </span>NoopInformationExtension {
<a href=#572 id=572 data-nosnippet>572</a> <span class="kw">type </span>Error = Error;
<a href=#573 id=573 data-nosnippet>573</a>
<a href=#574 id=574 data-nosnippet>574</a> <span class="kw">async fn </span>nodes(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Vec&lt;NodeInfo&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#575 id=575 data-nosnippet>575</a> <span class="prelude-val">Ok</span>(<span class="macro">vec!</span>[])
<a href=#576 id=576 data-nosnippet>576</a> }
<a href=#577 id=577 data-nosnippet>577</a>
<a href=#578 id=578 data-nosnippet>578</a> <span class="kw">async fn </span>procedures(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Vec&lt;(String, ProcedureInfo)&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#579 id=579 data-nosnippet>579</a> <span class="prelude-val">Ok</span>(<span class="macro">vec!</span>[])
<a href=#580 id=580 data-nosnippet>580</a> }
<a href=#581 id=581 data-nosnippet>581</a>
<a href=#582 id=582 data-nosnippet>582</a> <span class="kw">async fn </span>region_stats(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Vec&lt;RegionStat&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#583 id=583 data-nosnippet>583</a> <span class="prelude-val">Ok</span>(<span class="macro">vec!</span>[])
<a href=#584 id=584 data-nosnippet>584</a> }
<a href=#585 id=585 data-nosnippet>585</a>
<a href=#586 id=586 data-nosnippet>586</a> <span class="kw">async fn </span>flow_stats(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;FlowStat&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#587 id=587 data-nosnippet>587</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
<a href=#588 id=588 data-nosnippet>588</a> }
<a href=#589 id=589 data-nosnippet>589</a>
<a href=#590 id=590 data-nosnippet>590</a> <span class="kw">async fn </span>inspect_datanode(
<a href=#591 id=591 data-nosnippet>591</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#592 id=592 data-nosnippet>592</a> _request: DatanodeInspectRequest,
<a href=#593 id=593 data-nosnippet>593</a> ) -&gt; std::result::Result&lt;SendableRecordBatchStream, <span class="self">Self</span>::Error&gt; {
<a href=#594 id=594 data-nosnippet>594</a> <span class="prelude-val">Ok</span>(common_recordbatch::RecordBatches::empty().as_stream())
<a href=#595 id=595 data-nosnippet>595</a> }
<a href=#596 id=596 data-nosnippet>596</a>}
<a href=#597 id=597 data-nosnippet>597</a>
<a href=#598 id=598 data-nosnippet>598</a><span class="attr">#[cfg(test)]
<a href=#599 id=599 data-nosnippet>599</a></span><span class="kw">mod </span>tests {
<a href=#600 id=600 data-nosnippet>600</a> <span class="kw">use </span>store_api::region_info::RegionInfoEntry;
<a href=#601 id=601 data-nosnippet>601</a>
<a href=#602 id=602 data-nosnippet>602</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#603 id=603 data-nosnippet>603</a>
<a href=#604 id=604 data-nosnippet>604</a> <span class="attr">#[test]
<a href=#605 id=605 data-nosnippet>605</a> </span><span class="kw">fn </span>test_datanode_inspect_region_info_build_plan() {
<a href=#606 id=606 data-nosnippet>606</a> <span class="kw">let </span>plan = DatanodeInspectRequest {
<a href=#607 id=607 data-nosnippet>607</a> kind: DatanodeInspectKind::RegionInfo,
<a href=#608 id=608 data-nosnippet>608</a> scan: ScanRequest::default(),
<a href=#609 id=609 data-nosnippet>609</a> }
<a href=#610 id=610 data-nosnippet>610</a> .build_plan()
<a href=#611 id=611 data-nosnippet>611</a> .unwrap();
<a href=#612 id=612 data-nosnippet>612</a>
<a href=#613 id=613 data-nosnippet>613</a> <span class="kw">let </span>LogicalPlan::TableScan(scan) = plan <span class="kw">else </span>{
<a href=#614 id=614 data-nosnippet>614</a> <span class="macro">panic!</span>(<span class="string">"expected table scan"</span>);
<a href=#615 id=615 data-nosnippet>615</a> };
<a href=#616 id=616 data-nosnippet>616</a> <span class="macro">assert_eq!</span>(
<a href=#617 id=617 data-nosnippet>617</a> scan.table_name.to_string(),
<a href=#618 id=618 data-nosnippet>618</a> RegionInfoEntry::reserved_table_name_for_inspection()
<a href=#619 id=619 data-nosnippet>619</a> );
<a href=#620 id=620 data-nosnippet>620</a> }
<a href=#621 id=621 data-nosnippet>621</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,383 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/cluster_info.rs`."><title>cluster_info.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>cluster_info.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::time::Duration;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_CLUSTER_INFO_TABLE_ID;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_meta::cluster::{DatanodeStatus, NodeInfo, NodeStatus};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_time::timestamp::Timestamp;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>common_workload::DatanodeWorkloadType;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, ScalarVectorBuilder, VectorRef};
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>datatypes::timestamp::TimestampMillisecond;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>datatypes::value::Value;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span>datatypes::vectors::{
<a href=#35 id=35 data-nosnippet>35</a> Int64VectorBuilder, StringVectorBuilder, TimestampMillisecondVectorBuilder,
<a href=#36 id=36 data-nosnippet>36</a>};
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>serde::Serialize;
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span>snafu::ResultExt;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span><span class="kw">crate</span>::error::{CreateRecordBatchSnafu, InternalSnafu, <span class="prelude-ty">Result</span>};
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{CLUSTER_INFO, InformationTable, Predicates};
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::utils;
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">const </span>PEER_TYPE_FRONTEND: <span class="kw-2">&amp;</span>str = <span class="string">"FRONTEND"</span>;
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">const </span>PEER_TYPE_METASRV: <span class="kw-2">&amp;</span>str = <span class="string">"METASRV"</span>;
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">const </span>PEER_ID: <span class="kw-2">&amp;</span>str = <span class="string">"peer_id"</span>;
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">const </span>PEER_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"peer_type"</span>;
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">const </span>PEER_ADDR: <span class="kw-2">&amp;</span>str = <span class="string">"peer_addr"</span>;
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">const </span>PEER_HOSTNAME: <span class="kw-2">&amp;</span>str = <span class="string">"peer_hostname"</span>;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">const </span>TOTAL_CPU_MILLICORES: <span class="kw-2">&amp;</span>str = <span class="string">"total_cpu_millicores"</span>;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">const </span>TOTAL_MEMORY_BYTES: <span class="kw-2">&amp;</span>str = <span class="string">"total_memory_bytes"</span>;
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">const </span>CPU_USAGE_MILLICORES: <span class="kw-2">&amp;</span>str = <span class="string">"cpu_usage_millicores"</span>;
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">const </span>MEMORY_USAGE_BYTES: <span class="kw-2">&amp;</span>str = <span class="string">"memory_usage_bytes"</span>;
<a href=#57 id=57 data-nosnippet>57</a><span class="kw">const </span>VERSION: <span class="kw-2">&amp;</span>str = <span class="string">"version"</span>;
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">const </span>GIT_COMMIT: <span class="kw-2">&amp;</span>str = <span class="string">"git_commit"</span>;
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">const </span>START_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"start_time"</span>;
<a href=#60 id=60 data-nosnippet>60</a><span class="kw">const </span>UPTIME: <span class="kw-2">&amp;</span>str = <span class="string">"uptime"</span>;
<a href=#61 id=61 data-nosnippet>61</a><span class="kw">const </span>ACTIVE_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"active_time"</span>;
<a href=#62 id=62 data-nosnippet>62</a><span class="kw">const </span>NODE_STATUS: <span class="kw-2">&amp;</span>str = <span class="string">"node_status"</span>;
<a href=#63 id=63 data-nosnippet>63</a>
<a href=#64 id=64 data-nosnippet>64</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#65 id=65 data-nosnippet>65</a>
<a href=#66 id=66 data-nosnippet>66</a><span class="doccomment">/// The `CLUSTER_INFO` table provides information about the current topology information of the cluster.
<a href=#67 id=67 data-nosnippet>67</a>///
<a href=#68 id=68 data-nosnippet>68</a>/// - `peer_id`: the peer server id.
<a href=#69 id=69 data-nosnippet>69</a>/// - `peer_type`: the peer type, such as `datanode`, `frontend`, `metasrv` etc.
<a href=#70 id=70 data-nosnippet>70</a>/// - `peer_addr`: the peer gRPC address.
<a href=#71 id=71 data-nosnippet>71</a>/// - `peer_hostname`: the hostname of the peer.
<a href=#72 id=72 data-nosnippet>72</a>/// - `total_cpu_millicores`: the total CPU millicores of the peer.
<a href=#73 id=73 data-nosnippet>73</a>/// - `total_memory_bytes`: the total memory bytes of the peer.
<a href=#74 id=74 data-nosnippet>74</a>/// - `cpu_usage_millicores`: the CPU usage millicores of the peer.
<a href=#75 id=75 data-nosnippet>75</a>/// - `memory_usage_bytes`: the memory usage bytes of the peer.
<a href=#76 id=76 data-nosnippet>76</a>/// - `version`: the build package version of the peer.
<a href=#77 id=77 data-nosnippet>77</a>/// - `git_commit`: the build git commit hash of the peer.
<a href=#78 id=78 data-nosnippet>78</a>/// - `start_time`: the starting time of the peer.
<a href=#79 id=79 data-nosnippet>79</a>/// - `uptime`: the uptime of the peer.
<a href=#80 id=80 data-nosnippet>80</a>/// - `active_time`: the time since the last activity of the peer.
<a href=#81 id=81 data-nosnippet>81</a>/// - `node_status`: the status info of the peer.
<a href=#82 id=82 data-nosnippet>82</a>///
<a href=#83 id=83 data-nosnippet>83</a></span><span class="attr">#[derive(Debug)]
<a href=#84 id=84 data-nosnippet>84</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaClusterInfo {
<a href=#85 id=85 data-nosnippet>85</a> schema: SchemaRef,
<a href=#86 id=86 data-nosnippet>86</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#87 id=87 data-nosnippet>87</a>}
<a href=#88 id=88 data-nosnippet>88</a>
<a href=#89 id=89 data-nosnippet>89</a><span class="kw">impl </span>InformationSchemaClusterInfo {
<a href=#90 id=90 data-nosnippet>90</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#91 id=91 data-nosnippet>91</a> <span class="self">Self </span>{
<a href=#92 id=92 data-nosnippet>92</a> schema: <span class="self">Self</span>::schema(),
<a href=#93 id=93 data-nosnippet>93</a> catalog_manager,
<a href=#94 id=94 data-nosnippet>94</a> }
<a href=#95 id=95 data-nosnippet>95</a> }
<a href=#96 id=96 data-nosnippet>96</a>
<a href=#97 id=97 data-nosnippet>97</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#98 id=98 data-nosnippet>98</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#99 id=99 data-nosnippet>99</a> ColumnSchema::new(PEER_ID, ConcreteDataType::int64_datatype(), <span class="bool-val">false</span>),
<a href=#100 id=100 data-nosnippet>100</a> ColumnSchema::new(PEER_TYPE, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#101 id=101 data-nosnippet>101</a> ColumnSchema::new(PEER_ADDR, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#102 id=102 data-nosnippet>102</a> ColumnSchema::new(PEER_HOSTNAME, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#103 id=103 data-nosnippet>103</a> ColumnSchema::new(
<a href=#104 id=104 data-nosnippet>104</a> TOTAL_CPU_MILLICORES,
<a href=#105 id=105 data-nosnippet>105</a> ConcreteDataType::int64_datatype(),
<a href=#106 id=106 data-nosnippet>106</a> <span class="bool-val">false</span>,
<a href=#107 id=107 data-nosnippet>107</a> ),
<a href=#108 id=108 data-nosnippet>108</a> ColumnSchema::new(
<a href=#109 id=109 data-nosnippet>109</a> TOTAL_MEMORY_BYTES,
<a href=#110 id=110 data-nosnippet>110</a> ConcreteDataType::int64_datatype(),
<a href=#111 id=111 data-nosnippet>111</a> <span class="bool-val">false</span>,
<a href=#112 id=112 data-nosnippet>112</a> ),
<a href=#113 id=113 data-nosnippet>113</a> ColumnSchema::new(
<a href=#114 id=114 data-nosnippet>114</a> CPU_USAGE_MILLICORES,
<a href=#115 id=115 data-nosnippet>115</a> ConcreteDataType::int64_datatype(),
<a href=#116 id=116 data-nosnippet>116</a> <span class="bool-val">false</span>,
<a href=#117 id=117 data-nosnippet>117</a> ),
<a href=#118 id=118 data-nosnippet>118</a> ColumnSchema::new(
<a href=#119 id=119 data-nosnippet>119</a> MEMORY_USAGE_BYTES,
<a href=#120 id=120 data-nosnippet>120</a> ConcreteDataType::int64_datatype(),
<a href=#121 id=121 data-nosnippet>121</a> <span class="bool-val">false</span>,
<a href=#122 id=122 data-nosnippet>122</a> ),
<a href=#123 id=123 data-nosnippet>123</a> ColumnSchema::new(VERSION, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#124 id=124 data-nosnippet>124</a> ColumnSchema::new(GIT_COMMIT, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#125 id=125 data-nosnippet>125</a> ColumnSchema::new(
<a href=#126 id=126 data-nosnippet>126</a> START_TIME,
<a href=#127 id=127 data-nosnippet>127</a> ConcreteDataType::timestamp_millisecond_datatype(),
<a href=#128 id=128 data-nosnippet>128</a> <span class="bool-val">true</span>,
<a href=#129 id=129 data-nosnippet>129</a> ),
<a href=#130 id=130 data-nosnippet>130</a> ColumnSchema::new(UPTIME, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#131 id=131 data-nosnippet>131</a> ColumnSchema::new(ACTIVE_TIME, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#132 id=132 data-nosnippet>132</a> ColumnSchema::new(NODE_STATUS, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#133 id=133 data-nosnippet>133</a> ]))
<a href=#134 id=134 data-nosnippet>134</a> }
<a href=#135 id=135 data-nosnippet>135</a>
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaClusterInfoBuilder {
<a href=#137 id=137 data-nosnippet>137</a> InformationSchemaClusterInfoBuilder::new(<span class="self">self</span>.schema.clone(), <span class="self">self</span>.catalog_manager.clone())
<a href=#138 id=138 data-nosnippet>138</a> }
<a href=#139 id=139 data-nosnippet>139</a>}
<a href=#140 id=140 data-nosnippet>140</a>
<a href=#141 id=141 data-nosnippet>141</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaClusterInfo {
<a href=#142 id=142 data-nosnippet>142</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#143 id=143 data-nosnippet>143</a> INFORMATION_SCHEMA_CLUSTER_INFO_TABLE_ID
<a href=#144 id=144 data-nosnippet>144</a> }
<a href=#145 id=145 data-nosnippet>145</a>
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#147 id=147 data-nosnippet>147</a> CLUSTER_INFO
<a href=#148 id=148 data-nosnippet>148</a> }
<a href=#149 id=149 data-nosnippet>149</a>
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#151 id=151 data-nosnippet>151</a> <span class="self">self</span>.schema.clone()
<a href=#152 id=152 data-nosnippet>152</a> }
<a href=#153 id=153 data-nosnippet>153</a>
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#157 id=157 data-nosnippet>157</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#158 id=158 data-nosnippet>158</a> schema,
<a href=#159 id=159 data-nosnippet>159</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#160 id=160 data-nosnippet>160</a> builder
<a href=#161 id=161 data-nosnippet>161</a> .make_cluster_info(<span class="prelude-val">Some</span>(request))
<a href=#162 id=162 data-nosnippet>162</a> .<span class="kw">await
<a href=#163 id=163 data-nosnippet>163</a> </span>.map(|x| x.into_df_record_batch())
<a href=#164 id=164 data-nosnippet>164</a> .map_err(Into::into)
<a href=#165 id=165 data-nosnippet>165</a> }),
<a href=#166 id=166 data-nosnippet>166</a> ));
<a href=#167 id=167 data-nosnippet>167</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#168 id=168 data-nosnippet>168</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#169 id=169 data-nosnippet>169</a> .map_err(BoxedError::new)
<a href=#170 id=170 data-nosnippet>170</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#171 id=171 data-nosnippet>171</a> ))
<a href=#172 id=172 data-nosnippet>172</a> }
<a href=#173 id=173 data-nosnippet>173</a>}
<a href=#174 id=174 data-nosnippet>174</a>
<a href=#175 id=175 data-nosnippet>175</a><span class="kw">struct </span>InformationSchemaClusterInfoBuilder {
<a href=#176 id=176 data-nosnippet>176</a> schema: SchemaRef,
<a href=#177 id=177 data-nosnippet>177</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#178 id=178 data-nosnippet>178</a>
<a href=#179 id=179 data-nosnippet>179</a> peer_ids: Int64VectorBuilder,
<a href=#180 id=180 data-nosnippet>180</a> peer_types: StringVectorBuilder,
<a href=#181 id=181 data-nosnippet>181</a> peer_addrs: StringVectorBuilder,
<a href=#182 id=182 data-nosnippet>182</a> peer_hostnames: StringVectorBuilder,
<a href=#183 id=183 data-nosnippet>183</a> total_cpu_millicores: Int64VectorBuilder,
<a href=#184 id=184 data-nosnippet>184</a> total_memory_bytes: Int64VectorBuilder,
<a href=#185 id=185 data-nosnippet>185</a> cpu_usage_millicores: Int64VectorBuilder,
<a href=#186 id=186 data-nosnippet>186</a> memory_usage_bytes: Int64VectorBuilder,
<a href=#187 id=187 data-nosnippet>187</a> versions: StringVectorBuilder,
<a href=#188 id=188 data-nosnippet>188</a> git_commits: StringVectorBuilder,
<a href=#189 id=189 data-nosnippet>189</a> start_times: TimestampMillisecondVectorBuilder,
<a href=#190 id=190 data-nosnippet>190</a> uptimes: StringVectorBuilder,
<a href=#191 id=191 data-nosnippet>191</a> active_times: StringVectorBuilder,
<a href=#192 id=192 data-nosnippet>192</a> node_status: StringVectorBuilder,
<a href=#193 id=193 data-nosnippet>193</a>}
<a href=#194 id=194 data-nosnippet>194</a>
<a href=#195 id=195 data-nosnippet>195</a><span class="kw">impl </span>InformationSchemaClusterInfoBuilder {
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">fn </span>new(schema: SchemaRef, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#197 id=197 data-nosnippet>197</a> <span class="self">Self </span>{
<a href=#198 id=198 data-nosnippet>198</a> schema,
<a href=#199 id=199 data-nosnippet>199</a> catalog_manager,
<a href=#200 id=200 data-nosnippet>200</a> peer_ids: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#201 id=201 data-nosnippet>201</a> peer_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#202 id=202 data-nosnippet>202</a> peer_addrs: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#203 id=203 data-nosnippet>203</a> peer_hostnames: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#204 id=204 data-nosnippet>204</a> total_cpu_millicores: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#205 id=205 data-nosnippet>205</a> total_memory_bytes: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#206 id=206 data-nosnippet>206</a> cpu_usage_millicores: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#207 id=207 data-nosnippet>207</a> memory_usage_bytes: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#208 id=208 data-nosnippet>208</a> versions: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#209 id=209 data-nosnippet>209</a> git_commits: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#210 id=210 data-nosnippet>210</a> start_times: TimestampMillisecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#211 id=211 data-nosnippet>211</a> uptimes: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#212 id=212 data-nosnippet>212</a> active_times: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#213 id=213 data-nosnippet>213</a> node_status: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#214 id=214 data-nosnippet>214</a> }
<a href=#215 id=215 data-nosnippet>215</a> }
<a href=#216 id=216 data-nosnippet>216</a>
<a href=#217 id=217 data-nosnippet>217</a> <span class="doccomment">/// Construct the `information_schema.cluster_info` virtual table
<a href=#218 id=218 data-nosnippet>218</a> </span><span class="kw">async fn </span>make_cluster_info(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#219 id=219 data-nosnippet>219</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">let </span>information_extension = utils::information_extension(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#221 id=221 data-nosnippet>221</a> <span class="kw">let </span>node_infos = information_extension.nodes().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#222 id=222 data-nosnippet>222</a> <span class="kw">for </span>node_info <span class="kw">in </span>node_infos {
<a href=#223 id=223 data-nosnippet>223</a> <span class="self">self</span>.add_node_info(<span class="kw-2">&amp;</span>predicates, node_info);
<a href=#224 id=224 data-nosnippet>224</a> }
<a href=#225 id=225 data-nosnippet>225</a> <span class="self">self</span>.finish()
<a href=#226 id=226 data-nosnippet>226</a> }
<a href=#227 id=227 data-nosnippet>227</a>
<a href=#228 id=228 data-nosnippet>228</a> <span class="kw">fn </span>add_node_info(<span class="kw-2">&amp;mut </span><span class="self">self</span>, predicates: <span class="kw-2">&amp;</span>Predicates, node_info: NodeInfo) {
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">let </span>peer_type = node_info.status.role_name();
<a href=#230 id=230 data-nosnippet>230</a> <span class="kw">let </span>peer_id = peer_id(peer_type, node_info.peer.id);
<a href=#231 id=231 data-nosnippet>231</a>
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">let </span>row = [
<a href=#233 id=233 data-nosnippet>233</a> (PEER_ID, <span class="kw-2">&amp;</span>Value::from(peer_id)),
<a href=#234 id=234 data-nosnippet>234</a> (PEER_TYPE, <span class="kw-2">&amp;</span>Value::from(peer_type)),
<a href=#235 id=235 data-nosnippet>235</a> (PEER_ADDR, <span class="kw-2">&amp;</span>Value::from(node_info.peer.addr.as_str())),
<a href=#236 id=236 data-nosnippet>236</a> (PEER_HOSTNAME, <span class="kw-2">&amp;</span>Value::from(node_info.hostname.as_str())),
<a href=#237 id=237 data-nosnippet>237</a> (VERSION, <span class="kw-2">&amp;</span>Value::from(node_info.version.as_str())),
<a href=#238 id=238 data-nosnippet>238</a> (GIT_COMMIT, <span class="kw-2">&amp;</span>Value::from(node_info.git_commit.as_str())),
<a href=#239 id=239 data-nosnippet>239</a> ];
<a href=#240 id=240 data-nosnippet>240</a>
<a href=#241 id=241 data-nosnippet>241</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">return</span>;
<a href=#243 id=243 data-nosnippet>243</a> }
<a href=#244 id=244 data-nosnippet>244</a>
<a href=#245 id=245 data-nosnippet>245</a> <span class="self">self</span>.peer_ids.push(<span class="prelude-val">Some</span>(peer_id));
<a href=#246 id=246 data-nosnippet>246</a> <span class="self">self</span>.peer_types.push(<span class="prelude-val">Some</span>(peer_type));
<a href=#247 id=247 data-nosnippet>247</a> <span class="self">self</span>.peer_addrs.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>node_info.peer.addr));
<a href=#248 id=248 data-nosnippet>248</a> <span class="self">self</span>.peer_hostnames.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>node_info.hostname));
<a href=#249 id=249 data-nosnippet>249</a> <span class="self">self</span>.versions.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>node_info.version));
<a href=#250 id=250 data-nosnippet>250</a> <span class="self">self</span>.git_commits.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>node_info.git_commit));
<a href=#251 id=251 data-nosnippet>251</a> <span class="kw">if </span>node_info.start_time_ms &gt; <span class="number">0 </span>{
<a href=#252 id=252 data-nosnippet>252</a> <span class="self">self</span>.start_times
<a href=#253 id=253 data-nosnippet>253</a> .push(<span class="prelude-val">Some</span>(TimestampMillisecond(Timestamp::new_millisecond(
<a href=#254 id=254 data-nosnippet>254</a> node_info.start_time_ms <span class="kw">as </span>i64,
<a href=#255 id=255 data-nosnippet>255</a> ))));
<a href=#256 id=256 data-nosnippet>256</a> <span class="self">self</span>.uptimes.push(<span class="prelude-val">Some</span>(
<a href=#257 id=257 data-nosnippet>257</a> <span class="self">Self</span>::format_duration_since(node_info.start_time_ms).as_str(),
<a href=#258 id=258 data-nosnippet>258</a> ));
<a href=#259 id=259 data-nosnippet>259</a> } <span class="kw">else </span>{
<a href=#260 id=260 data-nosnippet>260</a> <span class="self">self</span>.start_times.push(<span class="prelude-val">None</span>);
<a href=#261 id=261 data-nosnippet>261</a> <span class="self">self</span>.uptimes.push(<span class="prelude-val">None</span>);
<a href=#262 id=262 data-nosnippet>262</a> }
<a href=#263 id=263 data-nosnippet>263</a> <span class="self">self</span>.total_cpu_millicores
<a href=#264 id=264 data-nosnippet>264</a> .push(<span class="prelude-val">Some</span>(node_info.total_cpu_millicores));
<a href=#265 id=265 data-nosnippet>265</a> <span class="self">self</span>.total_memory_bytes
<a href=#266 id=266 data-nosnippet>266</a> .push(<span class="prelude-val">Some</span>(node_info.total_memory_bytes));
<a href=#267 id=267 data-nosnippet>267</a> <span class="self">self</span>.cpu_usage_millicores
<a href=#268 id=268 data-nosnippet>268</a> .push(<span class="prelude-val">Some</span>(node_info.cpu_usage_millicores));
<a href=#269 id=269 data-nosnippet>269</a> <span class="self">self</span>.memory_usage_bytes
<a href=#270 id=270 data-nosnippet>270</a> .push(<span class="prelude-val">Some</span>(node_info.memory_usage_bytes));
<a href=#271 id=271 data-nosnippet>271</a>
<a href=#272 id=272 data-nosnippet>272</a> <span class="kw">if </span>node_info.last_activity_ts &gt; <span class="number">0 </span>{
<a href=#273 id=273 data-nosnippet>273</a> <span class="self">self</span>.active_times.push(<span class="prelude-val">Some</span>(
<a href=#274 id=274 data-nosnippet>274</a> <span class="self">Self</span>::format_duration_since(node_info.last_activity_ts <span class="kw">as </span>u64).as_str(),
<a href=#275 id=275 data-nosnippet>275</a> ));
<a href=#276 id=276 data-nosnippet>276</a> } <span class="kw">else </span>{
<a href=#277 id=277 data-nosnippet>277</a> <span class="self">self</span>.active_times.push(<span class="prelude-val">None</span>);
<a href=#278 id=278 data-nosnippet>278</a> }
<a href=#279 id=279 data-nosnippet>279</a> <span class="self">self</span>.node_status
<a href=#280 id=280 data-nosnippet>280</a> .push(format_node_status(<span class="kw-2">&amp;</span>node_info).as_deref());
<a href=#281 id=281 data-nosnippet>281</a> }
<a href=#282 id=282 data-nosnippet>282</a>
<a href=#283 id=283 data-nosnippet>283</a> <span class="kw">fn </span>format_duration_since(ts: u64) -&gt; String {
<a href=#284 id=284 data-nosnippet>284</a> <span class="kw">let </span>now = common_time::util::current_time_millis() <span class="kw">as </span>u64;
<a href=#285 id=285 data-nosnippet>285</a> <span class="kw">let </span>duration_since = now - ts;
<a href=#286 id=286 data-nosnippet>286</a> humantime::format_duration(Duration::from_millis(duration_since)).to_string()
<a href=#287 id=287 data-nosnippet>287</a> }
<a href=#288 id=288 data-nosnippet>288</a>
<a href=#289 id=289 data-nosnippet>289</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#290 id=290 data-nosnippet>290</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#291 id=291 data-nosnippet>291</a> Arc::new(<span class="self">self</span>.peer_ids.finish()),
<a href=#292 id=292 data-nosnippet>292</a> Arc::new(<span class="self">self</span>.peer_types.finish()),
<a href=#293 id=293 data-nosnippet>293</a> Arc::new(<span class="self">self</span>.peer_addrs.finish()),
<a href=#294 id=294 data-nosnippet>294</a> Arc::new(<span class="self">self</span>.peer_hostnames.finish()),
<a href=#295 id=295 data-nosnippet>295</a> Arc::new(<span class="self">self</span>.total_cpu_millicores.finish()),
<a href=#296 id=296 data-nosnippet>296</a> Arc::new(<span class="self">self</span>.total_memory_bytes.finish()),
<a href=#297 id=297 data-nosnippet>297</a> Arc::new(<span class="self">self</span>.cpu_usage_millicores.finish()),
<a href=#298 id=298 data-nosnippet>298</a> Arc::new(<span class="self">self</span>.memory_usage_bytes.finish()),
<a href=#299 id=299 data-nosnippet>299</a> Arc::new(<span class="self">self</span>.versions.finish()),
<a href=#300 id=300 data-nosnippet>300</a> Arc::new(<span class="self">self</span>.git_commits.finish()),
<a href=#301 id=301 data-nosnippet>301</a> Arc::new(<span class="self">self</span>.start_times.finish()),
<a href=#302 id=302 data-nosnippet>302</a> Arc::new(<span class="self">self</span>.uptimes.finish()),
<a href=#303 id=303 data-nosnippet>303</a> Arc::new(<span class="self">self</span>.active_times.finish()),
<a href=#304 id=304 data-nosnippet>304</a> Arc::new(<span class="self">self</span>.node_status.finish()),
<a href=#305 id=305 data-nosnippet>305</a> ];
<a href=#306 id=306 data-nosnippet>306</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#307 id=307 data-nosnippet>307</a> }
<a href=#308 id=308 data-nosnippet>308</a>}
<a href=#309 id=309 data-nosnippet>309</a>
<a href=#310 id=310 data-nosnippet>310</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaClusterInfo {
<a href=#311 id=311 data-nosnippet>311</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#312 id=312 data-nosnippet>312</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#313 id=313 data-nosnippet>313</a> }
<a href=#314 id=314 data-nosnippet>314</a>
<a href=#315 id=315 data-nosnippet>315</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#316 id=316 data-nosnippet>316</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#317 id=317 data-nosnippet>317</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#318 id=318 data-nosnippet>318</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#319 id=319 data-nosnippet>319</a> schema,
<a href=#320 id=320 data-nosnippet>320</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#321 id=321 data-nosnippet>321</a> builder
<a href=#322 id=322 data-nosnippet>322</a> .make_cluster_info(<span class="prelude-val">None</span>)
<a href=#323 id=323 data-nosnippet>323</a> .<span class="kw">await
<a href=#324 id=324 data-nosnippet>324</a> </span>.map(|x| x.into_df_record_batch())
<a href=#325 id=325 data-nosnippet>325</a> .map_err(Into::into)
<a href=#326 id=326 data-nosnippet>326</a> }),
<a href=#327 id=327 data-nosnippet>327</a> ))
<a href=#328 id=328 data-nosnippet>328</a> }
<a href=#329 id=329 data-nosnippet>329</a>}
<a href=#330 id=330 data-nosnippet>330</a>
<a href=#331 id=331 data-nosnippet>331</a><span class="kw">fn </span>peer_id(peer_type: <span class="kw-2">&amp;</span>str, peer_id: u64) -&gt; i64 {
<a href=#332 id=332 data-nosnippet>332</a> <span class="kw">if </span>peer_type == PEER_TYPE_FRONTEND || peer_type == PEER_TYPE_METASRV {
<a href=#333 id=333 data-nosnippet>333</a> -<span class="number">1
<a href=#334 id=334 data-nosnippet>334</a> </span>} <span class="kw">else </span>{
<a href=#335 id=335 data-nosnippet>335</a> peer_id <span class="kw">as </span>i64
<a href=#336 id=336 data-nosnippet>336</a> }
<a href=#337 id=337 data-nosnippet>337</a>}
<a href=#338 id=338 data-nosnippet>338</a>
<a href=#339 id=339 data-nosnippet>339</a><span class="attr">#[derive(Serialize)]
<a href=#340 id=340 data-nosnippet>340</a></span><span class="kw">struct </span>DisplayMetasrvStatus {
<a href=#341 id=341 data-nosnippet>341</a> is_leader: bool,
<a href=#342 id=342 data-nosnippet>342</a>}
<a href=#343 id=343 data-nosnippet>343</a>
<a href=#344 id=344 data-nosnippet>344</a><span class="attr">#[derive(Serialize)]
<a href=#345 id=345 data-nosnippet>345</a></span><span class="kw">struct </span>DisplayDatanodeStatus {
<a href=#346 id=346 data-nosnippet>346</a> workloads: Vec&lt;DatanodeWorkloadType&gt;,
<a href=#347 id=347 data-nosnippet>347</a> leader_regions: usize,
<a href=#348 id=348 data-nosnippet>348</a> follower_regions: usize,
<a href=#349 id=349 data-nosnippet>349</a>}
<a href=#350 id=350 data-nosnippet>350</a>
<a href=#351 id=351 data-nosnippet>351</a><span class="kw">impl </span>From&lt;<span class="kw-2">&amp;</span>DatanodeStatus&gt; <span class="kw">for </span>DisplayDatanodeStatus {
<a href=#352 id=352 data-nosnippet>352</a> <span class="kw">fn </span>from(status: <span class="kw-2">&amp;</span>DatanodeStatus) -&gt; <span class="self">Self </span>{
<a href=#353 id=353 data-nosnippet>353</a> <span class="self">Self </span>{
<a href=#354 id=354 data-nosnippet>354</a> workloads: status
<a href=#355 id=355 data-nosnippet>355</a> .workloads
<a href=#356 id=356 data-nosnippet>356</a> .types
<a href=#357 id=357 data-nosnippet>357</a> .iter()
<a href=#358 id=358 data-nosnippet>358</a> .flat_map(|w| DatanodeWorkloadType::from_i32(<span class="kw-2">*</span>w))
<a href=#359 id=359 data-nosnippet>359</a> .collect(),
<a href=#360 id=360 data-nosnippet>360</a> leader_regions: status.leader_regions,
<a href=#361 id=361 data-nosnippet>361</a> follower_regions: status.follower_regions,
<a href=#362 id=362 data-nosnippet>362</a> }
<a href=#363 id=363 data-nosnippet>363</a> }
<a href=#364 id=364 data-nosnippet>364</a>}
<a href=#365 id=365 data-nosnippet>365</a>
<a href=#366 id=366 data-nosnippet>366</a><span class="kw">fn </span>format_node_status(node_info: <span class="kw-2">&amp;</span>NodeInfo) -&gt; <span class="prelude-ty">Option</span>&lt;String&gt; {
<a href=#367 id=367 data-nosnippet>367</a> <span class="kw">match </span><span class="kw-2">&amp;</span>node_info.status {
<a href=#368 id=368 data-nosnippet>368</a> NodeStatus::Datanode(datanode_status) =&gt; {
<a href=#369 id=369 data-nosnippet>369</a> serde_json::to_string(<span class="kw-2">&amp;</span>DisplayDatanodeStatus::from(datanode_status)).ok()
<a href=#370 id=370 data-nosnippet>370</a> }
<a href=#371 id=371 data-nosnippet>371</a> NodeStatus::Frontend(<span class="kw">_</span>) =&gt; <span class="prelude-val">None</span>,
<a href=#372 id=372 data-nosnippet>372</a> NodeStatus::Flownode(<span class="kw">_</span>) =&gt; <span class="prelude-val">None</span>,
<a href=#373 id=373 data-nosnippet>373</a> NodeStatus::Metasrv(metasrv_status) =&gt; {
<a href=#374 id=374 data-nosnippet>374</a> <span class="kw">if </span>metasrv_status.is_leader {
<a href=#375 id=375 data-nosnippet>375</a> serde_json::to_string(<span class="kw-2">&amp;</span>DisplayMetasrvStatus { is_leader: <span class="bool-val">true </span>}).ok()
<a href=#376 id=376 data-nosnippet>376</a> } <span class="kw">else </span>{
<a href=#377 id=377 data-nosnippet>377</a> <span class="prelude-val">None
<a href=#378 id=378 data-nosnippet>378</a> </span>}
<a href=#379 id=379 data-nosnippet>379</a> }
<a href=#380 id=380 data-nosnippet>380</a> NodeStatus::Standalone =&gt; <span class="prelude-val">None</span>,
<a href=#381 id=381 data-nosnippet>381</a> }
<a href=#382 id=382 data-nosnippet>382</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,466 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/columns.rs`."><title>columns.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>columns.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_catalog::consts::{
<a href=#19 id=19 data-nosnippet>19</a> INFORMATION_SCHEMA_COLUMNS_TABLE_ID, SEMANTIC_TYPE_FIELD, SEMANTIC_TYPE_PRIMARY_KEY,
<a href=#20 id=20 data-nosnippet>20</a> SEMANTIC_TYPE_TIME_INDEX,
<a href=#21 id=21 data-nosnippet>21</a>};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, DataType, MutableVector};
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datatypes::scalars::ScalarVectorBuilder;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>datatypes::value::Value;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>datatypes::vectors::{
<a href=#34 id=34 data-nosnippet>34</a> Int64Vector, Int64VectorBuilder, StringVector, StringVectorBuilder, VectorRef,
<a href=#35 id=35 data-nosnippet>35</a>};
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>futures::TryStreamExt;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>snafu::{OptionExt, ResultExt};
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span>sql::statements;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#43 id=43 data-nosnippet>43</a> CreateRecordBatchSnafu, InternalSnafu, <span class="prelude-ty">Result</span>, UpgradeWeakCatalogManagerRefSnafu,
<a href=#44 id=44 data-nosnippet>44</a>};
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::Predicates;
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{COLUMNS, InformationTable};
<a href=#47 id=47 data-nosnippet>47</a>
<a href=#48 id=48 data-nosnippet>48</a><span class="attr">#[derive(Debug)]
<a href=#49 id=49 data-nosnippet>49</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaColumns {
<a href=#50 id=50 data-nosnippet>50</a> schema: SchemaRef,
<a href=#51 id=51 data-nosnippet>51</a> catalog_name: String,
<a href=#52 id=52 data-nosnippet>52</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#53 id=53 data-nosnippet>53</a>}
<a href=#54 id=54 data-nosnippet>54</a>
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">pub const </span>TABLE_CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"table_catalog"</span>;
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">pub const </span>TABLE_SCHEMA: <span class="kw-2">&amp;</span>str = <span class="string">"table_schema"</span>;
<a href=#57 id=57 data-nosnippet>57</a><span class="kw">pub const </span>TABLE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_name"</span>;
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">pub const </span>COLUMN_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"column_name"</span>;
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">pub const </span>REGION_ID: <span class="kw-2">&amp;</span>str = <span class="string">"region_id"</span>;
<a href=#60 id=60 data-nosnippet>60</a><span class="kw">pub const </span>PEER_ID: <span class="kw-2">&amp;</span>str = <span class="string">"peer_id"</span>;
<a href=#61 id=61 data-nosnippet>61</a><span class="kw">const </span>ORDINAL_POSITION: <span class="kw-2">&amp;</span>str = <span class="string">"ordinal_position"</span>;
<a href=#62 id=62 data-nosnippet>62</a><span class="kw">const </span>CHARACTER_MAXIMUM_LENGTH: <span class="kw-2">&amp;</span>str = <span class="string">"character_maximum_length"</span>;
<a href=#63 id=63 data-nosnippet>63</a><span class="kw">const </span>CHARACTER_OCTET_LENGTH: <span class="kw-2">&amp;</span>str = <span class="string">"character_octet_length"</span>;
<a href=#64 id=64 data-nosnippet>64</a><span class="kw">const </span>NUMERIC_PRECISION: <span class="kw-2">&amp;</span>str = <span class="string">"numeric_precision"</span>;
<a href=#65 id=65 data-nosnippet>65</a><span class="kw">const </span>NUMERIC_SCALE: <span class="kw-2">&amp;</span>str = <span class="string">"numeric_scale"</span>;
<a href=#66 id=66 data-nosnippet>66</a><span class="kw">const </span>DATETIME_PRECISION: <span class="kw-2">&amp;</span>str = <span class="string">"datetime_precision"</span>;
<a href=#67 id=67 data-nosnippet>67</a><span class="kw">const </span>CHARACTER_SET_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"character_set_name"</span>;
<a href=#68 id=68 data-nosnippet>68</a><span class="kw">pub const </span>COLLATION_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"collation_name"</span>;
<a href=#69 id=69 data-nosnippet>69</a><span class="kw">pub const </span>COLUMN_KEY: <span class="kw-2">&amp;</span>str = <span class="string">"column_key"</span>;
<a href=#70 id=70 data-nosnippet>70</a><span class="kw">pub const </span>EXTRA: <span class="kw-2">&amp;</span>str = <span class="string">"extra"</span>;
<a href=#71 id=71 data-nosnippet>71</a><span class="kw">pub const </span>PRIVILEGES: <span class="kw-2">&amp;</span>str = <span class="string">"privileges"</span>;
<a href=#72 id=72 data-nosnippet>72</a><span class="kw">const </span>GENERATION_EXPRESSION: <span class="kw-2">&amp;</span>str = <span class="string">"generation_expression"</span>;
<a href=#73 id=73 data-nosnippet>73</a><span class="comment">// Extension field to keep greptime data type name
<a href=#74 id=74 data-nosnippet>74</a></span><span class="kw">pub const </span>GREPTIME_DATA_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"greptime_data_type"</span>;
<a href=#75 id=75 data-nosnippet>75</a><span class="kw">pub const </span>DATA_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"data_type"</span>;
<a href=#76 id=76 data-nosnippet>76</a><span class="kw">pub const </span>SEMANTIC_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"semantic_type"</span>;
<a href=#77 id=77 data-nosnippet>77</a><span class="kw">pub const </span>COLUMN_DEFAULT: <span class="kw-2">&amp;</span>str = <span class="string">"column_default"</span>;
<a href=#78 id=78 data-nosnippet>78</a><span class="kw">pub const </span>IS_NULLABLE: <span class="kw-2">&amp;</span>str = <span class="string">"is_nullable"</span>;
<a href=#79 id=79 data-nosnippet>79</a><span class="kw">const </span>COLUMN_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"column_type"</span>;
<a href=#80 id=80 data-nosnippet>80</a><span class="kw">pub const </span>COLUMN_COMMENT: <span class="kw-2">&amp;</span>str = <span class="string">"column_comment"</span>;
<a href=#81 id=81 data-nosnippet>81</a><span class="kw">const </span>SRS_ID: <span class="kw-2">&amp;</span>str = <span class="string">"srs_id"</span>;
<a href=#82 id=82 data-nosnippet>82</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#83 id=83 data-nosnippet>83</a>
<a href=#84 id=84 data-nosnippet>84</a><span class="comment">// The maximum length of string type
<a href=#85 id=85 data-nosnippet>85</a></span><span class="kw">const </span>MAX_STRING_LENGTH: i64 = <span class="number">2147483647</span>;
<a href=#86 id=86 data-nosnippet>86</a><span class="kw">const </span>UTF8_CHARSET_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"utf8"</span>;
<a href=#87 id=87 data-nosnippet>87</a><span class="kw">const </span>UTF8_COLLATE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"utf8_bin"</span>;
<a href=#88 id=88 data-nosnippet>88</a><span class="kw">const </span>PRI_COLUMN_KEY: <span class="kw-2">&amp;</span>str = <span class="string">"PRI"</span>;
<a href=#89 id=89 data-nosnippet>89</a><span class="kw">const </span>TIME_INDEX_COLUMN_KEY: <span class="kw-2">&amp;</span>str = <span class="string">"TIME INDEX"</span>;
<a href=#90 id=90 data-nosnippet>90</a><span class="kw">const </span>DEFAULT_PRIVILEGES: <span class="kw-2">&amp;</span>str = <span class="string">"select,insert"</span>;
<a href=#91 id=91 data-nosnippet>91</a><span class="kw">const </span>EMPTY_STR: <span class="kw-2">&amp;</span>str = <span class="string">""</span>;
<a href=#92 id=92 data-nosnippet>92</a><span class="kw">const </span>YES: <span class="kw-2">&amp;</span>str = <span class="string">"YES"</span>;
<a href=#93 id=93 data-nosnippet>93</a><span class="kw">const </span>NO: <span class="kw-2">&amp;</span>str = <span class="string">"NO"</span>;
<a href=#94 id=94 data-nosnippet>94</a>
<a href=#95 id=95 data-nosnippet>95</a><span class="kw">impl </span>InformationSchemaColumns {
<a href=#96 id=96 data-nosnippet>96</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_name: String, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#97 id=97 data-nosnippet>97</a> <span class="self">Self </span>{
<a href=#98 id=98 data-nosnippet>98</a> schema: <span class="self">Self</span>::schema(),
<a href=#99 id=99 data-nosnippet>99</a> catalog_name,
<a href=#100 id=100 data-nosnippet>100</a> catalog_manager,
<a href=#101 id=101 data-nosnippet>101</a> }
<a href=#102 id=102 data-nosnippet>102</a> }
<a href=#103 id=103 data-nosnippet>103</a>
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#105 id=105 data-nosnippet>105</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#106 id=106 data-nosnippet>106</a> ColumnSchema::new(TABLE_CATALOG, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#107 id=107 data-nosnippet>107</a> ColumnSchema::new(TABLE_SCHEMA, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#108 id=108 data-nosnippet>108</a> ColumnSchema::new(TABLE_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#109 id=109 data-nosnippet>109</a> ColumnSchema::new(COLUMN_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#110 id=110 data-nosnippet>110</a> ColumnSchema::new(ORDINAL_POSITION, ConcreteDataType::int64_datatype(), <span class="bool-val">false</span>),
<a href=#111 id=111 data-nosnippet>111</a> ColumnSchema::new(
<a href=#112 id=112 data-nosnippet>112</a> CHARACTER_MAXIMUM_LENGTH,
<a href=#113 id=113 data-nosnippet>113</a> ConcreteDataType::int64_datatype(),
<a href=#114 id=114 data-nosnippet>114</a> <span class="bool-val">true</span>,
<a href=#115 id=115 data-nosnippet>115</a> ),
<a href=#116 id=116 data-nosnippet>116</a> ColumnSchema::new(
<a href=#117 id=117 data-nosnippet>117</a> CHARACTER_OCTET_LENGTH,
<a href=#118 id=118 data-nosnippet>118</a> ConcreteDataType::int64_datatype(),
<a href=#119 id=119 data-nosnippet>119</a> <span class="bool-val">true</span>,
<a href=#120 id=120 data-nosnippet>120</a> ),
<a href=#121 id=121 data-nosnippet>121</a> ColumnSchema::new(NUMERIC_PRECISION, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#122 id=122 data-nosnippet>122</a> ColumnSchema::new(NUMERIC_SCALE, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#123 id=123 data-nosnippet>123</a> ColumnSchema::new(DATETIME_PRECISION, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#124 id=124 data-nosnippet>124</a> ColumnSchema::new(
<a href=#125 id=125 data-nosnippet>125</a> CHARACTER_SET_NAME,
<a href=#126 id=126 data-nosnippet>126</a> ConcreteDataType::string_datatype(),
<a href=#127 id=127 data-nosnippet>127</a> <span class="bool-val">true</span>,
<a href=#128 id=128 data-nosnippet>128</a> ),
<a href=#129 id=129 data-nosnippet>129</a> ColumnSchema::new(COLLATION_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#130 id=130 data-nosnippet>130</a> ColumnSchema::new(COLUMN_KEY, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#131 id=131 data-nosnippet>131</a> ColumnSchema::new(EXTRA, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#132 id=132 data-nosnippet>132</a> ColumnSchema::new(PRIVILEGES, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#133 id=133 data-nosnippet>133</a> ColumnSchema::new(
<a href=#134 id=134 data-nosnippet>134</a> GENERATION_EXPRESSION,
<a href=#135 id=135 data-nosnippet>135</a> ConcreteDataType::string_datatype(),
<a href=#136 id=136 data-nosnippet>136</a> <span class="bool-val">false</span>,
<a href=#137 id=137 data-nosnippet>137</a> ),
<a href=#138 id=138 data-nosnippet>138</a> ColumnSchema::new(
<a href=#139 id=139 data-nosnippet>139</a> GREPTIME_DATA_TYPE,
<a href=#140 id=140 data-nosnippet>140</a> ConcreteDataType::string_datatype(),
<a href=#141 id=141 data-nosnippet>141</a> <span class="bool-val">false</span>,
<a href=#142 id=142 data-nosnippet>142</a> ),
<a href=#143 id=143 data-nosnippet>143</a> ColumnSchema::new(DATA_TYPE, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#144 id=144 data-nosnippet>144</a> ColumnSchema::new(SEMANTIC_TYPE, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#145 id=145 data-nosnippet>145</a> ColumnSchema::new(COLUMN_DEFAULT, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#146 id=146 data-nosnippet>146</a> ColumnSchema::new(IS_NULLABLE, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#147 id=147 data-nosnippet>147</a> ColumnSchema::new(COLUMN_TYPE, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#148 id=148 data-nosnippet>148</a> ColumnSchema::new(COLUMN_COMMENT, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#149 id=149 data-nosnippet>149</a> ColumnSchema::new(SRS_ID, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#150 id=150 data-nosnippet>150</a> ]))
<a href=#151 id=151 data-nosnippet>151</a> }
<a href=#152 id=152 data-nosnippet>152</a>
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaColumnsBuilder {
<a href=#154 id=154 data-nosnippet>154</a> InformationSchemaColumnsBuilder::new(
<a href=#155 id=155 data-nosnippet>155</a> <span class="self">self</span>.schema.clone(),
<a href=#156 id=156 data-nosnippet>156</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#157 id=157 data-nosnippet>157</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#158 id=158 data-nosnippet>158</a> )
<a href=#159 id=159 data-nosnippet>159</a> }
<a href=#160 id=160 data-nosnippet>160</a>}
<a href=#161 id=161 data-nosnippet>161</a>
<a href=#162 id=162 data-nosnippet>162</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaColumns {
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#164 id=164 data-nosnippet>164</a> INFORMATION_SCHEMA_COLUMNS_TABLE_ID
<a href=#165 id=165 data-nosnippet>165</a> }
<a href=#166 id=166 data-nosnippet>166</a>
<a href=#167 id=167 data-nosnippet>167</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#168 id=168 data-nosnippet>168</a> COLUMNS
<a href=#169 id=169 data-nosnippet>169</a> }
<a href=#170 id=170 data-nosnippet>170</a>
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#172 id=172 data-nosnippet>172</a> <span class="self">self</span>.schema.clone()
<a href=#173 id=173 data-nosnippet>173</a> }
<a href=#174 id=174 data-nosnippet>174</a>
<a href=#175 id=175 data-nosnippet>175</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#176 id=176 data-nosnippet>176</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#177 id=177 data-nosnippet>177</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#179 id=179 data-nosnippet>179</a> schema,
<a href=#180 id=180 data-nosnippet>180</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#181 id=181 data-nosnippet>181</a> builder
<a href=#182 id=182 data-nosnippet>182</a> .make_columns(<span class="prelude-val">Some</span>(request))
<a href=#183 id=183 data-nosnippet>183</a> .<span class="kw">await
<a href=#184 id=184 data-nosnippet>184</a> </span>.map(|x| x.into_df_record_batch())
<a href=#185 id=185 data-nosnippet>185</a> .map_err(Into::into)
<a href=#186 id=186 data-nosnippet>186</a> }),
<a href=#187 id=187 data-nosnippet>187</a> ));
<a href=#188 id=188 data-nosnippet>188</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#189 id=189 data-nosnippet>189</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#190 id=190 data-nosnippet>190</a> .map_err(BoxedError::new)
<a href=#191 id=191 data-nosnippet>191</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#192 id=192 data-nosnippet>192</a> ))
<a href=#193 id=193 data-nosnippet>193</a> }
<a href=#194 id=194 data-nosnippet>194</a>}
<a href=#195 id=195 data-nosnippet>195</a>
<a href=#196 id=196 data-nosnippet>196</a><span class="kw">struct </span>InformationSchemaColumnsBuilder {
<a href=#197 id=197 data-nosnippet>197</a> schema: SchemaRef,
<a href=#198 id=198 data-nosnippet>198</a> catalog_name: String,
<a href=#199 id=199 data-nosnippet>199</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#200 id=200 data-nosnippet>200</a>
<a href=#201 id=201 data-nosnippet>201</a> catalog_names: StringVectorBuilder,
<a href=#202 id=202 data-nosnippet>202</a> schema_names: StringVectorBuilder,
<a href=#203 id=203 data-nosnippet>203</a> table_names: StringVectorBuilder,
<a href=#204 id=204 data-nosnippet>204</a> column_names: StringVectorBuilder,
<a href=#205 id=205 data-nosnippet>205</a> ordinal_positions: Int64VectorBuilder,
<a href=#206 id=206 data-nosnippet>206</a> character_maximum_lengths: Int64VectorBuilder,
<a href=#207 id=207 data-nosnippet>207</a> character_octet_lengths: Int64VectorBuilder,
<a href=#208 id=208 data-nosnippet>208</a> numeric_precisions: Int64VectorBuilder,
<a href=#209 id=209 data-nosnippet>209</a> numeric_scales: Int64VectorBuilder,
<a href=#210 id=210 data-nosnippet>210</a> datetime_precisions: Int64VectorBuilder,
<a href=#211 id=211 data-nosnippet>211</a> character_set_names: StringVectorBuilder,
<a href=#212 id=212 data-nosnippet>212</a> collation_names: StringVectorBuilder,
<a href=#213 id=213 data-nosnippet>213</a> column_keys: StringVectorBuilder,
<a href=#214 id=214 data-nosnippet>214</a> greptime_data_types: StringVectorBuilder,
<a href=#215 id=215 data-nosnippet>215</a> data_types: StringVectorBuilder,
<a href=#216 id=216 data-nosnippet>216</a> semantic_types: StringVectorBuilder,
<a href=#217 id=217 data-nosnippet>217</a> column_defaults: StringVectorBuilder,
<a href=#218 id=218 data-nosnippet>218</a> is_nullables: StringVectorBuilder,
<a href=#219 id=219 data-nosnippet>219</a> column_types: StringVectorBuilder,
<a href=#220 id=220 data-nosnippet>220</a> column_comments: StringVectorBuilder,
<a href=#221 id=221 data-nosnippet>221</a>}
<a href=#222 id=222 data-nosnippet>222</a>
<a href=#223 id=223 data-nosnippet>223</a><span class="kw">impl </span>InformationSchemaColumnsBuilder {
<a href=#224 id=224 data-nosnippet>224</a> <span class="kw">fn </span>new(
<a href=#225 id=225 data-nosnippet>225</a> schema: SchemaRef,
<a href=#226 id=226 data-nosnippet>226</a> catalog_name: String,
<a href=#227 id=227 data-nosnippet>227</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#228 id=228 data-nosnippet>228</a> ) -&gt; <span class="self">Self </span>{
<a href=#229 id=229 data-nosnippet>229</a> <span class="self">Self </span>{
<a href=#230 id=230 data-nosnippet>230</a> schema,
<a href=#231 id=231 data-nosnippet>231</a> catalog_name,
<a href=#232 id=232 data-nosnippet>232</a> catalog_manager,
<a href=#233 id=233 data-nosnippet>233</a> catalog_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#234 id=234 data-nosnippet>234</a> schema_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#235 id=235 data-nosnippet>235</a> table_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#236 id=236 data-nosnippet>236</a> column_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#237 id=237 data-nosnippet>237</a> ordinal_positions: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#238 id=238 data-nosnippet>238</a> character_maximum_lengths: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#239 id=239 data-nosnippet>239</a> character_octet_lengths: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#240 id=240 data-nosnippet>240</a> numeric_precisions: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#241 id=241 data-nosnippet>241</a> numeric_scales: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#242 id=242 data-nosnippet>242</a> datetime_precisions: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#243 id=243 data-nosnippet>243</a> character_set_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#244 id=244 data-nosnippet>244</a> collation_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#245 id=245 data-nosnippet>245</a> column_keys: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#246 id=246 data-nosnippet>246</a> greptime_data_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#247 id=247 data-nosnippet>247</a> data_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#248 id=248 data-nosnippet>248</a> semantic_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#249 id=249 data-nosnippet>249</a> column_defaults: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#250 id=250 data-nosnippet>250</a> is_nullables: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#251 id=251 data-nosnippet>251</a> column_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#252 id=252 data-nosnippet>252</a> column_comments: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#253 id=253 data-nosnippet>253</a> }
<a href=#254 id=254 data-nosnippet>254</a> }
<a href=#255 id=255 data-nosnippet>255</a>
<a href=#256 id=256 data-nosnippet>256</a> <span class="doccomment">/// Construct the `information_schema.columns` virtual table
<a href=#257 id=257 data-nosnippet>257</a> </span><span class="kw">async fn </span>make_columns(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#258 id=258 data-nosnippet>258</a> <span class="kw">let </span>catalog_name = <span class="self">self</span>.catalog_name.clone();
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">let </span>catalog_manager = <span class="self">self
<a href=#260 id=260 data-nosnippet>260</a> </span>.catalog_manager
<a href=#261 id=261 data-nosnippet>261</a> .upgrade()
<a href=#262 id=262 data-nosnippet>262</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#264 id=264 data-nosnippet>264</a>
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">for </span>schema_name <span class="kw">in </span>catalog_manager.schema_names(<span class="kw-2">&amp;</span>catalog_name, <span class="prelude-val">None</span>).<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#266 id=266 data-nosnippet>266</a> <span class="kw">let </span><span class="kw-2">mut </span>stream = catalog_manager.tables(<span class="kw-2">&amp;</span>catalog_name, <span class="kw-2">&amp;</span>schema_name, <span class="prelude-val">None</span>);
<a href=#267 id=267 data-nosnippet>267</a>
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(table) = stream.try_next().<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#269 id=269 data-nosnippet>269</a> <span class="kw">let </span>keys = <span class="kw-2">&amp;</span>table.table_info().meta.primary_key_indices;
<a href=#270 id=270 data-nosnippet>270</a> <span class="kw">let </span>schema = table.schema();
<a href=#271 id=271 data-nosnippet>271</a>
<a href=#272 id=272 data-nosnippet>272</a> <span class="kw">for </span>(idx, column) <span class="kw">in </span>schema.column_schemas().iter().enumerate() {
<a href=#273 id=273 data-nosnippet>273</a> <span class="kw">let </span>semantic_type = <span class="kw">if </span>column.is_time_index() {
<a href=#274 id=274 data-nosnippet>274</a> SEMANTIC_TYPE_TIME_INDEX
<a href=#275 id=275 data-nosnippet>275</a> } <span class="kw">else if </span>keys.contains(<span class="kw-2">&amp;</span>idx) {
<a href=#276 id=276 data-nosnippet>276</a> SEMANTIC_TYPE_PRIMARY_KEY
<a href=#277 id=277 data-nosnippet>277</a> } <span class="kw">else </span>{
<a href=#278 id=278 data-nosnippet>278</a> SEMANTIC_TYPE_FIELD
<a href=#279 id=279 data-nosnippet>279</a> };
<a href=#280 id=280 data-nosnippet>280</a>
<a href=#281 id=281 data-nosnippet>281</a> <span class="self">self</span>.add_column(
<a href=#282 id=282 data-nosnippet>282</a> <span class="kw-2">&amp;</span>predicates,
<a href=#283 id=283 data-nosnippet>283</a> idx,
<a href=#284 id=284 data-nosnippet>284</a> <span class="kw-2">&amp;</span>catalog_name,
<a href=#285 id=285 data-nosnippet>285</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#286 id=286 data-nosnippet>286</a> <span class="kw-2">&amp;</span>table.table_info().name,
<a href=#287 id=287 data-nosnippet>287</a> semantic_type,
<a href=#288 id=288 data-nosnippet>288</a> column,
<a href=#289 id=289 data-nosnippet>289</a> );
<a href=#290 id=290 data-nosnippet>290</a> }
<a href=#291 id=291 data-nosnippet>291</a> }
<a href=#292 id=292 data-nosnippet>292</a> }
<a href=#293 id=293 data-nosnippet>293</a>
<a href=#294 id=294 data-nosnippet>294</a> <span class="self">self</span>.finish()
<a href=#295 id=295 data-nosnippet>295</a> }
<a href=#296 id=296 data-nosnippet>296</a>
<a href=#297 id=297 data-nosnippet>297</a> <span class="attr">#[allow(clippy::too_many_arguments)]
<a href=#298 id=298 data-nosnippet>298</a> </span><span class="kw">fn </span>add_column(
<a href=#299 id=299 data-nosnippet>299</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#300 id=300 data-nosnippet>300</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#301 id=301 data-nosnippet>301</a> index: usize,
<a href=#302 id=302 data-nosnippet>302</a> catalog_name: <span class="kw-2">&amp;</span>str,
<a href=#303 id=303 data-nosnippet>303</a> schema_name: <span class="kw-2">&amp;</span>str,
<a href=#304 id=304 data-nosnippet>304</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#305 id=305 data-nosnippet>305</a> semantic_type: <span class="kw-2">&amp;</span>str,
<a href=#306 id=306 data-nosnippet>306</a> column_schema: <span class="kw-2">&amp;</span>ColumnSchema,
<a href=#307 id=307 data-nosnippet>307</a> ) {
<a href=#308 id=308 data-nosnippet>308</a> <span class="comment">// Use sql data type name
<a href=#309 id=309 data-nosnippet>309</a> </span><span class="kw">let </span>data_type = statements::concrete_data_type_to_sql_data_type(<span class="kw-2">&amp;</span>column_schema.data_type)
<a href=#310 id=310 data-nosnippet>310</a> .map(|dt| dt.to_string().to_lowercase())
<a href=#311 id=311 data-nosnippet>311</a> .unwrap_or_else(|<span class="kw">_</span>| column_schema.data_type.name());
<a href=#312 id=312 data-nosnippet>312</a>
<a href=#313 id=313 data-nosnippet>313</a> <span class="kw">let </span>column_key = <span class="kw">match </span>semantic_type {
<a href=#314 id=314 data-nosnippet>314</a> SEMANTIC_TYPE_PRIMARY_KEY =&gt; PRI_COLUMN_KEY,
<a href=#315 id=315 data-nosnippet>315</a> SEMANTIC_TYPE_TIME_INDEX =&gt; TIME_INDEX_COLUMN_KEY,
<a href=#316 id=316 data-nosnippet>316</a> <span class="kw">_ </span>=&gt; EMPTY_STR,
<a href=#317 id=317 data-nosnippet>317</a> };
<a href=#318 id=318 data-nosnippet>318</a>
<a href=#319 id=319 data-nosnippet>319</a> <span class="kw">let </span>row = [
<a href=#320 id=320 data-nosnippet>320</a> (TABLE_CATALOG, <span class="kw-2">&amp;</span>Value::from(catalog_name)),
<a href=#321 id=321 data-nosnippet>321</a> (TABLE_SCHEMA, <span class="kw-2">&amp;</span>Value::from(schema_name)),
<a href=#322 id=322 data-nosnippet>322</a> (TABLE_NAME, <span class="kw-2">&amp;</span>Value::from(table_name)),
<a href=#323 id=323 data-nosnippet>323</a> (COLUMN_NAME, <span class="kw-2">&amp;</span>Value::from(column_schema.name.as_str())),
<a href=#324 id=324 data-nosnippet>324</a> (DATA_TYPE, <span class="kw-2">&amp;</span>Value::from(data_type.as_str())),
<a href=#325 id=325 data-nosnippet>325</a> (SEMANTIC_TYPE, <span class="kw-2">&amp;</span>Value::from(semantic_type)),
<a href=#326 id=326 data-nosnippet>326</a> (ORDINAL_POSITION, <span class="kw-2">&amp;</span>Value::from((index + <span class="number">1</span>) <span class="kw">as </span>i64)),
<a href=#327 id=327 data-nosnippet>327</a> (COLUMN_KEY, <span class="kw-2">&amp;</span>Value::from(column_key)),
<a href=#328 id=328 data-nosnippet>328</a> ];
<a href=#329 id=329 data-nosnippet>329</a>
<a href=#330 id=330 data-nosnippet>330</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#331 id=331 data-nosnippet>331</a> <span class="kw">return</span>;
<a href=#332 id=332 data-nosnippet>332</a> }
<a href=#333 id=333 data-nosnippet>333</a>
<a href=#334 id=334 data-nosnippet>334</a> <span class="self">self</span>.catalog_names.push(<span class="prelude-val">Some</span>(catalog_name));
<a href=#335 id=335 data-nosnippet>335</a> <span class="self">self</span>.schema_names.push(<span class="prelude-val">Some</span>(schema_name));
<a href=#336 id=336 data-nosnippet>336</a> <span class="self">self</span>.table_names.push(<span class="prelude-val">Some</span>(table_name));
<a href=#337 id=337 data-nosnippet>337</a> <span class="self">self</span>.column_names.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>column_schema.name));
<a href=#338 id=338 data-nosnippet>338</a> <span class="comment">// Starts from 1
<a href=#339 id=339 data-nosnippet>339</a> </span><span class="self">self</span>.ordinal_positions.push(<span class="prelude-val">Some</span>((index + <span class="number">1</span>) <span class="kw">as </span>i64));
<a href=#340 id=340 data-nosnippet>340</a>
<a href=#341 id=341 data-nosnippet>341</a> <span class="kw">if </span>column_schema.data_type.is_string() {
<a href=#342 id=342 data-nosnippet>342</a> <span class="self">self</span>.character_maximum_lengths.push(<span class="prelude-val">Some</span>(MAX_STRING_LENGTH));
<a href=#343 id=343 data-nosnippet>343</a> <span class="self">self</span>.character_octet_lengths.push(<span class="prelude-val">Some</span>(MAX_STRING_LENGTH));
<a href=#344 id=344 data-nosnippet>344</a> <span class="self">self</span>.numeric_precisions.push(<span class="prelude-val">None</span>);
<a href=#345 id=345 data-nosnippet>345</a> <span class="self">self</span>.numeric_scales.push(<span class="prelude-val">None</span>);
<a href=#346 id=346 data-nosnippet>346</a> <span class="self">self</span>.datetime_precisions.push(<span class="prelude-val">None</span>);
<a href=#347 id=347 data-nosnippet>347</a> <span class="self">self</span>.character_set_names.push(<span class="prelude-val">Some</span>(UTF8_CHARSET_NAME));
<a href=#348 id=348 data-nosnippet>348</a> <span class="self">self</span>.collation_names.push(<span class="prelude-val">Some</span>(UTF8_COLLATE_NAME));
<a href=#349 id=349 data-nosnippet>349</a> } <span class="kw">else if </span>column_schema.data_type.is_numeric() || column_schema.data_type.is_decimal() {
<a href=#350 id=350 data-nosnippet>350</a> <span class="self">self</span>.character_maximum_lengths.push(<span class="prelude-val">None</span>);
<a href=#351 id=351 data-nosnippet>351</a> <span class="self">self</span>.character_octet_lengths.push(<span class="prelude-val">None</span>);
<a href=#352 id=352 data-nosnippet>352</a>
<a href=#353 id=353 data-nosnippet>353</a> <span class="self">self</span>.numeric_precisions.push(
<a href=#354 id=354 data-nosnippet>354</a> column_schema
<a href=#355 id=355 data-nosnippet>355</a> .data_type
<a href=#356 id=356 data-nosnippet>356</a> .numeric_precision()
<a href=#357 id=357 data-nosnippet>357</a> .map(|x| x <span class="kw">as </span>i64),
<a href=#358 id=358 data-nosnippet>358</a> );
<a href=#359 id=359 data-nosnippet>359</a> <span class="self">self</span>.numeric_scales
<a href=#360 id=360 data-nosnippet>360</a> .push(column_schema.data_type.numeric_scale().map(|x| x <span class="kw">as </span>i64));
<a href=#361 id=361 data-nosnippet>361</a>
<a href=#362 id=362 data-nosnippet>362</a> <span class="self">self</span>.datetime_precisions.push(<span class="prelude-val">None</span>);
<a href=#363 id=363 data-nosnippet>363</a> <span class="self">self</span>.character_set_names.push(<span class="prelude-val">None</span>);
<a href=#364 id=364 data-nosnippet>364</a> <span class="self">self</span>.collation_names.push(<span class="prelude-val">None</span>);
<a href=#365 id=365 data-nosnippet>365</a> } <span class="kw">else </span>{
<a href=#366 id=366 data-nosnippet>366</a> <span class="self">self</span>.character_maximum_lengths.push(<span class="prelude-val">None</span>);
<a href=#367 id=367 data-nosnippet>367</a> <span class="self">self</span>.character_octet_lengths.push(<span class="prelude-val">None</span>);
<a href=#368 id=368 data-nosnippet>368</a> <span class="self">self</span>.numeric_precisions.push(<span class="prelude-val">None</span>);
<a href=#369 id=369 data-nosnippet>369</a> <span class="self">self</span>.numeric_scales.push(<span class="prelude-val">None</span>);
<a href=#370 id=370 data-nosnippet>370</a>
<a href=#371 id=371 data-nosnippet>371</a> <span class="kw">match </span><span class="kw-2">&amp;</span>column_schema.data_type {
<a href=#372 id=372 data-nosnippet>372</a> ConcreteDataType::Timestamp(ts_type) =&gt; {
<a href=#373 id=373 data-nosnippet>373</a> <span class="self">self</span>.datetime_precisions
<a href=#374 id=374 data-nosnippet>374</a> .push(<span class="prelude-val">Some</span>(ts_type.precision() <span class="kw">as </span>i64));
<a href=#375 id=375 data-nosnippet>375</a> }
<a href=#376 id=376 data-nosnippet>376</a> ConcreteDataType::Time(time_type) =&gt; {
<a href=#377 id=377 data-nosnippet>377</a> <span class="self">self</span>.datetime_precisions
<a href=#378 id=378 data-nosnippet>378</a> .push(<span class="prelude-val">Some</span>(time_type.precision() <span class="kw">as </span>i64));
<a href=#379 id=379 data-nosnippet>379</a> }
<a href=#380 id=380 data-nosnippet>380</a> <span class="kw">_ </span>=&gt; <span class="self">self</span>.datetime_precisions.push(<span class="prelude-val">None</span>),
<a href=#381 id=381 data-nosnippet>381</a> }
<a href=#382 id=382 data-nosnippet>382</a>
<a href=#383 id=383 data-nosnippet>383</a> <span class="self">self</span>.character_set_names.push(<span class="prelude-val">None</span>);
<a href=#384 id=384 data-nosnippet>384</a> <span class="self">self</span>.collation_names.push(<span class="prelude-val">None</span>);
<a href=#385 id=385 data-nosnippet>385</a> }
<a href=#386 id=386 data-nosnippet>386</a>
<a href=#387 id=387 data-nosnippet>387</a> <span class="self">self</span>.column_keys.push(<span class="prelude-val">Some</span>(column_key));
<a href=#388 id=388 data-nosnippet>388</a> <span class="self">self</span>.greptime_data_types
<a href=#389 id=389 data-nosnippet>389</a> .push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>column_schema.data_type.name()));
<a href=#390 id=390 data-nosnippet>390</a> <span class="self">self</span>.data_types.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>data_type));
<a href=#391 id=391 data-nosnippet>391</a> <span class="self">self</span>.semantic_types.push(<span class="prelude-val">Some</span>(semantic_type));
<a href=#392 id=392 data-nosnippet>392</a> <span class="self">self</span>.column_defaults.push(
<a href=#393 id=393 data-nosnippet>393</a> column_schema
<a href=#394 id=394 data-nosnippet>394</a> .default_constraint()
<a href=#395 id=395 data-nosnippet>395</a> .map(|s| <span class="macro">format!</span>(<span class="string">"{}"</span>, s))
<a href=#396 id=396 data-nosnippet>396</a> .as_deref(),
<a href=#397 id=397 data-nosnippet>397</a> );
<a href=#398 id=398 data-nosnippet>398</a> <span class="kw">if </span>column_schema.is_nullable() {
<a href=#399 id=399 data-nosnippet>399</a> <span class="self">self</span>.is_nullables.push(<span class="prelude-val">Some</span>(YES));
<a href=#400 id=400 data-nosnippet>400</a> } <span class="kw">else </span>{
<a href=#401 id=401 data-nosnippet>401</a> <span class="self">self</span>.is_nullables.push(<span class="prelude-val">Some</span>(NO));
<a href=#402 id=402 data-nosnippet>402</a> }
<a href=#403 id=403 data-nosnippet>403</a> <span class="self">self</span>.column_types.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>data_type));
<a href=#404 id=404 data-nosnippet>404</a> <span class="kw">let </span>column_comment = column_schema.column_comment().map(|x| x.as_ref());
<a href=#405 id=405 data-nosnippet>405</a> <span class="self">self</span>.column_comments.push(column_comment);
<a href=#406 id=406 data-nosnippet>406</a> }
<a href=#407 id=407 data-nosnippet>407</a>
<a href=#408 id=408 data-nosnippet>408</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#409 id=409 data-nosnippet>409</a> <span class="kw">let </span>rows_num = <span class="self">self</span>.collation_names.len();
<a href=#410 id=410 data-nosnippet>410</a>
<a href=#411 id=411 data-nosnippet>411</a> <span class="kw">let </span>privileges = Arc::new(StringVector::from(<span class="macro">vec!</span>[DEFAULT_PRIVILEGES; rows_num]));
<a href=#412 id=412 data-nosnippet>412</a> <span class="kw">let </span>empty_string = Arc::new(StringVector::from(<span class="macro">vec!</span>[EMPTY_STR; rows_num]));
<a href=#413 id=413 data-nosnippet>413</a> <span class="kw">let </span>srs_ids = Arc::new(Int64Vector::from(<span class="macro">vec!</span>[<span class="prelude-val">None</span>; rows_num]));
<a href=#414 id=414 data-nosnippet>414</a>
<a href=#415 id=415 data-nosnippet>415</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#416 id=416 data-nosnippet>416</a> Arc::new(<span class="self">self</span>.catalog_names.finish()),
<a href=#417 id=417 data-nosnippet>417</a> Arc::new(<span class="self">self</span>.schema_names.finish()),
<a href=#418 id=418 data-nosnippet>418</a> Arc::new(<span class="self">self</span>.table_names.finish()),
<a href=#419 id=419 data-nosnippet>419</a> Arc::new(<span class="self">self</span>.column_names.finish()),
<a href=#420 id=420 data-nosnippet>420</a> Arc::new(<span class="self">self</span>.ordinal_positions.finish()),
<a href=#421 id=421 data-nosnippet>421</a> Arc::new(<span class="self">self</span>.character_maximum_lengths.finish()),
<a href=#422 id=422 data-nosnippet>422</a> Arc::new(<span class="self">self</span>.character_octet_lengths.finish()),
<a href=#423 id=423 data-nosnippet>423</a> Arc::new(<span class="self">self</span>.numeric_precisions.finish()),
<a href=#424 id=424 data-nosnippet>424</a> Arc::new(<span class="self">self</span>.numeric_scales.finish()),
<a href=#425 id=425 data-nosnippet>425</a> Arc::new(<span class="self">self</span>.datetime_precisions.finish()),
<a href=#426 id=426 data-nosnippet>426</a> Arc::new(<span class="self">self</span>.character_set_names.finish()),
<a href=#427 id=427 data-nosnippet>427</a> Arc::new(<span class="self">self</span>.collation_names.finish()),
<a href=#428 id=428 data-nosnippet>428</a> Arc::new(<span class="self">self</span>.column_keys.finish()),
<a href=#429 id=429 data-nosnippet>429</a> empty_string.clone(),
<a href=#430 id=430 data-nosnippet>430</a> privileges,
<a href=#431 id=431 data-nosnippet>431</a> empty_string,
<a href=#432 id=432 data-nosnippet>432</a> Arc::new(<span class="self">self</span>.greptime_data_types.finish()),
<a href=#433 id=433 data-nosnippet>433</a> Arc::new(<span class="self">self</span>.data_types.finish()),
<a href=#434 id=434 data-nosnippet>434</a> Arc::new(<span class="self">self</span>.semantic_types.finish()),
<a href=#435 id=435 data-nosnippet>435</a> Arc::new(<span class="self">self</span>.column_defaults.finish()),
<a href=#436 id=436 data-nosnippet>436</a> Arc::new(<span class="self">self</span>.is_nullables.finish()),
<a href=#437 id=437 data-nosnippet>437</a> Arc::new(<span class="self">self</span>.column_types.finish()),
<a href=#438 id=438 data-nosnippet>438</a> Arc::new(<span class="self">self</span>.column_comments.finish()),
<a href=#439 id=439 data-nosnippet>439</a> srs_ids,
<a href=#440 id=440 data-nosnippet>440</a> ];
<a href=#441 id=441 data-nosnippet>441</a>
<a href=#442 id=442 data-nosnippet>442</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#443 id=443 data-nosnippet>443</a> }
<a href=#444 id=444 data-nosnippet>444</a>}
<a href=#445 id=445 data-nosnippet>445</a>
<a href=#446 id=446 data-nosnippet>446</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaColumns {
<a href=#447 id=447 data-nosnippet>447</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#448 id=448 data-nosnippet>448</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#449 id=449 data-nosnippet>449</a> }
<a href=#450 id=450 data-nosnippet>450</a>
<a href=#451 id=451 data-nosnippet>451</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#452 id=452 data-nosnippet>452</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#453 id=453 data-nosnippet>453</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#454 id=454 data-nosnippet>454</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#455 id=455 data-nosnippet>455</a> schema,
<a href=#456 id=456 data-nosnippet>456</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#457 id=457 data-nosnippet>457</a> builder
<a href=#458 id=458 data-nosnippet>458</a> .make_columns(<span class="prelude-val">None</span>)
<a href=#459 id=459 data-nosnippet>459</a> .<span class="kw">await
<a href=#460 id=460 data-nosnippet>460</a> </span>.map(|x| x.into_df_record_batch())
<a href=#461 id=461 data-nosnippet>461</a> .map_err(Into::into)
<a href=#462 id=462 data-nosnippet>462</a> }),
<a href=#463 id=463 data-nosnippet>463</a> ))
<a href=#464 id=464 data-nosnippet>464</a> }
<a href=#465 id=465 data-nosnippet>465</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,286 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/flow_statistics.rs`."><title>flow_statistics.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>flow_statistics.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_FLOW_STATISTICS_TABLE_ID;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_meta::key::FlowId;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::key::flow::FlowMetadataManager;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_meta::key::flow::flow_state::FlowStat;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_recordbatch::{DfSendableRecordBatchStream, RecordBatch, SendableRecordBatchStream};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_time::util::current_time_millis;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datatypes::prelude::ConcreteDataType <span class="kw">as </span>CDT;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::scalars::ScalarVectorBuilder;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>datatypes::timestamp::TimestampMillisecond;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>datatypes::value::Value;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>datatypes::vectors::{
<a href=#34 id=34 data-nosnippet>34</a> Int64VectorBuilder, StringVectorBuilder, TimestampMillisecondVectorBuilder,
<a href=#35 id=35 data-nosnippet>35</a> UInt32VectorBuilder, UInt64VectorBuilder, VectorRef,
<a href=#36 id=36 data-nosnippet>36</a>};
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>futures::TryStreamExt;
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span>snafu::ResultExt;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span><span class="kw">crate</span>::error::{CreateRecordBatchSnafu, InternalSnafu, ListFlowsSnafu, <span class="prelude-ty">Result</span>};
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::{FLOW_STATISTICS, Predicates};
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::InformationTable;
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::utils;
<a href=#46 id=46 data-nosnippet>46</a>
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a><span class="comment">// rows of information_schema.flow_statistics
<a href=#50 id=50 data-nosnippet>50</a></span><span class="kw">pub const </span>FLOW_ID: <span class="kw-2">&amp;</span>str = <span class="string">"flow_id"</span>;
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">pub const </span>FLOW_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"flow_name"</span>;
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">pub const </span>START_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"start_time"</span>;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">pub const </span>LAST_EXECUTION_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"last_execution_time"</span>;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">pub const </span>UPTIME_SECONDS: <span class="kw-2">&amp;</span>str = <span class="string">"uptime_seconds"</span>;
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">pub const </span>STATE_SIZE: <span class="kw-2">&amp;</span>str = <span class="string">"state_size"</span>;
<a href=#56 id=56 data-nosnippet>56</a>
<a href=#57 id=57 data-nosnippet>57</a><span class="doccomment">/// The `information_schema.flow_statistics` provides runtime statistics about flows.
<a href=#58 id=58 data-nosnippet>58</a></span><span class="attr">#[derive(Debug)]
<a href=#59 id=59 data-nosnippet>59</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaFlowStatistics {
<a href=#60 id=60 data-nosnippet>60</a> schema: SchemaRef,
<a href=#61 id=61 data-nosnippet>61</a> catalog_name: String,
<a href=#62 id=62 data-nosnippet>62</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#63 id=63 data-nosnippet>63</a> flow_metadata_manager: Arc&lt;FlowMetadataManager&gt;,
<a href=#64 id=64 data-nosnippet>64</a>}
<a href=#65 id=65 data-nosnippet>65</a>
<a href=#66 id=66 data-nosnippet>66</a><span class="kw">impl </span>InformationSchemaFlowStatistics {
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(
<a href=#68 id=68 data-nosnippet>68</a> catalog_name: String,
<a href=#69 id=69 data-nosnippet>69</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#70 id=70 data-nosnippet>70</a> flow_metadata_manager: Arc&lt;FlowMetadataManager&gt;,
<a href=#71 id=71 data-nosnippet>71</a> ) -&gt; <span class="self">Self </span>{
<a href=#72 id=72 data-nosnippet>72</a> <span class="self">Self </span>{
<a href=#73 id=73 data-nosnippet>73</a> schema: <span class="self">Self</span>::schema(),
<a href=#74 id=74 data-nosnippet>74</a> catalog_name,
<a href=#75 id=75 data-nosnippet>75</a> catalog_manager,
<a href=#76 id=76 data-nosnippet>76</a> flow_metadata_manager,
<a href=#77 id=77 data-nosnippet>77</a> }
<a href=#78 id=78 data-nosnippet>78</a> }
<a href=#79 id=79 data-nosnippet>79</a>
<a href=#80 id=80 data-nosnippet>80</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#81 id=81 data-nosnippet>81</a> Arc::new(Schema::new(
<a href=#82 id=82 data-nosnippet>82</a> <span class="macro">vec!</span>[
<a href=#83 id=83 data-nosnippet>83</a> (FLOW_ID, CDT::uint32_datatype(), <span class="bool-val">false</span>),
<a href=#84 id=84 data-nosnippet>84</a> (FLOW_NAME, CDT::string_datatype(), <span class="bool-val">false</span>),
<a href=#85 id=85 data-nosnippet>85</a> (START_TIME, CDT::timestamp_millisecond_datatype(), <span class="bool-val">true</span>),
<a href=#86 id=86 data-nosnippet>86</a> (
<a href=#87 id=87 data-nosnippet>87</a> LAST_EXECUTION_TIME,
<a href=#88 id=88 data-nosnippet>88</a> CDT::timestamp_millisecond_datatype(),
<a href=#89 id=89 data-nosnippet>89</a> <span class="bool-val">true</span>,
<a href=#90 id=90 data-nosnippet>90</a> ),
<a href=#91 id=91 data-nosnippet>91</a> (UPTIME_SECONDS, CDT::int64_datatype(), <span class="bool-val">true</span>),
<a href=#92 id=92 data-nosnippet>92</a> (STATE_SIZE, CDT::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#93 id=93 data-nosnippet>93</a> ]
<a href=#94 id=94 data-nosnippet>94</a> .into_iter()
<a href=#95 id=95 data-nosnippet>95</a> .map(|(name, ty, nullable)| ColumnSchema::new(name, ty, nullable))
<a href=#96 id=96 data-nosnippet>96</a> .collect(),
<a href=#97 id=97 data-nosnippet>97</a> ))
<a href=#98 id=98 data-nosnippet>98</a> }
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaFlowStatisticsBuilder {
<a href=#101 id=101 data-nosnippet>101</a> InformationSchemaFlowStatisticsBuilder::new(
<a href=#102 id=102 data-nosnippet>102</a> <span class="self">self</span>.schema.clone(),
<a href=#103 id=103 data-nosnippet>103</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#104 id=104 data-nosnippet>104</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#105 id=105 data-nosnippet>105</a> <span class="kw-2">&amp;</span><span class="self">self</span>.flow_metadata_manager,
<a href=#106 id=106 data-nosnippet>106</a> )
<a href=#107 id=107 data-nosnippet>107</a> }
<a href=#108 id=108 data-nosnippet>108</a>}
<a href=#109 id=109 data-nosnippet>109</a>
<a href=#110 id=110 data-nosnippet>110</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaFlowStatistics {
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#112 id=112 data-nosnippet>112</a> INFORMATION_SCHEMA_FLOW_STATISTICS_TABLE_ID
<a href=#113 id=113 data-nosnippet>113</a> }
<a href=#114 id=114 data-nosnippet>114</a>
<a href=#115 id=115 data-nosnippet>115</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#116 id=116 data-nosnippet>116</a> FLOW_STATISTICS
<a href=#117 id=117 data-nosnippet>117</a> }
<a href=#118 id=118 data-nosnippet>118</a>
<a href=#119 id=119 data-nosnippet>119</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#120 id=120 data-nosnippet>120</a> <span class="self">self</span>.schema.clone()
<a href=#121 id=121 data-nosnippet>121</a> }
<a href=#122 id=122 data-nosnippet>122</a>
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#126 id=126 data-nosnippet>126</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#127 id=127 data-nosnippet>127</a> schema,
<a href=#128 id=128 data-nosnippet>128</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#129 id=129 data-nosnippet>129</a> builder
<a href=#130 id=130 data-nosnippet>130</a> .make_flow_statistics(<span class="prelude-val">Some</span>(request))
<a href=#131 id=131 data-nosnippet>131</a> .<span class="kw">await
<a href=#132 id=132 data-nosnippet>132</a> </span>.map(|x| x.into_df_record_batch())
<a href=#133 id=133 data-nosnippet>133</a> .map_err(|err| datafusion::error::DataFusionError::External(Box::new(err)))
<a href=#134 id=134 data-nosnippet>134</a> }),
<a href=#135 id=135 data-nosnippet>135</a> ));
<a href=#136 id=136 data-nosnippet>136</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#137 id=137 data-nosnippet>137</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#138 id=138 data-nosnippet>138</a> .map_err(BoxedError::new)
<a href=#139 id=139 data-nosnippet>139</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#140 id=140 data-nosnippet>140</a> ))
<a href=#141 id=141 data-nosnippet>141</a> }
<a href=#142 id=142 data-nosnippet>142</a>}
<a href=#143 id=143 data-nosnippet>143</a>
<a href=#144 id=144 data-nosnippet>144</a><span class="doccomment">/// Builds the `information_schema.flow_statistics` table row by row.
<a href=#145 id=145 data-nosnippet>145</a></span><span class="kw">struct </span>InformationSchemaFlowStatisticsBuilder {
<a href=#146 id=146 data-nosnippet>146</a> schema: SchemaRef,
<a href=#147 id=147 data-nosnippet>147</a> catalog_name: String,
<a href=#148 id=148 data-nosnippet>148</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#149 id=149 data-nosnippet>149</a> flow_metadata_manager: Arc&lt;FlowMetadataManager&gt;,
<a href=#150 id=150 data-nosnippet>150</a>
<a href=#151 id=151 data-nosnippet>151</a> flow_ids: UInt32VectorBuilder,
<a href=#152 id=152 data-nosnippet>152</a> flow_names: StringVectorBuilder,
<a href=#153 id=153 data-nosnippet>153</a> start_times: TimestampMillisecondVectorBuilder,
<a href=#154 id=154 data-nosnippet>154</a> last_execution_times: TimestampMillisecondVectorBuilder,
<a href=#155 id=155 data-nosnippet>155</a> uptime_seconds: Int64VectorBuilder,
<a href=#156 id=156 data-nosnippet>156</a> state_sizes: UInt64VectorBuilder,
<a href=#157 id=157 data-nosnippet>157</a>}
<a href=#158 id=158 data-nosnippet>158</a>
<a href=#159 id=159 data-nosnippet>159</a><span class="kw">impl </span>InformationSchemaFlowStatisticsBuilder {
<a href=#160 id=160 data-nosnippet>160</a> <span class="kw">fn </span>new(
<a href=#161 id=161 data-nosnippet>161</a> schema: SchemaRef,
<a href=#162 id=162 data-nosnippet>162</a> catalog_name: String,
<a href=#163 id=163 data-nosnippet>163</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#164 id=164 data-nosnippet>164</a> flow_metadata_manager: <span class="kw-2">&amp;</span>Arc&lt;FlowMetadataManager&gt;,
<a href=#165 id=165 data-nosnippet>165</a> ) -&gt; <span class="self">Self </span>{
<a href=#166 id=166 data-nosnippet>166</a> <span class="self">Self </span>{
<a href=#167 id=167 data-nosnippet>167</a> schema,
<a href=#168 id=168 data-nosnippet>168</a> catalog_name,
<a href=#169 id=169 data-nosnippet>169</a> catalog_manager,
<a href=#170 id=170 data-nosnippet>170</a> flow_metadata_manager: flow_metadata_manager.clone(),
<a href=#171 id=171 data-nosnippet>171</a>
<a href=#172 id=172 data-nosnippet>172</a> flow_ids: UInt32VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#173 id=173 data-nosnippet>173</a> flow_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#174 id=174 data-nosnippet>174</a> start_times: TimestampMillisecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#175 id=175 data-nosnippet>175</a> last_execution_times: TimestampMillisecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#176 id=176 data-nosnippet>176</a> uptime_seconds: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#177 id=177 data-nosnippet>177</a> state_sizes: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#178 id=178 data-nosnippet>178</a> }
<a href=#179 id=179 data-nosnippet>179</a> }
<a href=#180 id=180 data-nosnippet>180</a>
<a href=#181 id=181 data-nosnippet>181</a> <span class="doccomment">/// Construct the `information_schema.flow_statistics` virtual table.
<a href=#182 id=182 data-nosnippet>182</a> </span><span class="kw">async fn </span>make_flow_statistics(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#183 id=183 data-nosnippet>183</a> <span class="kw">let </span>catalog_name = <span class="self">self</span>.catalog_name.clone();
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#185 id=185 data-nosnippet>185</a>
<a href=#186 id=186 data-nosnippet>186</a> <span class="kw">let </span>flow_info_manager = <span class="self">self</span>.flow_metadata_manager.clone();
<a href=#187 id=187 data-nosnippet>187</a>
<a href=#188 id=188 data-nosnippet>188</a> <span class="kw">let </span><span class="kw-2">mut </span>stream = flow_info_manager
<a href=#189 id=189 data-nosnippet>189</a> .flow_name_manager()
<a href=#190 id=190 data-nosnippet>190</a> .flow_names(<span class="kw-2">&amp;</span>catalog_name)
<a href=#191 id=191 data-nosnippet>191</a> .<span class="kw">await</span>;
<a href=#192 id=192 data-nosnippet>192</a>
<a href=#193 id=193 data-nosnippet>193</a> <span class="kw">let </span>flow_stat = {
<a href=#194 id=194 data-nosnippet>194</a> <span class="kw">let </span>information_extension = utils::information_extension(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#195 id=195 data-nosnippet>195</a> information_extension.flow_stats().<span class="kw">await</span><span class="question-mark">?
<a href=#196 id=196 data-nosnippet>196</a> </span>};
<a href=#197 id=197 data-nosnippet>197</a>
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">let </span>now = current_time_millis();
<a href=#199 id=199 data-nosnippet>199</a>
<a href=#200 id=200 data-nosnippet>200</a> <span class="kw">while let </span><span class="prelude-val">Some</span>((flow_name, flow_id)) = stream
<a href=#201 id=201 data-nosnippet>201</a> .try_next()
<a href=#202 id=202 data-nosnippet>202</a> .<span class="kw">await
<a href=#203 id=203 data-nosnippet>203</a> </span>.map_err(BoxedError::new)
<a href=#204 id=204 data-nosnippet>204</a> .context(ListFlowsSnafu {
<a href=#205 id=205 data-nosnippet>205</a> catalog: <span class="kw-2">&amp;</span>catalog_name,
<a href=#206 id=206 data-nosnippet>206</a> })<span class="question-mark">?
<a href=#207 id=207 data-nosnippet>207</a> </span>{
<a href=#208 id=208 data-nosnippet>208</a> <span class="self">self</span>.add_flow_statistic(<span class="kw-2">&amp;</span>predicates, flow_id.flow_id(), <span class="kw-2">&amp;</span>flow_name, <span class="kw-2">&amp;</span>flow_stat, now);
<a href=#209 id=209 data-nosnippet>209</a> }
<a href=#210 id=210 data-nosnippet>210</a>
<a href=#211 id=211 data-nosnippet>211</a> <span class="self">self</span>.finish()
<a href=#212 id=212 data-nosnippet>212</a> }
<a href=#213 id=213 data-nosnippet>213</a>
<a href=#214 id=214 data-nosnippet>214</a> <span class="kw">fn </span>add_flow_statistic(
<a href=#215 id=215 data-nosnippet>215</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#216 id=216 data-nosnippet>216</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#217 id=217 data-nosnippet>217</a> flow_id: FlowId,
<a href=#218 id=218 data-nosnippet>218</a> flow_name: <span class="kw-2">&amp;</span>str,
<a href=#219 id=219 data-nosnippet>219</a> flow_stat: <span class="kw-2">&amp;</span><span class="prelude-ty">Option</span>&lt;FlowStat&gt;,
<a href=#220 id=220 data-nosnippet>220</a> now: i64,
<a href=#221 id=221 data-nosnippet>221</a> ) {
<a href=#222 id=222 data-nosnippet>222</a> <span class="kw">let </span>row = [
<a href=#223 id=223 data-nosnippet>223</a> (FLOW_ID, <span class="kw-2">&amp;</span>Value::from(flow_id)),
<a href=#224 id=224 data-nosnippet>224</a> (FLOW_NAME, <span class="kw-2">&amp;</span>Value::from(flow_name.to_string())),
<a href=#225 id=225 data-nosnippet>225</a> ];
<a href=#226 id=226 data-nosnippet>226</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#227 id=227 data-nosnippet>227</a> <span class="kw">return</span>;
<a href=#228 id=228 data-nosnippet>228</a> }
<a href=#229 id=229 data-nosnippet>229</a>
<a href=#230 id=230 data-nosnippet>230</a> <span class="kw">let </span>start_time = flow_stat
<a href=#231 id=231 data-nosnippet>231</a> .as_ref()
<a href=#232 id=232 data-nosnippet>232</a> .and_then(|stat| stat.start_time_map.get(<span class="kw-2">&amp;</span>flow_id).copied());
<a href=#233 id=233 data-nosnippet>233</a>
<a href=#234 id=234 data-nosnippet>234</a> <span class="self">self</span>.flow_ids.push(<span class="prelude-val">Some</span>(flow_id));
<a href=#235 id=235 data-nosnippet>235</a> <span class="self">self</span>.flow_names.push(<span class="prelude-val">Some</span>(flow_name));
<a href=#236 id=236 data-nosnippet>236</a> <span class="self">self</span>.start_times
<a href=#237 id=237 data-nosnippet>237</a> .push(start_time.map(TimestampMillisecond::new));
<a href=#238 id=238 data-nosnippet>238</a> <span class="self">self</span>.last_execution_times
<a href=#239 id=239 data-nosnippet>239</a> .push(flow_stat.as_ref().and_then(|stat| {
<a href=#240 id=240 data-nosnippet>240</a> stat.last_exec_time_map
<a href=#241 id=241 data-nosnippet>241</a> .get(<span class="kw-2">&amp;</span>flow_id)
<a href=#242 id=242 data-nosnippet>242</a> .map(|v| TimestampMillisecond::new(<span class="kw-2">*</span>v))
<a href=#243 id=243 data-nosnippet>243</a> }));
<a href=#244 id=244 data-nosnippet>244</a> <span class="self">self</span>.uptime_seconds
<a href=#245 id=245 data-nosnippet>245</a> .push(start_time.map(|start| ((now - start) / <span class="number">1000</span>).max(<span class="number">0</span>)));
<a href=#246 id=246 data-nosnippet>246</a> <span class="self">self</span>.state_sizes.push(
<a href=#247 id=247 data-nosnippet>247</a> flow_stat
<a href=#248 id=248 data-nosnippet>248</a> .as_ref()
<a href=#249 id=249 data-nosnippet>249</a> .and_then(|stat| stat.state_size.get(<span class="kw-2">&amp;</span>flow_id).map(|v| <span class="kw-2">*</span>v <span class="kw">as </span>u64)),
<a href=#250 id=250 data-nosnippet>250</a> );
<a href=#251 id=251 data-nosnippet>251</a> }
<a href=#252 id=252 data-nosnippet>252</a>
<a href=#253 id=253 data-nosnippet>253</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#254 id=254 data-nosnippet>254</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#255 id=255 data-nosnippet>255</a> Arc::new(<span class="self">self</span>.flow_ids.finish()),
<a href=#256 id=256 data-nosnippet>256</a> Arc::new(<span class="self">self</span>.flow_names.finish()),
<a href=#257 id=257 data-nosnippet>257</a> Arc::new(<span class="self">self</span>.start_times.finish()),
<a href=#258 id=258 data-nosnippet>258</a> Arc::new(<span class="self">self</span>.last_execution_times.finish()),
<a href=#259 id=259 data-nosnippet>259</a> Arc::new(<span class="self">self</span>.uptime_seconds.finish()),
<a href=#260 id=260 data-nosnippet>260</a> Arc::new(<span class="self">self</span>.state_sizes.finish()),
<a href=#261 id=261 data-nosnippet>261</a> ];
<a href=#262 id=262 data-nosnippet>262</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#263 id=263 data-nosnippet>263</a> }
<a href=#264 id=264 data-nosnippet>264</a>}
<a href=#265 id=265 data-nosnippet>265</a>
<a href=#266 id=266 data-nosnippet>266</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaFlowStatistics {
<a href=#267 id=267 data-nosnippet>267</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>arrow_schema::SchemaRef {
<a href=#268 id=268 data-nosnippet>268</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#269 id=269 data-nosnippet>269</a> }
<a href=#270 id=270 data-nosnippet>270</a>
<a href=#271 id=271 data-nosnippet>271</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#272 id=272 data-nosnippet>272</a> <span class="kw">let </span>schema: Arc&lt;arrow_schema::Schema&gt; = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#273 id=273 data-nosnippet>273</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#274 id=274 data-nosnippet>274</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#275 id=275 data-nosnippet>275</a> schema,
<a href=#276 id=276 data-nosnippet>276</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#277 id=277 data-nosnippet>277</a> builder
<a href=#278 id=278 data-nosnippet>278</a> .make_flow_statistics(<span class="prelude-val">None</span>)
<a href=#279 id=279 data-nosnippet>279</a> .<span class="kw">await
<a href=#280 id=280 data-nosnippet>280</a> </span>.map(|x| x.into_df_record_batch())
<a href=#281 id=281 data-nosnippet>281</a> .map_err(Into::into)
<a href=#282 id=282 data-nosnippet>282</a> }),
<a href=#283 id=283 data-nosnippet>283</a> ))
<a href=#284 id=284 data-nosnippet>284</a> }
<a href=#285 id=285 data-nosnippet>285</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,566 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/flows.rs`."><title>flows.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>flows.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_FLOW_TABLE_ID;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_meta::ddl::create_flow::{FlowType, effective_eval_schedule_from_flow_info};
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::key::FlowId;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_meta::key::flow::FlowMetadataManager;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_meta::key::flow::flow_info::FlowInfoValue;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_meta::key::flow::flow_state::FlowStat;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>common_recordbatch::{DfSendableRecordBatchStream, RecordBatch, SendableRecordBatchStream};
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::prelude::ConcreteDataType <span class="kw">as </span>CDT;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datatypes::scalars::ScalarVectorBuilder;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>datatypes::timestamp::TimestampMillisecond;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>datatypes::value::Value;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span>datatypes::vectors::{
<a href=#35 id=35 data-nosnippet>35</a> Int64VectorBuilder, StringVectorBuilder, TimestampMillisecondVectorBuilder,
<a href=#36 id=36 data-nosnippet>36</a> UInt32VectorBuilder, UInt64VectorBuilder, VectorRef,
<a href=#37 id=37 data-nosnippet>37</a>};
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span>futures::TryStreamExt;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span>snafu::{OptionExt, ResultExt};
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">use </span>sql::ast::Ident;
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span>sql::dialect::GreptimeDbDialect;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span>sql::parser::ParserContext;
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">use </span>sql::statements::create::{CreateFlow, SqlOrTql};
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">use </span>sql::statements::statement::Statement;
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#46 id=46 data-nosnippet>46</a>
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#49 id=49 data-nosnippet>49</a> CreateRecordBatchSnafu, FlowInfoNotFoundSnafu, InternalSnafu, JsonSnafu, ListFlowsSnafu,
<a href=#50 id=50 data-nosnippet>50</a> <span class="prelude-ty">Result</span>, UpgradeWeakCatalogManagerRefSnafu,
<a href=#51 id=51 data-nosnippet>51</a>};
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::{FLOWS, Predicates};
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::InformationTable;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::utils;
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#57 id=57 data-nosnippet>57</a>
<a href=#58 id=58 data-nosnippet>58</a><span class="comment">// rows of information_schema.flows
<a href=#59 id=59 data-nosnippet>59</a>// pk is (flow_name, flow_id, table_catalog)
<a href=#60 id=60 data-nosnippet>60</a></span><span class="kw">pub const </span>FLOW_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"flow_name"</span>;
<a href=#61 id=61 data-nosnippet>61</a><span class="kw">pub const </span>FLOW_ID: <span class="kw-2">&amp;</span>str = <span class="string">"flow_id"</span>;
<a href=#62 id=62 data-nosnippet>62</a><span class="kw">pub const </span>STATE_SIZE: <span class="kw-2">&amp;</span>str = <span class="string">"state_size"</span>;
<a href=#63 id=63 data-nosnippet>63</a><span class="kw">pub const </span>TABLE_CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"table_catalog"</span>;
<a href=#64 id=64 data-nosnippet>64</a><span class="kw">pub const </span>FLOW_DEFINITION: <span class="kw-2">&amp;</span>str = <span class="string">"flow_definition"</span>;
<a href=#65 id=65 data-nosnippet>65</a><span class="kw">pub const </span>COMMENT: <span class="kw-2">&amp;</span>str = <span class="string">"comment"</span>;
<a href=#66 id=66 data-nosnippet>66</a><span class="kw">pub const </span>EXPIRE_AFTER: <span class="kw-2">&amp;</span>str = <span class="string">"expire_after"</span>;
<a href=#67 id=67 data-nosnippet>67</a><span class="kw">pub const </span>SOURCE_TABLE_IDS: <span class="kw-2">&amp;</span>str = <span class="string">"source_table_ids"</span>;
<a href=#68 id=68 data-nosnippet>68</a><span class="kw">pub const </span>SINK_TABLE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"sink_table_name"</span>;
<a href=#69 id=69 data-nosnippet>69</a><span class="kw">pub const </span>FLOWNODE_IDS: <span class="kw-2">&amp;</span>str = <span class="string">"flownode_ids"</span>;
<a href=#70 id=70 data-nosnippet>70</a><span class="kw">pub const </span>OPTIONS: <span class="kw-2">&amp;</span>str = <span class="string">"options"</span>;
<a href=#71 id=71 data-nosnippet>71</a><span class="kw">pub const </span>CREATED_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"created_time"</span>;
<a href=#72 id=72 data-nosnippet>72</a><span class="kw">pub const </span>UPDATED_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"updated_time"</span>;
<a href=#73 id=73 data-nosnippet>73</a><span class="kw">pub const </span>LAST_EXECUTION_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"last_execution_time"</span>;
<a href=#74 id=74 data-nosnippet>74</a><span class="kw">pub const </span>SOURCE_TABLE_NAMES: <span class="kw-2">&amp;</span>str = <span class="string">"source_table_names"</span>;
<a href=#75 id=75 data-nosnippet>75</a><span class="kw">pub const </span>FLOWNODE_ADDRS: <span class="kw-2">&amp;</span>str = <span class="string">"flownode_addrs"</span>;
<a href=#76 id=76 data-nosnippet>76</a>
<a href=#77 id=77 data-nosnippet>77</a><span class="doccomment">/// The `information_schema.flows` to provides information about flows in databases.
<a href=#78 id=78 data-nosnippet>78</a></span><span class="attr">#[derive(Debug)]
<a href=#79 id=79 data-nosnippet>79</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaFlows {
<a href=#80 id=80 data-nosnippet>80</a> schema: SchemaRef,
<a href=#81 id=81 data-nosnippet>81</a> catalog_name: String,
<a href=#82 id=82 data-nosnippet>82</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#83 id=83 data-nosnippet>83</a> flow_metadata_manager: Arc&lt;FlowMetadataManager&gt;,
<a href=#84 id=84 data-nosnippet>84</a>}
<a href=#85 id=85 data-nosnippet>85</a>
<a href=#86 id=86 data-nosnippet>86</a><span class="kw">impl </span>InformationSchemaFlows {
<a href=#87 id=87 data-nosnippet>87</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(
<a href=#88 id=88 data-nosnippet>88</a> catalog_name: String,
<a href=#89 id=89 data-nosnippet>89</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#90 id=90 data-nosnippet>90</a> flow_metadata_manager: Arc&lt;FlowMetadataManager&gt;,
<a href=#91 id=91 data-nosnippet>91</a> ) -&gt; <span class="self">Self </span>{
<a href=#92 id=92 data-nosnippet>92</a> <span class="self">Self </span>{
<a href=#93 id=93 data-nosnippet>93</a> schema: <span class="self">Self</span>::schema(),
<a href=#94 id=94 data-nosnippet>94</a> catalog_name,
<a href=#95 id=95 data-nosnippet>95</a> catalog_manager,
<a href=#96 id=96 data-nosnippet>96</a> flow_metadata_manager,
<a href=#97 id=97 data-nosnippet>97</a> }
<a href=#98 id=98 data-nosnippet>98</a> }
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> <span class="doccomment">/// for complex fields(including [`SOURCE_TABLE_IDS`], [`FLOWNODE_IDS`], [`OPTIONS`] and
<a href=#101 id=101 data-nosnippet>101</a> /// [`FLOWNODE_ADDRS`]), it will be serialized to json string for now
<a href=#102 id=102 data-nosnippet>102</a> /// TODO(discord9): use a better way to store complex fields like json type
<a href=#103 id=103 data-nosnippet>103</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#104 id=104 data-nosnippet>104</a> Arc::new(Schema::new(
<a href=#105 id=105 data-nosnippet>105</a> <span class="macro">vec!</span>[
<a href=#106 id=106 data-nosnippet>106</a> (FLOW_NAME, CDT::string_datatype(), <span class="bool-val">false</span>),
<a href=#107 id=107 data-nosnippet>107</a> (FLOW_ID, CDT::uint32_datatype(), <span class="bool-val">false</span>),
<a href=#108 id=108 data-nosnippet>108</a> (STATE_SIZE, CDT::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#109 id=109 data-nosnippet>109</a> (TABLE_CATALOG, CDT::string_datatype(), <span class="bool-val">false</span>),
<a href=#110 id=110 data-nosnippet>110</a> (FLOW_DEFINITION, CDT::string_datatype(), <span class="bool-val">false</span>),
<a href=#111 id=111 data-nosnippet>111</a> (COMMENT, CDT::string_datatype(), <span class="bool-val">true</span>),
<a href=#112 id=112 data-nosnippet>112</a> (EXPIRE_AFTER, CDT::int64_datatype(), <span class="bool-val">true</span>),
<a href=#113 id=113 data-nosnippet>113</a> (SOURCE_TABLE_IDS, CDT::string_datatype(), <span class="bool-val">true</span>),
<a href=#114 id=114 data-nosnippet>114</a> (SINK_TABLE_NAME, CDT::string_datatype(), <span class="bool-val">false</span>),
<a href=#115 id=115 data-nosnippet>115</a> (FLOWNODE_IDS, CDT::string_datatype(), <span class="bool-val">true</span>),
<a href=#116 id=116 data-nosnippet>116</a> (OPTIONS, CDT::string_datatype(), <span class="bool-val">true</span>),
<a href=#117 id=117 data-nosnippet>117</a> (CREATED_TIME, CDT::timestamp_millisecond_datatype(), <span class="bool-val">false</span>),
<a href=#118 id=118 data-nosnippet>118</a> (UPDATED_TIME, CDT::timestamp_millisecond_datatype(), <span class="bool-val">false</span>),
<a href=#119 id=119 data-nosnippet>119</a> (
<a href=#120 id=120 data-nosnippet>120</a> LAST_EXECUTION_TIME,
<a href=#121 id=121 data-nosnippet>121</a> CDT::timestamp_millisecond_datatype(),
<a href=#122 id=122 data-nosnippet>122</a> <span class="bool-val">true</span>,
<a href=#123 id=123 data-nosnippet>123</a> ),
<a href=#124 id=124 data-nosnippet>124</a> (SOURCE_TABLE_NAMES, CDT::string_datatype(), <span class="bool-val">true</span>),
<a href=#125 id=125 data-nosnippet>125</a> (FLOWNODE_ADDRS, CDT::string_datatype(), <span class="bool-val">true</span>),
<a href=#126 id=126 data-nosnippet>126</a> ]
<a href=#127 id=127 data-nosnippet>127</a> .into_iter()
<a href=#128 id=128 data-nosnippet>128</a> .map(|(name, ty, nullable)| ColumnSchema::new(name, ty, nullable))
<a href=#129 id=129 data-nosnippet>129</a> .collect(),
<a href=#130 id=130 data-nosnippet>130</a> ))
<a href=#131 id=131 data-nosnippet>131</a> }
<a href=#132 id=132 data-nosnippet>132</a>
<a href=#133 id=133 data-nosnippet>133</a> <span class="doccomment">/// Generates the CREATE FLOW statement for the flow_definition column
<a href=#134 id=134 data-nosnippet>134</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>generate_show_create_flow(flow_info: <span class="kw-2">&amp;</span>FlowInfoValue) -&gt; <span class="prelude-ty">Result</span>&lt;String&gt; {
<a href=#135 id=135 data-nosnippet>135</a> <span class="kw">let </span><span class="kw-2">mut </span>parser_ctx = ParserContext::new(<span class="kw-2">&amp;</span>GreptimeDbDialect {}, flow_info.raw_sql())
<a href=#136 id=136 data-nosnippet>136</a> .map_err(BoxedError::new)
<a href=#137 id=137 data-nosnippet>137</a> .context(InternalSnafu)<span class="question-mark">?</span>;
<a href=#138 id=138 data-nosnippet>138</a>
<a href=#139 id=139 data-nosnippet>139</a> <span class="kw">let </span>query = parser_ctx
<a href=#140 id=140 data-nosnippet>140</a> .parse_statement()
<a href=#141 id=141 data-nosnippet>141</a> .map_err(BoxedError::new)
<a href=#142 id=142 data-nosnippet>142</a> .context(InternalSnafu)<span class="question-mark">?</span>;
<a href=#143 id=143 data-nosnippet>143</a>
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">let </span>raw_query = <span class="kw">match </span><span class="kw-2">&amp;</span>query {
<a href=#145 id=145 data-nosnippet>145</a> Statement::Tql(<span class="kw">_</span>) =&gt; flow_info.raw_sql().clone(),
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">_ </span>=&gt; query.to_string(),
<a href=#147 id=147 data-nosnippet>147</a> };
<a href=#148 id=148 data-nosnippet>148</a>
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">let </span>query = Box::new(
<a href=#150 id=150 data-nosnippet>150</a> SqlOrTql::try_from_statement(query, <span class="kw-2">&amp;</span>raw_query)
<a href=#151 id=151 data-nosnippet>151</a> .map_err(BoxedError::new)
<a href=#152 id=152 data-nosnippet>152</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#153 id=153 data-nosnippet>153</a> );
<a href=#154 id=154 data-nosnippet>154</a>
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">let </span>comment = <span class="kw">if </span>flow_info.comment().is_empty() {
<a href=#156 id=156 data-nosnippet>156</a> <span class="prelude-val">None
<a href=#157 id=157 data-nosnippet>157</a> </span>} <span class="kw">else </span>{
<a href=#158 id=158 data-nosnippet>158</a> <span class="prelude-val">Some</span>(flow_info.comment().clone())
<a href=#159 id=159 data-nosnippet>159</a> };
<a href=#160 id=160 data-nosnippet>160</a>
<a href=#161 id=161 data-nosnippet>161</a> <span class="kw">let </span>stmt = CreateFlow {
<a href=#162 id=162 data-nosnippet>162</a> flow_name: sql::ast::ObjectName::from(<span class="macro">vec!</span>[Ident::new(flow_info.flow_name())]),
<a href=#163 id=163 data-nosnippet>163</a> sink_table_name: sql::ast::ObjectName::from(<span class="macro">vec!</span>[
<a href=#164 id=164 data-nosnippet>164</a> Ident::new(<span class="kw-2">&amp;</span>flow_info.sink_table_name().schema_name),
<a href=#165 id=165 data-nosnippet>165</a> Ident::new(<span class="kw-2">&amp;</span>flow_info.sink_table_name().table_name),
<a href=#166 id=166 data-nosnippet>166</a> ]),
<a href=#167 id=167 data-nosnippet>167</a> or_replace: <span class="bool-val">false</span>,
<a href=#168 id=168 data-nosnippet>168</a> if_not_exists: <span class="bool-val">true</span>,
<a href=#169 id=169 data-nosnippet>169</a> expire_after: flow_info.expire_after(),
<a href=#170 id=170 data-nosnippet>170</a> eval_interval: flow_info.eval_interval(),
<a href=#171 id=171 data-nosnippet>171</a> eval_offset: effective_eval_schedule_from_flow_info(flow_info)
<a href=#172 id=172 data-nosnippet>172</a> .map_err(BoxedError::new)
<a href=#173 id=173 data-nosnippet>173</a> .context(InternalSnafu)<span class="question-mark">?
<a href=#174 id=174 data-nosnippet>174</a> </span>.map(|schedule| schedule.anchor_secs)
<a href=#175 id=175 data-nosnippet>175</a> .filter(|anchor_secs| <span class="kw-2">*</span>anchor_secs != <span class="number">0</span>),
<a href=#176 id=176 data-nosnippet>176</a> comment,
<a href=#177 id=177 data-nosnippet>177</a> flow_options: sql::statements::OptionMap::from_filtered_string_map(
<a href=#178 id=178 data-nosnippet>178</a> flow_info.options(),
<a href=#179 id=179 data-nosnippet>179</a> <span class="kw-2">&amp;</span>[FlowType::FLOW_TYPE_KEY],
<a href=#180 id=180 data-nosnippet>180</a> ),
<a href=#181 id=181 data-nosnippet>181</a> query,
<a href=#182 id=182 data-nosnippet>182</a> };
<a href=#183 id=183 data-nosnippet>183</a>
<a href=#184 id=184 data-nosnippet>184</a> <span class="prelude-val">Ok</span>(stmt.to_string())
<a href=#185 id=185 data-nosnippet>185</a> }
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaFlowsBuilder {
<a href=#188 id=188 data-nosnippet>188</a> InformationSchemaFlowsBuilder::new(
<a href=#189 id=189 data-nosnippet>189</a> <span class="self">self</span>.schema.clone(),
<a href=#190 id=190 data-nosnippet>190</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#191 id=191 data-nosnippet>191</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#192 id=192 data-nosnippet>192</a> <span class="kw-2">&amp;</span><span class="self">self</span>.flow_metadata_manager,
<a href=#193 id=193 data-nosnippet>193</a> )
<a href=#194 id=194 data-nosnippet>194</a> }
<a href=#195 id=195 data-nosnippet>195</a>}
<a href=#196 id=196 data-nosnippet>196</a>
<a href=#197 id=197 data-nosnippet>197</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaFlows {
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#199 id=199 data-nosnippet>199</a> INFORMATION_SCHEMA_FLOW_TABLE_ID
<a href=#200 id=200 data-nosnippet>200</a> }
<a href=#201 id=201 data-nosnippet>201</a>
<a href=#202 id=202 data-nosnippet>202</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#203 id=203 data-nosnippet>203</a> FLOWS
<a href=#204 id=204 data-nosnippet>204</a> }
<a href=#205 id=205 data-nosnippet>205</a>
<a href=#206 id=206 data-nosnippet>206</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#207 id=207 data-nosnippet>207</a> <span class="self">self</span>.schema.clone()
<a href=#208 id=208 data-nosnippet>208</a> }
<a href=#209 id=209 data-nosnippet>209</a>
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#211 id=211 data-nosnippet>211</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#212 id=212 data-nosnippet>212</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#214 id=214 data-nosnippet>214</a> schema,
<a href=#215 id=215 data-nosnippet>215</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#216 id=216 data-nosnippet>216</a> builder
<a href=#217 id=217 data-nosnippet>217</a> .make_flows(<span class="prelude-val">Some</span>(request))
<a href=#218 id=218 data-nosnippet>218</a> .<span class="kw">await
<a href=#219 id=219 data-nosnippet>219</a> </span>.map(|x| x.into_df_record_batch())
<a href=#220 id=220 data-nosnippet>220</a> .map_err(|err| datafusion::error::DataFusionError::External(Box::new(err)))
<a href=#221 id=221 data-nosnippet>221</a> }),
<a href=#222 id=222 data-nosnippet>222</a> ));
<a href=#223 id=223 data-nosnippet>223</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#224 id=224 data-nosnippet>224</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#225 id=225 data-nosnippet>225</a> .map_err(BoxedError::new)
<a href=#226 id=226 data-nosnippet>226</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#227 id=227 data-nosnippet>227</a> ))
<a href=#228 id=228 data-nosnippet>228</a> }
<a href=#229 id=229 data-nosnippet>229</a>}
<a href=#230 id=230 data-nosnippet>230</a>
<a href=#231 id=231 data-nosnippet>231</a><span class="doccomment">/// Builds the `information_schema.FLOWS` table row by row
<a href=#232 id=232 data-nosnippet>232</a>///
<a href=#233 id=233 data-nosnippet>233</a>/// columns are based on [`FlowInfoValue`]
<a href=#234 id=234 data-nosnippet>234</a></span><span class="kw">struct </span>InformationSchemaFlowsBuilder {
<a href=#235 id=235 data-nosnippet>235</a> schema: SchemaRef,
<a href=#236 id=236 data-nosnippet>236</a> catalog_name: String,
<a href=#237 id=237 data-nosnippet>237</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#238 id=238 data-nosnippet>238</a> flow_metadata_manager: Arc&lt;FlowMetadataManager&gt;,
<a href=#239 id=239 data-nosnippet>239</a>
<a href=#240 id=240 data-nosnippet>240</a> flow_names: StringVectorBuilder,
<a href=#241 id=241 data-nosnippet>241</a> flow_ids: UInt32VectorBuilder,
<a href=#242 id=242 data-nosnippet>242</a> state_sizes: UInt64VectorBuilder,
<a href=#243 id=243 data-nosnippet>243</a> table_catalogs: StringVectorBuilder,
<a href=#244 id=244 data-nosnippet>244</a> raw_sqls: StringVectorBuilder,
<a href=#245 id=245 data-nosnippet>245</a> comments: StringVectorBuilder,
<a href=#246 id=246 data-nosnippet>246</a> expire_afters: Int64VectorBuilder,
<a href=#247 id=247 data-nosnippet>247</a> source_table_id_groups: StringVectorBuilder,
<a href=#248 id=248 data-nosnippet>248</a> sink_table_names: StringVectorBuilder,
<a href=#249 id=249 data-nosnippet>249</a> flownode_id_groups: StringVectorBuilder,
<a href=#250 id=250 data-nosnippet>250</a> option_groups: StringVectorBuilder,
<a href=#251 id=251 data-nosnippet>251</a> created_time: TimestampMillisecondVectorBuilder,
<a href=#252 id=252 data-nosnippet>252</a> updated_time: TimestampMillisecondVectorBuilder,
<a href=#253 id=253 data-nosnippet>253</a> last_execution_time: TimestampMillisecondVectorBuilder,
<a href=#254 id=254 data-nosnippet>254</a> source_table_names: StringVectorBuilder,
<a href=#255 id=255 data-nosnippet>255</a> flownode_addr_groups: StringVectorBuilder,
<a href=#256 id=256 data-nosnippet>256</a>}
<a href=#257 id=257 data-nosnippet>257</a>
<a href=#258 id=258 data-nosnippet>258</a><span class="kw">impl </span>InformationSchemaFlowsBuilder {
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">fn </span>new(
<a href=#260 id=260 data-nosnippet>260</a> schema: SchemaRef,
<a href=#261 id=261 data-nosnippet>261</a> catalog_name: String,
<a href=#262 id=262 data-nosnippet>262</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#263 id=263 data-nosnippet>263</a> flow_metadata_manager: <span class="kw-2">&amp;</span>Arc&lt;FlowMetadataManager&gt;,
<a href=#264 id=264 data-nosnippet>264</a> ) -&gt; <span class="self">Self </span>{
<a href=#265 id=265 data-nosnippet>265</a> <span class="self">Self </span>{
<a href=#266 id=266 data-nosnippet>266</a> schema,
<a href=#267 id=267 data-nosnippet>267</a> catalog_name,
<a href=#268 id=268 data-nosnippet>268</a> catalog_manager,
<a href=#269 id=269 data-nosnippet>269</a> flow_metadata_manager: flow_metadata_manager.clone(),
<a href=#270 id=270 data-nosnippet>270</a>
<a href=#271 id=271 data-nosnippet>271</a> flow_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#272 id=272 data-nosnippet>272</a> flow_ids: UInt32VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#273 id=273 data-nosnippet>273</a> state_sizes: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#274 id=274 data-nosnippet>274</a> table_catalogs: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#275 id=275 data-nosnippet>275</a> raw_sqls: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#276 id=276 data-nosnippet>276</a> comments: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#277 id=277 data-nosnippet>277</a> expire_afters: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#278 id=278 data-nosnippet>278</a> source_table_id_groups: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#279 id=279 data-nosnippet>279</a> sink_table_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#280 id=280 data-nosnippet>280</a> flownode_id_groups: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#281 id=281 data-nosnippet>281</a> option_groups: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#282 id=282 data-nosnippet>282</a> created_time: TimestampMillisecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#283 id=283 data-nosnippet>283</a> updated_time: TimestampMillisecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#284 id=284 data-nosnippet>284</a> last_execution_time: TimestampMillisecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#285 id=285 data-nosnippet>285</a> source_table_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#286 id=286 data-nosnippet>286</a> flownode_addr_groups: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#287 id=287 data-nosnippet>287</a> }
<a href=#288 id=288 data-nosnippet>288</a> }
<a href=#289 id=289 data-nosnippet>289</a>
<a href=#290 id=290 data-nosnippet>290</a> <span class="doccomment">/// Construct the `information_schema.flows` virtual table
<a href=#291 id=291 data-nosnippet>291</a> </span><span class="kw">async fn </span>make_flows(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#292 id=292 data-nosnippet>292</a> <span class="kw">let </span>catalog_name = <span class="self">self</span>.catalog_name.clone();
<a href=#293 id=293 data-nosnippet>293</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#294 id=294 data-nosnippet>294</a>
<a href=#295 id=295 data-nosnippet>295</a> <span class="kw">let </span>flow_info_manager = <span class="self">self</span>.flow_metadata_manager.clone();
<a href=#296 id=296 data-nosnippet>296</a>
<a href=#297 id=297 data-nosnippet>297</a> <span class="comment">// TODO(discord9): use `AsyncIterator` once it's stable-ish
<a href=#298 id=298 data-nosnippet>298</a> </span><span class="kw">let </span><span class="kw-2">mut </span>stream = flow_info_manager
<a href=#299 id=299 data-nosnippet>299</a> .flow_name_manager()
<a href=#300 id=300 data-nosnippet>300</a> .flow_names(<span class="kw-2">&amp;</span>catalog_name)
<a href=#301 id=301 data-nosnippet>301</a> .<span class="kw">await</span>;
<a href=#302 id=302 data-nosnippet>302</a>
<a href=#303 id=303 data-nosnippet>303</a> <span class="kw">let </span>flow_stat = {
<a href=#304 id=304 data-nosnippet>304</a> <span class="kw">let </span>information_extension = utils::information_extension(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#305 id=305 data-nosnippet>305</a> information_extension.flow_stats().<span class="kw">await</span><span class="question-mark">?
<a href=#306 id=306 data-nosnippet>306</a> </span>};
<a href=#307 id=307 data-nosnippet>307</a>
<a href=#308 id=308 data-nosnippet>308</a> <span class="kw">while let </span><span class="prelude-val">Some</span>((flow_name, flow_id)) = stream
<a href=#309 id=309 data-nosnippet>309</a> .try_next()
<a href=#310 id=310 data-nosnippet>310</a> .<span class="kw">await
<a href=#311 id=311 data-nosnippet>311</a> </span>.map_err(BoxedError::new)
<a href=#312 id=312 data-nosnippet>312</a> .context(ListFlowsSnafu {
<a href=#313 id=313 data-nosnippet>313</a> catalog: <span class="kw-2">&amp;</span>catalog_name,
<a href=#314 id=314 data-nosnippet>314</a> })<span class="question-mark">?
<a href=#315 id=315 data-nosnippet>315</a> </span>{
<a href=#316 id=316 data-nosnippet>316</a> <span class="kw">let </span>flow_info = flow_info_manager
<a href=#317 id=317 data-nosnippet>317</a> .flow_info_manager()
<a href=#318 id=318 data-nosnippet>318</a> .get(flow_id.flow_id())
<a href=#319 id=319 data-nosnippet>319</a> .<span class="kw">await
<a href=#320 id=320 data-nosnippet>320</a> </span>.map_err(BoxedError::new)
<a href=#321 id=321 data-nosnippet>321</a> .context(InternalSnafu)<span class="question-mark">?
<a href=#322 id=322 data-nosnippet>322</a> </span>.with_context(|| FlowInfoNotFoundSnafu {
<a href=#323 id=323 data-nosnippet>323</a> catalog_name: catalog_name.clone(),
<a href=#324 id=324 data-nosnippet>324</a> flow_name: flow_name.clone(),
<a href=#325 id=325 data-nosnippet>325</a> })<span class="question-mark">?</span>;
<a href=#326 id=326 data-nosnippet>326</a> <span class="self">self</span>.add_flow(<span class="kw-2">&amp;</span>predicates, flow_id.flow_id(), flow_info, <span class="kw-2">&amp;</span>flow_stat)
<a href=#327 id=327 data-nosnippet>327</a> .<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#328 id=328 data-nosnippet>328</a> }
<a href=#329 id=329 data-nosnippet>329</a>
<a href=#330 id=330 data-nosnippet>330</a> <span class="self">self</span>.finish()
<a href=#331 id=331 data-nosnippet>331</a> }
<a href=#332 id=332 data-nosnippet>332</a>
<a href=#333 id=333 data-nosnippet>333</a> <span class="kw">async fn </span>add_flow(
<a href=#334 id=334 data-nosnippet>334</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#335 id=335 data-nosnippet>335</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#336 id=336 data-nosnippet>336</a> flow_id: FlowId,
<a href=#337 id=337 data-nosnippet>337</a> flow_info: FlowInfoValue,
<a href=#338 id=338 data-nosnippet>338</a> flow_stat: <span class="kw-2">&amp;</span><span class="prelude-ty">Option</span>&lt;FlowStat&gt;,
<a href=#339 id=339 data-nosnippet>339</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#340 id=340 data-nosnippet>340</a> <span class="kw">let </span>row = [
<a href=#341 id=341 data-nosnippet>341</a> (FLOW_NAME, <span class="kw-2">&amp;</span>Value::from(flow_info.flow_name().clone())),
<a href=#342 id=342 data-nosnippet>342</a> (FLOW_ID, <span class="kw-2">&amp;</span>Value::from(flow_id)),
<a href=#343 id=343 data-nosnippet>343</a> (
<a href=#344 id=344 data-nosnippet>344</a> TABLE_CATALOG,
<a href=#345 id=345 data-nosnippet>345</a> <span class="kw-2">&amp;</span>Value::from(flow_info.catalog_name().clone()),
<a href=#346 id=346 data-nosnippet>346</a> ),
<a href=#347 id=347 data-nosnippet>347</a> ];
<a href=#348 id=348 data-nosnippet>348</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#349 id=349 data-nosnippet>349</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#350 id=350 data-nosnippet>350</a> }
<a href=#351 id=351 data-nosnippet>351</a> <span class="self">self</span>.flow_names.push(<span class="prelude-val">Some</span>(flow_info.flow_name()));
<a href=#352 id=352 data-nosnippet>352</a> <span class="self">self</span>.flow_ids.push(<span class="prelude-val">Some</span>(flow_id));
<a href=#353 id=353 data-nosnippet>353</a> <span class="self">self</span>.state_sizes.push(
<a href=#354 id=354 data-nosnippet>354</a> flow_stat
<a href=#355 id=355 data-nosnippet>355</a> .as_ref()
<a href=#356 id=356 data-nosnippet>356</a> .and_then(|state| state.state_size.get(<span class="kw-2">&amp;</span>flow_id).map(|v| <span class="kw-2">*</span>v <span class="kw">as </span>u64)),
<a href=#357 id=357 data-nosnippet>357</a> );
<a href=#358 id=358 data-nosnippet>358</a> <span class="self">self</span>.table_catalogs.push(<span class="prelude-val">Some</span>(flow_info.catalog_name()));
<a href=#359 id=359 data-nosnippet>359</a> <span class="self">self</span>.raw_sqls
<a href=#360 id=360 data-nosnippet>360</a> .push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>InformationSchemaFlows::generate_show_create_flow(
<a href=#361 id=361 data-nosnippet>361</a> <span class="kw-2">&amp;</span>flow_info,
<a href=#362 id=362 data-nosnippet>362</a> )<span class="question-mark">?</span>));
<a href=#363 id=363 data-nosnippet>363</a> <span class="self">self</span>.comments.push(<span class="prelude-val">Some</span>(flow_info.comment()));
<a href=#364 id=364 data-nosnippet>364</a> <span class="self">self</span>.expire_afters.push(flow_info.expire_after());
<a href=#365 id=365 data-nosnippet>365</a> <span class="self">self</span>.source_table_id_groups.push(<span class="prelude-val">Some</span>(
<a href=#366 id=366 data-nosnippet>366</a> <span class="kw-2">&amp;</span>serde_json::to_string(flow_info.source_table_ids()).context(JsonSnafu {
<a href=#367 id=367 data-nosnippet>367</a> input: <span class="macro">format!</span>(<span class="string">"{:?}"</span>, flow_info.source_table_ids()),
<a href=#368 id=368 data-nosnippet>368</a> })<span class="question-mark">?</span>,
<a href=#369 id=369 data-nosnippet>369</a> ));
<a href=#370 id=370 data-nosnippet>370</a> <span class="self">self</span>.sink_table_names
<a href=#371 id=371 data-nosnippet>371</a> .push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>flow_info.sink_table_name().to_string()));
<a href=#372 id=372 data-nosnippet>372</a> <span class="self">self</span>.flownode_id_groups.push(<span class="prelude-val">Some</span>(
<a href=#373 id=373 data-nosnippet>373</a> <span class="kw-2">&amp;</span>serde_json::to_string(flow_info.flownode_ids()).context({
<a href=#374 id=374 data-nosnippet>374</a> JsonSnafu {
<a href=#375 id=375 data-nosnippet>375</a> input: <span class="macro">format!</span>(<span class="string">"{:?}"</span>, flow_info.flownode_ids()),
<a href=#376 id=376 data-nosnippet>376</a> }
<a href=#377 id=377 data-nosnippet>377</a> })<span class="question-mark">?</span>,
<a href=#378 id=378 data-nosnippet>378</a> ));
<a href=#379 id=379 data-nosnippet>379</a> <span class="self">self</span>.option_groups
<a href=#380 id=380 data-nosnippet>380</a> .push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>serde_json::to_string(flow_info.options()).context(
<a href=#381 id=381 data-nosnippet>381</a> JsonSnafu {
<a href=#382 id=382 data-nosnippet>382</a> input: <span class="macro">format!</span>(<span class="string">"{:?}"</span>, flow_info.options()),
<a href=#383 id=383 data-nosnippet>383</a> },
<a href=#384 id=384 data-nosnippet>384</a> )<span class="question-mark">?</span>));
<a href=#385 id=385 data-nosnippet>385</a> <span class="self">self</span>.created_time
<a href=#386 id=386 data-nosnippet>386</a> .push(<span class="prelude-val">Some</span>(flow_info.created_time().timestamp_millis().into()));
<a href=#387 id=387 data-nosnippet>387</a> <span class="self">self</span>.updated_time
<a href=#388 id=388 data-nosnippet>388</a> .push(<span class="prelude-val">Some</span>(flow_info.updated_time().timestamp_millis().into()));
<a href=#389 id=389 data-nosnippet>389</a> <span class="self">self</span>.last_execution_time
<a href=#390 id=390 data-nosnippet>390</a> .push(flow_stat.as_ref().and_then(|state| {
<a href=#391 id=391 data-nosnippet>391</a> state
<a href=#392 id=392 data-nosnippet>392</a> .last_exec_time_map
<a href=#393 id=393 data-nosnippet>393</a> .get(<span class="kw-2">&amp;</span>flow_id)
<a href=#394 id=394 data-nosnippet>394</a> .map(|v| TimestampMillisecond::new(<span class="kw-2">*</span>v))
<a href=#395 id=395 data-nosnippet>395</a> }));
<a href=#396 id=396 data-nosnippet>396</a> <span class="kw">let </span>flownode_addrs = <span class="self">self
<a href=#397 id=397 data-nosnippet>397</a> </span>.flow_metadata_manager
<a href=#398 id=398 data-nosnippet>398</a> .flownode_addrs(flow_id)
<a href=#399 id=399 data-nosnippet>399</a> .<span class="kw">await
<a href=#400 id=400 data-nosnippet>400</a> </span>.map_err(BoxedError::new)
<a href=#401 id=401 data-nosnippet>401</a> .context(InternalSnafu)<span class="question-mark">?</span>;
<a href=#402 id=402 data-nosnippet>402</a> <span class="kw">if </span>flownode_addrs.is_empty() {
<a href=#403 id=403 data-nosnippet>403</a> <span class="self">self</span>.flownode_addr_groups.push(<span class="prelude-val">None</span>);
<a href=#404 id=404 data-nosnippet>404</a> } <span class="kw">else </span>{
<a href=#405 id=405 data-nosnippet>405</a> <span class="kw">let </span>flownode_addrs_json =
<a href=#406 id=406 data-nosnippet>406</a> serde_json::to_string(<span class="kw-2">&amp;</span>flownode_addrs).with_context(|<span class="kw">_</span>| JsonSnafu {
<a href=#407 id=407 data-nosnippet>407</a> input: <span class="macro">format!</span>(<span class="string">"{:?}"</span>, flownode_addrs),
<a href=#408 id=408 data-nosnippet>408</a> })<span class="question-mark">?</span>;
<a href=#409 id=409 data-nosnippet>409</a> <span class="self">self</span>.flownode_addr_groups.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>flownode_addrs_json));
<a href=#410 id=410 data-nosnippet>410</a> }
<a href=#411 id=411 data-nosnippet>411</a>
<a href=#412 id=412 data-nosnippet>412</a> <span class="kw">let </span><span class="kw-2">mut </span>source_table_names = <span class="macro">vec!</span>[];
<a href=#413 id=413 data-nosnippet>413</a> <span class="kw">let </span>catalog_manager = <span class="self">self
<a href=#414 id=414 data-nosnippet>414</a> </span>.catalog_manager
<a href=#415 id=415 data-nosnippet>415</a> .upgrade()
<a href=#416 id=416 data-nosnippet>416</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#417 id=417 data-nosnippet>417</a> <span class="kw">for </span>table_id <span class="kw">in </span>flow_info.source_table_ids() {
<a href=#418 id=418 data-nosnippet>418</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table_info) = catalog_manager.table_info_by_id(<span class="kw-2">*</span>table_id).<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#419 id=419 data-nosnippet>419</a> source_table_names.push(table_info.full_table_name());
<a href=#420 id=420 data-nosnippet>420</a> }
<a href=#421 id=421 data-nosnippet>421</a> }
<a href=#422 id=422 data-nosnippet>422</a>
<a href=#423 id=423 data-nosnippet>423</a> <span class="kw">let </span>source_table_names = source_table_names.join(<span class="string">","</span>);
<a href=#424 id=424 data-nosnippet>424</a> <span class="self">self</span>.source_table_names.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>source_table_names));
<a href=#425 id=425 data-nosnippet>425</a>
<a href=#426 id=426 data-nosnippet>426</a> <span class="prelude-val">Ok</span>(())
<a href=#427 id=427 data-nosnippet>427</a> }
<a href=#428 id=428 data-nosnippet>428</a>
<a href=#429 id=429 data-nosnippet>429</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#430 id=430 data-nosnippet>430</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#431 id=431 data-nosnippet>431</a> Arc::new(<span class="self">self</span>.flow_names.finish()),
<a href=#432 id=432 data-nosnippet>432</a> Arc::new(<span class="self">self</span>.flow_ids.finish()),
<a href=#433 id=433 data-nosnippet>433</a> Arc::new(<span class="self">self</span>.state_sizes.finish()),
<a href=#434 id=434 data-nosnippet>434</a> Arc::new(<span class="self">self</span>.table_catalogs.finish()),
<a href=#435 id=435 data-nosnippet>435</a> Arc::new(<span class="self">self</span>.raw_sqls.finish()),
<a href=#436 id=436 data-nosnippet>436</a> Arc::new(<span class="self">self</span>.comments.finish()),
<a href=#437 id=437 data-nosnippet>437</a> Arc::new(<span class="self">self</span>.expire_afters.finish()),
<a href=#438 id=438 data-nosnippet>438</a> Arc::new(<span class="self">self</span>.source_table_id_groups.finish()),
<a href=#439 id=439 data-nosnippet>439</a> Arc::new(<span class="self">self</span>.sink_table_names.finish()),
<a href=#440 id=440 data-nosnippet>440</a> Arc::new(<span class="self">self</span>.flownode_id_groups.finish()),
<a href=#441 id=441 data-nosnippet>441</a> Arc::new(<span class="self">self</span>.option_groups.finish()),
<a href=#442 id=442 data-nosnippet>442</a> Arc::new(<span class="self">self</span>.created_time.finish()),
<a href=#443 id=443 data-nosnippet>443</a> Arc::new(<span class="self">self</span>.updated_time.finish()),
<a href=#444 id=444 data-nosnippet>444</a> Arc::new(<span class="self">self</span>.last_execution_time.finish()),
<a href=#445 id=445 data-nosnippet>445</a> Arc::new(<span class="self">self</span>.source_table_names.finish()),
<a href=#446 id=446 data-nosnippet>446</a> Arc::new(<span class="self">self</span>.flownode_addr_groups.finish()),
<a href=#447 id=447 data-nosnippet>447</a> ];
<a href=#448 id=448 data-nosnippet>448</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#449 id=449 data-nosnippet>449</a> }
<a href=#450 id=450 data-nosnippet>450</a>}
<a href=#451 id=451 data-nosnippet>451</a>
<a href=#452 id=452 data-nosnippet>452</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaFlows {
<a href=#453 id=453 data-nosnippet>453</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>arrow_schema::SchemaRef {
<a href=#454 id=454 data-nosnippet>454</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#455 id=455 data-nosnippet>455</a> }
<a href=#456 id=456 data-nosnippet>456</a>
<a href=#457 id=457 data-nosnippet>457</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#458 id=458 data-nosnippet>458</a> <span class="kw">let </span>schema: Arc&lt;arrow_schema::Schema&gt; = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#459 id=459 data-nosnippet>459</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#460 id=460 data-nosnippet>460</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#461 id=461 data-nosnippet>461</a> schema,
<a href=#462 id=462 data-nosnippet>462</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#463 id=463 data-nosnippet>463</a> builder
<a href=#464 id=464 data-nosnippet>464</a> .make_flows(<span class="prelude-val">None</span>)
<a href=#465 id=465 data-nosnippet>465</a> .<span class="kw">await
<a href=#466 id=466 data-nosnippet>466</a> </span>.map(|x| x.into_df_record_batch())
<a href=#467 id=467 data-nosnippet>467</a> .map_err(Into::into)
<a href=#468 id=468 data-nosnippet>468</a> }),
<a href=#469 id=469 data-nosnippet>469</a> ))
<a href=#470 id=470 data-nosnippet>470</a> }
<a href=#471 id=471 data-nosnippet>471</a>}
<a href=#472 id=472 data-nosnippet>472</a>
<a href=#473 id=473 data-nosnippet>473</a><span class="attr">#[cfg(test)]
<a href=#474 id=474 data-nosnippet>474</a></span><span class="kw">mod </span>tests {
<a href=#475 id=475 data-nosnippet>475</a> <span class="kw">use </span>std::collections::{BTreeMap, HashMap};
<a href=#476 id=476 data-nosnippet>476</a>
<a href=#477 id=477 data-nosnippet>477</a> <span class="kw">use </span>common_meta::key::flow::flow_info::{FlowMissedTickPolicy, FlowScheduleConfig, FlowStatus};
<a href=#478 id=478 data-nosnippet>478</a> <span class="kw">use </span>sql::parser::ParseOptions;
<a href=#479 id=479 data-nosnippet>479</a> <span class="kw">use </span>table::table_name::TableName;
<a href=#480 id=480 data-nosnippet>480</a>
<a href=#481 id=481 data-nosnippet>481</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#482 id=482 data-nosnippet>482</a>
<a href=#483 id=483 data-nosnippet>483</a> <span class="kw">fn </span>flow_info_for_show_create(
<a href=#484 id=484 data-nosnippet>484</a> raw_sql: <span class="kw-2">&amp;</span>str,
<a href=#485 id=485 data-nosnippet>485</a> eval_interval_secs: <span class="prelude-ty">Option</span>&lt;i64&gt;,
<a href=#486 id=486 data-nosnippet>486</a> anchor_secs: i64,
<a href=#487 id=487 data-nosnippet>487</a> options: HashMap&lt;String, String&gt;,
<a href=#488 id=488 data-nosnippet>488</a> ) -&gt; FlowInfoValue {
<a href=#489 id=489 data-nosnippet>489</a> <span class="kw">let </span>created_time = chrono::DateTime::from_timestamp(<span class="number">1_700_000_000</span>, <span class="number">0</span>).unwrap();
<a href=#490 id=490 data-nosnippet>490</a> FlowInfoValue {
<a href=#491 id=491 data-nosnippet>491</a> source_table_ids: <span class="macro">vec!</span>[],
<a href=#492 id=492 data-nosnippet>492</a> all_source_table_names: <span class="macro">vec!</span>[],
<a href=#493 id=493 data-nosnippet>493</a> unresolved_source_table_names: <span class="macro">vec!</span>[],
<a href=#494 id=494 data-nosnippet>494</a> sink_table_name: TableName::new(<span class="string">"greptime"</span>, <span class="string">"public"</span>, <span class="string">"sink"</span>),
<a href=#495 id=495 data-nosnippet>495</a> flownode_ids: BTreeMap::new(),
<a href=#496 id=496 data-nosnippet>496</a> catalog_name: <span class="string">"greptime"</span>.to_string(),
<a href=#497 id=497 data-nosnippet>497</a> query_context: <span class="prelude-val">None</span>,
<a href=#498 id=498 data-nosnippet>498</a> flow_name: <span class="string">"my_flow"</span>.to_string(),
<a href=#499 id=499 data-nosnippet>499</a> raw_sql: raw_sql.to_string(),
<a href=#500 id=500 data-nosnippet>500</a> expire_after: <span class="prelude-val">None</span>,
<a href=#501 id=501 data-nosnippet>501</a> eval_interval_secs,
<a href=#502 id=502 data-nosnippet>502</a> comment: String::new(),
<a href=#503 id=503 data-nosnippet>503</a> options,
<a href=#504 id=504 data-nosnippet>504</a> status: FlowStatus::Active,
<a href=#505 id=505 data-nosnippet>505</a> created_time,
<a href=#506 id=506 data-nosnippet>506</a> updated_time: created_time,
<a href=#507 id=507 data-nosnippet>507</a> eval_schedule: eval_interval_secs.map(|interval| FlowScheduleConfig {
<a href=#508 id=508 data-nosnippet>508</a> anchor_secs,
<a href=#509 id=509 data-nosnippet>509</a> start_secs: anchor_secs + interval,
<a href=#510 id=510 data-nosnippet>510</a> missed_tick_policy: FlowMissedTickPolicy::BoundedCatchUp,
<a href=#511 id=511 data-nosnippet>511</a> catchup_max_runs: <span class="number">3</span>,
<a href=#512 id=512 data-nosnippet>512</a> catchup_max_lag_secs: <span class="number">300</span>,
<a href=#513 id=513 data-nosnippet>513</a> }),
<a href=#514 id=514 data-nosnippet>514</a> }
<a href=#515 id=515 data-nosnippet>515</a> }
<a href=#516 id=516 data-nosnippet>516</a>
<a href=#517 id=517 data-nosnippet>517</a> <span class="attr">#[test]
<a href=#518 id=518 data-nosnippet>518</a> </span><span class="kw">fn </span>test_generate_show_create_flow_with_eval_offset() {
<a href=#519 id=519 data-nosnippet>519</a> <span class="comment">// `raw_sql` stores only the query part (the `AS` clause).
<a href=#520 id=520 data-nosnippet>520</a> </span><span class="kw">let </span>raw_sql = <span class="string">"SELECT max(c1) FROM public.src"</span>;
<a href=#521 id=521 data-nosnippet>521</a> <span class="kw">let </span>flow_info = flow_info_for_show_create(raw_sql, <span class="prelude-val">Some</span>(<span class="number">3600</span>), <span class="number">120</span>, HashMap::new());
<a href=#522 id=522 data-nosnippet>522</a> <span class="kw">let </span>sql = InformationSchemaFlows::generate_show_create_flow(<span class="kw-2">&amp;</span>flow_info).unwrap();
<a href=#523 id=523 data-nosnippet>523</a> <span class="macro">assert!</span>(
<a href=#524 id=524 data-nosnippet>524</a> sql.contains(<span class="string">"EVAL OFFSET '120 s'"</span>),
<a href=#525 id=525 data-nosnippet>525</a> <span class="string">"EVAL OFFSET must be emitted, got:\n{sql}"
<a href=#526 id=526 data-nosnippet>526</a> </span>);
<a href=#527 id=527 data-nosnippet>527</a> <span class="macro">assert!</span>(
<a href=#528 id=528 data-nosnippet>528</a> !sql.contains(<span class="string">"__greptime_internal_eval_offset_secs"</span>),
<a href=#529 id=529 data-nosnippet>529</a> <span class="string">"internal key must be absent, got:\n{sql}"
<a href=#530 id=530 data-nosnippet>530</a> </span>);
<a href=#531 id=531 data-nosnippet>531</a>
<a href=#532 id=532 data-nosnippet>532</a> <span class="kw">let </span>stmts = ParserContext::create_with_dialect(
<a href=#533 id=533 data-nosnippet>533</a> <span class="kw-2">&amp;</span>sql,
<a href=#534 id=534 data-nosnippet>534</a> <span class="kw-2">&amp;</span>GreptimeDbDialect {},
<a href=#535 id=535 data-nosnippet>535</a> ParseOptions::default(),
<a href=#536 id=536 data-nosnippet>536</a> )
<a href=#537 id=537 data-nosnippet>537</a> .unwrap();
<a href=#538 id=538 data-nosnippet>538</a> <span class="kw">let </span>Statement::CreateFlow(reparsed) = <span class="kw-2">&amp;</span>stmts[<span class="number">0</span>] <span class="kw">else </span>{
<a href=#539 id=539 data-nosnippet>539</a> <span class="macro">panic!</span>(<span class="string">"unexpected stmt: {:?}"</span>, stmts[<span class="number">0</span>]);
<a href=#540 id=540 data-nosnippet>540</a> };
<a href=#541 id=541 data-nosnippet>541</a> <span class="macro">assert_eq!</span>(reparsed.eval_interval, <span class="prelude-val">Some</span>(<span class="number">3600</span>));
<a href=#542 id=542 data-nosnippet>542</a> <span class="macro">assert_eq!</span>(reparsed.eval_offset, <span class="prelude-val">Some</span>(<span class="number">120</span>));
<a href=#543 id=543 data-nosnippet>543</a> }
<a href=#544 id=544 data-nosnippet>544</a>
<a href=#545 id=545 data-nosnippet>545</a> <span class="attr">#[test]
<a href=#546 id=546 data-nosnippet>546</a> </span><span class="kw">fn </span>test_generate_show_create_flow_omits_zero_offset() {
<a href=#547 id=547 data-nosnippet>547</a> <span class="kw">let </span>raw_sql = <span class="string">"SELECT max(c1) FROM public.src"</span>;
<a href=#548 id=548 data-nosnippet>548</a> <span class="kw">let </span>flow_info = flow_info_for_show_create(raw_sql, <span class="prelude-val">Some</span>(<span class="number">3600</span>), <span class="number">0</span>, HashMap::new());
<a href=#549 id=549 data-nosnippet>549</a> <span class="kw">let </span>sql = InformationSchemaFlows::generate_show_create_flow(<span class="kw-2">&amp;</span>flow_info).unwrap();
<a href=#550 id=550 data-nosnippet>550</a> <span class="macro">assert!</span>(
<a href=#551 id=551 data-nosnippet>551</a> !sql.contains(<span class="string">"EVAL OFFSET"</span>),
<a href=#552 id=552 data-nosnippet>552</a> <span class="string">"zero offset must be omitted, got:\n{sql}"
<a href=#553 id=553 data-nosnippet>553</a> </span>);
<a href=#554 id=554 data-nosnippet>554</a> <span class="kw">let </span>stmts = ParserContext::create_with_dialect(
<a href=#555 id=555 data-nosnippet>555</a> <span class="kw-2">&amp;</span>sql,
<a href=#556 id=556 data-nosnippet>556</a> <span class="kw-2">&amp;</span>GreptimeDbDialect {},
<a href=#557 id=557 data-nosnippet>557</a> ParseOptions::default(),
<a href=#558 id=558 data-nosnippet>558</a> )
<a href=#559 id=559 data-nosnippet>559</a> .unwrap();
<a href=#560 id=560 data-nosnippet>560</a> <span class="kw">let </span>Statement::CreateFlow(reparsed) = <span class="kw-2">&amp;</span>stmts[<span class="number">0</span>] <span class="kw">else </span>{
<a href=#561 id=561 data-nosnippet>561</a> <span class="macro">panic!</span>(<span class="string">"unexpected stmt: {:?}"</span>, stmts[<span class="number">0</span>]);
<a href=#562 id=562 data-nosnippet>562</a> };
<a href=#563 id=563 data-nosnippet>563</a> <span class="macro">assert_eq!</span>(reparsed.eval_offset, <span class="prelude-val">None</span>);
<a href=#564 id=564 data-nosnippet>564</a> }
<a href=#565 id=565 data-nosnippet>565</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,432 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/information_memory_table.rs`."><title>information_memory_table.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>information_memory_table.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::Arc;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_catalog::consts::{METRIC_ENGINE, MITO_ENGINE};
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>datatypes::schema::{Schema, SchemaRef};
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>datatypes::vectors::{Int64Vector, StringVector, VectorRef};
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::table_names::<span class="kw-2">*</span>;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::utils::tables::{
<a href=#23 id=23 data-nosnippet>23</a> bigint_column, string_column, string_columns, timestamp_micro_column,
<a href=#24 id=24 data-nosnippet>24</a>};
<a href=#25 id=25 data-nosnippet>25</a>
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">const </span>NO_VALUE: <span class="kw-2">&amp;</span>str = <span class="string">"NO"</span>;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="doccomment">/// Find the schema and columns by the table_name, only valid for memory tables.
<a href=#29 id=29 data-nosnippet>29</a>/// Safety: the user MUST ensure the table schema exists, panic otherwise.
<a href=#30 id=30 data-nosnippet>30</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>get_schema_columns(table_name: <span class="kw-2">&amp;</span>str) -&gt; (SchemaRef, Vec&lt;VectorRef&gt;) {
<a href=#31 id=31 data-nosnippet>31</a> <span class="kw">let </span>(column_schemas, columns): (<span class="kw">_</span>, Vec&lt;VectorRef&gt;) = <span class="kw">match </span>table_name {
<a href=#32 id=32 data-nosnippet>32</a> COLUMN_PRIVILEGES =&gt; (
<a href=#33 id=33 data-nosnippet>33</a> string_columns(<span class="kw-2">&amp;</span>[
<a href=#34 id=34 data-nosnippet>34</a> <span class="string">"GRANTEE"</span>,
<a href=#35 id=35 data-nosnippet>35</a> <span class="string">"TABLE_CATALOG"</span>,
<a href=#36 id=36 data-nosnippet>36</a> <span class="string">"TABLE_SCHEMA"</span>,
<a href=#37 id=37 data-nosnippet>37</a> <span class="string">"TABLE_NAME"</span>,
<a href=#38 id=38 data-nosnippet>38</a> <span class="string">"COLUMN_NAME"</span>,
<a href=#39 id=39 data-nosnippet>39</a> <span class="string">"PRIVILEGE_TYPE"</span>,
<a href=#40 id=40 data-nosnippet>40</a> <span class="string">"IS_GRANTABLE"</span>,
<a href=#41 id=41 data-nosnippet>41</a> ]),
<a href=#42 id=42 data-nosnippet>42</a> <span class="macro">vec!</span>[],
<a href=#43 id=43 data-nosnippet>43</a> ),
<a href=#44 id=44 data-nosnippet>44</a>
<a href=#45 id=45 data-nosnippet>45</a> COLUMN_STATISTICS =&gt; (
<a href=#46 id=46 data-nosnippet>46</a> string_columns(<span class="kw-2">&amp;</span>[
<a href=#47 id=47 data-nosnippet>47</a> <span class="string">"SCHEMA_NAME"</span>,
<a href=#48 id=48 data-nosnippet>48</a> <span class="string">"TABLE_NAME"</span>,
<a href=#49 id=49 data-nosnippet>49</a> <span class="string">"COLUMN_NAME"</span>,
<a href=#50 id=50 data-nosnippet>50</a> <span class="comment">// TODO(dennis): It must be a JSON type, but we don't support it yet
<a href=#51 id=51 data-nosnippet>51</a> </span><span class="string">"HISTOGRAM"</span>,
<a href=#52 id=52 data-nosnippet>52</a> ]),
<a href=#53 id=53 data-nosnippet>53</a> <span class="macro">vec!</span>[],
<a href=#54 id=54 data-nosnippet>54</a> ),
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a> ENGINES =&gt; (
<a href=#57 id=57 data-nosnippet>57</a> string_columns(<span class="kw-2">&amp;</span>[
<a href=#58 id=58 data-nosnippet>58</a> <span class="string">"ENGINE"</span>,
<a href=#59 id=59 data-nosnippet>59</a> <span class="string">"SUPPORT"</span>,
<a href=#60 id=60 data-nosnippet>60</a> <span class="string">"COMMENT"</span>,
<a href=#61 id=61 data-nosnippet>61</a> <span class="string">"TRANSACTIONS"</span>,
<a href=#62 id=62 data-nosnippet>62</a> <span class="string">"XA"</span>,
<a href=#63 id=63 data-nosnippet>63</a> <span class="string">"SAVEPOINTS"</span>,
<a href=#64 id=64 data-nosnippet>64</a> ]),
<a href=#65 id=65 data-nosnippet>65</a> <span class="macro">vec!</span>[
<a href=#66 id=66 data-nosnippet>66</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[MITO_ENGINE, METRIC_ENGINE])),
<a href=#67 id=67 data-nosnippet>67</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"DEFAULT"</span>, <span class="string">"YES"</span>])),
<a href=#68 id=68 data-nosnippet>68</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[
<a href=#69 id=69 data-nosnippet>69</a> <span class="string">"Storage engine for time-series data"</span>,
<a href=#70 id=70 data-nosnippet>70</a> <span class="string">"Storage engine for observability scenarios, which is adept at handling a large number of small tables, making it particularly suitable for cloud-native monitoring"</span>,
<a href=#71 id=71 data-nosnippet>71</a> ])),
<a href=#72 id=72 data-nosnippet>72</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[NO_VALUE, NO_VALUE])),
<a href=#73 id=73 data-nosnippet>73</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[NO_VALUE, NO_VALUE])),
<a href=#74 id=74 data-nosnippet>74</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[NO_VALUE, NO_VALUE])),
<a href=#75 id=75 data-nosnippet>75</a> ],
<a href=#76 id=76 data-nosnippet>76</a> ),
<a href=#77 id=77 data-nosnippet>77</a>
<a href=#78 id=78 data-nosnippet>78</a> BUILD_INFO =&gt; {
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw">let </span>build_info = common_version::build_info();
<a href=#80 id=80 data-nosnippet>80</a> (
<a href=#81 id=81 data-nosnippet>81</a> string_columns(<span class="kw-2">&amp;</span>[
<a href=#82 id=82 data-nosnippet>82</a> <span class="string">"GIT_BRANCH"</span>,
<a href=#83 id=83 data-nosnippet>83</a> <span class="string">"GIT_COMMIT"</span>,
<a href=#84 id=84 data-nosnippet>84</a> <span class="string">"GIT_COMMIT_SHORT"</span>,
<a href=#85 id=85 data-nosnippet>85</a> <span class="string">"GIT_CLEAN"</span>,
<a href=#86 id=86 data-nosnippet>86</a> <span class="string">"PKG_VERSION"</span>,
<a href=#87 id=87 data-nosnippet>87</a> ]),
<a href=#88 id=88 data-nosnippet>88</a> <span class="macro">vec!</span>[
<a href=#89 id=89 data-nosnippet>89</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[build_info.branch.to_string()])),
<a href=#90 id=90 data-nosnippet>90</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[build_info.commit.to_string()])),
<a href=#91 id=91 data-nosnippet>91</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[
<a href=#92 id=92 data-nosnippet>92</a> build_info.commit_short.to_string(),
<a href=#93 id=93 data-nosnippet>93</a> ])),
<a href=#94 id=94 data-nosnippet>94</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[build_info.clean.to_string()])),
<a href=#95 id=95 data-nosnippet>95</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[build_info.version.to_string()])),
<a href=#96 id=96 data-nosnippet>96</a> ],
<a href=#97 id=97 data-nosnippet>97</a> )
<a href=#98 id=98 data-nosnippet>98</a> }
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> CHARACTER_SETS =&gt; (
<a href=#101 id=101 data-nosnippet>101</a> <span class="macro">vec!</span>[
<a href=#102 id=102 data-nosnippet>102</a> string_column(<span class="string">"CHARACTER_SET_NAME"</span>),
<a href=#103 id=103 data-nosnippet>103</a> string_column(<span class="string">"DEFAULT_COLLATE_NAME"</span>),
<a href=#104 id=104 data-nosnippet>104</a> string_column(<span class="string">"DESCRIPTION"</span>),
<a href=#105 id=105 data-nosnippet>105</a> bigint_column(<span class="string">"MAXLEN"</span>),
<a href=#106 id=106 data-nosnippet>106</a> ],
<a href=#107 id=107 data-nosnippet>107</a> <span class="macro">vec!</span>[
<a href=#108 id=108 data-nosnippet>108</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"utf8"</span>])),
<a href=#109 id=109 data-nosnippet>109</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"utf8_bin"</span>])),
<a href=#110 id=110 data-nosnippet>110</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"UTF-8 Unicode"</span>])),
<a href=#111 id=111 data-nosnippet>111</a> Arc::new(Int64Vector::from_slice([<span class="number">4</span>])),
<a href=#112 id=112 data-nosnippet>112</a> ],
<a href=#113 id=113 data-nosnippet>113</a> ),
<a href=#114 id=114 data-nosnippet>114</a>
<a href=#115 id=115 data-nosnippet>115</a> COLLATIONS =&gt; (
<a href=#116 id=116 data-nosnippet>116</a> <span class="macro">vec!</span>[
<a href=#117 id=117 data-nosnippet>117</a> string_column(<span class="string">"COLLATION_NAME"</span>),
<a href=#118 id=118 data-nosnippet>118</a> string_column(<span class="string">"CHARACTER_SET_NAME"</span>),
<a href=#119 id=119 data-nosnippet>119</a> bigint_column(<span class="string">"ID"</span>),
<a href=#120 id=120 data-nosnippet>120</a> string_column(<span class="string">"IS_DEFAULT"</span>),
<a href=#121 id=121 data-nosnippet>121</a> string_column(<span class="string">"IS_COMPILED"</span>),
<a href=#122 id=122 data-nosnippet>122</a> bigint_column(<span class="string">"SORTLEN"</span>),
<a href=#123 id=123 data-nosnippet>123</a> ],
<a href=#124 id=124 data-nosnippet>124</a> <span class="macro">vec!</span>[
<a href=#125 id=125 data-nosnippet>125</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"utf8_bin"</span>])),
<a href=#126 id=126 data-nosnippet>126</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"utf8"</span>])),
<a href=#127 id=127 data-nosnippet>127</a> Arc::new(Int64Vector::from_slice([<span class="number">1</span>])),
<a href=#128 id=128 data-nosnippet>128</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"Yes"</span>])),
<a href=#129 id=129 data-nosnippet>129</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"Yes"</span>])),
<a href=#130 id=130 data-nosnippet>130</a> Arc::new(Int64Vector::from_slice([<span class="number">1</span>])),
<a href=#131 id=131 data-nosnippet>131</a> ],
<a href=#132 id=132 data-nosnippet>132</a> ),
<a href=#133 id=133 data-nosnippet>133</a>
<a href=#134 id=134 data-nosnippet>134</a> COLLATION_CHARACTER_SET_APPLICABILITY =&gt; (
<a href=#135 id=135 data-nosnippet>135</a> <span class="macro">vec!</span>[
<a href=#136 id=136 data-nosnippet>136</a> string_column(<span class="string">"COLLATION_NAME"</span>),
<a href=#137 id=137 data-nosnippet>137</a> string_column(<span class="string">"CHARACTER_SET_NAME"</span>),
<a href=#138 id=138 data-nosnippet>138</a> ],
<a href=#139 id=139 data-nosnippet>139</a> <span class="macro">vec!</span>[
<a href=#140 id=140 data-nosnippet>140</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"utf8_bin"</span>])),
<a href=#141 id=141 data-nosnippet>141</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"utf8"</span>])),
<a href=#142 id=142 data-nosnippet>142</a> ],
<a href=#143 id=143 data-nosnippet>143</a> ),
<a href=#144 id=144 data-nosnippet>144</a>
<a href=#145 id=145 data-nosnippet>145</a> CHECK_CONSTRAINTS =&gt; (
<a href=#146 id=146 data-nosnippet>146</a> string_columns(<span class="kw-2">&amp;</span>[
<a href=#147 id=147 data-nosnippet>147</a> <span class="string">"CONSTRAINT_CATALOG"</span>,
<a href=#148 id=148 data-nosnippet>148</a> <span class="string">"CONSTRAINT_SCHEMA"</span>,
<a href=#149 id=149 data-nosnippet>149</a> <span class="string">"CONSTRAINT_NAME"</span>,
<a href=#150 id=150 data-nosnippet>150</a> <span class="string">"CHECK_CLAUSE"</span>,
<a href=#151 id=151 data-nosnippet>151</a> ]),
<a href=#152 id=152 data-nosnippet>152</a> <span class="comment">// Not support check constraints yet
<a href=#153 id=153 data-nosnippet>153</a> </span><span class="macro">vec!</span>[],
<a href=#154 id=154 data-nosnippet>154</a> ),
<a href=#155 id=155 data-nosnippet>155</a>
<a href=#156 id=156 data-nosnippet>156</a> EVENTS =&gt; (
<a href=#157 id=157 data-nosnippet>157</a> <span class="macro">vec!</span>[
<a href=#158 id=158 data-nosnippet>158</a> string_column(<span class="string">"EVENT_CATALOG"</span>),
<a href=#159 id=159 data-nosnippet>159</a> string_column(<span class="string">"EVENT_SCHEMA"</span>),
<a href=#160 id=160 data-nosnippet>160</a> string_column(<span class="string">"EVENT_NAME"</span>),
<a href=#161 id=161 data-nosnippet>161</a> string_column(<span class="string">"DEFINER"</span>),
<a href=#162 id=162 data-nosnippet>162</a> string_column(<span class="string">"TIME_ZONE"</span>),
<a href=#163 id=163 data-nosnippet>163</a> string_column(<span class="string">"EVENT_BODY"</span>),
<a href=#164 id=164 data-nosnippet>164</a> string_column(<span class="string">"EVENT_DEFINITION"</span>),
<a href=#165 id=165 data-nosnippet>165</a> string_column(<span class="string">"EVENT_TYPE"</span>),
<a href=#166 id=166 data-nosnippet>166</a> timestamp_micro_column(<span class="string">"EXECUTE_AT"</span>),
<a href=#167 id=167 data-nosnippet>167</a> bigint_column(<span class="string">"INTERVAL_VALUE"</span>),
<a href=#168 id=168 data-nosnippet>168</a> string_column(<span class="string">"INTERVAL_FIELD"</span>),
<a href=#169 id=169 data-nosnippet>169</a> string_column(<span class="string">"SQL_MODE"</span>),
<a href=#170 id=170 data-nosnippet>170</a> timestamp_micro_column(<span class="string">"STARTS"</span>),
<a href=#171 id=171 data-nosnippet>171</a> timestamp_micro_column(<span class="string">"ENDS"</span>),
<a href=#172 id=172 data-nosnippet>172</a> string_column(<span class="string">"STATUS"</span>),
<a href=#173 id=173 data-nosnippet>173</a> string_column(<span class="string">"ON_COMPLETION"</span>),
<a href=#174 id=174 data-nosnippet>174</a> timestamp_micro_column(<span class="string">"CREATED"</span>),
<a href=#175 id=175 data-nosnippet>175</a> timestamp_micro_column(<span class="string">"LAST_ALTERED"</span>),
<a href=#176 id=176 data-nosnippet>176</a> timestamp_micro_column(<span class="string">"LAST_EXECUTED"</span>),
<a href=#177 id=177 data-nosnippet>177</a> string_column(<span class="string">"EVENT_COMMENT"</span>),
<a href=#178 id=178 data-nosnippet>178</a> bigint_column(<span class="string">"ORIGINATOR"</span>),
<a href=#179 id=179 data-nosnippet>179</a> string_column(<span class="string">"CHARACTER_SET_CLIENT"</span>),
<a href=#180 id=180 data-nosnippet>180</a> string_column(<span class="string">"COLLATION_CONNECTION"</span>),
<a href=#181 id=181 data-nosnippet>181</a> string_column(<span class="string">"DATABASE_COLLATION"</span>),
<a href=#182 id=182 data-nosnippet>182</a> ],
<a href=#183 id=183 data-nosnippet>183</a> <span class="macro">vec!</span>[],
<a href=#184 id=184 data-nosnippet>184</a> ),
<a href=#185 id=185 data-nosnippet>185</a>
<a href=#186 id=186 data-nosnippet>186</a> FILES =&gt; (
<a href=#187 id=187 data-nosnippet>187</a> <span class="macro">vec!</span>[
<a href=#188 id=188 data-nosnippet>188</a> bigint_column(<span class="string">"FILE_ID"</span>),
<a href=#189 id=189 data-nosnippet>189</a> string_column(<span class="string">"FILE_NAME"</span>),
<a href=#190 id=190 data-nosnippet>190</a> string_column(<span class="string">"FILE_TYPE"</span>),
<a href=#191 id=191 data-nosnippet>191</a> string_column(<span class="string">"TABLESPACE_NAME"</span>),
<a href=#192 id=192 data-nosnippet>192</a> string_column(<span class="string">"TABLE_CATALOG"</span>),
<a href=#193 id=193 data-nosnippet>193</a> string_column(<span class="string">"TABLE_SCHEMA"</span>),
<a href=#194 id=194 data-nosnippet>194</a> string_column(<span class="string">"TABLE_NAME"</span>),
<a href=#195 id=195 data-nosnippet>195</a> string_column(<span class="string">"LOGFILE_GROUP_NAME"</span>),
<a href=#196 id=196 data-nosnippet>196</a> bigint_column(<span class="string">"LOGFILE_GROUP_NUMBER"</span>),
<a href=#197 id=197 data-nosnippet>197</a> string_column(<span class="string">"ENGINE"</span>),
<a href=#198 id=198 data-nosnippet>198</a> string_column(<span class="string">"FULLTEXT_KEYS"</span>),
<a href=#199 id=199 data-nosnippet>199</a> bigint_column(<span class="string">"DELETED_ROWS"</span>),
<a href=#200 id=200 data-nosnippet>200</a> bigint_column(<span class="string">"UPDATE_COUNT"</span>),
<a href=#201 id=201 data-nosnippet>201</a> bigint_column(<span class="string">"FREE_EXTENTS"</span>),
<a href=#202 id=202 data-nosnippet>202</a> bigint_column(<span class="string">"TOTAL_EXTENTS"</span>),
<a href=#203 id=203 data-nosnippet>203</a> bigint_column(<span class="string">"EXTENT_SIZE"</span>),
<a href=#204 id=204 data-nosnippet>204</a> bigint_column(<span class="string">"INITIAL_SIZE"</span>),
<a href=#205 id=205 data-nosnippet>205</a> bigint_column(<span class="string">"MAXIMUM_SIZE"</span>),
<a href=#206 id=206 data-nosnippet>206</a> bigint_column(<span class="string">"AUTOEXTEND_SIZE"</span>),
<a href=#207 id=207 data-nosnippet>207</a> timestamp_micro_column(<span class="string">"CREATION_TIME"</span>),
<a href=#208 id=208 data-nosnippet>208</a> timestamp_micro_column(<span class="string">"LAST_UPDATE_TIME"</span>),
<a href=#209 id=209 data-nosnippet>209</a> timestamp_micro_column(<span class="string">"LAST_ACCESS_TIME"</span>),
<a href=#210 id=210 data-nosnippet>210</a> timestamp_micro_column(<span class="string">"RECOVER_TIME"</span>),
<a href=#211 id=211 data-nosnippet>211</a> bigint_column(<span class="string">"TRANSACTION_COUNTER"</span>),
<a href=#212 id=212 data-nosnippet>212</a> string_column(<span class="string">"VERSION"</span>),
<a href=#213 id=213 data-nosnippet>213</a> string_column(<span class="string">"ROW_FORMAT"</span>),
<a href=#214 id=214 data-nosnippet>214</a> bigint_column(<span class="string">"TABLE_ROWS"</span>),
<a href=#215 id=215 data-nosnippet>215</a> bigint_column(<span class="string">"AVG_ROW_LENGTH"</span>),
<a href=#216 id=216 data-nosnippet>216</a> bigint_column(<span class="string">"DATA_LENGTH"</span>),
<a href=#217 id=217 data-nosnippet>217</a> bigint_column(<span class="string">"MAX_DATA_LENGTH"</span>),
<a href=#218 id=218 data-nosnippet>218</a> bigint_column(<span class="string">"INDEX_LENGTH"</span>),
<a href=#219 id=219 data-nosnippet>219</a> bigint_column(<span class="string">"DATA_FREE"</span>),
<a href=#220 id=220 data-nosnippet>220</a> timestamp_micro_column(<span class="string">"CREATE_TIME"</span>),
<a href=#221 id=221 data-nosnippet>221</a> timestamp_micro_column(<span class="string">"UPDATE_TIME"</span>),
<a href=#222 id=222 data-nosnippet>222</a> timestamp_micro_column(<span class="string">"CHECK_TIME"</span>),
<a href=#223 id=223 data-nosnippet>223</a> string_column(<span class="string">"CHECKSUM"</span>),
<a href=#224 id=224 data-nosnippet>224</a> string_column(<span class="string">"STATUS"</span>),
<a href=#225 id=225 data-nosnippet>225</a> string_column(<span class="string">"EXTRA"</span>),
<a href=#226 id=226 data-nosnippet>226</a> ],
<a href=#227 id=227 data-nosnippet>227</a> <span class="macro">vec!</span>[],
<a href=#228 id=228 data-nosnippet>228</a> ),
<a href=#229 id=229 data-nosnippet>229</a>
<a href=#230 id=230 data-nosnippet>230</a> OPTIMIZER_TRACE =&gt; (
<a href=#231 id=231 data-nosnippet>231</a> <span class="macro">vec!</span>[
<a href=#232 id=232 data-nosnippet>232</a> string_column(<span class="string">"QUERY"</span>),
<a href=#233 id=233 data-nosnippet>233</a> string_column(<span class="string">"TRACE"</span>),
<a href=#234 id=234 data-nosnippet>234</a> bigint_column(<span class="string">"MISSING_BYTES_BEYOND_MAX_MEM_SIZE"</span>),
<a href=#235 id=235 data-nosnippet>235</a> bigint_column(<span class="string">"INSUFFICIENT_PRIVILEGES"</span>),
<a href=#236 id=236 data-nosnippet>236</a> ],
<a href=#237 id=237 data-nosnippet>237</a> <span class="macro">vec!</span>[],
<a href=#238 id=238 data-nosnippet>238</a> ),
<a href=#239 id=239 data-nosnippet>239</a>
<a href=#240 id=240 data-nosnippet>240</a> <span class="comment">// MySQL(https://dev.mysql.com/doc/refman/8.2/en/information-schema-parameters-table.html)
<a href=#241 id=241 data-nosnippet>241</a> // has the spec that is different from
<a href=#242 id=242 data-nosnippet>242</a> // PostgreSQL(https://www.postgresql.org/docs/current/infoschema-parameters.html).
<a href=#243 id=243 data-nosnippet>243</a> // Follow `MySQL` spec here.
<a href=#244 id=244 data-nosnippet>244</a> </span>PARAMETERS =&gt; (
<a href=#245 id=245 data-nosnippet>245</a> <span class="macro">vec!</span>[
<a href=#246 id=246 data-nosnippet>246</a> string_column(<span class="string">"SPECIFIC_CATALOG"</span>),
<a href=#247 id=247 data-nosnippet>247</a> string_column(<span class="string">"SPECIFIC_SCHEMA"</span>),
<a href=#248 id=248 data-nosnippet>248</a> string_column(<span class="string">"SPECIFIC_NAME"</span>),
<a href=#249 id=249 data-nosnippet>249</a> bigint_column(<span class="string">"ORDINAL_POSITION"</span>),
<a href=#250 id=250 data-nosnippet>250</a> string_column(<span class="string">"PARAMETER_MODE"</span>),
<a href=#251 id=251 data-nosnippet>251</a> string_column(<span class="string">"PARAMETER_NAME"</span>),
<a href=#252 id=252 data-nosnippet>252</a> string_column(<span class="string">"DATA_TYPE"</span>),
<a href=#253 id=253 data-nosnippet>253</a> bigint_column(<span class="string">"CHARACTER_MAXIMUM_LENGTH"</span>),
<a href=#254 id=254 data-nosnippet>254</a> bigint_column(<span class="string">"CHARACTER_OCTET_LENGTH"</span>),
<a href=#255 id=255 data-nosnippet>255</a> bigint_column(<span class="string">"NUMERIC_PRECISION"</span>),
<a href=#256 id=256 data-nosnippet>256</a> bigint_column(<span class="string">"NUMERIC_SCALE"</span>),
<a href=#257 id=257 data-nosnippet>257</a> bigint_column(<span class="string">"DATETIME_PRECISION"</span>),
<a href=#258 id=258 data-nosnippet>258</a> string_column(<span class="string">"CHARACTER_SET_NAME"</span>),
<a href=#259 id=259 data-nosnippet>259</a> string_column(<span class="string">"COLLATION_NAME"</span>),
<a href=#260 id=260 data-nosnippet>260</a> string_column(<span class="string">"DTD_IDENTIFIER"</span>),
<a href=#261 id=261 data-nosnippet>261</a> string_column(<span class="string">"ROUTINE_TYPE"</span>),
<a href=#262 id=262 data-nosnippet>262</a> ],
<a href=#263 id=263 data-nosnippet>263</a> <span class="macro">vec!</span>[],
<a href=#264 id=264 data-nosnippet>264</a> ),
<a href=#265 id=265 data-nosnippet>265</a>
<a href=#266 id=266 data-nosnippet>266</a> PROFILING =&gt; (
<a href=#267 id=267 data-nosnippet>267</a> <span class="macro">vec!</span>[
<a href=#268 id=268 data-nosnippet>268</a> bigint_column(<span class="string">"QUERY_ID"</span>),
<a href=#269 id=269 data-nosnippet>269</a> bigint_column(<span class="string">"SEQ"</span>),
<a href=#270 id=270 data-nosnippet>270</a> string_column(<span class="string">"STATE"</span>),
<a href=#271 id=271 data-nosnippet>271</a> bigint_column(<span class="string">"DURATION"</span>),
<a href=#272 id=272 data-nosnippet>272</a> bigint_column(<span class="string">"CPU_USER"</span>),
<a href=#273 id=273 data-nosnippet>273</a> bigint_column(<span class="string">"CPU_SYSTEM"</span>),
<a href=#274 id=274 data-nosnippet>274</a> bigint_column(<span class="string">"CONTEXT_VOLUNTARY"</span>),
<a href=#275 id=275 data-nosnippet>275</a> bigint_column(<span class="string">"CONTEXT_INVOLUNTARY"</span>),
<a href=#276 id=276 data-nosnippet>276</a> bigint_column(<span class="string">"BLOCK_OPS_IN"</span>),
<a href=#277 id=277 data-nosnippet>277</a> bigint_column(<span class="string">"BLOCK_OPS_OUT"</span>),
<a href=#278 id=278 data-nosnippet>278</a> bigint_column(<span class="string">"MESSAGES_SENT"</span>),
<a href=#279 id=279 data-nosnippet>279</a> bigint_column(<span class="string">"MESSAGES_RECEIVED"</span>),
<a href=#280 id=280 data-nosnippet>280</a> bigint_column(<span class="string">"PAGE_FAULTS_MAJOR"</span>),
<a href=#281 id=281 data-nosnippet>281</a> bigint_column(<span class="string">"PAGE_FAULTS_MINOR"</span>),
<a href=#282 id=282 data-nosnippet>282</a> bigint_column(<span class="string">"SWAPS"</span>),
<a href=#283 id=283 data-nosnippet>283</a> string_column(<span class="string">"SOURCE_FUNCTION"</span>),
<a href=#284 id=284 data-nosnippet>284</a> string_column(<span class="string">"SOURCE_FILE"</span>),
<a href=#285 id=285 data-nosnippet>285</a> bigint_column(<span class="string">"SOURCE_LINE"</span>),
<a href=#286 id=286 data-nosnippet>286</a> ],
<a href=#287 id=287 data-nosnippet>287</a> <span class="macro">vec!</span>[],
<a href=#288 id=288 data-nosnippet>288</a> ),
<a href=#289 id=289 data-nosnippet>289</a>
<a href=#290 id=290 data-nosnippet>290</a> <span class="comment">// TODO: _Must_ reimplement this table when foreign key constraint is supported.
<a href=#291 id=291 data-nosnippet>291</a> </span>REFERENTIAL_CONSTRAINTS =&gt; (
<a href=#292 id=292 data-nosnippet>292</a> <span class="macro">vec!</span>[
<a href=#293 id=293 data-nosnippet>293</a> string_column(<span class="string">"CONSTRAINT_CATALOG"</span>),
<a href=#294 id=294 data-nosnippet>294</a> string_column(<span class="string">"CONSTRAINT_SCHEMA"</span>),
<a href=#295 id=295 data-nosnippet>295</a> string_column(<span class="string">"CONSTRAINT_NAME"</span>),
<a href=#296 id=296 data-nosnippet>296</a> string_column(<span class="string">"UNIQUE_CONSTRAINT_CATALOG"</span>),
<a href=#297 id=297 data-nosnippet>297</a> string_column(<span class="string">"UNIQUE_CONSTRAINT_SCHEMA"</span>),
<a href=#298 id=298 data-nosnippet>298</a> string_column(<span class="string">"UNIQUE_CONSTRAINT_NAME"</span>),
<a href=#299 id=299 data-nosnippet>299</a> string_column(<span class="string">"MATCH_OPTION"</span>),
<a href=#300 id=300 data-nosnippet>300</a> string_column(<span class="string">"UPDATE_RULE"</span>),
<a href=#301 id=301 data-nosnippet>301</a> string_column(<span class="string">"DELETE_RULE"</span>),
<a href=#302 id=302 data-nosnippet>302</a> string_column(<span class="string">"TABLE_NAME"</span>),
<a href=#303 id=303 data-nosnippet>303</a> string_column(<span class="string">"REFERENCED_TABLE_NAME"</span>),
<a href=#304 id=304 data-nosnippet>304</a> ],
<a href=#305 id=305 data-nosnippet>305</a> <span class="macro">vec!</span>[],
<a href=#306 id=306 data-nosnippet>306</a> ),
<a href=#307 id=307 data-nosnippet>307</a>
<a href=#308 id=308 data-nosnippet>308</a> ROUTINES =&gt; (
<a href=#309 id=309 data-nosnippet>309</a> <span class="macro">vec!</span>[
<a href=#310 id=310 data-nosnippet>310</a> string_column(<span class="string">"SPECIFIC_NAME"</span>),
<a href=#311 id=311 data-nosnippet>311</a> string_column(<span class="string">"ROUTINE_CATALOG"</span>),
<a href=#312 id=312 data-nosnippet>312</a> string_column(<span class="string">"ROUTINE_SCHEMA"</span>),
<a href=#313 id=313 data-nosnippet>313</a> string_column(<span class="string">"ROUTINE_NAME"</span>),
<a href=#314 id=314 data-nosnippet>314</a> string_column(<span class="string">"ROUTINE_TYPE"</span>),
<a href=#315 id=315 data-nosnippet>315</a> string_column(<span class="string">"DATA_TYPE"</span>),
<a href=#316 id=316 data-nosnippet>316</a> bigint_column(<span class="string">"CHARACTER_MAXIMUM_LENGTH"</span>),
<a href=#317 id=317 data-nosnippet>317</a> bigint_column(<span class="string">"CHARACTER_OCTET_LENGTH"</span>),
<a href=#318 id=318 data-nosnippet>318</a> bigint_column(<span class="string">"NUMERIC_PRECISION"</span>),
<a href=#319 id=319 data-nosnippet>319</a> bigint_column(<span class="string">"NUMERIC_SCALE"</span>),
<a href=#320 id=320 data-nosnippet>320</a> bigint_column(<span class="string">"DATETIME_PRECISION"</span>),
<a href=#321 id=321 data-nosnippet>321</a> string_column(<span class="string">"CHARACTER_SET_NAME"</span>),
<a href=#322 id=322 data-nosnippet>322</a> string_column(<span class="string">"COLLATION_NAME"</span>),
<a href=#323 id=323 data-nosnippet>323</a> string_column(<span class="string">"DTD_IDENTIFIER"</span>),
<a href=#324 id=324 data-nosnippet>324</a> string_column(<span class="string">"ROUTINE_BODY"</span>),
<a href=#325 id=325 data-nosnippet>325</a> string_column(<span class="string">"ROUTINE_DEFINITION"</span>),
<a href=#326 id=326 data-nosnippet>326</a> string_column(<span class="string">"EXTERNAL_NAME"</span>),
<a href=#327 id=327 data-nosnippet>327</a> string_column(<span class="string">"EXTERNAL_LANGUAGE"</span>),
<a href=#328 id=328 data-nosnippet>328</a> string_column(<span class="string">"PARAMETER_STYLE"</span>),
<a href=#329 id=329 data-nosnippet>329</a> string_column(<span class="string">"IS_DETERMINISTIC"</span>),
<a href=#330 id=330 data-nosnippet>330</a> string_column(<span class="string">"SQL_DATA_ACCESS"</span>),
<a href=#331 id=331 data-nosnippet>331</a> string_column(<span class="string">"SQL_PATH"</span>),
<a href=#332 id=332 data-nosnippet>332</a> string_column(<span class="string">"SECURITY_TYPE"</span>),
<a href=#333 id=333 data-nosnippet>333</a> timestamp_micro_column(<span class="string">"CREATED"</span>),
<a href=#334 id=334 data-nosnippet>334</a> timestamp_micro_column(<span class="string">"LAST_ALTERED"</span>),
<a href=#335 id=335 data-nosnippet>335</a> string_column(<span class="string">"SQL_MODE"</span>),
<a href=#336 id=336 data-nosnippet>336</a> string_column(<span class="string">"ROUTINE_COMMENT"</span>),
<a href=#337 id=337 data-nosnippet>337</a> string_column(<span class="string">"DEFINER"</span>),
<a href=#338 id=338 data-nosnippet>338</a> string_column(<span class="string">"CHARACTER_SET_CLIENT"</span>),
<a href=#339 id=339 data-nosnippet>339</a> string_column(<span class="string">"COLLATION_CONNECTION"</span>),
<a href=#340 id=340 data-nosnippet>340</a> string_column(<span class="string">"DATABASE_COLLATION"</span>),
<a href=#341 id=341 data-nosnippet>341</a> ],
<a href=#342 id=342 data-nosnippet>342</a> <span class="macro">vec!</span>[],
<a href=#343 id=343 data-nosnippet>343</a> ),
<a href=#344 id=344 data-nosnippet>344</a>
<a href=#345 id=345 data-nosnippet>345</a> SCHEMA_PRIVILEGES =&gt; (
<a href=#346 id=346 data-nosnippet>346</a> <span class="macro">vec!</span>[
<a href=#347 id=347 data-nosnippet>347</a> string_column(<span class="string">"GRANTEE"</span>),
<a href=#348 id=348 data-nosnippet>348</a> string_column(<span class="string">"TABLE_CATALOG"</span>),
<a href=#349 id=349 data-nosnippet>349</a> string_column(<span class="string">"TABLE_SCHEMA"</span>),
<a href=#350 id=350 data-nosnippet>350</a> string_column(<span class="string">"PRIVILEGE_TYPE"</span>),
<a href=#351 id=351 data-nosnippet>351</a> string_column(<span class="string">"IS_GRANTABLE"</span>),
<a href=#352 id=352 data-nosnippet>352</a> ],
<a href=#353 id=353 data-nosnippet>353</a> <span class="macro">vec!</span>[],
<a href=#354 id=354 data-nosnippet>354</a> ),
<a href=#355 id=355 data-nosnippet>355</a>
<a href=#356 id=356 data-nosnippet>356</a> TABLE_PRIVILEGES =&gt; (
<a href=#357 id=357 data-nosnippet>357</a> <span class="macro">vec!</span>[
<a href=#358 id=358 data-nosnippet>358</a> string_column(<span class="string">"GRANTEE"</span>),
<a href=#359 id=359 data-nosnippet>359</a> string_column(<span class="string">"TABLE_CATALOG"</span>),
<a href=#360 id=360 data-nosnippet>360</a> string_column(<span class="string">"TABLE_SCHEMA"</span>),
<a href=#361 id=361 data-nosnippet>361</a> string_column(<span class="string">"TABLE_NAME"</span>),
<a href=#362 id=362 data-nosnippet>362</a> string_column(<span class="string">"PRIVILEGE_TYPE"</span>),
<a href=#363 id=363 data-nosnippet>363</a> string_column(<span class="string">"IS_GRANTABLE"</span>),
<a href=#364 id=364 data-nosnippet>364</a> ],
<a href=#365 id=365 data-nosnippet>365</a> <span class="macro">vec!</span>[],
<a href=#366 id=366 data-nosnippet>366</a> ),
<a href=#367 id=367 data-nosnippet>367</a>
<a href=#368 id=368 data-nosnippet>368</a> <span class="comment">// TODO: Considering store internal metrics in `global_status` and
<a href=#369 id=369 data-nosnippet>369</a> // `session_status` tables.
<a href=#370 id=370 data-nosnippet>370</a> </span>GLOBAL_STATUS =&gt; (
<a href=#371 id=371 data-nosnippet>371</a> <span class="macro">vec!</span>[
<a href=#372 id=372 data-nosnippet>372</a> string_column(<span class="string">"VARIABLE_NAME"</span>),
<a href=#373 id=373 data-nosnippet>373</a> string_column(<span class="string">"VARIABLE_VALUE"</span>),
<a href=#374 id=374 data-nosnippet>374</a> ],
<a href=#375 id=375 data-nosnippet>375</a> <span class="macro">vec!</span>[],
<a href=#376 id=376 data-nosnippet>376</a> ),
<a href=#377 id=377 data-nosnippet>377</a>
<a href=#378 id=378 data-nosnippet>378</a> SESSION_STATUS =&gt; (
<a href=#379 id=379 data-nosnippet>379</a> <span class="macro">vec!</span>[
<a href=#380 id=380 data-nosnippet>380</a> string_column(<span class="string">"VARIABLE_NAME"</span>),
<a href=#381 id=381 data-nosnippet>381</a> string_column(<span class="string">"VARIABLE_VALUE"</span>),
<a href=#382 id=382 data-nosnippet>382</a> ],
<a href=#383 id=383 data-nosnippet>383</a> <span class="macro">vec!</span>[],
<a href=#384 id=384 data-nosnippet>384</a> ),
<a href=#385 id=385 data-nosnippet>385</a>
<a href=#386 id=386 data-nosnippet>386</a> <span class="comment">// GreptimeDB has no pluggable components.
<a href=#387 id=387 data-nosnippet>387</a> </span>PLUGINS =&gt; (
<a href=#388 id=388 data-nosnippet>388</a> string_columns(<span class="kw-2">&amp;</span>[
<a href=#389 id=389 data-nosnippet>389</a> <span class="string">"PLUGIN_NAME"</span>,
<a href=#390 id=390 data-nosnippet>390</a> <span class="string">"PLUGIN_VERSION"</span>,
<a href=#391 id=391 data-nosnippet>391</a> <span class="string">"PLUGIN_STATUS"</span>,
<a href=#392 id=392 data-nosnippet>392</a> <span class="string">"PLUGIN_TYPE"</span>,
<a href=#393 id=393 data-nosnippet>393</a> <span class="string">"PLUGIN_TYPE_VERSION"</span>,
<a href=#394 id=394 data-nosnippet>394</a> <span class="string">"PLUGIN_LIBRARY"</span>,
<a href=#395 id=395 data-nosnippet>395</a> <span class="string">"PLUGIN_LIBRARY_VERSION"</span>,
<a href=#396 id=396 data-nosnippet>396</a> <span class="string">"PLUGIN_AUTHOR"</span>,
<a href=#397 id=397 data-nosnippet>397</a> <span class="string">"PLUGIN_DESCRIPTION"</span>,
<a href=#398 id=398 data-nosnippet>398</a> <span class="string">"PLUGIN_LICENSE"</span>,
<a href=#399 id=399 data-nosnippet>399</a> <span class="string">"LOAD_OPTION"</span>,
<a href=#400 id=400 data-nosnippet>400</a> ]),
<a href=#401 id=401 data-nosnippet>401</a> <span class="macro">vec!</span>[],
<a href=#402 id=402 data-nosnippet>402</a> ),
<a href=#403 id=403 data-nosnippet>403</a>
<a href=#404 id=404 data-nosnippet>404</a> <span class="comment">// Privileges are not exposed through `information_schema`, same as the other
<a href=#405 id=405 data-nosnippet>405</a> // `*_privileges` tables above.
<a href=#406 id=406 data-nosnippet>406</a> </span>USER_PRIVILEGES =&gt; (
<a href=#407 id=407 data-nosnippet>407</a> string_columns(<span class="kw-2">&amp;</span>[<span class="string">"GRANTEE"</span>, <span class="string">"TABLE_CATALOG"</span>, <span class="string">"PRIVILEGE_TYPE"</span>, <span class="string">"IS_GRANTABLE"</span>]),
<a href=#408 id=408 data-nosnippet>408</a> <span class="macro">vec!</span>[],
<a href=#409 id=409 data-nosnippet>409</a> ),
<a href=#410 id=410 data-nosnippet>410</a>
<a href=#411 id=411 data-nosnippet>411</a> <span class="comment">// Sessions are reported through `information_schema.process_list` and
<a href=#412 id=412 data-nosnippet>412</a> // `SHOW PROCESSLIST`; this table carries the MySQL column shape only.
<a href=#413 id=413 data-nosnippet>413</a> </span>PROCESSLIST =&gt; (
<a href=#414 id=414 data-nosnippet>414</a> <span class="macro">vec!</span>[
<a href=#415 id=415 data-nosnippet>415</a> bigint_column(<span class="string">"ID"</span>),
<a href=#416 id=416 data-nosnippet>416</a> string_column(<span class="string">"USER"</span>),
<a href=#417 id=417 data-nosnippet>417</a> string_column(<span class="string">"HOST"</span>),
<a href=#418 id=418 data-nosnippet>418</a> string_column(<span class="string">"DB"</span>),
<a href=#419 id=419 data-nosnippet>419</a> string_column(<span class="string">"COMMAND"</span>),
<a href=#420 id=420 data-nosnippet>420</a> bigint_column(<span class="string">"TIME"</span>),
<a href=#421 id=421 data-nosnippet>421</a> string_column(<span class="string">"STATE"</span>),
<a href=#422 id=422 data-nosnippet>422</a> string_column(<span class="string">"INFO"</span>),
<a href=#423 id=423 data-nosnippet>423</a> ],
<a href=#424 id=424 data-nosnippet>424</a> <span class="macro">vec!</span>[],
<a href=#425 id=425 data-nosnippet>425</a> ),
<a href=#426 id=426 data-nosnippet>426</a>
<a href=#427 id=427 data-nosnippet>427</a> <span class="kw">_ </span>=&gt; <span class="macro">unreachable!</span>(<span class="string">"Unknown table in information_schema: {}"</span>, table_name),
<a href=#428 id=428 data-nosnippet>428</a> };
<a href=#429 id=429 data-nosnippet>429</a>
<a href=#430 id=430 data-nosnippet>430</a> (Arc::new(Schema::new(column_schemas)), columns)
<a href=#431 id=431 data-nosnippet>431</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,370 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/key_column_usage.rs`."><title>key_column_usage.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>key_column_usage.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_KEY_COLUMN_USAGE_TABLE_ID;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, MutableVector, ScalarVectorBuilder, VectorRef};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datatypes::value::Value;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::vectors::{StringVector, StringVectorBuilder, UInt32VectorBuilder};
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>futures_util::TryStreamExt;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>snafu::{OptionExt, ResultExt};
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#33 id=33 data-nosnippet>33</a>
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#36 id=36 data-nosnippet>36</a> CreateRecordBatchSnafu, InternalSnafu, <span class="prelude-ty">Result</span>, UpgradeWeakCatalogManagerRefSnafu,
<a href=#37 id=37 data-nosnippet>37</a>};
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{
<a href=#39 id=39 data-nosnippet>39</a> InformationTable, KEY_COLUMN_USAGE, Predicates, primary_key_encoding_index_type,
<a href=#40 id=40 data-nosnippet>40</a>};
<a href=#41 id=41 data-nosnippet>41</a>
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">pub const </span>CONSTRAINT_SCHEMA: <span class="kw-2">&amp;</span>str = <span class="string">"constraint_schema"</span>;
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">pub const </span>CONSTRAINT_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"constraint_name"</span>;
<a href=#44 id=44 data-nosnippet>44</a><span class="comment">// It's always `def` in MySQL
<a href=#45 id=45 data-nosnippet>45</a></span><span class="kw">pub const </span>TABLE_CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"table_catalog"</span>;
<a href=#46 id=46 data-nosnippet>46</a><span class="comment">// The real catalog name for this key column.
<a href=#47 id=47 data-nosnippet>47</a></span><span class="kw">pub const </span>REAL_TABLE_CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"real_table_catalog"</span>;
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">pub const </span>TABLE_SCHEMA: <span class="kw-2">&amp;</span>str = <span class="string">"table_schema"</span>;
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">pub const </span>TABLE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_name"</span>;
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">pub const </span>COLUMN_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"column_name"</span>;
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">pub const </span>ORDINAL_POSITION: <span class="kw-2">&amp;</span>str = <span class="string">"ordinal_position"</span>;
<a href=#52 id=52 data-nosnippet>52</a><span class="doccomment">/// The type of the index.
<a href=#53 id=53 data-nosnippet>53</a></span><span class="kw">pub const </span>GREPTIME_INDEX_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"greptime_index_type"</span>;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a><span class="doccomment">/// Time index constraint name
<a href=#57 id=57 data-nosnippet>57</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>CONSTRAINT_NAME_TIME_INDEX: <span class="kw-2">&amp;</span>str = <span class="string">"TIME INDEX"</span>;
<a href=#58 id=58 data-nosnippet>58</a>
<a href=#59 id=59 data-nosnippet>59</a><span class="doccomment">/// Primary key constraint name
<a href=#60 id=60 data-nosnippet>60</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>CONSTRAINT_NAME_PRI: <span class="kw-2">&amp;</span>str = <span class="string">"PRIMARY"</span>;
<a href=#61 id=61 data-nosnippet>61</a>
<a href=#62 id=62 data-nosnippet>62</a><span class="doccomment">/// Inverted index name
<a href=#63 id=63 data-nosnippet>63</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>CONSTRAINT_NAME_INVERTED_INDEX: <span class="kw-2">&amp;</span>str = <span class="string">"INVERTED INDEX"</span>;
<a href=#64 id=64 data-nosnippet>64</a>
<a href=#65 id=65 data-nosnippet>65</a><span class="doccomment">/// Fulltext index name
<a href=#66 id=66 data-nosnippet>66</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>CONSTRAINT_NAME_FULLTEXT_INDEX: <span class="kw-2">&amp;</span>str = <span class="string">"FULLTEXT INDEX"</span>;
<a href=#67 id=67 data-nosnippet>67</a>
<a href=#68 id=68 data-nosnippet>68</a><span class="doccomment">/// Skipping index name
<a href=#69 id=69 data-nosnippet>69</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>CONSTRAINT_NAME_SKIPPING_INDEX: <span class="kw-2">&amp;</span>str = <span class="string">"SKIPPING INDEX"</span>;
<a href=#70 id=70 data-nosnippet>70</a>
<a href=#71 id=71 data-nosnippet>71</a><span class="doccomment">/// The virtual table implementation for `information_schema.KEY_COLUMN_USAGE`.
<a href=#72 id=72 data-nosnippet>72</a>///
<a href=#73 id=73 data-nosnippet>73</a>/// Provides an extra column `greptime_index_type` for the index type of the key column.
<a href=#74 id=74 data-nosnippet>74</a></span><span class="attr">#[derive(Debug)]
<a href=#75 id=75 data-nosnippet>75</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaKeyColumnUsage {
<a href=#76 id=76 data-nosnippet>76</a> schema: SchemaRef,
<a href=#77 id=77 data-nosnippet>77</a> catalog_name: String,
<a href=#78 id=78 data-nosnippet>78</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#79 id=79 data-nosnippet>79</a>}
<a href=#80 id=80 data-nosnippet>80</a>
<a href=#81 id=81 data-nosnippet>81</a><span class="kw">impl </span>InformationSchemaKeyColumnUsage {
<a href=#82 id=82 data-nosnippet>82</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_name: String, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#83 id=83 data-nosnippet>83</a> <span class="self">Self </span>{
<a href=#84 id=84 data-nosnippet>84</a> schema: <span class="self">Self</span>::schema(),
<a href=#85 id=85 data-nosnippet>85</a> catalog_name,
<a href=#86 id=86 data-nosnippet>86</a> catalog_manager,
<a href=#87 id=87 data-nosnippet>87</a> }
<a href=#88 id=88 data-nosnippet>88</a> }
<a href=#89 id=89 data-nosnippet>89</a>
<a href=#90 id=90 data-nosnippet>90</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#91 id=91 data-nosnippet>91</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#92 id=92 data-nosnippet>92</a> ColumnSchema::new(
<a href=#93 id=93 data-nosnippet>93</a> <span class="string">"constraint_catalog"</span>,
<a href=#94 id=94 data-nosnippet>94</a> ConcreteDataType::string_datatype(),
<a href=#95 id=95 data-nosnippet>95</a> <span class="bool-val">false</span>,
<a href=#96 id=96 data-nosnippet>96</a> ),
<a href=#97 id=97 data-nosnippet>97</a> ColumnSchema::new(
<a href=#98 id=98 data-nosnippet>98</a> CONSTRAINT_SCHEMA,
<a href=#99 id=99 data-nosnippet>99</a> ConcreteDataType::string_datatype(),
<a href=#100 id=100 data-nosnippet>100</a> <span class="bool-val">false</span>,
<a href=#101 id=101 data-nosnippet>101</a> ),
<a href=#102 id=102 data-nosnippet>102</a> ColumnSchema::new(CONSTRAINT_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#103 id=103 data-nosnippet>103</a> ColumnSchema::new(TABLE_CATALOG, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#104 id=104 data-nosnippet>104</a> ColumnSchema::new(
<a href=#105 id=105 data-nosnippet>105</a> REAL_TABLE_CATALOG,
<a href=#106 id=106 data-nosnippet>106</a> ConcreteDataType::string_datatype(),
<a href=#107 id=107 data-nosnippet>107</a> <span class="bool-val">false</span>,
<a href=#108 id=108 data-nosnippet>108</a> ),
<a href=#109 id=109 data-nosnippet>109</a> ColumnSchema::new(TABLE_SCHEMA, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#110 id=110 data-nosnippet>110</a> ColumnSchema::new(TABLE_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#111 id=111 data-nosnippet>111</a> ColumnSchema::new(COLUMN_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#112 id=112 data-nosnippet>112</a> ColumnSchema::new(ORDINAL_POSITION, ConcreteDataType::uint32_datatype(), <span class="bool-val">false</span>),
<a href=#113 id=113 data-nosnippet>113</a> ColumnSchema::new(
<a href=#114 id=114 data-nosnippet>114</a> <span class="string">"position_in_unique_constraint"</span>,
<a href=#115 id=115 data-nosnippet>115</a> ConcreteDataType::uint32_datatype(),
<a href=#116 id=116 data-nosnippet>116</a> <span class="bool-val">true</span>,
<a href=#117 id=117 data-nosnippet>117</a> ),
<a href=#118 id=118 data-nosnippet>118</a> ColumnSchema::new(
<a href=#119 id=119 data-nosnippet>119</a> <span class="string">"referenced_table_schema"</span>,
<a href=#120 id=120 data-nosnippet>120</a> ConcreteDataType::string_datatype(),
<a href=#121 id=121 data-nosnippet>121</a> <span class="bool-val">true</span>,
<a href=#122 id=122 data-nosnippet>122</a> ),
<a href=#123 id=123 data-nosnippet>123</a> ColumnSchema::new(
<a href=#124 id=124 data-nosnippet>124</a> <span class="string">"referenced_table_name"</span>,
<a href=#125 id=125 data-nosnippet>125</a> ConcreteDataType::string_datatype(),
<a href=#126 id=126 data-nosnippet>126</a> <span class="bool-val">true</span>,
<a href=#127 id=127 data-nosnippet>127</a> ),
<a href=#128 id=128 data-nosnippet>128</a> ColumnSchema::new(
<a href=#129 id=129 data-nosnippet>129</a> <span class="string">"referenced_column_name"</span>,
<a href=#130 id=130 data-nosnippet>130</a> ConcreteDataType::string_datatype(),
<a href=#131 id=131 data-nosnippet>131</a> <span class="bool-val">true</span>,
<a href=#132 id=132 data-nosnippet>132</a> ),
<a href=#133 id=133 data-nosnippet>133</a> ColumnSchema::new(
<a href=#134 id=134 data-nosnippet>134</a> GREPTIME_INDEX_TYPE,
<a href=#135 id=135 data-nosnippet>135</a> ConcreteDataType::string_datatype(),
<a href=#136 id=136 data-nosnippet>136</a> <span class="bool-val">true</span>,
<a href=#137 id=137 data-nosnippet>137</a> ),
<a href=#138 id=138 data-nosnippet>138</a> ]))
<a href=#139 id=139 data-nosnippet>139</a> }
<a href=#140 id=140 data-nosnippet>140</a>
<a href=#141 id=141 data-nosnippet>141</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaKeyColumnUsageBuilder {
<a href=#142 id=142 data-nosnippet>142</a> InformationSchemaKeyColumnUsageBuilder::new(
<a href=#143 id=143 data-nosnippet>143</a> <span class="self">self</span>.schema.clone(),
<a href=#144 id=144 data-nosnippet>144</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#145 id=145 data-nosnippet>145</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#146 id=146 data-nosnippet>146</a> )
<a href=#147 id=147 data-nosnippet>147</a> }
<a href=#148 id=148 data-nosnippet>148</a>}
<a href=#149 id=149 data-nosnippet>149</a>
<a href=#150 id=150 data-nosnippet>150</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaKeyColumnUsage {
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#152 id=152 data-nosnippet>152</a> INFORMATION_SCHEMA_KEY_COLUMN_USAGE_TABLE_ID
<a href=#153 id=153 data-nosnippet>153</a> }
<a href=#154 id=154 data-nosnippet>154</a>
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#156 id=156 data-nosnippet>156</a> KEY_COLUMN_USAGE
<a href=#157 id=157 data-nosnippet>157</a> }
<a href=#158 id=158 data-nosnippet>158</a>
<a href=#159 id=159 data-nosnippet>159</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#160 id=160 data-nosnippet>160</a> <span class="self">self</span>.schema.clone()
<a href=#161 id=161 data-nosnippet>161</a> }
<a href=#162 id=162 data-nosnippet>162</a>
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#164 id=164 data-nosnippet>164</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#165 id=165 data-nosnippet>165</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#166 id=166 data-nosnippet>166</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#167 id=167 data-nosnippet>167</a> schema,
<a href=#168 id=168 data-nosnippet>168</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#169 id=169 data-nosnippet>169</a> builder
<a href=#170 id=170 data-nosnippet>170</a> .make_key_column_usage(<span class="prelude-val">Some</span>(request))
<a href=#171 id=171 data-nosnippet>171</a> .<span class="kw">await
<a href=#172 id=172 data-nosnippet>172</a> </span>.map(|x| x.into_df_record_batch())
<a href=#173 id=173 data-nosnippet>173</a> .map_err(Into::into)
<a href=#174 id=174 data-nosnippet>174</a> }),
<a href=#175 id=175 data-nosnippet>175</a> ));
<a href=#176 id=176 data-nosnippet>176</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#177 id=177 data-nosnippet>177</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#178 id=178 data-nosnippet>178</a> .map_err(BoxedError::new)
<a href=#179 id=179 data-nosnippet>179</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#180 id=180 data-nosnippet>180</a> ))
<a href=#181 id=181 data-nosnippet>181</a> }
<a href=#182 id=182 data-nosnippet>182</a>}
<a href=#183 id=183 data-nosnippet>183</a>
<a href=#184 id=184 data-nosnippet>184</a><span class="doccomment">/// Builds the `information_schema.KEY_COLUMN_USAGE` table row by row
<a href=#185 id=185 data-nosnippet>185</a>///
<a href=#186 id=186 data-nosnippet>186</a>/// Columns are based on &lt;https://dev.mysql.com/doc/refman/8.2/en/information-schema-key-column-usage-table.html&gt;
<a href=#187 id=187 data-nosnippet>187</a></span><span class="kw">struct </span>InformationSchemaKeyColumnUsageBuilder {
<a href=#188 id=188 data-nosnippet>188</a> schema: SchemaRef,
<a href=#189 id=189 data-nosnippet>189</a> catalog_name: String,
<a href=#190 id=190 data-nosnippet>190</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#191 id=191 data-nosnippet>191</a>
<a href=#192 id=192 data-nosnippet>192</a> constraint_catalog: StringVectorBuilder,
<a href=#193 id=193 data-nosnippet>193</a> constraint_schema: StringVectorBuilder,
<a href=#194 id=194 data-nosnippet>194</a> constraint_name: StringVectorBuilder,
<a href=#195 id=195 data-nosnippet>195</a> table_catalog: StringVectorBuilder,
<a href=#196 id=196 data-nosnippet>196</a> real_table_catalog: StringVectorBuilder,
<a href=#197 id=197 data-nosnippet>197</a> table_schema: StringVectorBuilder,
<a href=#198 id=198 data-nosnippet>198</a> table_name: StringVectorBuilder,
<a href=#199 id=199 data-nosnippet>199</a> column_name: StringVectorBuilder,
<a href=#200 id=200 data-nosnippet>200</a> ordinal_position: UInt32VectorBuilder,
<a href=#201 id=201 data-nosnippet>201</a> position_in_unique_constraint: UInt32VectorBuilder,
<a href=#202 id=202 data-nosnippet>202</a> greptime_index_type: StringVectorBuilder,
<a href=#203 id=203 data-nosnippet>203</a>}
<a href=#204 id=204 data-nosnippet>204</a>
<a href=#205 id=205 data-nosnippet>205</a><span class="kw">impl </span>InformationSchemaKeyColumnUsageBuilder {
<a href=#206 id=206 data-nosnippet>206</a> <span class="kw">fn </span>new(
<a href=#207 id=207 data-nosnippet>207</a> schema: SchemaRef,
<a href=#208 id=208 data-nosnippet>208</a> catalog_name: String,
<a href=#209 id=209 data-nosnippet>209</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#210 id=210 data-nosnippet>210</a> ) -&gt; <span class="self">Self </span>{
<a href=#211 id=211 data-nosnippet>211</a> <span class="self">Self </span>{
<a href=#212 id=212 data-nosnippet>212</a> schema,
<a href=#213 id=213 data-nosnippet>213</a> catalog_name,
<a href=#214 id=214 data-nosnippet>214</a> catalog_manager,
<a href=#215 id=215 data-nosnippet>215</a> constraint_catalog: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#216 id=216 data-nosnippet>216</a> constraint_schema: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#217 id=217 data-nosnippet>217</a> constraint_name: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#218 id=218 data-nosnippet>218</a> table_catalog: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#219 id=219 data-nosnippet>219</a> real_table_catalog: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#220 id=220 data-nosnippet>220</a> table_schema: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#221 id=221 data-nosnippet>221</a> table_name: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#222 id=222 data-nosnippet>222</a> column_name: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#223 id=223 data-nosnippet>223</a> ordinal_position: UInt32VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#224 id=224 data-nosnippet>224</a> position_in_unique_constraint: UInt32VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#225 id=225 data-nosnippet>225</a> greptime_index_type: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#226 id=226 data-nosnippet>226</a> }
<a href=#227 id=227 data-nosnippet>227</a> }
<a href=#228 id=228 data-nosnippet>228</a>
<a href=#229 id=229 data-nosnippet>229</a> <span class="doccomment">/// Construct the `information_schema.KEY_COLUMN_USAGE` virtual table
<a href=#230 id=230 data-nosnippet>230</a> </span><span class="kw">async fn </span>make_key_column_usage(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#231 id=231 data-nosnippet>231</a> <span class="kw">let </span>catalog_name = <span class="self">self</span>.catalog_name.clone();
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">let </span>catalog_manager = <span class="self">self
<a href=#233 id=233 data-nosnippet>233</a> </span>.catalog_manager
<a href=#234 id=234 data-nosnippet>234</a> .upgrade()
<a href=#235 id=235 data-nosnippet>235</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#236 id=236 data-nosnippet>236</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#237 id=237 data-nosnippet>237</a>
<a href=#238 id=238 data-nosnippet>238</a> <span class="kw">for </span>schema_name <span class="kw">in </span>catalog_manager.schema_names(<span class="kw-2">&amp;</span>catalog_name, <span class="prelude-val">None</span>).<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#239 id=239 data-nosnippet>239</a> <span class="kw">let </span><span class="kw-2">mut </span>stream = catalog_manager.tables(<span class="kw-2">&amp;</span>catalog_name, <span class="kw-2">&amp;</span>schema_name, <span class="prelude-val">None</span>);
<a href=#240 id=240 data-nosnippet>240</a>
<a href=#241 id=241 data-nosnippet>241</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(table) = stream.try_next().<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">let </span>table_info = table.table_info();
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">let </span>table_name = <span class="kw-2">&amp;</span>table_info.name;
<a href=#244 id=244 data-nosnippet>244</a> <span class="kw">let </span>keys = <span class="kw-2">&amp;</span>table_info.meta.primary_key_indices;
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw">let </span>schema = table.schema();
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">let </span>primary_key_encoding =
<a href=#247 id=247 data-nosnippet>247</a> primary_key_encoding_index_type(<span class="kw-2">&amp;</span>table_info.meta.options.extra_options);
<a href=#248 id=248 data-nosnippet>248</a>
<a href=#249 id=249 data-nosnippet>249</a> <span class="kw">for </span>(idx, column) <span class="kw">in </span>schema.column_schemas().iter().enumerate() {
<a href=#250 id=250 data-nosnippet>250</a> <span class="kw">if </span>column.is_time_index() {
<a href=#251 id=251 data-nosnippet>251</a> <span class="self">self</span>.add_key_column_usage(
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw-2">&amp;</span>predicates,
<a href=#253 id=253 data-nosnippet>253</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#254 id=254 data-nosnippet>254</a> CONSTRAINT_NAME_TIME_INDEX,
<a href=#255 id=255 data-nosnippet>255</a> <span class="kw-2">&amp;</span>catalog_name,
<a href=#256 id=256 data-nosnippet>256</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#257 id=257 data-nosnippet>257</a> table_name,
<a href=#258 id=258 data-nosnippet>258</a> <span class="kw-2">&amp;</span>column.name,
<a href=#259 id=259 data-nosnippet>259</a> <span class="number">1</span>, <span class="comment">//always 1 for time index
<a href=#260 id=260 data-nosnippet>260</a> </span><span class="string">""</span>,
<a href=#261 id=261 data-nosnippet>261</a> );
<a href=#262 id=262 data-nosnippet>262</a> }
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(pk_seq) = keys.iter().position(|k| <span class="kw-2">*</span>k == idx) {
<a href=#264 id=264 data-nosnippet>264</a> <span class="self">self</span>.add_key_column_usage(
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw-2">&amp;</span>predicates,
<a href=#266 id=266 data-nosnippet>266</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#267 id=267 data-nosnippet>267</a> CONSTRAINT_NAME_PRI,
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw-2">&amp;</span>catalog_name,
<a href=#269 id=269 data-nosnippet>269</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#270 id=270 data-nosnippet>270</a> table_name,
<a href=#271 id=271 data-nosnippet>271</a> <span class="kw-2">&amp;</span>column.name,
<a href=#272 id=272 data-nosnippet>272</a> pk_seq <span class="kw">as </span>u32 + <span class="number">1</span>,
<a href=#273 id=273 data-nosnippet>273</a> primary_key_encoding,
<a href=#274 id=274 data-nosnippet>274</a> );
<a href=#275 id=275 data-nosnippet>275</a> }
<a href=#276 id=276 data-nosnippet>276</a> }
<a href=#277 id=277 data-nosnippet>277</a> }
<a href=#278 id=278 data-nosnippet>278</a> }
<a href=#279 id=279 data-nosnippet>279</a>
<a href=#280 id=280 data-nosnippet>280</a> <span class="self">self</span>.finish()
<a href=#281 id=281 data-nosnippet>281</a> }
<a href=#282 id=282 data-nosnippet>282</a>
<a href=#283 id=283 data-nosnippet>283</a> <span class="comment">// TODO(dimbtp): Foreign key constraint has not `None` value for last 4
<a href=#284 id=284 data-nosnippet>284</a> // fields, but it is not supported yet.
<a href=#285 id=285 data-nosnippet>285</a> </span><span class="attr">#[allow(clippy::too_many_arguments)]
<a href=#286 id=286 data-nosnippet>286</a> </span><span class="kw">fn </span>add_key_column_usage(
<a href=#287 id=287 data-nosnippet>287</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#288 id=288 data-nosnippet>288</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#289 id=289 data-nosnippet>289</a> constraint_schema: <span class="kw-2">&amp;</span>str,
<a href=#290 id=290 data-nosnippet>290</a> constraint_name: <span class="kw-2">&amp;</span>str,
<a href=#291 id=291 data-nosnippet>291</a> table_catalog: <span class="kw-2">&amp;</span>str,
<a href=#292 id=292 data-nosnippet>292</a> table_schema: <span class="kw-2">&amp;</span>str,
<a href=#293 id=293 data-nosnippet>293</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#294 id=294 data-nosnippet>294</a> column_name: <span class="kw-2">&amp;</span>str,
<a href=#295 id=295 data-nosnippet>295</a> ordinal_position: u32,
<a href=#296 id=296 data-nosnippet>296</a> index_types: <span class="kw-2">&amp;</span>str,
<a href=#297 id=297 data-nosnippet>297</a> ) {
<a href=#298 id=298 data-nosnippet>298</a> <span class="kw">let </span>row = [
<a href=#299 id=299 data-nosnippet>299</a> (CONSTRAINT_SCHEMA, <span class="kw-2">&amp;</span>Value::from(constraint_schema)),
<a href=#300 id=300 data-nosnippet>300</a> (CONSTRAINT_NAME, <span class="kw-2">&amp;</span>Value::from(constraint_name)),
<a href=#301 id=301 data-nosnippet>301</a> (REAL_TABLE_CATALOG, <span class="kw-2">&amp;</span>Value::from(table_catalog)),
<a href=#302 id=302 data-nosnippet>302</a> (TABLE_SCHEMA, <span class="kw-2">&amp;</span>Value::from(table_schema)),
<a href=#303 id=303 data-nosnippet>303</a> (TABLE_NAME, <span class="kw-2">&amp;</span>Value::from(table_name)),
<a href=#304 id=304 data-nosnippet>304</a> (COLUMN_NAME, <span class="kw-2">&amp;</span>Value::from(column_name)),
<a href=#305 id=305 data-nosnippet>305</a> (ORDINAL_POSITION, <span class="kw-2">&amp;</span>Value::from(ordinal_position)),
<a href=#306 id=306 data-nosnippet>306</a> (GREPTIME_INDEX_TYPE, <span class="kw-2">&amp;</span>Value::from(index_types)),
<a href=#307 id=307 data-nosnippet>307</a> ];
<a href=#308 id=308 data-nosnippet>308</a>
<a href=#309 id=309 data-nosnippet>309</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#310 id=310 data-nosnippet>310</a> <span class="kw">return</span>;
<a href=#311 id=311 data-nosnippet>311</a> }
<a href=#312 id=312 data-nosnippet>312</a>
<a href=#313 id=313 data-nosnippet>313</a> <span class="self">self</span>.constraint_catalog.push(<span class="prelude-val">Some</span>(<span class="string">"def"</span>));
<a href=#314 id=314 data-nosnippet>314</a> <span class="self">self</span>.constraint_schema.push(<span class="prelude-val">Some</span>(constraint_schema));
<a href=#315 id=315 data-nosnippet>315</a> <span class="self">self</span>.constraint_name.push(<span class="prelude-val">Some</span>(constraint_name));
<a href=#316 id=316 data-nosnippet>316</a> <span class="self">self</span>.table_catalog.push(<span class="prelude-val">Some</span>(<span class="string">"def"</span>));
<a href=#317 id=317 data-nosnippet>317</a> <span class="self">self</span>.real_table_catalog.push(<span class="prelude-val">Some</span>(table_catalog));
<a href=#318 id=318 data-nosnippet>318</a> <span class="self">self</span>.table_schema.push(<span class="prelude-val">Some</span>(table_schema));
<a href=#319 id=319 data-nosnippet>319</a> <span class="self">self</span>.table_name.push(<span class="prelude-val">Some</span>(table_name));
<a href=#320 id=320 data-nosnippet>320</a> <span class="self">self</span>.column_name.push(<span class="prelude-val">Some</span>(column_name));
<a href=#321 id=321 data-nosnippet>321</a> <span class="self">self</span>.ordinal_position.push(<span class="prelude-val">Some</span>(ordinal_position));
<a href=#322 id=322 data-nosnippet>322</a> <span class="self">self</span>.position_in_unique_constraint.push(<span class="prelude-val">None</span>);
<a href=#323 id=323 data-nosnippet>323</a> <span class="self">self</span>.greptime_index_type.push(<span class="prelude-val">Some</span>(index_types));
<a href=#324 id=324 data-nosnippet>324</a> }
<a href=#325 id=325 data-nosnippet>325</a>
<a href=#326 id=326 data-nosnippet>326</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#327 id=327 data-nosnippet>327</a> <span class="kw">let </span>rows_num = <span class="self">self</span>.table_catalog.len();
<a href=#328 id=328 data-nosnippet>328</a>
<a href=#329 id=329 data-nosnippet>329</a> <span class="kw">let </span>null_string_vector = Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="prelude-val">None </span><span class="kw">as </span><span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt;; rows_num]));
<a href=#330 id=330 data-nosnippet>330</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#331 id=331 data-nosnippet>331</a> Arc::new(<span class="self">self</span>.constraint_catalog.finish()),
<a href=#332 id=332 data-nosnippet>332</a> Arc::new(<span class="self">self</span>.constraint_schema.finish()),
<a href=#333 id=333 data-nosnippet>333</a> Arc::new(<span class="self">self</span>.constraint_name.finish()),
<a href=#334 id=334 data-nosnippet>334</a> Arc::new(<span class="self">self</span>.table_catalog.finish()),
<a href=#335 id=335 data-nosnippet>335</a> Arc::new(<span class="self">self</span>.real_table_catalog.finish()),
<a href=#336 id=336 data-nosnippet>336</a> Arc::new(<span class="self">self</span>.table_schema.finish()),
<a href=#337 id=337 data-nosnippet>337</a> Arc::new(<span class="self">self</span>.table_name.finish()),
<a href=#338 id=338 data-nosnippet>338</a> Arc::new(<span class="self">self</span>.column_name.finish()),
<a href=#339 id=339 data-nosnippet>339</a> Arc::new(<span class="self">self</span>.ordinal_position.finish()),
<a href=#340 id=340 data-nosnippet>340</a> Arc::new(<span class="self">self</span>.position_in_unique_constraint.finish()),
<a href=#341 id=341 data-nosnippet>341</a> null_string_vector.clone(),
<a href=#342 id=342 data-nosnippet>342</a> null_string_vector.clone(),
<a href=#343 id=343 data-nosnippet>343</a> null_string_vector,
<a href=#344 id=344 data-nosnippet>344</a> Arc::new(<span class="self">self</span>.greptime_index_type.finish()),
<a href=#345 id=345 data-nosnippet>345</a> ];
<a href=#346 id=346 data-nosnippet>346</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#347 id=347 data-nosnippet>347</a> }
<a href=#348 id=348 data-nosnippet>348</a>}
<a href=#349 id=349 data-nosnippet>349</a>
<a href=#350 id=350 data-nosnippet>350</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaKeyColumnUsage {
<a href=#351 id=351 data-nosnippet>351</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#352 id=352 data-nosnippet>352</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#353 id=353 data-nosnippet>353</a> }
<a href=#354 id=354 data-nosnippet>354</a>
<a href=#355 id=355 data-nosnippet>355</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#356 id=356 data-nosnippet>356</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#357 id=357 data-nosnippet>357</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#358 id=358 data-nosnippet>358</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#359 id=359 data-nosnippet>359</a> schema,
<a href=#360 id=360 data-nosnippet>360</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#361 id=361 data-nosnippet>361</a> builder
<a href=#362 id=362 data-nosnippet>362</a> .make_key_column_usage(<span class="prelude-val">None</span>)
<a href=#363 id=363 data-nosnippet>363</a> .<span class="kw">await
<a href=#364 id=364 data-nosnippet>364</a> </span>.map(|x| x.into_df_record_batch())
<a href=#365 id=365 data-nosnippet>365</a> .map_err(Into::into)
<a href=#366 id=366 data-nosnippet>366</a> }),
<a href=#367 id=367 data-nosnippet>367</a> ))
<a href=#368 id=368 data-nosnippet>368</a> }
<a href=#369 id=369 data-nosnippet>369</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,424 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/partitions.rs`."><title>partitions.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>partitions.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>core::pin::pin;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_PARTITIONS_TABLE_ID;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, ScalarVectorBuilder, VectorRef};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::timestamp::TimestampSecond;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datatypes::value::Value;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>datatypes::vectors::{
<a href=#32 id=32 data-nosnippet>32</a> Int64Vector, Int64VectorBuilder, MutableVector, StringVector, StringVectorBuilder,
<a href=#33 id=33 data-nosnippet>33</a> TimestampSecondVector, TimestampSecondVectorBuilder, UInt64VectorBuilder,
<a href=#34 id=34 data-nosnippet>34</a>};
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span>futures::{StreamExt, TryStreamExt};
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>partition::manager::PartitionInfo;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>snafu::{OptionExt, ResultExt};
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span>table::metadata::{TableInfo, TableType};
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#43 id=43 data-nosnippet>43</a> CreateRecordBatchSnafu, FindPartitionsSnafu, InternalSnafu, PartitionManagerNotFoundSnafu,
<a href=#44 id=44 data-nosnippet>44</a> <span class="prelude-ty">Result</span>, UpgradeWeakCatalogManagerRefSnafu,
<a href=#45 id=45 data-nosnippet>45</a>};
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">use </span><span class="kw">crate</span>::kvbackend::KvBackendCatalogManager;
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{InformationTable, PARTITIONS, Predicates};
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">const </span>TABLE_CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"table_catalog"</span>;
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">const </span>TABLE_SCHEMA: <span class="kw-2">&amp;</span>str = <span class="string">"table_schema"</span>;
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">const </span>TABLE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_name"</span>;
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">const </span>PARTITION_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"partition_name"</span>;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">const </span>PARTITION_EXPRESSION: <span class="kw-2">&amp;</span>str = <span class="string">"partition_expression"</span>;
<a href=#54 id=54 data-nosnippet>54</a><span class="doccomment">/// The region id
<a href=#55 id=55 data-nosnippet>55</a></span><span class="kw">const </span>GREPTIME_PARTITION_ID: <span class="kw-2">&amp;</span>str = <span class="string">"greptime_partition_id"</span>;
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#57 id=57 data-nosnippet>57</a>
<a href=#58 id=58 data-nosnippet>58</a><span class="doccomment">/// The `PARTITIONS` table provides information about partitioned tables.
<a href=#59 id=59 data-nosnippet>59</a>/// See https://dev.mysql.com/doc/refman/8.0/en/information-schema-partitions-table.html
<a href=#60 id=60 data-nosnippet>60</a>/// We provide an extral column `greptime_partition_id` for GreptimeDB region id.
<a href=#61 id=61 data-nosnippet>61</a></span><span class="attr">#[derive(Debug)]
<a href=#62 id=62 data-nosnippet>62</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaPartitions {
<a href=#63 id=63 data-nosnippet>63</a> schema: SchemaRef,
<a href=#64 id=64 data-nosnippet>64</a> catalog_name: String,
<a href=#65 id=65 data-nosnippet>65</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#66 id=66 data-nosnippet>66</a>}
<a href=#67 id=67 data-nosnippet>67</a>
<a href=#68 id=68 data-nosnippet>68</a><span class="kw">impl </span>InformationSchemaPartitions {
<a href=#69 id=69 data-nosnippet>69</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_name: String, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#70 id=70 data-nosnippet>70</a> <span class="self">Self </span>{
<a href=#71 id=71 data-nosnippet>71</a> schema: <span class="self">Self</span>::schema(),
<a href=#72 id=72 data-nosnippet>72</a> catalog_name,
<a href=#73 id=73 data-nosnippet>73</a> catalog_manager,
<a href=#74 id=74 data-nosnippet>74</a> }
<a href=#75 id=75 data-nosnippet>75</a> }
<a href=#76 id=76 data-nosnippet>76</a>
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#78 id=78 data-nosnippet>78</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#79 id=79 data-nosnippet>79</a> ColumnSchema::new(TABLE_CATALOG, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#80 id=80 data-nosnippet>80</a> ColumnSchema::new(TABLE_SCHEMA, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#81 id=81 data-nosnippet>81</a> ColumnSchema::new(TABLE_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#82 id=82 data-nosnippet>82</a> ColumnSchema::new(PARTITION_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#83 id=83 data-nosnippet>83</a> ColumnSchema::new(
<a href=#84 id=84 data-nosnippet>84</a> <span class="string">"subpartition_name"</span>,
<a href=#85 id=85 data-nosnippet>85</a> ConcreteDataType::string_datatype(),
<a href=#86 id=86 data-nosnippet>86</a> <span class="bool-val">true</span>,
<a href=#87 id=87 data-nosnippet>87</a> ),
<a href=#88 id=88 data-nosnippet>88</a> ColumnSchema::new(
<a href=#89 id=89 data-nosnippet>89</a> <span class="string">"partition_ordinal_position"</span>,
<a href=#90 id=90 data-nosnippet>90</a> ConcreteDataType::int64_datatype(),
<a href=#91 id=91 data-nosnippet>91</a> <span class="bool-val">true</span>,
<a href=#92 id=92 data-nosnippet>92</a> ),
<a href=#93 id=93 data-nosnippet>93</a> ColumnSchema::new(
<a href=#94 id=94 data-nosnippet>94</a> <span class="string">"subpartition_ordinal_position"</span>,
<a href=#95 id=95 data-nosnippet>95</a> ConcreteDataType::int64_datatype(),
<a href=#96 id=96 data-nosnippet>96</a> <span class="bool-val">true</span>,
<a href=#97 id=97 data-nosnippet>97</a> ),
<a href=#98 id=98 data-nosnippet>98</a> ColumnSchema::new(
<a href=#99 id=99 data-nosnippet>99</a> <span class="string">"partition_method"</span>,
<a href=#100 id=100 data-nosnippet>100</a> ConcreteDataType::string_datatype(),
<a href=#101 id=101 data-nosnippet>101</a> <span class="bool-val">true</span>,
<a href=#102 id=102 data-nosnippet>102</a> ),
<a href=#103 id=103 data-nosnippet>103</a> ColumnSchema::new(
<a href=#104 id=104 data-nosnippet>104</a> <span class="string">"subpartition_method"</span>,
<a href=#105 id=105 data-nosnippet>105</a> ConcreteDataType::string_datatype(),
<a href=#106 id=106 data-nosnippet>106</a> <span class="bool-val">true</span>,
<a href=#107 id=107 data-nosnippet>107</a> ),
<a href=#108 id=108 data-nosnippet>108</a> ColumnSchema::new(
<a href=#109 id=109 data-nosnippet>109</a> PARTITION_EXPRESSION,
<a href=#110 id=110 data-nosnippet>110</a> ConcreteDataType::string_datatype(),
<a href=#111 id=111 data-nosnippet>111</a> <span class="bool-val">true</span>,
<a href=#112 id=112 data-nosnippet>112</a> ),
<a href=#113 id=113 data-nosnippet>113</a> ColumnSchema::new(
<a href=#114 id=114 data-nosnippet>114</a> <span class="string">"subpartition_expression"</span>,
<a href=#115 id=115 data-nosnippet>115</a> ConcreteDataType::string_datatype(),
<a href=#116 id=116 data-nosnippet>116</a> <span class="bool-val">true</span>,
<a href=#117 id=117 data-nosnippet>117</a> ),
<a href=#118 id=118 data-nosnippet>118</a> ColumnSchema::new(
<a href=#119 id=119 data-nosnippet>119</a> <span class="string">"partition_description"</span>,
<a href=#120 id=120 data-nosnippet>120</a> ConcreteDataType::string_datatype(),
<a href=#121 id=121 data-nosnippet>121</a> <span class="bool-val">true</span>,
<a href=#122 id=122 data-nosnippet>122</a> ),
<a href=#123 id=123 data-nosnippet>123</a> ColumnSchema::new(<span class="string">"table_rows"</span>, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#124 id=124 data-nosnippet>124</a> ColumnSchema::new(<span class="string">"avg_row_length"</span>, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#125 id=125 data-nosnippet>125</a> ColumnSchema::new(<span class="string">"data_length"</span>, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#126 id=126 data-nosnippet>126</a> ColumnSchema::new(<span class="string">"max_data_length"</span>, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#127 id=127 data-nosnippet>127</a> ColumnSchema::new(<span class="string">"index_length"</span>, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#128 id=128 data-nosnippet>128</a> ColumnSchema::new(<span class="string">"data_free"</span>, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#129 id=129 data-nosnippet>129</a> ColumnSchema::new(
<a href=#130 id=130 data-nosnippet>130</a> <span class="string">"create_time"</span>,
<a href=#131 id=131 data-nosnippet>131</a> ConcreteDataType::timestamp_second_datatype(),
<a href=#132 id=132 data-nosnippet>132</a> <span class="bool-val">true</span>,
<a href=#133 id=133 data-nosnippet>133</a> ),
<a href=#134 id=134 data-nosnippet>134</a> ColumnSchema::new(
<a href=#135 id=135 data-nosnippet>135</a> <span class="string">"update_time"</span>,
<a href=#136 id=136 data-nosnippet>136</a> ConcreteDataType::timestamp_second_datatype(),
<a href=#137 id=137 data-nosnippet>137</a> <span class="bool-val">true</span>,
<a href=#138 id=138 data-nosnippet>138</a> ),
<a href=#139 id=139 data-nosnippet>139</a> ColumnSchema::new(
<a href=#140 id=140 data-nosnippet>140</a> <span class="string">"check_time"</span>,
<a href=#141 id=141 data-nosnippet>141</a> ConcreteDataType::timestamp_second_datatype(),
<a href=#142 id=142 data-nosnippet>142</a> <span class="bool-val">true</span>,
<a href=#143 id=143 data-nosnippet>143</a> ),
<a href=#144 id=144 data-nosnippet>144</a> ColumnSchema::new(<span class="string">"checksum"</span>, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#145 id=145 data-nosnippet>145</a> ColumnSchema::new(
<a href=#146 id=146 data-nosnippet>146</a> <span class="string">"partition_comment"</span>,
<a href=#147 id=147 data-nosnippet>147</a> ConcreteDataType::string_datatype(),
<a href=#148 id=148 data-nosnippet>148</a> <span class="bool-val">true</span>,
<a href=#149 id=149 data-nosnippet>149</a> ),
<a href=#150 id=150 data-nosnippet>150</a> ColumnSchema::new(<span class="string">"nodegroup"</span>, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#151 id=151 data-nosnippet>151</a> ColumnSchema::new(<span class="string">"tablespace_name"</span>, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#152 id=152 data-nosnippet>152</a> ColumnSchema::new(
<a href=#153 id=153 data-nosnippet>153</a> GREPTIME_PARTITION_ID,
<a href=#154 id=154 data-nosnippet>154</a> ConcreteDataType::uint64_datatype(),
<a href=#155 id=155 data-nosnippet>155</a> <span class="bool-val">true</span>,
<a href=#156 id=156 data-nosnippet>156</a> ),
<a href=#157 id=157 data-nosnippet>157</a> ]))
<a href=#158 id=158 data-nosnippet>158</a> }
<a href=#159 id=159 data-nosnippet>159</a>
<a href=#160 id=160 data-nosnippet>160</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaPartitionsBuilder {
<a href=#161 id=161 data-nosnippet>161</a> InformationSchemaPartitionsBuilder::new(
<a href=#162 id=162 data-nosnippet>162</a> <span class="self">self</span>.schema.clone(),
<a href=#163 id=163 data-nosnippet>163</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#164 id=164 data-nosnippet>164</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#165 id=165 data-nosnippet>165</a> )
<a href=#166 id=166 data-nosnippet>166</a> }
<a href=#167 id=167 data-nosnippet>167</a>}
<a href=#168 id=168 data-nosnippet>168</a>
<a href=#169 id=169 data-nosnippet>169</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaPartitions {
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#171 id=171 data-nosnippet>171</a> INFORMATION_SCHEMA_PARTITIONS_TABLE_ID
<a href=#172 id=172 data-nosnippet>172</a> }
<a href=#173 id=173 data-nosnippet>173</a>
<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#175 id=175 data-nosnippet>175</a> PARTITIONS
<a href=#176 id=176 data-nosnippet>176</a> }
<a href=#177 id=177 data-nosnippet>177</a>
<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#179 id=179 data-nosnippet>179</a> <span class="self">self</span>.schema.clone()
<a href=#180 id=180 data-nosnippet>180</a> }
<a href=#181 id=181 data-nosnippet>181</a>
<a href=#182 id=182 data-nosnippet>182</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#183 id=183 data-nosnippet>183</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#186 id=186 data-nosnippet>186</a> schema,
<a href=#187 id=187 data-nosnippet>187</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#188 id=188 data-nosnippet>188</a> builder
<a href=#189 id=189 data-nosnippet>189</a> .make_partitions(<span class="prelude-val">Some</span>(request))
<a href=#190 id=190 data-nosnippet>190</a> .<span class="kw">await
<a href=#191 id=191 data-nosnippet>191</a> </span>.map(|x| x.into_df_record_batch())
<a href=#192 id=192 data-nosnippet>192</a> .map_err(Into::into)
<a href=#193 id=193 data-nosnippet>193</a> }),
<a href=#194 id=194 data-nosnippet>194</a> ));
<a href=#195 id=195 data-nosnippet>195</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#196 id=196 data-nosnippet>196</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#197 id=197 data-nosnippet>197</a> .map_err(BoxedError::new)
<a href=#198 id=198 data-nosnippet>198</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#199 id=199 data-nosnippet>199</a> ))
<a href=#200 id=200 data-nosnippet>200</a> }
<a href=#201 id=201 data-nosnippet>201</a>}
<a href=#202 id=202 data-nosnippet>202</a>
<a href=#203 id=203 data-nosnippet>203</a><span class="kw">struct </span>InformationSchemaPartitionsBuilder {
<a href=#204 id=204 data-nosnippet>204</a> schema: SchemaRef,
<a href=#205 id=205 data-nosnippet>205</a> catalog_name: String,
<a href=#206 id=206 data-nosnippet>206</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#207 id=207 data-nosnippet>207</a>
<a href=#208 id=208 data-nosnippet>208</a> catalog_names: StringVectorBuilder,
<a href=#209 id=209 data-nosnippet>209</a> schema_names: StringVectorBuilder,
<a href=#210 id=210 data-nosnippet>210</a> table_names: StringVectorBuilder,
<a href=#211 id=211 data-nosnippet>211</a> partition_names: StringVectorBuilder,
<a href=#212 id=212 data-nosnippet>212</a> partition_ordinal_positions: Int64VectorBuilder,
<a href=#213 id=213 data-nosnippet>213</a> partition_expressions: StringVectorBuilder,
<a href=#214 id=214 data-nosnippet>214</a> partition_descriptions: StringVectorBuilder,
<a href=#215 id=215 data-nosnippet>215</a> create_times: TimestampSecondVectorBuilder,
<a href=#216 id=216 data-nosnippet>216</a> partition_ids: UInt64VectorBuilder,
<a href=#217 id=217 data-nosnippet>217</a>}
<a href=#218 id=218 data-nosnippet>218</a>
<a href=#219 id=219 data-nosnippet>219</a><span class="kw">impl </span>InformationSchemaPartitionsBuilder {
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">fn </span>new(
<a href=#221 id=221 data-nosnippet>221</a> schema: SchemaRef,
<a href=#222 id=222 data-nosnippet>222</a> catalog_name: String,
<a href=#223 id=223 data-nosnippet>223</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#224 id=224 data-nosnippet>224</a> ) -&gt; <span class="self">Self </span>{
<a href=#225 id=225 data-nosnippet>225</a> <span class="self">Self </span>{
<a href=#226 id=226 data-nosnippet>226</a> schema,
<a href=#227 id=227 data-nosnippet>227</a> catalog_name,
<a href=#228 id=228 data-nosnippet>228</a> catalog_manager,
<a href=#229 id=229 data-nosnippet>229</a> catalog_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#230 id=230 data-nosnippet>230</a> schema_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#231 id=231 data-nosnippet>231</a> table_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#232 id=232 data-nosnippet>232</a> partition_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#233 id=233 data-nosnippet>233</a> partition_ordinal_positions: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#234 id=234 data-nosnippet>234</a> partition_expressions: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#235 id=235 data-nosnippet>235</a> partition_descriptions: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#236 id=236 data-nosnippet>236</a> create_times: TimestampSecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#237 id=237 data-nosnippet>237</a> partition_ids: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#238 id=238 data-nosnippet>238</a> }
<a href=#239 id=239 data-nosnippet>239</a> }
<a href=#240 id=240 data-nosnippet>240</a>
<a href=#241 id=241 data-nosnippet>241</a> <span class="doccomment">/// Construct the `information_schema.partitions` virtual table
<a href=#242 id=242 data-nosnippet>242</a> </span><span class="kw">async fn </span>make_partitions(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">let </span>catalog_name = <span class="self">self</span>.catalog_name.clone();
<a href=#244 id=244 data-nosnippet>244</a> <span class="kw">let </span>catalog_manager = <span class="self">self
<a href=#245 id=245 data-nosnippet>245</a> </span>.catalog_manager
<a href=#246 id=246 data-nosnippet>246</a> .upgrade()
<a href=#247 id=247 data-nosnippet>247</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#248 id=248 data-nosnippet>248</a>
<a href=#249 id=249 data-nosnippet>249</a> <span class="kw">let </span>partition_manager = catalog_manager
<a href=#250 id=250 data-nosnippet>250</a> .as_any()
<a href=#251 id=251 data-nosnippet>251</a> .downcast_ref::&lt;KvBackendCatalogManager&gt;()
<a href=#252 id=252 data-nosnippet>252</a> .map(|catalog_manager| catalog_manager.partition_manager())
<a href=#253 id=253 data-nosnippet>253</a> .context(PartitionManagerNotFoundSnafu)<span class="question-mark">?</span>;
<a href=#254 id=254 data-nosnippet>254</a>
<a href=#255 id=255 data-nosnippet>255</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#256 id=256 data-nosnippet>256</a>
<a href=#257 id=257 data-nosnippet>257</a> <span class="kw">for </span>schema_name <span class="kw">in </span>catalog_manager.schema_names(<span class="kw-2">&amp;</span>catalog_name, <span class="prelude-val">None</span>).<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#258 id=258 data-nosnippet>258</a> <span class="kw">let </span>table_info_stream = catalog_manager
<a href=#259 id=259 data-nosnippet>259</a> .tables(<span class="kw-2">&amp;</span>catalog_name, <span class="kw-2">&amp;</span>schema_name, <span class="prelude-val">None</span>)
<a href=#260 id=260 data-nosnippet>260</a> .try_filter_map(|t| <span class="kw">async move </span>{
<a href=#261 id=261 data-nosnippet>261</a> <span class="kw">let </span>table_info = t.table_info();
<a href=#262 id=262 data-nosnippet>262</a> <span class="kw">if </span>table_info.table_type == TableType::Temporary {
<a href=#263 id=263 data-nosnippet>263</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
<a href=#264 id=264 data-nosnippet>264</a> } <span class="kw">else </span>{
<a href=#265 id=265 data-nosnippet>265</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(table_info))
<a href=#266 id=266 data-nosnippet>266</a> }
<a href=#267 id=267 data-nosnippet>267</a> });
<a href=#268 id=268 data-nosnippet>268</a>
<a href=#269 id=269 data-nosnippet>269</a> <span class="kw">const </span>BATCH_SIZE: usize = <span class="number">128</span>;
<a href=#270 id=270 data-nosnippet>270</a>
<a href=#271 id=271 data-nosnippet>271</a> <span class="comment">// Split table infos into chunks
<a href=#272 id=272 data-nosnippet>272</a> </span><span class="kw">let </span><span class="kw-2">mut </span>table_info_chunks = <span class="macro">pin!</span>(table_info_stream.ready_chunks(BATCH_SIZE));
<a href=#273 id=273 data-nosnippet>273</a>
<a href=#274 id=274 data-nosnippet>274</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(table_infos) = table_info_chunks.next().<span class="kw">await </span>{
<a href=#275 id=275 data-nosnippet>275</a> <span class="kw">let </span>table_infos = table_infos.into_iter().collect::&lt;<span class="prelude-ty">Result</span>&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;&gt;()<span class="question-mark">?</span>;
<a href=#276 id=276 data-nosnippet>276</a> <span class="kw">let </span>table_ids: Vec&lt;TableId&gt; =
<a href=#277 id=277 data-nosnippet>277</a> table_infos.iter().map(|info| info.ident.table_id).collect();
<a href=#278 id=278 data-nosnippet>278</a>
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">let </span><span class="kw-2">mut </span>table_partitions = partition_manager
<a href=#280 id=280 data-nosnippet>280</a> .batch_find_table_partitions(<span class="kw-2">&amp;</span>table_ids)
<a href=#281 id=281 data-nosnippet>281</a> .<span class="kw">await
<a href=#282 id=282 data-nosnippet>282</a> </span>.context(FindPartitionsSnafu)<span class="question-mark">?</span>;
<a href=#283 id=283 data-nosnippet>283</a>
<a href=#284 id=284 data-nosnippet>284</a> <span class="kw">for </span>table_info <span class="kw">in </span>table_infos {
<a href=#285 id=285 data-nosnippet>285</a> <span class="kw">let </span>partitions = table_partitions
<a href=#286 id=286 data-nosnippet>286</a> .remove(<span class="kw-2">&amp;</span>table_info.ident.table_id)
<a href=#287 id=287 data-nosnippet>287</a> .unwrap_or(<span class="macro">vec!</span>[]);
<a href=#288 id=288 data-nosnippet>288</a>
<a href=#289 id=289 data-nosnippet>289</a> <span class="self">self</span>.add_partitions(
<a href=#290 id=290 data-nosnippet>290</a> <span class="kw-2">&amp;</span>predicates,
<a href=#291 id=291 data-nosnippet>291</a> <span class="kw-2">&amp;</span>table_info,
<a href=#292 id=292 data-nosnippet>292</a> <span class="kw-2">&amp;</span>catalog_name,
<a href=#293 id=293 data-nosnippet>293</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#294 id=294 data-nosnippet>294</a> <span class="kw-2">&amp;</span>table_info.name,
<a href=#295 id=295 data-nosnippet>295</a> <span class="kw-2">&amp;</span>partitions,
<a href=#296 id=296 data-nosnippet>296</a> );
<a href=#297 id=297 data-nosnippet>297</a> }
<a href=#298 id=298 data-nosnippet>298</a> }
<a href=#299 id=299 data-nosnippet>299</a> }
<a href=#300 id=300 data-nosnippet>300</a>
<a href=#301 id=301 data-nosnippet>301</a> <span class="self">self</span>.finish()
<a href=#302 id=302 data-nosnippet>302</a> }
<a href=#303 id=303 data-nosnippet>303</a>
<a href=#304 id=304 data-nosnippet>304</a> <span class="attr">#[allow(clippy::too_many_arguments)]
<a href=#305 id=305 data-nosnippet>305</a> </span><span class="kw">fn </span>add_partitions(
<a href=#306 id=306 data-nosnippet>306</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#307 id=307 data-nosnippet>307</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#308 id=308 data-nosnippet>308</a> table_info: <span class="kw-2">&amp;</span>TableInfo,
<a href=#309 id=309 data-nosnippet>309</a> catalog_name: <span class="kw-2">&amp;</span>str,
<a href=#310 id=310 data-nosnippet>310</a> schema_name: <span class="kw-2">&amp;</span>str,
<a href=#311 id=311 data-nosnippet>311</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#312 id=312 data-nosnippet>312</a> partitions: <span class="kw-2">&amp;</span>[PartitionInfo],
<a href=#313 id=313 data-nosnippet>313</a> ) {
<a href=#314 id=314 data-nosnippet>314</a> <span class="kw">let </span>row = [
<a href=#315 id=315 data-nosnippet>315</a> (TABLE_CATALOG, <span class="kw-2">&amp;</span>Value::from(catalog_name)),
<a href=#316 id=316 data-nosnippet>316</a> (TABLE_SCHEMA, <span class="kw-2">&amp;</span>Value::from(schema_name)),
<a href=#317 id=317 data-nosnippet>317</a> (TABLE_NAME, <span class="kw-2">&amp;</span>Value::from(table_name)),
<a href=#318 id=318 data-nosnippet>318</a> ];
<a href=#319 id=319 data-nosnippet>319</a>
<a href=#320 id=320 data-nosnippet>320</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#321 id=321 data-nosnippet>321</a> <span class="kw">return</span>;
<a href=#322 id=322 data-nosnippet>322</a> }
<a href=#323 id=323 data-nosnippet>323</a>
<a href=#324 id=324 data-nosnippet>324</a> <span class="comment">// Get partition column names (shared by all partitions)
<a href=#325 id=325 data-nosnippet>325</a> // In MySQL, PARTITION_EXPRESSION is the partitioning function expression (e.g., column name)
<a href=#326 id=326 data-nosnippet>326</a> </span><span class="kw">let </span>partition_columns: String = table_info
<a href=#327 id=327 data-nosnippet>327</a> .meta
<a href=#328 id=328 data-nosnippet>328</a> .partition_column_names()
<a href=#329 id=329 data-nosnippet>329</a> .cloned()
<a href=#330 id=330 data-nosnippet>330</a> .collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;()
<a href=#331 id=331 data-nosnippet>331</a> .join(<span class="string">", "</span>);
<a href=#332 id=332 data-nosnippet>332</a>
<a href=#333 id=333 data-nosnippet>333</a> <span class="kw">let </span>partition_expr_str = <span class="kw">if </span>partition_columns.is_empty() {
<a href=#334 id=334 data-nosnippet>334</a> <span class="prelude-val">None
<a href=#335 id=335 data-nosnippet>335</a> </span>} <span class="kw">else </span>{
<a href=#336 id=336 data-nosnippet>336</a> <span class="prelude-val">Some</span>(partition_columns)
<a href=#337 id=337 data-nosnippet>337</a> };
<a href=#338 id=338 data-nosnippet>338</a>
<a href=#339 id=339 data-nosnippet>339</a> <span class="kw">for </span>(index, partition) <span class="kw">in </span>partitions.iter().enumerate() {
<a href=#340 id=340 data-nosnippet>340</a> <span class="kw">let </span>partition_name = <span class="macro">format!</span>(<span class="string">"p{index}"</span>);
<a href=#341 id=341 data-nosnippet>341</a>
<a href=#342 id=342 data-nosnippet>342</a> <span class="self">self</span>.catalog_names.push(<span class="prelude-val">Some</span>(catalog_name));
<a href=#343 id=343 data-nosnippet>343</a> <span class="self">self</span>.schema_names.push(<span class="prelude-val">Some</span>(schema_name));
<a href=#344 id=344 data-nosnippet>344</a> <span class="self">self</span>.table_names.push(<span class="prelude-val">Some</span>(table_name));
<a href=#345 id=345 data-nosnippet>345</a> <span class="self">self</span>.partition_names.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>partition_name));
<a href=#346 id=346 data-nosnippet>346</a> <span class="self">self</span>.partition_ordinal_positions
<a href=#347 id=347 data-nosnippet>347</a> .push(<span class="prelude-val">Some</span>((index + <span class="number">1</span>) <span class="kw">as </span>i64));
<a href=#348 id=348 data-nosnippet>348</a> <span class="comment">// PARTITION_EXPRESSION: partition column names (same for all partitions)
<a href=#349 id=349 data-nosnippet>349</a> </span><span class="self">self</span>.partition_expressions
<a href=#350 id=350 data-nosnippet>350</a> .push(partition_expr_str.as_deref());
<a href=#351 id=351 data-nosnippet>351</a> <span class="comment">// PARTITION_DESCRIPTION: partition boundary expression (different for each partition)
<a href=#352 id=352 data-nosnippet>352</a> </span><span class="kw">let </span>description = partition.partition_expr.as_ref().map(|e| e.to_string());
<a href=#353 id=353 data-nosnippet>353</a> <span class="self">self</span>.partition_descriptions.push(description.as_deref());
<a href=#354 id=354 data-nosnippet>354</a> <span class="self">self</span>.create_times.push(<span class="prelude-val">Some</span>(TimestampSecond::from(
<a href=#355 id=355 data-nosnippet>355</a> table_info.meta.created_on.timestamp(),
<a href=#356 id=356 data-nosnippet>356</a> )));
<a href=#357 id=357 data-nosnippet>357</a> <span class="self">self</span>.partition_ids.push(<span class="prelude-val">Some</span>(partition.id.as_u64()));
<a href=#358 id=358 data-nosnippet>358</a> }
<a href=#359 id=359 data-nosnippet>359</a> }
<a href=#360 id=360 data-nosnippet>360</a>
<a href=#361 id=361 data-nosnippet>361</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#362 id=362 data-nosnippet>362</a> <span class="kw">let </span>rows_num = <span class="self">self</span>.catalog_names.len();
<a href=#363 id=363 data-nosnippet>363</a>
<a href=#364 id=364 data-nosnippet>364</a> <span class="kw">let </span>null_string_vector = Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="prelude-val">None </span><span class="kw">as </span><span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt;; rows_num]));
<a href=#365 id=365 data-nosnippet>365</a> <span class="kw">let </span>null_i64_vector = Arc::new(Int64Vector::from(<span class="macro">vec!</span>[<span class="prelude-val">None</span>; rows_num]));
<a href=#366 id=366 data-nosnippet>366</a> <span class="kw">let </span>null_timestamp_second_vector =
<a href=#367 id=367 data-nosnippet>367</a> Arc::new(TimestampSecondVector::from(<span class="macro">vec!</span>[<span class="prelude-val">None</span>; rows_num]));
<a href=#368 id=368 data-nosnippet>368</a> <span class="kw">let </span>partition_methods = Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="prelude-val">Some</span>(<span class="string">"RANGE"</span>); rows_num]));
<a href=#369 id=369 data-nosnippet>369</a>
<a href=#370 id=370 data-nosnippet>370</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#371 id=371 data-nosnippet>371</a> Arc::new(<span class="self">self</span>.catalog_names.finish()),
<a href=#372 id=372 data-nosnippet>372</a> Arc::new(<span class="self">self</span>.schema_names.finish()),
<a href=#373 id=373 data-nosnippet>373</a> Arc::new(<span class="self">self</span>.table_names.finish()),
<a href=#374 id=374 data-nosnippet>374</a> Arc::new(<span class="self">self</span>.partition_names.finish()),
<a href=#375 id=375 data-nosnippet>375</a> null_string_vector.clone(),
<a href=#376 id=376 data-nosnippet>376</a> Arc::new(<span class="self">self</span>.partition_ordinal_positions.finish()),
<a href=#377 id=377 data-nosnippet>377</a> null_i64_vector.clone(),
<a href=#378 id=378 data-nosnippet>378</a> partition_methods,
<a href=#379 id=379 data-nosnippet>379</a> null_string_vector.clone(),
<a href=#380 id=380 data-nosnippet>380</a> Arc::new(<span class="self">self</span>.partition_expressions.finish()),
<a href=#381 id=381 data-nosnippet>381</a> null_string_vector.clone(),
<a href=#382 id=382 data-nosnippet>382</a> Arc::new(<span class="self">self</span>.partition_descriptions.finish()),
<a href=#383 id=383 data-nosnippet>383</a> <span class="comment">// TODO(dennis): rows and index statistics info
<a href=#384 id=384 data-nosnippet>384</a> </span>null_i64_vector.clone(),
<a href=#385 id=385 data-nosnippet>385</a> null_i64_vector.clone(),
<a href=#386 id=386 data-nosnippet>386</a> null_i64_vector.clone(),
<a href=#387 id=387 data-nosnippet>387</a> null_i64_vector.clone(),
<a href=#388 id=388 data-nosnippet>388</a> null_i64_vector.clone(),
<a href=#389 id=389 data-nosnippet>389</a> null_i64_vector.clone(),
<a href=#390 id=390 data-nosnippet>390</a> Arc::new(<span class="self">self</span>.create_times.finish()),
<a href=#391 id=391 data-nosnippet>391</a> <span class="comment">// TODO(dennis): supports update_time
<a href=#392 id=392 data-nosnippet>392</a> </span>null_timestamp_second_vector.clone(),
<a href=#393 id=393 data-nosnippet>393</a> null_timestamp_second_vector,
<a href=#394 id=394 data-nosnippet>394</a> null_i64_vector,
<a href=#395 id=395 data-nosnippet>395</a> null_string_vector.clone(),
<a href=#396 id=396 data-nosnippet>396</a> null_string_vector.clone(),
<a href=#397 id=397 data-nosnippet>397</a> null_string_vector,
<a href=#398 id=398 data-nosnippet>398</a> Arc::new(<span class="self">self</span>.partition_ids.finish()),
<a href=#399 id=399 data-nosnippet>399</a> ];
<a href=#400 id=400 data-nosnippet>400</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#401 id=401 data-nosnippet>401</a> }
<a href=#402 id=402 data-nosnippet>402</a>}
<a href=#403 id=403 data-nosnippet>403</a>
<a href=#404 id=404 data-nosnippet>404</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaPartitions {
<a href=#405 id=405 data-nosnippet>405</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#406 id=406 data-nosnippet>406</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#407 id=407 data-nosnippet>407</a> }
<a href=#408 id=408 data-nosnippet>408</a>
<a href=#409 id=409 data-nosnippet>409</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#410 id=410 data-nosnippet>410</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#411 id=411 data-nosnippet>411</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#412 id=412 data-nosnippet>412</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#413 id=413 data-nosnippet>413</a> schema,
<a href=#414 id=414 data-nosnippet>414</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#415 id=415 data-nosnippet>415</a> builder
<a href=#416 id=416 data-nosnippet>416</a> .make_partitions(<span class="prelude-val">None</span>)
<a href=#417 id=417 data-nosnippet>417</a> .<span class="kw">await
<a href=#418 id=418 data-nosnippet>418</a> </span>.map(|x| x.into_df_record_batch())
<a href=#419 id=419 data-nosnippet>419</a> .map_err(Into::into)
<a href=#420 id=420 data-nosnippet>420</a> }),
<a href=#421 id=421 data-nosnippet>421</a> ))
<a href=#422 id=422 data-nosnippet>422</a> }
<a href=#423 id=423 data-nosnippet>423</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,241 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/procedure_info.rs`."><title>procedure_info.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>procedure_info.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_PROCEDURE_INFO_TABLE_ID;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_procedure::ProcedureInfo;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_time::timestamp::Timestamp;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, ScalarVectorBuilder, VectorRef};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datatypes::timestamp::TimestampMillisecond;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>datatypes::value::Value;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>datatypes::vectors::{StringVectorBuilder, TimestampMillisecondVectorBuilder};
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>snafu::ResultExt;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#35 id=35 data-nosnippet>35</a>
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span><span class="kw">crate</span>::error::{CreateRecordBatchSnafu, InternalSnafu, <span class="prelude-ty">Result</span>};
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{InformationTable, PROCEDURE_INFO, Predicates};
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::utils;
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">const </span>PROCEDURE_ID: <span class="kw-2">&amp;</span>str = <span class="string">"procedure_id"</span>;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">const </span>PROCEDURE_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"procedure_type"</span>;
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">const </span>START_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"start_time"</span>;
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">const </span>END_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"end_time"</span>;
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">const </span>STATUS: <span class="kw-2">&amp;</span>str = <span class="string">"status"</span>;
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">const </span>LOCK_KEYS: <span class="kw-2">&amp;</span>str = <span class="string">"lock_keys"</span>;
<a href=#47 id=47 data-nosnippet>47</a>
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#49 id=49 data-nosnippet>49</a>
<a href=#50 id=50 data-nosnippet>50</a><span class="doccomment">/// The `PROCEDURE_INFO` table provides information about the current procedure information of the cluster.
<a href=#51 id=51 data-nosnippet>51</a>///
<a href=#52 id=52 data-nosnippet>52</a>/// - `procedure_id`: the unique identifier of the procedure.
<a href=#53 id=53 data-nosnippet>53</a>/// - `procedure_name`: the name of the procedure.
<a href=#54 id=54 data-nosnippet>54</a>/// - `start_time`: the starting execution time of the procedure.
<a href=#55 id=55 data-nosnippet>55</a>/// - `end_time`: the ending execution time of the procedure.
<a href=#56 id=56 data-nosnippet>56</a>/// - `status`: the status of the procedure.
<a href=#57 id=57 data-nosnippet>57</a>/// - `lock_keys`: the lock keys of the procedure.
<a href=#58 id=58 data-nosnippet>58</a></span><span class="attr">#[derive(Debug)]
<a href=#59 id=59 data-nosnippet>59</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaProcedureInfo {
<a href=#60 id=60 data-nosnippet>60</a> schema: SchemaRef,
<a href=#61 id=61 data-nosnippet>61</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#62 id=62 data-nosnippet>62</a>}
<a href=#63 id=63 data-nosnippet>63</a>
<a href=#64 id=64 data-nosnippet>64</a><span class="kw">impl </span>InformationSchemaProcedureInfo {
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#66 id=66 data-nosnippet>66</a> <span class="self">Self </span>{
<a href=#67 id=67 data-nosnippet>67</a> schema: <span class="self">Self</span>::schema(),
<a href=#68 id=68 data-nosnippet>68</a> catalog_manager,
<a href=#69 id=69 data-nosnippet>69</a> }
<a href=#70 id=70 data-nosnippet>70</a> }
<a href=#71 id=71 data-nosnippet>71</a>
<a href=#72 id=72 data-nosnippet>72</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#73 id=73 data-nosnippet>73</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#74 id=74 data-nosnippet>74</a> ColumnSchema::new(PROCEDURE_ID, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#75 id=75 data-nosnippet>75</a> ColumnSchema::new(PROCEDURE_TYPE, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#76 id=76 data-nosnippet>76</a> ColumnSchema::new(
<a href=#77 id=77 data-nosnippet>77</a> START_TIME,
<a href=#78 id=78 data-nosnippet>78</a> ConcreteDataType::timestamp_millisecond_datatype(),
<a href=#79 id=79 data-nosnippet>79</a> <span class="bool-val">true</span>,
<a href=#80 id=80 data-nosnippet>80</a> ),
<a href=#81 id=81 data-nosnippet>81</a> ColumnSchema::new(
<a href=#82 id=82 data-nosnippet>82</a> END_TIME,
<a href=#83 id=83 data-nosnippet>83</a> ConcreteDataType::timestamp_millisecond_datatype(),
<a href=#84 id=84 data-nosnippet>84</a> <span class="bool-val">true</span>,
<a href=#85 id=85 data-nosnippet>85</a> ),
<a href=#86 id=86 data-nosnippet>86</a> ColumnSchema::new(STATUS, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#87 id=87 data-nosnippet>87</a> ColumnSchema::new(LOCK_KEYS, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#88 id=88 data-nosnippet>88</a> ]))
<a href=#89 id=89 data-nosnippet>89</a> }
<a href=#90 id=90 data-nosnippet>90</a>
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaProcedureInfoBuilder {
<a href=#92 id=92 data-nosnippet>92</a> InformationSchemaProcedureInfoBuilder::new(
<a href=#93 id=93 data-nosnippet>93</a> <span class="self">self</span>.schema.clone(),
<a href=#94 id=94 data-nosnippet>94</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#95 id=95 data-nosnippet>95</a> )
<a href=#96 id=96 data-nosnippet>96</a> }
<a href=#97 id=97 data-nosnippet>97</a>}
<a href=#98 id=98 data-nosnippet>98</a>
<a href=#99 id=99 data-nosnippet>99</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaProcedureInfo {
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#101 id=101 data-nosnippet>101</a> INFORMATION_SCHEMA_PROCEDURE_INFO_TABLE_ID
<a href=#102 id=102 data-nosnippet>102</a> }
<a href=#103 id=103 data-nosnippet>103</a>
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#105 id=105 data-nosnippet>105</a> PROCEDURE_INFO
<a href=#106 id=106 data-nosnippet>106</a> }
<a href=#107 id=107 data-nosnippet>107</a>
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#109 id=109 data-nosnippet>109</a> <span class="self">self</span>.schema.clone()
<a href=#110 id=110 data-nosnippet>110</a> }
<a href=#111 id=111 data-nosnippet>111</a>
<a href=#112 id=112 data-nosnippet>112</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#115 id=115 data-nosnippet>115</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#116 id=116 data-nosnippet>116</a> schema,
<a href=#117 id=117 data-nosnippet>117</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#118 id=118 data-nosnippet>118</a> builder
<a href=#119 id=119 data-nosnippet>119</a> .make_procedure_info(<span class="prelude-val">Some</span>(request))
<a href=#120 id=120 data-nosnippet>120</a> .<span class="kw">await
<a href=#121 id=121 data-nosnippet>121</a> </span>.map(|x| x.into_df_record_batch())
<a href=#122 id=122 data-nosnippet>122</a> .map_err(Into::into)
<a href=#123 id=123 data-nosnippet>123</a> }),
<a href=#124 id=124 data-nosnippet>124</a> ));
<a href=#125 id=125 data-nosnippet>125</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#126 id=126 data-nosnippet>126</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#127 id=127 data-nosnippet>127</a> .map_err(BoxedError::new)
<a href=#128 id=128 data-nosnippet>128</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#129 id=129 data-nosnippet>129</a> ))
<a href=#130 id=130 data-nosnippet>130</a> }
<a href=#131 id=131 data-nosnippet>131</a>}
<a href=#132 id=132 data-nosnippet>132</a>
<a href=#133 id=133 data-nosnippet>133</a><span class="kw">struct </span>InformationSchemaProcedureInfoBuilder {
<a href=#134 id=134 data-nosnippet>134</a> schema: SchemaRef,
<a href=#135 id=135 data-nosnippet>135</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#136 id=136 data-nosnippet>136</a>
<a href=#137 id=137 data-nosnippet>137</a> procedure_ids: StringVectorBuilder,
<a href=#138 id=138 data-nosnippet>138</a> procedure_types: StringVectorBuilder,
<a href=#139 id=139 data-nosnippet>139</a> start_times: TimestampMillisecondVectorBuilder,
<a href=#140 id=140 data-nosnippet>140</a> end_times: TimestampMillisecondVectorBuilder,
<a href=#141 id=141 data-nosnippet>141</a> statuses: StringVectorBuilder,
<a href=#142 id=142 data-nosnippet>142</a> lock_keys: StringVectorBuilder,
<a href=#143 id=143 data-nosnippet>143</a>}
<a href=#144 id=144 data-nosnippet>144</a>
<a href=#145 id=145 data-nosnippet>145</a><span class="kw">impl </span>InformationSchemaProcedureInfoBuilder {
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">fn </span>new(schema: SchemaRef, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#147 id=147 data-nosnippet>147</a> <span class="self">Self </span>{
<a href=#148 id=148 data-nosnippet>148</a> schema,
<a href=#149 id=149 data-nosnippet>149</a> catalog_manager,
<a href=#150 id=150 data-nosnippet>150</a> procedure_ids: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#151 id=151 data-nosnippet>151</a> procedure_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#152 id=152 data-nosnippet>152</a> start_times: TimestampMillisecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#153 id=153 data-nosnippet>153</a> end_times: TimestampMillisecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#154 id=154 data-nosnippet>154</a> statuses: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#155 id=155 data-nosnippet>155</a> lock_keys: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#156 id=156 data-nosnippet>156</a> }
<a href=#157 id=157 data-nosnippet>157</a> }
<a href=#158 id=158 data-nosnippet>158</a>
<a href=#159 id=159 data-nosnippet>159</a> <span class="doccomment">/// Construct the `information_schema.procedure_info` virtual table
<a href=#160 id=160 data-nosnippet>160</a> </span><span class="kw">async fn </span>make_procedure_info(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#161 id=161 data-nosnippet>161</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#162 id=162 data-nosnippet>162</a> <span class="kw">let </span>information_extension = utils::information_extension(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">let </span>procedures = information_extension.procedures().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#164 id=164 data-nosnippet>164</a> <span class="kw">for </span>(status, procedure_info) <span class="kw">in </span>procedures {
<a href=#165 id=165 data-nosnippet>165</a> <span class="self">self</span>.add_procedure(<span class="kw-2">&amp;</span>predicates, status, procedure_info);
<a href=#166 id=166 data-nosnippet>166</a> }
<a href=#167 id=167 data-nosnippet>167</a> <span class="self">self</span>.finish()
<a href=#168 id=168 data-nosnippet>168</a> }
<a href=#169 id=169 data-nosnippet>169</a>
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw">fn </span>add_procedure(
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#172 id=172 data-nosnippet>172</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#173 id=173 data-nosnippet>173</a> status: String,
<a href=#174 id=174 data-nosnippet>174</a> procedure_info: ProcedureInfo,
<a href=#175 id=175 data-nosnippet>175</a> ) {
<a href=#176 id=176 data-nosnippet>176</a> <span class="kw">let </span>ProcedureInfo {
<a href=#177 id=177 data-nosnippet>177</a> id,
<a href=#178 id=178 data-nosnippet>178</a> type_name,
<a href=#179 id=179 data-nosnippet>179</a> start_time_ms,
<a href=#180 id=180 data-nosnippet>180</a> end_time_ms,
<a href=#181 id=181 data-nosnippet>181</a> lock_keys,
<a href=#182 id=182 data-nosnippet>182</a> ..
<a href=#183 id=183 data-nosnippet>183</a> } = procedure_info;
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">let </span>pid = id.to_string();
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">let </span>start_time = TimestampMillisecond(Timestamp::new_millisecond(start_time_ms));
<a href=#186 id=186 data-nosnippet>186</a> <span class="kw">let </span>end_time = TimestampMillisecond(Timestamp::new_millisecond(end_time_ms));
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">let </span>lock_keys = lock_keys.join(<span class="string">","</span>);
<a href=#188 id=188 data-nosnippet>188</a>
<a href=#189 id=189 data-nosnippet>189</a> <span class="kw">let </span>row = [
<a href=#190 id=190 data-nosnippet>190</a> (PROCEDURE_ID, <span class="kw-2">&amp;</span>Value::from(pid.clone())),
<a href=#191 id=191 data-nosnippet>191</a> (PROCEDURE_TYPE, <span class="kw-2">&amp;</span>Value::from(type_name.clone())),
<a href=#192 id=192 data-nosnippet>192</a> (START_TIME, <span class="kw-2">&amp;</span>Value::from(start_time)),
<a href=#193 id=193 data-nosnippet>193</a> (END_TIME, <span class="kw-2">&amp;</span>Value::from(end_time)),
<a href=#194 id=194 data-nosnippet>194</a> (STATUS, <span class="kw-2">&amp;</span>Value::from(status.clone())),
<a href=#195 id=195 data-nosnippet>195</a> (LOCK_KEYS, <span class="kw-2">&amp;</span>Value::from(lock_keys.clone())),
<a href=#196 id=196 data-nosnippet>196</a> ];
<a href=#197 id=197 data-nosnippet>197</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">return</span>;
<a href=#199 id=199 data-nosnippet>199</a> }
<a href=#200 id=200 data-nosnippet>200</a> <span class="self">self</span>.procedure_ids.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>pid));
<a href=#201 id=201 data-nosnippet>201</a> <span class="self">self</span>.procedure_types.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>type_name));
<a href=#202 id=202 data-nosnippet>202</a> <span class="self">self</span>.start_times.push(<span class="prelude-val">Some</span>(start_time));
<a href=#203 id=203 data-nosnippet>203</a> <span class="self">self</span>.end_times.push(<span class="prelude-val">Some</span>(end_time));
<a href=#204 id=204 data-nosnippet>204</a> <span class="self">self</span>.statuses.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>status));
<a href=#205 id=205 data-nosnippet>205</a> <span class="self">self</span>.lock_keys.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>lock_keys));
<a href=#206 id=206 data-nosnippet>206</a> }
<a href=#207 id=207 data-nosnippet>207</a>
<a href=#208 id=208 data-nosnippet>208</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#209 id=209 data-nosnippet>209</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#210 id=210 data-nosnippet>210</a> Arc::new(<span class="self">self</span>.procedure_ids.finish()),
<a href=#211 id=211 data-nosnippet>211</a> Arc::new(<span class="self">self</span>.procedure_types.finish()),
<a href=#212 id=212 data-nosnippet>212</a> Arc::new(<span class="self">self</span>.start_times.finish()),
<a href=#213 id=213 data-nosnippet>213</a> Arc::new(<span class="self">self</span>.end_times.finish()),
<a href=#214 id=214 data-nosnippet>214</a> Arc::new(<span class="self">self</span>.statuses.finish()),
<a href=#215 id=215 data-nosnippet>215</a> Arc::new(<span class="self">self</span>.lock_keys.finish()),
<a href=#216 id=216 data-nosnippet>216</a> ];
<a href=#217 id=217 data-nosnippet>217</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#218 id=218 data-nosnippet>218</a> }
<a href=#219 id=219 data-nosnippet>219</a>}
<a href=#220 id=220 data-nosnippet>220</a>
<a href=#221 id=221 data-nosnippet>221</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaProcedureInfo {
<a href=#222 id=222 data-nosnippet>222</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#223 id=223 data-nosnippet>223</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#224 id=224 data-nosnippet>224</a> }
<a href=#225 id=225 data-nosnippet>225</a>
<a href=#226 id=226 data-nosnippet>226</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#227 id=227 data-nosnippet>227</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#228 id=228 data-nosnippet>228</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#229 id=229 data-nosnippet>229</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#230 id=230 data-nosnippet>230</a> schema,
<a href=#231 id=231 data-nosnippet>231</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#232 id=232 data-nosnippet>232</a> builder
<a href=#233 id=233 data-nosnippet>233</a> .make_procedure_info(<span class="prelude-val">None</span>)
<a href=#234 id=234 data-nosnippet>234</a> .<span class="kw">await
<a href=#235 id=235 data-nosnippet>235</a> </span>.map(|x| x.into_df_record_batch())
<a href=#236 id=236 data-nosnippet>236</a> .map_err(Into::into)
<a href=#237 id=237 data-nosnippet>237</a> }),
<a href=#238 id=238 data-nosnippet>238</a> ))
<a href=#239 id=239 data-nosnippet>239</a> }
<a href=#240 id=240 data-nosnippet>240</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,190 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/process_list.rs`."><title>process_list.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>process_list.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::Arc;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_PROCESS_LIST_TABLE_ID;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_frontend::DisplayProcessId;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_time::util::current_time_millis;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_time::{Duration, Timestamp};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datatypes::prelude::ConcreteDataType <span class="kw">as </span>CDT;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datatypes::scalars::ScalarVectorBuilder;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datatypes::value::Value;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::vectors::{
<a href=#30 id=30 data-nosnippet>30</a> DurationMillisecondVectorBuilder, StringVectorBuilder, TimestampMillisecondVectorBuilder,
<a href=#31 id=31 data-nosnippet>31</a> VectorRef,
<a href=#32 id=32 data-nosnippet>32</a>};
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>snafu::ResultExt;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#35 id=35 data-nosnippet>35</a>
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span><span class="kw">crate</span>::error::{<span class="self">self</span>, InternalSnafu};
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::Predicates;
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span><span class="kw">crate</span>::process_manager::ProcessManagerRef;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::InformationTable;
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="doccomment">/// Column names of `information_schema.process_list`
<a href=#42 id=42 data-nosnippet>42</a></span><span class="kw">pub const </span>ID: <span class="kw-2">&amp;</span>str = <span class="string">"id"</span>;
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">pub const </span>CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"catalog"</span>;
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">pub const </span>SCHEMAS: <span class="kw-2">&amp;</span>str = <span class="string">"schemas"</span>;
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">pub const </span>QUERY: <span class="kw-2">&amp;</span>str = <span class="string">"query"</span>;
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">pub const </span>CLIENT: <span class="kw-2">&amp;</span>str = <span class="string">"client"</span>;
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">pub const </span>FRONTEND: <span class="kw-2">&amp;</span>str = <span class="string">"frontend"</span>;
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">pub const </span>START_TIMESTAMP: <span class="kw-2">&amp;</span>str = <span class="string">"start_timestamp"</span>;
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">pub const </span>ELAPSED_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"elapsed_time"</span>;
<a href=#50 id=50 data-nosnippet>50</a>
<a href=#51 id=51 data-nosnippet>51</a><span class="doccomment">/// `information_schema.process_list` table implementation that tracks running
<a href=#52 id=52 data-nosnippet>52</a>/// queries in current cluster.
<a href=#53 id=53 data-nosnippet>53</a></span><span class="kw">pub struct </span>InformationSchemaProcessList {
<a href=#54 id=54 data-nosnippet>54</a> schema: SchemaRef,
<a href=#55 id=55 data-nosnippet>55</a> process_manager: ProcessManagerRef,
<a href=#56 id=56 data-nosnippet>56</a>}
<a href=#57 id=57 data-nosnippet>57</a>
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">impl </span>InformationSchemaProcessList {
<a href=#59 id=59 data-nosnippet>59</a> <span class="kw">pub fn </span>new(process_manager: ProcessManagerRef) -&gt; <span class="self">Self </span>{
<a href=#60 id=60 data-nosnippet>60</a> <span class="self">Self </span>{
<a href=#61 id=61 data-nosnippet>61</a> schema: <span class="self">Self</span>::schema(),
<a href=#62 id=62 data-nosnippet>62</a> process_manager,
<a href=#63 id=63 data-nosnippet>63</a> }
<a href=#64 id=64 data-nosnippet>64</a> }
<a href=#65 id=65 data-nosnippet>65</a>
<a href=#66 id=66 data-nosnippet>66</a> <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#67 id=67 data-nosnippet>67</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#68 id=68 data-nosnippet>68</a> ColumnSchema::new(ID, CDT::string_datatype(), <span class="bool-val">false</span>),
<a href=#69 id=69 data-nosnippet>69</a> ColumnSchema::new(CATALOG, CDT::string_datatype(), <span class="bool-val">false</span>),
<a href=#70 id=70 data-nosnippet>70</a> ColumnSchema::new(SCHEMAS, CDT::string_datatype(), <span class="bool-val">false</span>),
<a href=#71 id=71 data-nosnippet>71</a> ColumnSchema::new(QUERY, CDT::string_datatype(), <span class="bool-val">false</span>),
<a href=#72 id=72 data-nosnippet>72</a> ColumnSchema::new(CLIENT, CDT::string_datatype(), <span class="bool-val">false</span>),
<a href=#73 id=73 data-nosnippet>73</a> ColumnSchema::new(FRONTEND, CDT::string_datatype(), <span class="bool-val">false</span>),
<a href=#74 id=74 data-nosnippet>74</a> ColumnSchema::new(
<a href=#75 id=75 data-nosnippet>75</a> START_TIMESTAMP,
<a href=#76 id=76 data-nosnippet>76</a> CDT::timestamp_millisecond_datatype(),
<a href=#77 id=77 data-nosnippet>77</a> <span class="bool-val">false</span>,
<a href=#78 id=78 data-nosnippet>78</a> ),
<a href=#79 id=79 data-nosnippet>79</a> ColumnSchema::new(ELAPSED_TIME, CDT::duration_millisecond_datatype(), <span class="bool-val">false</span>),
<a href=#80 id=80 data-nosnippet>80</a> ]))
<a href=#81 id=81 data-nosnippet>81</a> }
<a href=#82 id=82 data-nosnippet>82</a>}
<a href=#83 id=83 data-nosnippet>83</a>
<a href=#84 id=84 data-nosnippet>84</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaProcessList {
<a href=#85 id=85 data-nosnippet>85</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#86 id=86 data-nosnippet>86</a> INFORMATION_SCHEMA_PROCESS_LIST_TABLE_ID
<a href=#87 id=87 data-nosnippet>87</a> }
<a href=#88 id=88 data-nosnippet>88</a>
<a href=#89 id=89 data-nosnippet>89</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#90 id=90 data-nosnippet>90</a> <span class="string">"process_list"
<a href=#91 id=91 data-nosnippet>91</a> </span>}
<a href=#92 id=92 data-nosnippet>92</a>
<a href=#93 id=93 data-nosnippet>93</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#94 id=94 data-nosnippet>94</a> <span class="self">self</span>.schema.clone()
<a href=#95 id=95 data-nosnippet>95</a> }
<a href=#96 id=96 data-nosnippet>96</a>
<a href=#97 id=97 data-nosnippet>97</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; error::Result&lt;SendableRecordBatchStream&gt; {
<a href=#98 id=98 data-nosnippet>98</a> <span class="kw">let </span>process_manager = <span class="self">self</span>.process_manager.clone();
<a href=#99 id=99 data-nosnippet>99</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#100 id=100 data-nosnippet>100</a> <span class="self">self</span>.schema.arrow_schema().clone(),
<a href=#101 id=101 data-nosnippet>101</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#102 id=102 data-nosnippet>102</a> make_process_list(process_manager, request)
<a href=#103 id=103 data-nosnippet>103</a> .<span class="kw">await
<a href=#104 id=104 data-nosnippet>104</a> </span>.map(RecordBatch::into_df_record_batch)
<a href=#105 id=105 data-nosnippet>105</a> .map_err(|e| datafusion::error::DataFusionError::External(Box::new(e)))
<a href=#106 id=106 data-nosnippet>106</a> }),
<a href=#107 id=107 data-nosnippet>107</a> ));
<a href=#108 id=108 data-nosnippet>108</a>
<a href=#109 id=109 data-nosnippet>109</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#110 id=110 data-nosnippet>110</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#111 id=111 data-nosnippet>111</a> .map_err(BoxedError::new)
<a href=#112 id=112 data-nosnippet>112</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#113 id=113 data-nosnippet>113</a> ))
<a href=#114 id=114 data-nosnippet>114</a> }
<a href=#115 id=115 data-nosnippet>115</a>}
<a href=#116 id=116 data-nosnippet>116</a>
<a href=#117 id=117 data-nosnippet>117</a><span class="doccomment">/// Build running process list.
<a href=#118 id=118 data-nosnippet>118</a></span><span class="kw">async fn </span>make_process_list(
<a href=#119 id=119 data-nosnippet>119</a> process_manager: ProcessManagerRef,
<a href=#120 id=120 data-nosnippet>120</a> request: ScanRequest,
<a href=#121 id=121 data-nosnippet>121</a>) -&gt; error::Result&lt;RecordBatch&gt; {
<a href=#122 id=122 data-nosnippet>122</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span><span class="prelude-val">Some</span>(request));
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">let </span>current_time = current_time_millis();
<a href=#124 id=124 data-nosnippet>124</a> <span class="comment">// todo(hl): find a way to extract user catalog to filter queries from other users.
<a href=#125 id=125 data-nosnippet>125</a> </span><span class="kw">let </span>queries = process_manager.list_all_processes(<span class="prelude-val">None</span>).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#126 id=126 data-nosnippet>126</a>
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw">let </span><span class="kw-2">mut </span>id_builder = StringVectorBuilder::with_capacity(queries.len());
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw">let </span><span class="kw-2">mut </span>catalog_builder = StringVectorBuilder::with_capacity(queries.len());
<a href=#129 id=129 data-nosnippet>129</a> <span class="kw">let </span><span class="kw-2">mut </span>schemas_builder = StringVectorBuilder::with_capacity(queries.len());
<a href=#130 id=130 data-nosnippet>130</a> <span class="kw">let </span><span class="kw-2">mut </span>query_builder = StringVectorBuilder::with_capacity(queries.len());
<a href=#131 id=131 data-nosnippet>131</a> <span class="kw">let </span><span class="kw-2">mut </span>client_builder = StringVectorBuilder::with_capacity(queries.len());
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">let </span><span class="kw-2">mut </span>frontend_builder = StringVectorBuilder::with_capacity(queries.len());
<a href=#133 id=133 data-nosnippet>133</a> <span class="kw">let </span><span class="kw-2">mut </span>start_time_builder = TimestampMillisecondVectorBuilder::with_capacity(queries.len());
<a href=#134 id=134 data-nosnippet>134</a> <span class="kw">let </span><span class="kw-2">mut </span>elapsed_time_builder = DurationMillisecondVectorBuilder::with_capacity(queries.len());
<a href=#135 id=135 data-nosnippet>135</a>
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw">for </span>process <span class="kw">in </span>queries {
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">let </span>display_id = DisplayProcessId {
<a href=#138 id=138 data-nosnippet>138</a> server_addr: process.frontend.clone(),
<a href=#139 id=139 data-nosnippet>139</a> id: process.id,
<a href=#140 id=140 data-nosnippet>140</a> }
<a href=#141 id=141 data-nosnippet>141</a> .to_string();
<a href=#142 id=142 data-nosnippet>142</a> <span class="kw">let </span>schemas = process.schemas.join(<span class="string">","</span>);
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">let </span>id = Value::from(display_id);
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">let </span>catalog = Value::from(process.catalog);
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">let </span>schemas = Value::from(schemas);
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">let </span>query = Value::from(process.query);
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">let </span>client = Value::from(process.client);
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">let </span>frontend = Value::from(process.frontend);
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">let </span>start_timestamp = Value::from(Timestamp::new_millisecond(process.start_timestamp));
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">let </span>elapsed_time = Value::from(Duration::new_millisecond(
<a href=#151 id=151 data-nosnippet>151</a> current_time - process.start_timestamp,
<a href=#152 id=152 data-nosnippet>152</a> ));
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">let </span>row = [
<a href=#154 id=154 data-nosnippet>154</a> (ID, <span class="kw-2">&amp;</span>id),
<a href=#155 id=155 data-nosnippet>155</a> (CATALOG, <span class="kw-2">&amp;</span>catalog),
<a href=#156 id=156 data-nosnippet>156</a> (SCHEMAS, <span class="kw-2">&amp;</span>schemas),
<a href=#157 id=157 data-nosnippet>157</a> (QUERY, <span class="kw-2">&amp;</span>query),
<a href=#158 id=158 data-nosnippet>158</a> (CLIENT, <span class="kw-2">&amp;</span>client),
<a href=#159 id=159 data-nosnippet>159</a> (FRONTEND, <span class="kw-2">&amp;</span>frontend),
<a href=#160 id=160 data-nosnippet>160</a> (START_TIMESTAMP, <span class="kw-2">&amp;</span>start_timestamp),
<a href=#161 id=161 data-nosnippet>161</a> (ELAPSED_TIME, <span class="kw-2">&amp;</span>elapsed_time),
<a href=#162 id=162 data-nosnippet>162</a> ];
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">if </span>predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#164 id=164 data-nosnippet>164</a> id_builder.push(id.as_string().as_deref());
<a href=#165 id=165 data-nosnippet>165</a> catalog_builder.push(catalog.as_string().as_deref());
<a href=#166 id=166 data-nosnippet>166</a> schemas_builder.push(schemas.as_string().as_deref());
<a href=#167 id=167 data-nosnippet>167</a> query_builder.push(query.as_string().as_deref());
<a href=#168 id=168 data-nosnippet>168</a> client_builder.push(client.as_string().as_deref());
<a href=#169 id=169 data-nosnippet>169</a> frontend_builder.push(frontend.as_string().as_deref());
<a href=#170 id=170 data-nosnippet>170</a> start_time_builder.push(start_timestamp.as_timestamp().map(|t| t.value().into()));
<a href=#171 id=171 data-nosnippet>171</a> elapsed_time_builder.push(elapsed_time.as_duration().map(|d| d.value().into()));
<a href=#172 id=172 data-nosnippet>172</a> }
<a href=#173 id=173 data-nosnippet>173</a> }
<a href=#174 id=174 data-nosnippet>174</a>
<a href=#175 id=175 data-nosnippet>175</a> RecordBatch::new(
<a href=#176 id=176 data-nosnippet>176</a> InformationSchemaProcessList::schema(),
<a href=#177 id=177 data-nosnippet>177</a> <span class="macro">vec!</span>[
<a href=#178 id=178 data-nosnippet>178</a> Arc::new(id_builder.finish()) <span class="kw">as </span>VectorRef,
<a href=#179 id=179 data-nosnippet>179</a> Arc::new(catalog_builder.finish()) <span class="kw">as </span>VectorRef,
<a href=#180 id=180 data-nosnippet>180</a> Arc::new(schemas_builder.finish()) <span class="kw">as </span>VectorRef,
<a href=#181 id=181 data-nosnippet>181</a> Arc::new(query_builder.finish()) <span class="kw">as </span>VectorRef,
<a href=#182 id=182 data-nosnippet>182</a> Arc::new(client_builder.finish()) <span class="kw">as </span>VectorRef,
<a href=#183 id=183 data-nosnippet>183</a> Arc::new(frontend_builder.finish()) <span class="kw">as </span>VectorRef,
<a href=#184 id=184 data-nosnippet>184</a> Arc::new(start_time_builder.finish()) <span class="kw">as </span>VectorRef,
<a href=#185 id=185 data-nosnippet>185</a> Arc::new(elapsed_time_builder.finish()) <span class="kw">as </span>VectorRef,
<a href=#186 id=186 data-nosnippet>186</a> ],
<a href=#187 id=187 data-nosnippet>187</a> )
<a href=#188 id=188 data-nosnippet>188</a> .context(error::CreateRecordBatchSnafu)
<a href=#189 id=189 data-nosnippet>189</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,104 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/region_info.rs`."><title>region_info.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>region_info.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_REGION_INFO_TABLE_ID;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_recordbatch::SendableRecordBatchStream;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_recordbatch::adapter::AsyncRecordBatchStreamAdapter;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>datafusion::physical_plan::ExecutionPlan;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>datatypes::schema::SchemaRef;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>snafu::ResultExt;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>store_api::region_info::RegionInfoEntry;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#26 id=26 data-nosnippet>26</a>
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span><span class="kw">crate</span>::error::{ProjectSchemaSnafu, <span class="prelude-ty">Result</span>};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::{
<a href=#30 id=30 data-nosnippet>30</a> DatanodeInspectKind, DatanodeInspectRequest, InformationTable, REGION_INFO,
<a href=#31 id=31 data-nosnippet>31</a>};
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::utils;
<a href=#33 id=33 data-nosnippet>33</a>
<a href=#34 id=34 data-nosnippet>34</a><span class="doccomment">/// Information schema table for region info.
<a href=#35 id=35 data-nosnippet>35</a></span><span class="kw">pub struct </span>InformationSchemaRegionInfo {
<a href=#36 id=36 data-nosnippet>36</a> schema: SchemaRef,
<a href=#37 id=37 data-nosnippet>37</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#38 id=38 data-nosnippet>38</a>}
<a href=#39 id=39 data-nosnippet>39</a>
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">impl </span>InformationSchemaRegionInfo {
<a href=#41 id=41 data-nosnippet>41</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#42 id=42 data-nosnippet>42</a> <span class="self">Self </span>{
<a href=#43 id=43 data-nosnippet>43</a> schema: RegionInfoEntry::schema(),
<a href=#44 id=44 data-nosnippet>44</a> catalog_manager,
<a href=#45 id=45 data-nosnippet>45</a> }
<a href=#46 id=46 data-nosnippet>46</a> }
<a href=#47 id=47 data-nosnippet>47</a>}
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaRegionInfo {
<a href=#50 id=50 data-nosnippet>50</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#51 id=51 data-nosnippet>51</a> INFORMATION_SCHEMA_REGION_INFO_TABLE_ID
<a href=#52 id=52 data-nosnippet>52</a> }
<a href=#53 id=53 data-nosnippet>53</a>
<a href=#54 id=54 data-nosnippet>54</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#55 id=55 data-nosnippet>55</a> REGION_INFO
<a href=#56 id=56 data-nosnippet>56</a> }
<a href=#57 id=57 data-nosnippet>57</a>
<a href=#58 id=58 data-nosnippet>58</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#59 id=59 data-nosnippet>59</a> <span class="self">self</span>.schema.clone()
<a href=#60 id=60 data-nosnippet>60</a> }
<a href=#61 id=61 data-nosnippet>61</a>
<a href=#62 id=62 data-nosnippet>62</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#63 id=63 data-nosnippet>63</a> <span class="kw">let </span>schema = <span class="kw">if let </span><span class="prelude-val">Some</span>(p) = request.projection.as_deref() {
<a href=#64 id=64 data-nosnippet>64</a> Arc::new(<span class="self">self</span>.schema.try_project(p).context(ProjectSchemaSnafu)<span class="question-mark">?</span>)
<a href=#65 id=65 data-nosnippet>65</a> } <span class="kw">else </span>{
<a href=#66 id=66 data-nosnippet>66</a> <span class="self">self</span>.schema.clone()
<a href=#67 id=67 data-nosnippet>67</a> };
<a href=#68 id=68 data-nosnippet>68</a>
<a href=#69 id=69 data-nosnippet>69</a> <span class="kw">let </span>info_ext = utils::information_extension(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">let </span>req = DatanodeInspectRequest {
<a href=#71 id=71 data-nosnippet>71</a> kind: DatanodeInspectKind::RegionInfo,
<a href=#72 id=72 data-nosnippet>72</a> scan: request,
<a href=#73 id=73 data-nosnippet>73</a> };
<a href=#74 id=74 data-nosnippet>74</a>
<a href=#75 id=75 data-nosnippet>75</a> <span class="kw">let </span>future = <span class="kw">async move </span>{
<a href=#76 id=76 data-nosnippet>76</a> info_ext
<a href=#77 id=77 data-nosnippet>77</a> .inspect_datanode(req)
<a href=#78 id=78 data-nosnippet>78</a> .<span class="kw">await
<a href=#79 id=79 data-nosnippet>79</a> </span>.map_err(BoxedError::new)
<a href=#80 id=80 data-nosnippet>80</a> .context(common_recordbatch::error::ExternalSnafu)
<a href=#81 id=81 data-nosnippet>81</a> };
<a href=#82 id=82 data-nosnippet>82</a> <span class="prelude-val">Ok</span>(Box::pin(AsyncRecordBatchStreamAdapter::new(
<a href=#83 id=83 data-nosnippet>83</a> schema,
<a href=#84 id=84 data-nosnippet>84</a> Box::pin(future),
<a href=#85 id=85 data-nosnippet>85</a> )))
<a href=#86 id=86 data-nosnippet>86</a> }
<a href=#87 id=87 data-nosnippet>87</a>
<a href=#88 id=88 data-nosnippet>88</a> <span class="kw">fn </span>scan_plan(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;&gt; {
<a href=#89 id=89 data-nosnippet>89</a> <span class="kw">let </span>schema = <span class="kw">if let </span><span class="prelude-val">Some</span>(p) = request.projection.as_deref() {
<a href=#90 id=90 data-nosnippet>90</a> Arc::new(<span class="self">self</span>.schema.try_project(p).context(ProjectSchemaSnafu)<span class="question-mark">?</span>)
<a href=#91 id=91 data-nosnippet>91</a> } <span class="kw">else </span>{
<a href=#92 id=92 data-nosnippet>92</a> <span class="self">self</span>.schema.clone()
<a href=#93 id=93 data-nosnippet>93</a> };
<a href=#94 id=94 data-nosnippet>94</a>
<a href=#95 id=95 data-nosnippet>95</a> <span class="kw">let </span>info_ext = utils::information_extension(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#96 id=96 data-nosnippet>96</a> <span class="kw">let </span>req = DatanodeInspectRequest {
<a href=#97 id=97 data-nosnippet>97</a> kind: DatanodeInspectKind::RegionInfo,
<a href=#98 id=98 data-nosnippet>98</a> scan: request,
<a href=#99 id=99 data-nosnippet>99</a> };
<a href=#100 id=100 data-nosnippet>100</a>
<a href=#101 id=101 data-nosnippet>101</a> info_ext.inspect_datanode_plan(req, schema)
<a href=#102 id=102 data-nosnippet>102</a> }
<a href=#103 id=103 data-nosnippet>103</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,418 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/region_peers.rs`."><title>region_peers.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>region_peers.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>core::pin::pin;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_REGION_PEERS_TABLE_ID;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_meta::rpc::router::RegionRoute;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>datafusion::common::HashMap;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, ScalarVectorBuilder, VectorRef};
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>datatypes::value::Value;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>datatypes::vectors::{Int64VectorBuilder, StringVectorBuilder, UInt64VectorBuilder};
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>futures::{StreamExt, TryStreamExt};
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span>snafu::{OptionExt, ResultExt};
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span>store_api::storage::{RegionId, ScanRequest, TableId};
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>table::metadata::TableType;
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#40 id=40 data-nosnippet>40</a> CreateRecordBatchSnafu, FindRegionRoutesSnafu, InternalSnafu, <span class="prelude-ty">Result</span>,
<a href=#41 id=41 data-nosnippet>41</a> UpgradeWeakCatalogManagerRefSnafu,
<a href=#42 id=42 data-nosnippet>42</a>};
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">use </span><span class="kw">crate</span>::kvbackend::KvBackendCatalogManager;
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{InformationTable, Predicates, REGION_PEERS};
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">pub const </span>TABLE_CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"table_catalog"</span>;
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">pub const </span>TABLE_SCHEMA: <span class="kw-2">&amp;</span>str = <span class="string">"table_schema"</span>;
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">pub const </span>TABLE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_name"</span>;
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">pub const </span>REGION_ID: <span class="kw-2">&amp;</span>str = <span class="string">"region_id"</span>;
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">pub const </span>PEER_ID: <span class="kw-2">&amp;</span>str = <span class="string">"peer_id"</span>;
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">const </span>PEER_ADDR: <span class="kw-2">&amp;</span>str = <span class="string">"peer_addr"</span>;
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">pub const </span>IS_LEADER: <span class="kw-2">&amp;</span>str = <span class="string">"is_leader"</span>;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">const </span>STATUS: <span class="kw-2">&amp;</span>str = <span class="string">"status"</span>;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">const </span>DOWN_SECONDS: <span class="kw-2">&amp;</span>str = <span class="string">"down_seconds"</span>;
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#56 id=56 data-nosnippet>56</a>
<a href=#57 id=57 data-nosnippet>57</a><span class="doccomment">/// The `REGION_PEERS` table provides information about the region distribution and routes. Including fields:
<a href=#58 id=58 data-nosnippet>58</a>///
<a href=#59 id=59 data-nosnippet>59</a>/// - `table_catalog`: the table catalog name
<a href=#60 id=60 data-nosnippet>60</a>/// - `table_schema`: the table schema name
<a href=#61 id=61 data-nosnippet>61</a>/// - `table_name`: the table name
<a href=#62 id=62 data-nosnippet>62</a>/// - `region_id`: the region id
<a href=#63 id=63 data-nosnippet>63</a>/// - `peer_id`: the region storage datanode peer id
<a href=#64 id=64 data-nosnippet>64</a>/// - `peer_addr`: the region storage datanode gRPC peer address
<a href=#65 id=65 data-nosnippet>65</a>/// - `is_leader`: whether the peer is the leader
<a href=#66 id=66 data-nosnippet>66</a>/// - `status`: the region status, `ALIVE` or `DOWNGRADED`.
<a href=#67 id=67 data-nosnippet>67</a>/// - `down_seconds`: the duration of being offline, in seconds.
<a href=#68 id=68 data-nosnippet>68</a></span><span class="attr">#[derive(Debug)]
<a href=#69 id=69 data-nosnippet>69</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaRegionPeers {
<a href=#70 id=70 data-nosnippet>70</a> schema: SchemaRef,
<a href=#71 id=71 data-nosnippet>71</a> catalog_name: String,
<a href=#72 id=72 data-nosnippet>72</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#73 id=73 data-nosnippet>73</a>}
<a href=#74 id=74 data-nosnippet>74</a>
<a href=#75 id=75 data-nosnippet>75</a><span class="kw">impl </span>InformationSchemaRegionPeers {
<a href=#76 id=76 data-nosnippet>76</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_name: String, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#77 id=77 data-nosnippet>77</a> <span class="self">Self </span>{
<a href=#78 id=78 data-nosnippet>78</a> schema: <span class="self">Self</span>::schema(),
<a href=#79 id=79 data-nosnippet>79</a> catalog_name,
<a href=#80 id=80 data-nosnippet>80</a> catalog_manager,
<a href=#81 id=81 data-nosnippet>81</a> }
<a href=#82 id=82 data-nosnippet>82</a> }
<a href=#83 id=83 data-nosnippet>83</a>
<a href=#84 id=84 data-nosnippet>84</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#85 id=85 data-nosnippet>85</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#86 id=86 data-nosnippet>86</a> ColumnSchema::new(TABLE_CATALOG, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#87 id=87 data-nosnippet>87</a> ColumnSchema::new(TABLE_SCHEMA, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#88 id=88 data-nosnippet>88</a> ColumnSchema::new(TABLE_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#89 id=89 data-nosnippet>89</a> ColumnSchema::new(REGION_ID, ConcreteDataType::uint64_datatype(), <span class="bool-val">false</span>),
<a href=#90 id=90 data-nosnippet>90</a> ColumnSchema::new(PEER_ID, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#91 id=91 data-nosnippet>91</a> ColumnSchema::new(PEER_ADDR, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#92 id=92 data-nosnippet>92</a> ColumnSchema::new(IS_LEADER, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#93 id=93 data-nosnippet>93</a> ColumnSchema::new(STATUS, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#94 id=94 data-nosnippet>94</a> ColumnSchema::new(DOWN_SECONDS, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#95 id=95 data-nosnippet>95</a> ]))
<a href=#96 id=96 data-nosnippet>96</a> }
<a href=#97 id=97 data-nosnippet>97</a>
<a href=#98 id=98 data-nosnippet>98</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaRegionPeersBuilder {
<a href=#99 id=99 data-nosnippet>99</a> InformationSchemaRegionPeersBuilder::new(
<a href=#100 id=100 data-nosnippet>100</a> <span class="self">self</span>.schema.clone(),
<a href=#101 id=101 data-nosnippet>101</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#102 id=102 data-nosnippet>102</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#103 id=103 data-nosnippet>103</a> )
<a href=#104 id=104 data-nosnippet>104</a> }
<a href=#105 id=105 data-nosnippet>105</a>}
<a href=#106 id=106 data-nosnippet>106</a>
<a href=#107 id=107 data-nosnippet>107</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaRegionPeers {
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#109 id=109 data-nosnippet>109</a> INFORMATION_SCHEMA_REGION_PEERS_TABLE_ID
<a href=#110 id=110 data-nosnippet>110</a> }
<a href=#111 id=111 data-nosnippet>111</a>
<a href=#112 id=112 data-nosnippet>112</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#113 id=113 data-nosnippet>113</a> REGION_PEERS
<a href=#114 id=114 data-nosnippet>114</a> }
<a href=#115 id=115 data-nosnippet>115</a>
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#117 id=117 data-nosnippet>117</a> <span class="self">self</span>.schema.clone()
<a href=#118 id=118 data-nosnippet>118</a> }
<a href=#119 id=119 data-nosnippet>119</a>
<a href=#120 id=120 data-nosnippet>120</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#121 id=121 data-nosnippet>121</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#122 id=122 data-nosnippet>122</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#124 id=124 data-nosnippet>124</a> schema,
<a href=#125 id=125 data-nosnippet>125</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#126 id=126 data-nosnippet>126</a> builder
<a href=#127 id=127 data-nosnippet>127</a> .make_region_peers(<span class="prelude-val">Some</span>(request))
<a href=#128 id=128 data-nosnippet>128</a> .<span class="kw">await
<a href=#129 id=129 data-nosnippet>129</a> </span>.map(|x| x.into_df_record_batch())
<a href=#130 id=130 data-nosnippet>130</a> .map_err(Into::into)
<a href=#131 id=131 data-nosnippet>131</a> }),
<a href=#132 id=132 data-nosnippet>132</a> ));
<a href=#133 id=133 data-nosnippet>133</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#134 id=134 data-nosnippet>134</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#135 id=135 data-nosnippet>135</a> .map_err(BoxedError::new)
<a href=#136 id=136 data-nosnippet>136</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#137 id=137 data-nosnippet>137</a> ))
<a href=#138 id=138 data-nosnippet>138</a> }
<a href=#139 id=139 data-nosnippet>139</a>}
<a href=#140 id=140 data-nosnippet>140</a>
<a href=#141 id=141 data-nosnippet>141</a><span class="kw">struct </span>InformationSchemaRegionPeersBuilder {
<a href=#142 id=142 data-nosnippet>142</a> schema: SchemaRef,
<a href=#143 id=143 data-nosnippet>143</a> catalog_name: String,
<a href=#144 id=144 data-nosnippet>144</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#145 id=145 data-nosnippet>145</a>
<a href=#146 id=146 data-nosnippet>146</a> table_catalogs: StringVectorBuilder,
<a href=#147 id=147 data-nosnippet>147</a> table_schemas: StringVectorBuilder,
<a href=#148 id=148 data-nosnippet>148</a> table_names: StringVectorBuilder,
<a href=#149 id=149 data-nosnippet>149</a> region_ids: UInt64VectorBuilder,
<a href=#150 id=150 data-nosnippet>150</a> peer_ids: UInt64VectorBuilder,
<a href=#151 id=151 data-nosnippet>151</a> peer_addrs: StringVectorBuilder,
<a href=#152 id=152 data-nosnippet>152</a> is_leaders: StringVectorBuilder,
<a href=#153 id=153 data-nosnippet>153</a> statuses: StringVectorBuilder,
<a href=#154 id=154 data-nosnippet>154</a> down_seconds: Int64VectorBuilder,
<a href=#155 id=155 data-nosnippet>155</a>}
<a href=#156 id=156 data-nosnippet>156</a>
<a href=#157 id=157 data-nosnippet>157</a><span class="kw">impl </span>InformationSchemaRegionPeersBuilder {
<a href=#158 id=158 data-nosnippet>158</a> <span class="kw">fn </span>new(
<a href=#159 id=159 data-nosnippet>159</a> schema: SchemaRef,
<a href=#160 id=160 data-nosnippet>160</a> catalog_name: String,
<a href=#161 id=161 data-nosnippet>161</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#162 id=162 data-nosnippet>162</a> ) -&gt; <span class="self">Self </span>{
<a href=#163 id=163 data-nosnippet>163</a> <span class="self">Self </span>{
<a href=#164 id=164 data-nosnippet>164</a> schema,
<a href=#165 id=165 data-nosnippet>165</a> catalog_name,
<a href=#166 id=166 data-nosnippet>166</a> catalog_manager,
<a href=#167 id=167 data-nosnippet>167</a> table_catalogs: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#168 id=168 data-nosnippet>168</a> table_schemas: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#169 id=169 data-nosnippet>169</a> table_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#170 id=170 data-nosnippet>170</a> region_ids: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#171 id=171 data-nosnippet>171</a> peer_ids: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#172 id=172 data-nosnippet>172</a> peer_addrs: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#173 id=173 data-nosnippet>173</a> is_leaders: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#174 id=174 data-nosnippet>174</a> statuses: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#175 id=175 data-nosnippet>175</a> down_seconds: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#176 id=176 data-nosnippet>176</a> }
<a href=#177 id=177 data-nosnippet>177</a> }
<a href=#178 id=178 data-nosnippet>178</a>
<a href=#179 id=179 data-nosnippet>179</a> <span class="doccomment">/// Construct the `information_schema.region_peers` virtual table
<a href=#180 id=180 data-nosnippet>180</a> </span><span class="kw">async fn </span>make_region_peers(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#181 id=181 data-nosnippet>181</a> <span class="kw">let </span>catalog_name = <span class="self">self</span>.catalog_name.clone();
<a href=#182 id=182 data-nosnippet>182</a> <span class="kw">let </span>catalog_manager = <span class="self">self
<a href=#183 id=183 data-nosnippet>183</a> </span>.catalog_manager
<a href=#184 id=184 data-nosnippet>184</a> .upgrade()
<a href=#185 id=185 data-nosnippet>185</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">let </span>partition_manager = catalog_manager
<a href=#188 id=188 data-nosnippet>188</a> .as_any()
<a href=#189 id=189 data-nosnippet>189</a> .downcast_ref::&lt;KvBackendCatalogManager&gt;()
<a href=#190 id=190 data-nosnippet>190</a> .map(|catalog_manager| catalog_manager.partition_manager());
<a href=#191 id=191 data-nosnippet>191</a>
<a href=#192 id=192 data-nosnippet>192</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#193 id=193 data-nosnippet>193</a>
<a href=#194 id=194 data-nosnippet>194</a> <span class="kw">for </span>schema_name <span class="kw">in </span>catalog_manager.schema_names(<span class="kw-2">&amp;</span>catalog_name, <span class="prelude-val">None</span>).<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#195 id=195 data-nosnippet>195</a> <span class="kw">let </span>table_stream = catalog_manager
<a href=#196 id=196 data-nosnippet>196</a> .tables(<span class="kw-2">&amp;</span>catalog_name, <span class="kw-2">&amp;</span>schema_name, <span class="prelude-val">None</span>)
<a href=#197 id=197 data-nosnippet>197</a> .try_filter_map(|t| <span class="kw">async move </span>{
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">let </span>table_info = t.table_info();
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">if </span>table_info.table_type == TableType::Temporary {
<a href=#200 id=200 data-nosnippet>200</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
<a href=#201 id=201 data-nosnippet>201</a> } <span class="kw">else </span>{
<a href=#202 id=202 data-nosnippet>202</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>((table_info.ident.table_id, table_info.name.clone())))
<a href=#203 id=203 data-nosnippet>203</a> }
<a href=#204 id=204 data-nosnippet>204</a> });
<a href=#205 id=205 data-nosnippet>205</a>
<a href=#206 id=206 data-nosnippet>206</a> <span class="kw">const </span>BATCH_SIZE: usize = <span class="number">128</span>;
<a href=#207 id=207 data-nosnippet>207</a>
<a href=#208 id=208 data-nosnippet>208</a> <span class="comment">// Split tables into chunks
<a href=#209 id=209 data-nosnippet>209</a> </span><span class="kw">let </span><span class="kw-2">mut </span>table_chunks = <span class="macro">pin!</span>(table_stream.ready_chunks(BATCH_SIZE));
<a href=#210 id=210 data-nosnippet>210</a>
<a href=#211 id=211 data-nosnippet>211</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(tables) = table_chunks.next().<span class="kw">await </span>{
<a href=#212 id=212 data-nosnippet>212</a> <span class="kw">let </span>tables = tables.into_iter().collect::&lt;<span class="prelude-ty">Result</span>&lt;HashMap&lt;<span class="kw">_</span>, <span class="kw">_</span>&gt;&gt;&gt;()<span class="question-mark">?</span>;
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">let </span>table_ids = tables.keys().cloned().collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;();
<a href=#214 id=214 data-nosnippet>214</a>
<a href=#215 id=215 data-nosnippet>215</a> <span class="kw">let </span>table_routes = <span class="kw">if let </span><span class="prelude-val">Some</span>(partition_manager) = <span class="kw-2">&amp;</span>partition_manager {
<a href=#216 id=216 data-nosnippet>216</a> partition_manager
<a href=#217 id=217 data-nosnippet>217</a> .batch_find_region_routes(<span class="kw-2">&amp;</span>table_ids)
<a href=#218 id=218 data-nosnippet>218</a> .<span class="kw">await
<a href=#219 id=219 data-nosnippet>219</a> </span>.context(FindRegionRoutesSnafu)<span class="question-mark">?
<a href=#220 id=220 data-nosnippet>220</a> </span>} <span class="kw">else </span>{
<a href=#221 id=221 data-nosnippet>221</a> table_ids.into_iter().map(|id| (id, <span class="macro">vec!</span>[])).collect()
<a href=#222 id=222 data-nosnippet>222</a> };
<a href=#223 id=223 data-nosnippet>223</a>
<a href=#224 id=224 data-nosnippet>224</a> <span class="kw">for </span>(table_id, routes) <span class="kw">in </span>table_routes {
<a href=#225 id=225 data-nosnippet>225</a> <span class="comment">// Safety: table_id is guaranteed to be in the map
<a href=#226 id=226 data-nosnippet>226</a> </span><span class="kw">let </span>table_name = tables.get(<span class="kw-2">&amp;</span>table_id).unwrap();
<a href=#227 id=227 data-nosnippet>227</a> <span class="self">self</span>.add_region_peers(
<a href=#228 id=228 data-nosnippet>228</a> <span class="kw-2">&amp;</span>catalog_name,
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#230 id=230 data-nosnippet>230</a> table_name,
<a href=#231 id=231 data-nosnippet>231</a> <span class="kw-2">&amp;</span>predicates,
<a href=#232 id=232 data-nosnippet>232</a> table_id,
<a href=#233 id=233 data-nosnippet>233</a> <span class="kw-2">&amp;</span>routes,
<a href=#234 id=234 data-nosnippet>234</a> );
<a href=#235 id=235 data-nosnippet>235</a> }
<a href=#236 id=236 data-nosnippet>236</a> }
<a href=#237 id=237 data-nosnippet>237</a> }
<a href=#238 id=238 data-nosnippet>238</a>
<a href=#239 id=239 data-nosnippet>239</a> <span class="self">self</span>.finish()
<a href=#240 id=240 data-nosnippet>240</a> }
<a href=#241 id=241 data-nosnippet>241</a>
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">fn </span>add_region_peers(
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#244 id=244 data-nosnippet>244</a> table_catalog: <span class="kw-2">&amp;</span>str,
<a href=#245 id=245 data-nosnippet>245</a> table_schema: <span class="kw-2">&amp;</span>str,
<a href=#246 id=246 data-nosnippet>246</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#247 id=247 data-nosnippet>247</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#248 id=248 data-nosnippet>248</a> table_id: TableId,
<a href=#249 id=249 data-nosnippet>249</a> routes: <span class="kw-2">&amp;</span>[RegionRoute],
<a href=#250 id=250 data-nosnippet>250</a> ) {
<a href=#251 id=251 data-nosnippet>251</a> <span class="kw">for </span>route <span class="kw">in </span>routes {
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw">let </span>region_id = RegionId::new(table_id, route.region.id.region_number()).as_u64();
<a href=#253 id=253 data-nosnippet>253</a> <span class="kw">let </span>peer_id = route.leader_peer.clone().map(|p| p.id);
<a href=#254 id=254 data-nosnippet>254</a> <span class="kw">let </span>peer_addr = route.leader_peer.clone().map(|p| p.addr);
<a href=#255 id=255 data-nosnippet>255</a> <span class="kw">let </span>state = <span class="kw">if let </span><span class="prelude-val">Some</span>(state) = route.leader_state {
<a href=#256 id=256 data-nosnippet>256</a> <span class="prelude-val">Some</span>(state.as_ref().to_string())
<a href=#257 id=257 data-nosnippet>257</a> } <span class="kw">else </span>{
<a href=#258 id=258 data-nosnippet>258</a> <span class="comment">// Alive by default
<a href=#259 id=259 data-nosnippet>259</a> </span><span class="prelude-val">Some</span>(<span class="string">"ALIVE"</span>.to_string())
<a href=#260 id=260 data-nosnippet>260</a> };
<a href=#261 id=261 data-nosnippet>261</a>
<a href=#262 id=262 data-nosnippet>262</a> <span class="kw">let </span>row = [
<a href=#263 id=263 data-nosnippet>263</a> (TABLE_CATALOG, <span class="kw-2">&amp;</span>Value::from(table_catalog)),
<a href=#264 id=264 data-nosnippet>264</a> (TABLE_SCHEMA, <span class="kw-2">&amp;</span>Value::from(table_schema)),
<a href=#265 id=265 data-nosnippet>265</a> (TABLE_NAME, <span class="kw-2">&amp;</span>Value::from(table_name)),
<a href=#266 id=266 data-nosnippet>266</a> (REGION_ID, <span class="kw-2">&amp;</span>Value::from(region_id)),
<a href=#267 id=267 data-nosnippet>267</a> ];
<a href=#268 id=268 data-nosnippet>268</a>
<a href=#269 id=269 data-nosnippet>269</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#270 id=270 data-nosnippet>270</a> <span class="kw">continue</span>;
<a href=#271 id=271 data-nosnippet>271</a> }
<a href=#272 id=272 data-nosnippet>272</a>
<a href=#273 id=273 data-nosnippet>273</a> <span class="self">self</span>.table_catalogs.push(<span class="prelude-val">Some</span>(table_catalog));
<a href=#274 id=274 data-nosnippet>274</a> <span class="self">self</span>.table_schemas.push(<span class="prelude-val">Some</span>(table_schema));
<a href=#275 id=275 data-nosnippet>275</a> <span class="self">self</span>.table_names.push(<span class="prelude-val">Some</span>(table_name));
<a href=#276 id=276 data-nosnippet>276</a> <span class="self">self</span>.region_ids.push(<span class="prelude-val">Some</span>(region_id));
<a href=#277 id=277 data-nosnippet>277</a> <span class="self">self</span>.peer_ids.push(peer_id);
<a href=#278 id=278 data-nosnippet>278</a> <span class="self">self</span>.peer_addrs.push(peer_addr.as_deref());
<a href=#279 id=279 data-nosnippet>279</a> <span class="self">self</span>.is_leaders.push(<span class="prelude-val">Some</span>(<span class="string">"Yes"</span>));
<a href=#280 id=280 data-nosnippet>280</a> <span class="self">self</span>.statuses.push(state.as_deref());
<a href=#281 id=281 data-nosnippet>281</a> <span class="self">self</span>.down_seconds
<a href=#282 id=282 data-nosnippet>282</a> .push(route.leader_down_millis().map(|m| m / <span class="number">1000</span>));
<a href=#283 id=283 data-nosnippet>283</a>
<a href=#284 id=284 data-nosnippet>284</a> <span class="kw">for </span>follower <span class="kw">in </span><span class="kw-2">&amp;</span>route.follower_peers {
<a href=#285 id=285 data-nosnippet>285</a> <span class="self">self</span>.table_catalogs.push(<span class="prelude-val">Some</span>(table_catalog));
<a href=#286 id=286 data-nosnippet>286</a> <span class="self">self</span>.table_schemas.push(<span class="prelude-val">Some</span>(table_schema));
<a href=#287 id=287 data-nosnippet>287</a> <span class="self">self</span>.table_names.push(<span class="prelude-val">Some</span>(table_name));
<a href=#288 id=288 data-nosnippet>288</a> <span class="self">self</span>.region_ids.push(<span class="prelude-val">Some</span>(region_id));
<a href=#289 id=289 data-nosnippet>289</a> <span class="self">self</span>.peer_ids.push(<span class="prelude-val">Some</span>(follower.id));
<a href=#290 id=290 data-nosnippet>290</a> <span class="self">self</span>.peer_addrs.push(<span class="prelude-val">Some</span>(follower.addr.as_str()));
<a href=#291 id=291 data-nosnippet>291</a> <span class="self">self</span>.is_leaders.push(<span class="prelude-val">Some</span>(<span class="string">"No"</span>));
<a href=#292 id=292 data-nosnippet>292</a> <span class="self">self</span>.statuses.push(<span class="prelude-val">None</span>);
<a href=#293 id=293 data-nosnippet>293</a> <span class="self">self</span>.down_seconds.push(<span class="prelude-val">None</span>);
<a href=#294 id=294 data-nosnippet>294</a> }
<a href=#295 id=295 data-nosnippet>295</a> }
<a href=#296 id=296 data-nosnippet>296</a> }
<a href=#297 id=297 data-nosnippet>297</a>
<a href=#298 id=298 data-nosnippet>298</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#299 id=299 data-nosnippet>299</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#300 id=300 data-nosnippet>300</a> Arc::new(<span class="self">self</span>.table_catalogs.finish()),
<a href=#301 id=301 data-nosnippet>301</a> Arc::new(<span class="self">self</span>.table_schemas.finish()),
<a href=#302 id=302 data-nosnippet>302</a> Arc::new(<span class="self">self</span>.table_names.finish()),
<a href=#303 id=303 data-nosnippet>303</a> Arc::new(<span class="self">self</span>.region_ids.finish()),
<a href=#304 id=304 data-nosnippet>304</a> Arc::new(<span class="self">self</span>.peer_ids.finish()),
<a href=#305 id=305 data-nosnippet>305</a> Arc::new(<span class="self">self</span>.peer_addrs.finish()),
<a href=#306 id=306 data-nosnippet>306</a> Arc::new(<span class="self">self</span>.is_leaders.finish()),
<a href=#307 id=307 data-nosnippet>307</a> Arc::new(<span class="self">self</span>.statuses.finish()),
<a href=#308 id=308 data-nosnippet>308</a> Arc::new(<span class="self">self</span>.down_seconds.finish()),
<a href=#309 id=309 data-nosnippet>309</a> ];
<a href=#310 id=310 data-nosnippet>310</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#311 id=311 data-nosnippet>311</a> }
<a href=#312 id=312 data-nosnippet>312</a>}
<a href=#313 id=313 data-nosnippet>313</a>
<a href=#314 id=314 data-nosnippet>314</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaRegionPeers {
<a href=#315 id=315 data-nosnippet>315</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#316 id=316 data-nosnippet>316</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#317 id=317 data-nosnippet>317</a> }
<a href=#318 id=318 data-nosnippet>318</a>
<a href=#319 id=319 data-nosnippet>319</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#320 id=320 data-nosnippet>320</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#321 id=321 data-nosnippet>321</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#322 id=322 data-nosnippet>322</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#323 id=323 data-nosnippet>323</a> schema,
<a href=#324 id=324 data-nosnippet>324</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#325 id=325 data-nosnippet>325</a> builder
<a href=#326 id=326 data-nosnippet>326</a> .make_region_peers(<span class="prelude-val">None</span>)
<a href=#327 id=327 data-nosnippet>327</a> .<span class="kw">await
<a href=#328 id=328 data-nosnippet>328</a> </span>.map(|x| x.into_df_record_batch())
<a href=#329 id=329 data-nosnippet>329</a> .map_err(Into::into)
<a href=#330 id=330 data-nosnippet>330</a> }),
<a href=#331 id=331 data-nosnippet>331</a> ))
<a href=#332 id=332 data-nosnippet>332</a> }
<a href=#333 id=333 data-nosnippet>333</a>}
<a href=#334 id=334 data-nosnippet>334</a>
<a href=#335 id=335 data-nosnippet>335</a><span class="attr">#[cfg(test)]
<a href=#336 id=336 data-nosnippet>336</a></span><span class="kw">mod </span>tests {
<a href=#337 id=337 data-nosnippet>337</a> <span class="kw">use </span>api::v1::meta::Peer;
<a href=#338 id=338 data-nosnippet>338</a> <span class="kw">use </span>arrow::array::AsArray;
<a href=#339 id=339 data-nosnippet>339</a> <span class="kw">use </span>common_meta::rpc::router::{Region, RegionRoute};
<a href=#340 id=340 data-nosnippet>340</a> <span class="kw">use </span>datafusion::common::ScalarValue;
<a href=#341 id=341 data-nosnippet>341</a> <span class="kw">use </span>datafusion::logical_expr::{BinaryExpr, Expr, Operator, col};
<a href=#342 id=342 data-nosnippet>342</a> <span class="kw">use </span>store_api::storage::{RegionId, ScanRequest};
<a href=#343 id=343 data-nosnippet>343</a>
<a href=#344 id=344 data-nosnippet>344</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#345 id=345 data-nosnippet>345</a>
<a href=#346 id=346 data-nosnippet>346</a> <span class="kw">fn </span>new_region_route(table_id: u32, region_number: u32, peer_id: u64) -&gt; RegionRoute {
<a href=#347 id=347 data-nosnippet>347</a> RegionRoute {
<a href=#348 id=348 data-nosnippet>348</a> region: Region {
<a href=#349 id=349 data-nosnippet>349</a> id: RegionId::new(table_id, region_number),
<a href=#350 id=350 data-nosnippet>350</a> ..Default::default()
<a href=#351 id=351 data-nosnippet>351</a> },
<a href=#352 id=352 data-nosnippet>352</a> leader_peer: <span class="prelude-val">Some</span>(Peer {
<a href=#353 id=353 data-nosnippet>353</a> id: peer_id,
<a href=#354 id=354 data-nosnippet>354</a> addr: <span class="macro">format!</span>(<span class="string">"127.0.0.1:{}"</span>, <span class="number">3000 </span>+ peer_id),
<a href=#355 id=355 data-nosnippet>355</a> }),
<a href=#356 id=356 data-nosnippet>356</a> follower_peers: <span class="macro">vec!</span>[],
<a href=#357 id=357 data-nosnippet>357</a> leader_state: <span class="prelude-val">None</span>,
<a href=#358 id=358 data-nosnippet>358</a> leader_down_since: <span class="prelude-val">None</span>,
<a href=#359 id=359 data-nosnippet>359</a> write_route_policy: <span class="prelude-val">None</span>,
<a href=#360 id=360 data-nosnippet>360</a> }
<a href=#361 id=361 data-nosnippet>361</a> }
<a href=#362 id=362 data-nosnippet>362</a>
<a href=#363 id=363 data-nosnippet>363</a> <span class="attr">#[test]
<a href=#364 id=364 data-nosnippet>364</a> </span><span class="kw">fn </span>test_add_region_peers_predicate_filters_correctly() {
<a href=#365 id=365 data-nosnippet>365</a> <span class="kw">let </span>schema = InformationSchemaRegionPeers::schema();
<a href=#366 id=366 data-nosnippet>366</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = InformationSchemaRegionPeersBuilder::new(
<a href=#367 id=367 data-nosnippet>367</a> schema,
<a href=#368 id=368 data-nosnippet>368</a> <span class="string">"greptime"</span>.to_string(),
<a href=#369 id=369 data-nosnippet>369</a> Weak::&lt;KvBackendCatalogManager&gt;::new(),
<a href=#370 id=370 data-nosnippet>370</a> );
<a href=#371 id=371 data-nosnippet>371</a>
<a href=#372 id=372 data-nosnippet>372</a> <span class="kw">let </span>table_id = <span class="number">1</span>;
<a href=#373 id=373 data-nosnippet>373</a> <span class="comment">// 3 regions: region_number 0, 1, 2
<a href=#374 id=374 data-nosnippet>374</a> </span><span class="kw">let </span>routes = <span class="macro">vec!</span>[
<a href=#375 id=375 data-nosnippet>375</a> new_region_route(table_id, <span class="number">0</span>, <span class="number">1</span>),
<a href=#376 id=376 data-nosnippet>376</a> new_region_route(table_id, <span class="number">1</span>, <span class="number">2</span>),
<a href=#377 id=377 data-nosnippet>377</a> new_region_route(table_id, <span class="number">2</span>, <span class="number">3</span>),
<a href=#378 id=378 data-nosnippet>378</a> ];
<a href=#379 id=379 data-nosnippet>379</a>
<a href=#380 id=380 data-nosnippet>380</a> <span class="comment">// Build a predicate that matches only the last region (region_number=2).
<a href=#381 id=381 data-nosnippet>381</a> // With the old `return` bug, encountering the first non-matching region
<a href=#382 id=382 data-nosnippet>382</a> // (region_number=0) would exit add_region_peers entirely, so region_number=2
<a href=#383 id=383 data-nosnippet>383</a> // would never be found.
<a href=#384 id=384 data-nosnippet>384</a> </span><span class="kw">let </span>target_region_id = RegionId::new(table_id, <span class="number">2</span>).as_u64();
<a href=#385 id=385 data-nosnippet>385</a> <span class="kw">let </span>filter = Expr::BinaryExpr(BinaryExpr::new(
<a href=#386 id=386 data-nosnippet>386</a> Box::new(col(REGION_ID)),
<a href=#387 id=387 data-nosnippet>387</a> Operator::Eq,
<a href=#388 id=388 data-nosnippet>388</a> Box::new(Expr::Literal(
<a href=#389 id=389 data-nosnippet>389</a> ScalarValue::UInt64(<span class="prelude-val">Some</span>(target_region_id)),
<a href=#390 id=390 data-nosnippet>390</a> <span class="prelude-val">None</span>,
<a href=#391 id=391 data-nosnippet>391</a> )),
<a href=#392 id=392 data-nosnippet>392</a> ));
<a href=#393 id=393 data-nosnippet>393</a> <span class="kw">let </span>request = ScanRequest {
<a href=#394 id=394 data-nosnippet>394</a> filters: <span class="macro">vec!</span>[filter],
<a href=#395 id=395 data-nosnippet>395</a> ..Default::default()
<a href=#396 id=396 data-nosnippet>396</a> };
<a href=#397 id=397 data-nosnippet>397</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span><span class="prelude-val">Some</span>(request));
<a href=#398 id=398 data-nosnippet>398</a>
<a href=#399 id=399 data-nosnippet>399</a> builder.add_region_peers(
<a href=#400 id=400 data-nosnippet>400</a> <span class="string">"greptime"</span>,
<a href=#401 id=401 data-nosnippet>401</a> <span class="string">"public"</span>,
<a href=#402 id=402 data-nosnippet>402</a> <span class="string">"test_table"</span>,
<a href=#403 id=403 data-nosnippet>403</a> <span class="kw-2">&amp;</span>predicates,
<a href=#404 id=404 data-nosnippet>404</a> table_id,
<a href=#405 id=405 data-nosnippet>405</a> <span class="kw-2">&amp;</span>routes,
<a href=#406 id=406 data-nosnippet>406</a> );
<a href=#407 id=407 data-nosnippet>407</a>
<a href=#408 id=408 data-nosnippet>408</a> <span class="kw">let </span>batch = builder.finish().unwrap();
<a href=#409 id=409 data-nosnippet>409</a> <span class="comment">// Should have exactly 1 row for the matching region
<a href=#410 id=410 data-nosnippet>410</a> </span><span class="macro">assert_eq!</span>(batch.num_rows(), <span class="number">1</span>);
<a href=#411 id=411 data-nosnippet>411</a> <span class="comment">// Verify it's the correct region
<a href=#412 id=412 data-nosnippet>412</a> </span><span class="kw">let </span>region_id_col = batch
<a href=#413 id=413 data-nosnippet>413</a> .column(<span class="number">3</span>)
<a href=#414 id=414 data-nosnippet>414</a> .as_primitive::&lt;arrow::datatypes::UInt64Type&gt;();
<a href=#415 id=415 data-nosnippet>415</a> <span class="macro">assert_eq!</span>(region_id_col.value(<span class="number">0</span>), target_region_id);
<a href=#416 id=416 data-nosnippet>416</a> }
<a href=#417 id=417 data-nosnippet>417</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,346 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/region_statistics.rs`."><title>region_statistics.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>region_statistics.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_REGION_STATISTICS_TABLE_ID;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::datanode::RegionStat;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_recordbatch::{DfSendableRecordBatchStream, RecordBatch, SendableRecordBatchStream};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_time::timestamp::TimeUnit;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, ScalarVectorBuilder, VectorRef};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::timestamp::TimestampMillisecond;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datatypes::value::Value;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>datatypes::vectors::{
<a href=#32 id=32 data-nosnippet>32</a> StringVectorBuilder, TimestampMillisecondVectorBuilder, UInt32VectorBuilder,
<a href=#33 id=33 data-nosnippet>33</a> UInt64VectorBuilder,
<a href=#34 id=34 data-nosnippet>34</a>};
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span>snafu::ResultExt;
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span><span class="kw">crate</span>::error::{CreateRecordBatchSnafu, InternalSnafu, <span class="prelude-ty">Result</span>};
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::Predicates;
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{InformationTable, REGION_STATISTICS};
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::utils;
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">const </span>REGION_ID: <span class="kw-2">&amp;</span>str = <span class="string">"region_id"</span>;
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">const </span>TABLE_ID: <span class="kw-2">&amp;</span>str = <span class="string">"table_id"</span>;
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">const </span>REGION_NUMBER: <span class="kw-2">&amp;</span>str = <span class="string">"region_number"</span>;
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">const </span>REGION_ROWS: <span class="kw-2">&amp;</span>str = <span class="string">"region_rows"</span>;
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">const </span>WRITTEN_BYTES: <span class="kw-2">&amp;</span>str = <span class="string">"written_bytes_since_open"</span>;
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">const </span>QUERY_CPU_TIME_MILLIS: <span class="kw-2">&amp;</span>str = <span class="string">"query_cpu_time_millis"</span>;
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">const </span>QUERY_SCANNED_BYTES: <span class="kw-2">&amp;</span>str = <span class="string">"query_scanned_bytes"</span>;
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">const </span>DISK_SIZE: <span class="kw-2">&amp;</span>str = <span class="string">"disk_size"</span>;
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">const </span>MEMTABLE_SIZE: <span class="kw-2">&amp;</span>str = <span class="string">"memtable_size"</span>;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">const </span>MANIFEST_SIZE: <span class="kw-2">&amp;</span>str = <span class="string">"manifest_size"</span>;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">const </span>SST_SIZE: <span class="kw-2">&amp;</span>str = <span class="string">"sst_size"</span>;
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">const </span>SST_NUM: <span class="kw-2">&amp;</span>str = <span class="string">"sst_num"</span>;
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">const </span>INDEX_SIZE: <span class="kw-2">&amp;</span>str = <span class="string">"index_size"</span>;
<a href=#57 id=57 data-nosnippet>57</a><span class="kw">const </span>ENGINE: <span class="kw-2">&amp;</span>str = <span class="string">"engine"</span>;
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">const </span>REGION_ROLE: <span class="kw-2">&amp;</span>str = <span class="string">"region_role"</span>;
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">const </span>MIN_TIMESTAMP: <span class="kw-2">&amp;</span>str = <span class="string">"min_timestamp"</span>;
<a href=#60 id=60 data-nosnippet>60</a><span class="kw">const </span>MAX_TIMESTAMP: <span class="kw-2">&amp;</span>str = <span class="string">"max_timestamp"</span>;
<a href=#61 id=61 data-nosnippet>61</a>
<a href=#62 id=62 data-nosnippet>62</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#63 id=63 data-nosnippet>63</a>
<a href=#64 id=64 data-nosnippet>64</a><span class="doccomment">/// The `REGION_STATISTICS` table provides information about the region statistics. Including fields:
<a href=#65 id=65 data-nosnippet>65</a>///
<a href=#66 id=66 data-nosnippet>66</a>/// - `region_id`: The region id.
<a href=#67 id=67 data-nosnippet>67</a>/// - `table_id`: The table id.
<a href=#68 id=68 data-nosnippet>68</a>/// - `region_number`: The region number.
<a href=#69 id=69 data-nosnippet>69</a>/// - `region_rows`: The number of rows in region.
<a href=#70 id=70 data-nosnippet>70</a>/// - `written_bytes_since_open`: The total bytes written of the region since region opened.
<a href=#71 id=71 data-nosnippet>71</a>/// - `query_cpu_time_millis`: The total query CPU time of the region since region opened, in milliseconds.
<a href=#72 id=72 data-nosnippet>72</a>/// - `query_scanned_bytes`: The total bytes scanned by queries since region opened.
<a href=#73 id=73 data-nosnippet>73</a>/// - `memtable_size`: The memtable size in bytes.
<a href=#74 id=74 data-nosnippet>74</a>/// - `disk_size`: The approximate disk size in bytes.
<a href=#75 id=75 data-nosnippet>75</a>/// - `manifest_size`: The manifest size in bytes.
<a href=#76 id=76 data-nosnippet>76</a>/// - `sst_size`: The sst data files size in bytes.
<a href=#77 id=77 data-nosnippet>77</a>/// - `index_size`: The sst index files size in bytes.
<a href=#78 id=78 data-nosnippet>78</a>/// - `engine`: The engine type.
<a href=#79 id=79 data-nosnippet>79</a>/// - `region_role`: The region role.
<a href=#80 id=80 data-nosnippet>80</a></span><span class="attr">#[derive(Debug)]
<a href=#81 id=81 data-nosnippet>81</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaRegionStatistics {
<a href=#82 id=82 data-nosnippet>82</a> schema: SchemaRef,
<a href=#83 id=83 data-nosnippet>83</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#84 id=84 data-nosnippet>84</a>}
<a href=#85 id=85 data-nosnippet>85</a>
<a href=#86 id=86 data-nosnippet>86</a><span class="kw">impl </span>InformationSchemaRegionStatistics {
<a href=#87 id=87 data-nosnippet>87</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#88 id=88 data-nosnippet>88</a> <span class="self">Self </span>{
<a href=#89 id=89 data-nosnippet>89</a> schema: <span class="self">Self</span>::schema(),
<a href=#90 id=90 data-nosnippet>90</a> catalog_manager,
<a href=#91 id=91 data-nosnippet>91</a> }
<a href=#92 id=92 data-nosnippet>92</a> }
<a href=#93 id=93 data-nosnippet>93</a>
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#95 id=95 data-nosnippet>95</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#96 id=96 data-nosnippet>96</a> ColumnSchema::new(REGION_ID, ConcreteDataType::uint64_datatype(), <span class="bool-val">false</span>),
<a href=#97 id=97 data-nosnippet>97</a> ColumnSchema::new(TABLE_ID, ConcreteDataType::uint32_datatype(), <span class="bool-val">false</span>),
<a href=#98 id=98 data-nosnippet>98</a> ColumnSchema::new(REGION_NUMBER, ConcreteDataType::uint32_datatype(), <span class="bool-val">false</span>),
<a href=#99 id=99 data-nosnippet>99</a> ColumnSchema::new(REGION_ROWS, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#100 id=100 data-nosnippet>100</a> ColumnSchema::new(WRITTEN_BYTES, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#101 id=101 data-nosnippet>101</a> ColumnSchema::new(
<a href=#102 id=102 data-nosnippet>102</a> QUERY_CPU_TIME_MILLIS,
<a href=#103 id=103 data-nosnippet>103</a> ConcreteDataType::uint64_datatype(),
<a href=#104 id=104 data-nosnippet>104</a> <span class="bool-val">true</span>,
<a href=#105 id=105 data-nosnippet>105</a> ),
<a href=#106 id=106 data-nosnippet>106</a> ColumnSchema::new(
<a href=#107 id=107 data-nosnippet>107</a> QUERY_SCANNED_BYTES,
<a href=#108 id=108 data-nosnippet>108</a> ConcreteDataType::uint64_datatype(),
<a href=#109 id=109 data-nosnippet>109</a> <span class="bool-val">true</span>,
<a href=#110 id=110 data-nosnippet>110</a> ),
<a href=#111 id=111 data-nosnippet>111</a> ColumnSchema::new(DISK_SIZE, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#112 id=112 data-nosnippet>112</a> ColumnSchema::new(MEMTABLE_SIZE, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#113 id=113 data-nosnippet>113</a> ColumnSchema::new(MANIFEST_SIZE, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#114 id=114 data-nosnippet>114</a> ColumnSchema::new(SST_SIZE, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#115 id=115 data-nosnippet>115</a> ColumnSchema::new(SST_NUM, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#116 id=116 data-nosnippet>116</a> ColumnSchema::new(INDEX_SIZE, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#117 id=117 data-nosnippet>117</a> ColumnSchema::new(ENGINE, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#118 id=118 data-nosnippet>118</a> ColumnSchema::new(REGION_ROLE, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#119 id=119 data-nosnippet>119</a> ColumnSchema::new(
<a href=#120 id=120 data-nosnippet>120</a> MIN_TIMESTAMP,
<a href=#121 id=121 data-nosnippet>121</a> ConcreteDataType::timestamp_millisecond_datatype(),
<a href=#122 id=122 data-nosnippet>122</a> <span class="bool-val">true</span>,
<a href=#123 id=123 data-nosnippet>123</a> ),
<a href=#124 id=124 data-nosnippet>124</a> ColumnSchema::new(
<a href=#125 id=125 data-nosnippet>125</a> MAX_TIMESTAMP,
<a href=#126 id=126 data-nosnippet>126</a> ConcreteDataType::timestamp_millisecond_datatype(),
<a href=#127 id=127 data-nosnippet>127</a> <span class="bool-val">true</span>,
<a href=#128 id=128 data-nosnippet>128</a> ),
<a href=#129 id=129 data-nosnippet>129</a> ]))
<a href=#130 id=130 data-nosnippet>130</a> }
<a href=#131 id=131 data-nosnippet>131</a>
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaRegionStatisticsBuilder {
<a href=#133 id=133 data-nosnippet>133</a> InformationSchemaRegionStatisticsBuilder::new(
<a href=#134 id=134 data-nosnippet>134</a> <span class="self">self</span>.schema.clone(),
<a href=#135 id=135 data-nosnippet>135</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#136 id=136 data-nosnippet>136</a> )
<a href=#137 id=137 data-nosnippet>137</a> }
<a href=#138 id=138 data-nosnippet>138</a>}
<a href=#139 id=139 data-nosnippet>139</a>
<a href=#140 id=140 data-nosnippet>140</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaRegionStatistics {
<a href=#141 id=141 data-nosnippet>141</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#142 id=142 data-nosnippet>142</a> INFORMATION_SCHEMA_REGION_STATISTICS_TABLE_ID
<a href=#143 id=143 data-nosnippet>143</a> }
<a href=#144 id=144 data-nosnippet>144</a>
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#146 id=146 data-nosnippet>146</a> REGION_STATISTICS
<a href=#147 id=147 data-nosnippet>147</a> }
<a href=#148 id=148 data-nosnippet>148</a>
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#150 id=150 data-nosnippet>150</a> <span class="self">self</span>.schema.clone()
<a href=#151 id=151 data-nosnippet>151</a> }
<a href=#152 id=152 data-nosnippet>152</a>
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#156 id=156 data-nosnippet>156</a>
<a href=#157 id=157 data-nosnippet>157</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#158 id=158 data-nosnippet>158</a> schema,
<a href=#159 id=159 data-nosnippet>159</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#160 id=160 data-nosnippet>160</a> builder
<a href=#161 id=161 data-nosnippet>161</a> .make_region_statistics(<span class="prelude-val">Some</span>(request))
<a href=#162 id=162 data-nosnippet>162</a> .<span class="kw">await
<a href=#163 id=163 data-nosnippet>163</a> </span>.map(|x| x.into_df_record_batch())
<a href=#164 id=164 data-nosnippet>164</a> .map_err(Into::into)
<a href=#165 id=165 data-nosnippet>165</a> }),
<a href=#166 id=166 data-nosnippet>166</a> ));
<a href=#167 id=167 data-nosnippet>167</a>
<a href=#168 id=168 data-nosnippet>168</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#169 id=169 data-nosnippet>169</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#170 id=170 data-nosnippet>170</a> .map_err(BoxedError::new)
<a href=#171 id=171 data-nosnippet>171</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#172 id=172 data-nosnippet>172</a> ))
<a href=#173 id=173 data-nosnippet>173</a> }
<a href=#174 id=174 data-nosnippet>174</a>}
<a href=#175 id=175 data-nosnippet>175</a>
<a href=#176 id=176 data-nosnippet>176</a><span class="kw">struct </span>InformationSchemaRegionStatisticsBuilder {
<a href=#177 id=177 data-nosnippet>177</a> schema: SchemaRef,
<a href=#178 id=178 data-nosnippet>178</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#179 id=179 data-nosnippet>179</a>
<a href=#180 id=180 data-nosnippet>180</a> region_ids: UInt64VectorBuilder,
<a href=#181 id=181 data-nosnippet>181</a> table_ids: UInt32VectorBuilder,
<a href=#182 id=182 data-nosnippet>182</a> region_numbers: UInt32VectorBuilder,
<a href=#183 id=183 data-nosnippet>183</a> region_rows: UInt64VectorBuilder,
<a href=#184 id=184 data-nosnippet>184</a> written_bytes: UInt64VectorBuilder,
<a href=#185 id=185 data-nosnippet>185</a> query_cpu_time_millis: UInt64VectorBuilder,
<a href=#186 id=186 data-nosnippet>186</a> query_scanned_bytes: UInt64VectorBuilder,
<a href=#187 id=187 data-nosnippet>187</a> disk_sizes: UInt64VectorBuilder,
<a href=#188 id=188 data-nosnippet>188</a> memtable_sizes: UInt64VectorBuilder,
<a href=#189 id=189 data-nosnippet>189</a> manifest_sizes: UInt64VectorBuilder,
<a href=#190 id=190 data-nosnippet>190</a> sst_sizes: UInt64VectorBuilder,
<a href=#191 id=191 data-nosnippet>191</a> sst_nums: UInt64VectorBuilder,
<a href=#192 id=192 data-nosnippet>192</a> index_sizes: UInt64VectorBuilder,
<a href=#193 id=193 data-nosnippet>193</a> engines: StringVectorBuilder,
<a href=#194 id=194 data-nosnippet>194</a> region_roles: StringVectorBuilder,
<a href=#195 id=195 data-nosnippet>195</a> min_timestamps: TimestampMillisecondVectorBuilder,
<a href=#196 id=196 data-nosnippet>196</a> max_timestamps: TimestampMillisecondVectorBuilder,
<a href=#197 id=197 data-nosnippet>197</a>}
<a href=#198 id=198 data-nosnippet>198</a>
<a href=#199 id=199 data-nosnippet>199</a><span class="kw">impl </span>InformationSchemaRegionStatisticsBuilder {
<a href=#200 id=200 data-nosnippet>200</a> <span class="kw">fn </span>new(schema: SchemaRef, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#201 id=201 data-nosnippet>201</a> <span class="self">Self </span>{
<a href=#202 id=202 data-nosnippet>202</a> schema,
<a href=#203 id=203 data-nosnippet>203</a> catalog_manager,
<a href=#204 id=204 data-nosnippet>204</a> region_ids: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#205 id=205 data-nosnippet>205</a> table_ids: UInt32VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#206 id=206 data-nosnippet>206</a> region_numbers: UInt32VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#207 id=207 data-nosnippet>207</a> region_rows: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#208 id=208 data-nosnippet>208</a> written_bytes: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#209 id=209 data-nosnippet>209</a> query_cpu_time_millis: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#210 id=210 data-nosnippet>210</a> query_scanned_bytes: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#211 id=211 data-nosnippet>211</a> disk_sizes: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#212 id=212 data-nosnippet>212</a> memtable_sizes: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#213 id=213 data-nosnippet>213</a> manifest_sizes: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#214 id=214 data-nosnippet>214</a> sst_sizes: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#215 id=215 data-nosnippet>215</a> sst_nums: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#216 id=216 data-nosnippet>216</a> index_sizes: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#217 id=217 data-nosnippet>217</a> engines: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#218 id=218 data-nosnippet>218</a> region_roles: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#219 id=219 data-nosnippet>219</a> min_timestamps: TimestampMillisecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#220 id=220 data-nosnippet>220</a> max_timestamps: TimestampMillisecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#221 id=221 data-nosnippet>221</a> }
<a href=#222 id=222 data-nosnippet>222</a> }
<a href=#223 id=223 data-nosnippet>223</a>
<a href=#224 id=224 data-nosnippet>224</a> <span class="doccomment">/// Construct a new `InformationSchemaRegionStatistics` from the collected data.
<a href=#225 id=225 data-nosnippet>225</a> </span><span class="kw">async fn </span>make_region_statistics(
<a href=#226 id=226 data-nosnippet>226</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#227 id=227 data-nosnippet>227</a> request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;,
<a href=#228 id=228 data-nosnippet>228</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#230 id=230 data-nosnippet>230</a> <span class="kw">let </span>information_extension = utils::information_extension(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#231 id=231 data-nosnippet>231</a> <span class="kw">let </span>region_stats = information_extension.region_stats().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">for </span>region_stat <span class="kw">in </span>region_stats {
<a href=#233 id=233 data-nosnippet>233</a> <span class="self">self</span>.add_region_statistic(<span class="kw-2">&amp;</span>predicates, region_stat);
<a href=#234 id=234 data-nosnippet>234</a> }
<a href=#235 id=235 data-nosnippet>235</a> <span class="self">self</span>.finish()
<a href=#236 id=236 data-nosnippet>236</a> }
<a href=#237 id=237 data-nosnippet>237</a>
<a href=#238 id=238 data-nosnippet>238</a> <span class="kw">fn </span>add_region_statistic(<span class="kw-2">&amp;mut </span><span class="self">self</span>, predicate: <span class="kw-2">&amp;</span>Predicates, region_stat: RegionStat) {
<a href=#239 id=239 data-nosnippet>239</a> <span class="kw">let </span>row = [
<a href=#240 id=240 data-nosnippet>240</a> (REGION_ID, <span class="kw-2">&amp;</span>Value::from(region_stat.id.as_u64())),
<a href=#241 id=241 data-nosnippet>241</a> (TABLE_ID, <span class="kw-2">&amp;</span>Value::from(region_stat.id.table_id())),
<a href=#242 id=242 data-nosnippet>242</a> (REGION_NUMBER, <span class="kw-2">&amp;</span>Value::from(region_stat.id.region_number())),
<a href=#243 id=243 data-nosnippet>243</a> (REGION_ROWS, <span class="kw-2">&amp;</span>Value::from(region_stat.num_rows)),
<a href=#244 id=244 data-nosnippet>244</a> (WRITTEN_BYTES, <span class="kw-2">&amp;</span>Value::from(region_stat.written_bytes)),
<a href=#245 id=245 data-nosnippet>245</a> (
<a href=#246 id=246 data-nosnippet>246</a> QUERY_CPU_TIME_MILLIS,
<a href=#247 id=247 data-nosnippet>247</a> <span class="kw-2">&amp;</span>Value::from(region_stat.query_cpu_time / <span class="number">1_000_000</span>),
<a href=#248 id=248 data-nosnippet>248</a> ),
<a href=#249 id=249 data-nosnippet>249</a> (
<a href=#250 id=250 data-nosnippet>250</a> QUERY_SCANNED_BYTES,
<a href=#251 id=251 data-nosnippet>251</a> <span class="kw-2">&amp;</span>Value::from(region_stat.query_scanned_bytes),
<a href=#252 id=252 data-nosnippet>252</a> ),
<a href=#253 id=253 data-nosnippet>253</a> (DISK_SIZE, <span class="kw-2">&amp;</span>Value::from(region_stat.approximate_bytes)),
<a href=#254 id=254 data-nosnippet>254</a> (MEMTABLE_SIZE, <span class="kw-2">&amp;</span>Value::from(region_stat.memtable_size)),
<a href=#255 id=255 data-nosnippet>255</a> (MANIFEST_SIZE, <span class="kw-2">&amp;</span>Value::from(region_stat.manifest_size)),
<a href=#256 id=256 data-nosnippet>256</a> (SST_SIZE, <span class="kw-2">&amp;</span>Value::from(region_stat.sst_size)),
<a href=#257 id=257 data-nosnippet>257</a> (SST_NUM, <span class="kw-2">&amp;</span>Value::from(region_stat.sst_num)),
<a href=#258 id=258 data-nosnippet>258</a> (INDEX_SIZE, <span class="kw-2">&amp;</span>Value::from(region_stat.index_size)),
<a href=#259 id=259 data-nosnippet>259</a> (ENGINE, <span class="kw-2">&amp;</span>Value::from(region_stat.engine.as_str())),
<a href=#260 id=260 data-nosnippet>260</a> (REGION_ROLE, <span class="kw-2">&amp;</span>Value::from(region_stat.role.to_string())),
<a href=#261 id=261 data-nosnippet>261</a> ];
<a href=#262 id=262 data-nosnippet>262</a>
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">if </span>!predicate.eval(<span class="kw-2">&amp;</span>row) {
<a href=#264 id=264 data-nosnippet>264</a> <span class="kw">return</span>;
<a href=#265 id=265 data-nosnippet>265</a> }
<a href=#266 id=266 data-nosnippet>266</a>
<a href=#267 id=267 data-nosnippet>267</a> <span class="self">self</span>.region_ids.push(<span class="prelude-val">Some</span>(region_stat.id.as_u64()));
<a href=#268 id=268 data-nosnippet>268</a> <span class="self">self</span>.table_ids.push(<span class="prelude-val">Some</span>(region_stat.id.table_id()));
<a href=#269 id=269 data-nosnippet>269</a> <span class="self">self</span>.region_numbers
<a href=#270 id=270 data-nosnippet>270</a> .push(<span class="prelude-val">Some</span>(region_stat.id.region_number()));
<a href=#271 id=271 data-nosnippet>271</a> <span class="self">self</span>.region_rows.push(<span class="prelude-val">Some</span>(region_stat.num_rows));
<a href=#272 id=272 data-nosnippet>272</a> <span class="self">self</span>.written_bytes.push(<span class="prelude-val">Some</span>(region_stat.written_bytes));
<a href=#273 id=273 data-nosnippet>273</a> <span class="self">self</span>.query_cpu_time_millis
<a href=#274 id=274 data-nosnippet>274</a> .push(<span class="prelude-val">Some</span>(region_stat.query_cpu_time / <span class="number">1_000_000</span>));
<a href=#275 id=275 data-nosnippet>275</a> <span class="self">self</span>.query_scanned_bytes
<a href=#276 id=276 data-nosnippet>276</a> .push(<span class="prelude-val">Some</span>(region_stat.query_scanned_bytes));
<a href=#277 id=277 data-nosnippet>277</a> <span class="self">self</span>.disk_sizes.push(<span class="prelude-val">Some</span>(region_stat.approximate_bytes));
<a href=#278 id=278 data-nosnippet>278</a> <span class="self">self</span>.memtable_sizes.push(<span class="prelude-val">Some</span>(region_stat.memtable_size));
<a href=#279 id=279 data-nosnippet>279</a> <span class="self">self</span>.manifest_sizes.push(<span class="prelude-val">Some</span>(region_stat.manifest_size));
<a href=#280 id=280 data-nosnippet>280</a> <span class="self">self</span>.sst_sizes.push(<span class="prelude-val">Some</span>(region_stat.sst_size));
<a href=#281 id=281 data-nosnippet>281</a> <span class="self">self</span>.sst_nums.push(<span class="prelude-val">Some</span>(region_stat.sst_num));
<a href=#282 id=282 data-nosnippet>282</a> <span class="self">self</span>.index_sizes.push(<span class="prelude-val">Some</span>(region_stat.index_size));
<a href=#283 id=283 data-nosnippet>283</a> <span class="self">self</span>.engines.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>region_stat.engine));
<a href=#284 id=284 data-nosnippet>284</a> <span class="self">self</span>.region_roles.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>region_stat.role.to_string()));
<a href=#285 id=285 data-nosnippet>285</a> <span class="comment">// Floor the min and ceil the max so the window stays a superset: a narrower
<a href=#286 id=286 data-nosnippet>286</a> // one would hide regions from a time-bounded lookup.
<a href=#287 id=287 data-nosnippet>287</a> </span><span class="self">self</span>.min_timestamps.push(
<a href=#288 id=288 data-nosnippet>288</a> region_stat
<a href=#289 id=289 data-nosnippet>289</a> .min_timestamp
<a href=#290 id=290 data-nosnippet>290</a> .and_then(|ts| ts.convert_to(TimeUnit::Millisecond))
<a href=#291 id=291 data-nosnippet>291</a> .map(TimestampMillisecond),
<a href=#292 id=292 data-nosnippet>292</a> );
<a href=#293 id=293 data-nosnippet>293</a> <span class="self">self</span>.max_timestamps.push(
<a href=#294 id=294 data-nosnippet>294</a> region_stat
<a href=#295 id=295 data-nosnippet>295</a> .max_timestamp
<a href=#296 id=296 data-nosnippet>296</a> .and_then(|ts| ts.convert_to_ceil(TimeUnit::Millisecond))
<a href=#297 id=297 data-nosnippet>297</a> .map(TimestampMillisecond),
<a href=#298 id=298 data-nosnippet>298</a> );
<a href=#299 id=299 data-nosnippet>299</a> }
<a href=#300 id=300 data-nosnippet>300</a>
<a href=#301 id=301 data-nosnippet>301</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#302 id=302 data-nosnippet>302</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#303 id=303 data-nosnippet>303</a> Arc::new(<span class="self">self</span>.region_ids.finish()),
<a href=#304 id=304 data-nosnippet>304</a> Arc::new(<span class="self">self</span>.table_ids.finish()),
<a href=#305 id=305 data-nosnippet>305</a> Arc::new(<span class="self">self</span>.region_numbers.finish()),
<a href=#306 id=306 data-nosnippet>306</a> Arc::new(<span class="self">self</span>.region_rows.finish()),
<a href=#307 id=307 data-nosnippet>307</a> Arc::new(<span class="self">self</span>.written_bytes.finish()),
<a href=#308 id=308 data-nosnippet>308</a> Arc::new(<span class="self">self</span>.query_cpu_time_millis.finish()),
<a href=#309 id=309 data-nosnippet>309</a> Arc::new(<span class="self">self</span>.query_scanned_bytes.finish()),
<a href=#310 id=310 data-nosnippet>310</a> Arc::new(<span class="self">self</span>.disk_sizes.finish()),
<a href=#311 id=311 data-nosnippet>311</a> Arc::new(<span class="self">self</span>.memtable_sizes.finish()),
<a href=#312 id=312 data-nosnippet>312</a> Arc::new(<span class="self">self</span>.manifest_sizes.finish()),
<a href=#313 id=313 data-nosnippet>313</a> Arc::new(<span class="self">self</span>.sst_sizes.finish()),
<a href=#314 id=314 data-nosnippet>314</a> Arc::new(<span class="self">self</span>.sst_nums.finish()),
<a href=#315 id=315 data-nosnippet>315</a> Arc::new(<span class="self">self</span>.index_sizes.finish()),
<a href=#316 id=316 data-nosnippet>316</a> Arc::new(<span class="self">self</span>.engines.finish()),
<a href=#317 id=317 data-nosnippet>317</a> Arc::new(<span class="self">self</span>.region_roles.finish()),
<a href=#318 id=318 data-nosnippet>318</a> Arc::new(<span class="self">self</span>.min_timestamps.finish()),
<a href=#319 id=319 data-nosnippet>319</a> Arc::new(<span class="self">self</span>.max_timestamps.finish()),
<a href=#320 id=320 data-nosnippet>320</a> ];
<a href=#321 id=321 data-nosnippet>321</a>
<a href=#322 id=322 data-nosnippet>322</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#323 id=323 data-nosnippet>323</a> }
<a href=#324 id=324 data-nosnippet>324</a>}
<a href=#325 id=325 data-nosnippet>325</a>
<a href=#326 id=326 data-nosnippet>326</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaRegionStatistics {
<a href=#327 id=327 data-nosnippet>327</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#328 id=328 data-nosnippet>328</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#329 id=329 data-nosnippet>329</a> }
<a href=#330 id=330 data-nosnippet>330</a>
<a href=#331 id=331 data-nosnippet>331</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#332 id=332 data-nosnippet>332</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#333 id=333 data-nosnippet>333</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#334 id=334 data-nosnippet>334</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#335 id=335 data-nosnippet>335</a> schema,
<a href=#336 id=336 data-nosnippet>336</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#337 id=337 data-nosnippet>337</a> builder
<a href=#338 id=338 data-nosnippet>338</a> .make_region_statistics(<span class="prelude-val">None</span>)
<a href=#339 id=339 data-nosnippet>339</a> .<span class="kw">await
<a href=#340 id=340 data-nosnippet>340</a> </span>.map(|x| x.into_df_record_batch())
<a href=#341 id=341 data-nosnippet>341</a> .map_err(Into::into)
<a href=#342 id=342 data-nosnippet>342</a> }),
<a href=#343 id=343 data-nosnippet>343</a> ))
<a href=#344 id=344 data-nosnippet>344</a> }
<a href=#345 id=345 data-nosnippet>345</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,259 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/schemata.rs`."><title>schemata.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>schemata.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_SCHEMATA_TABLE_ID;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::key::schema_name::SchemaNameKey;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, ScalarVectorBuilder, VectorRef};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::value::Value;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datatypes::vectors::StringVectorBuilder;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>snafu::{OptionExt, ResultExt};
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#33 id=33 data-nosnippet>33</a>
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#36 id=36 data-nosnippet>36</a> CreateRecordBatchSnafu, InternalSnafu, <span class="prelude-ty">Result</span>, TableMetadataManagerSnafu,
<a href=#37 id=37 data-nosnippet>37</a> UpgradeWeakCatalogManagerRefSnafu,
<a href=#38 id=38 data-nosnippet>38</a>};
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{InformationTable, Predicates, SCHEMATA};
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::utils;
<a href=#41 id=41 data-nosnippet>41</a>
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">pub const </span>CATALOG_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"catalog_name"</span>;
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">pub const </span>SCHEMA_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"schema_name"</span>;
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">const </span>DEFAULT_CHARACTER_SET_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"default_character_set_name"</span>;
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">const </span>DEFAULT_COLLATION_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"default_collation_name"</span>;
<a href=#46 id=46 data-nosnippet>46</a><span class="doccomment">/// The database options
<a href=#47 id=47 data-nosnippet>47</a></span><span class="kw">pub const </span>SCHEMA_OPTS: <span class="kw-2">&amp;</span>str = <span class="string">"options"</span>;
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#49 id=49 data-nosnippet>49</a>
<a href=#50 id=50 data-nosnippet>50</a><span class="doccomment">/// The `information_schema.schemata` table implementation.
<a href=#51 id=51 data-nosnippet>51</a></span><span class="attr">#[derive(Debug)]
<a href=#52 id=52 data-nosnippet>52</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaSchemata {
<a href=#53 id=53 data-nosnippet>53</a> schema: SchemaRef,
<a href=#54 id=54 data-nosnippet>54</a> catalog_name: String,
<a href=#55 id=55 data-nosnippet>55</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#56 id=56 data-nosnippet>56</a>}
<a href=#57 id=57 data-nosnippet>57</a>
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">impl </span>InformationSchemaSchemata {
<a href=#59 id=59 data-nosnippet>59</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_name: String, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#60 id=60 data-nosnippet>60</a> <span class="self">Self </span>{
<a href=#61 id=61 data-nosnippet>61</a> schema: <span class="self">Self</span>::schema(),
<a href=#62 id=62 data-nosnippet>62</a> catalog_name,
<a href=#63 id=63 data-nosnippet>63</a> catalog_manager,
<a href=#64 id=64 data-nosnippet>64</a> }
<a href=#65 id=65 data-nosnippet>65</a> }
<a href=#66 id=66 data-nosnippet>66</a>
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#68 id=68 data-nosnippet>68</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#69 id=69 data-nosnippet>69</a> ColumnSchema::new(CATALOG_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#70 id=70 data-nosnippet>70</a> ColumnSchema::new(SCHEMA_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#71 id=71 data-nosnippet>71</a> ColumnSchema::new(
<a href=#72 id=72 data-nosnippet>72</a> DEFAULT_CHARACTER_SET_NAME,
<a href=#73 id=73 data-nosnippet>73</a> ConcreteDataType::string_datatype(),
<a href=#74 id=74 data-nosnippet>74</a> <span class="bool-val">false</span>,
<a href=#75 id=75 data-nosnippet>75</a> ),
<a href=#76 id=76 data-nosnippet>76</a> ColumnSchema::new(
<a href=#77 id=77 data-nosnippet>77</a> DEFAULT_COLLATION_NAME,
<a href=#78 id=78 data-nosnippet>78</a> ConcreteDataType::string_datatype(),
<a href=#79 id=79 data-nosnippet>79</a> <span class="bool-val">false</span>,
<a href=#80 id=80 data-nosnippet>80</a> ),
<a href=#81 id=81 data-nosnippet>81</a> ColumnSchema::new(<span class="string">"sql_path"</span>, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#82 id=82 data-nosnippet>82</a> ColumnSchema::new(SCHEMA_OPTS, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#83 id=83 data-nosnippet>83</a> ]))
<a href=#84 id=84 data-nosnippet>84</a> }
<a href=#85 id=85 data-nosnippet>85</a>
<a href=#86 id=86 data-nosnippet>86</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaSchemataBuilder {
<a href=#87 id=87 data-nosnippet>87</a> InformationSchemaSchemataBuilder::new(
<a href=#88 id=88 data-nosnippet>88</a> <span class="self">self</span>.schema.clone(),
<a href=#89 id=89 data-nosnippet>89</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#90 id=90 data-nosnippet>90</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#91 id=91 data-nosnippet>91</a> )
<a href=#92 id=92 data-nosnippet>92</a> }
<a href=#93 id=93 data-nosnippet>93</a>}
<a href=#94 id=94 data-nosnippet>94</a>
<a href=#95 id=95 data-nosnippet>95</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaSchemata {
<a href=#96 id=96 data-nosnippet>96</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#97 id=97 data-nosnippet>97</a> INFORMATION_SCHEMA_SCHEMATA_TABLE_ID
<a href=#98 id=98 data-nosnippet>98</a> }
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#101 id=101 data-nosnippet>101</a> SCHEMATA
<a href=#102 id=102 data-nosnippet>102</a> }
<a href=#103 id=103 data-nosnippet>103</a>
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#105 id=105 data-nosnippet>105</a> <span class="self">self</span>.schema.clone()
<a href=#106 id=106 data-nosnippet>106</a> }
<a href=#107 id=107 data-nosnippet>107</a>
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#109 id=109 data-nosnippet>109</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#112 id=112 data-nosnippet>112</a> schema,
<a href=#113 id=113 data-nosnippet>113</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#114 id=114 data-nosnippet>114</a> builder
<a href=#115 id=115 data-nosnippet>115</a> .make_schemata(<span class="prelude-val">Some</span>(request))
<a href=#116 id=116 data-nosnippet>116</a> .<span class="kw">await
<a href=#117 id=117 data-nosnippet>117</a> </span>.map(|x| x.into_df_record_batch())
<a href=#118 id=118 data-nosnippet>118</a> .map_err(Into::into)
<a href=#119 id=119 data-nosnippet>119</a> }),
<a href=#120 id=120 data-nosnippet>120</a> ));
<a href=#121 id=121 data-nosnippet>121</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#122 id=122 data-nosnippet>122</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#123 id=123 data-nosnippet>123</a> .map_err(BoxedError::new)
<a href=#124 id=124 data-nosnippet>124</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#125 id=125 data-nosnippet>125</a> ))
<a href=#126 id=126 data-nosnippet>126</a> }
<a href=#127 id=127 data-nosnippet>127</a>}
<a href=#128 id=128 data-nosnippet>128</a>
<a href=#129 id=129 data-nosnippet>129</a><span class="doccomment">/// Builds the `information_schema.schemata` table row by row
<a href=#130 id=130 data-nosnippet>130</a>///
<a href=#131 id=131 data-nosnippet>131</a>/// Columns are based on &lt;https://docs.pingcap.com/tidb/stable/information-schema-schemata&gt;
<a href=#132 id=132 data-nosnippet>132</a></span><span class="kw">struct </span>InformationSchemaSchemataBuilder {
<a href=#133 id=133 data-nosnippet>133</a> schema: SchemaRef,
<a href=#134 id=134 data-nosnippet>134</a> catalog_name: String,
<a href=#135 id=135 data-nosnippet>135</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#136 id=136 data-nosnippet>136</a>
<a href=#137 id=137 data-nosnippet>137</a> catalog_names: StringVectorBuilder,
<a href=#138 id=138 data-nosnippet>138</a> schema_names: StringVectorBuilder,
<a href=#139 id=139 data-nosnippet>139</a> charset_names: StringVectorBuilder,
<a href=#140 id=140 data-nosnippet>140</a> collation_names: StringVectorBuilder,
<a href=#141 id=141 data-nosnippet>141</a> sql_paths: StringVectorBuilder,
<a href=#142 id=142 data-nosnippet>142</a> schema_options: StringVectorBuilder,
<a href=#143 id=143 data-nosnippet>143</a>}
<a href=#144 id=144 data-nosnippet>144</a>
<a href=#145 id=145 data-nosnippet>145</a><span class="kw">impl </span>InformationSchemaSchemataBuilder {
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">fn </span>new(
<a href=#147 id=147 data-nosnippet>147</a> schema: SchemaRef,
<a href=#148 id=148 data-nosnippet>148</a> catalog_name: String,
<a href=#149 id=149 data-nosnippet>149</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#150 id=150 data-nosnippet>150</a> ) -&gt; <span class="self">Self </span>{
<a href=#151 id=151 data-nosnippet>151</a> <span class="self">Self </span>{
<a href=#152 id=152 data-nosnippet>152</a> schema,
<a href=#153 id=153 data-nosnippet>153</a> catalog_name,
<a href=#154 id=154 data-nosnippet>154</a> catalog_manager,
<a href=#155 id=155 data-nosnippet>155</a> catalog_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#156 id=156 data-nosnippet>156</a> schema_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#157 id=157 data-nosnippet>157</a> charset_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#158 id=158 data-nosnippet>158</a> collation_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#159 id=159 data-nosnippet>159</a> sql_paths: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#160 id=160 data-nosnippet>160</a> schema_options: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#161 id=161 data-nosnippet>161</a> }
<a href=#162 id=162 data-nosnippet>162</a> }
<a href=#163 id=163 data-nosnippet>163</a>
<a href=#164 id=164 data-nosnippet>164</a> <span class="doccomment">/// Construct the `information_schema.schemata` virtual table
<a href=#165 id=165 data-nosnippet>165</a> </span><span class="kw">async fn </span>make_schemata(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#166 id=166 data-nosnippet>166</a> <span class="kw">let </span>catalog_name = <span class="self">self</span>.catalog_name.clone();
<a href=#167 id=167 data-nosnippet>167</a> <span class="kw">let </span>catalog_manager = <span class="self">self
<a href=#168 id=168 data-nosnippet>168</a> </span>.catalog_manager
<a href=#169 id=169 data-nosnippet>169</a> .upgrade()
<a href=#170 id=170 data-nosnippet>170</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">let </span>table_metadata_manager = utils::table_meta_manager(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#172 id=172 data-nosnippet>172</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#173 id=173 data-nosnippet>173</a>
<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">for </span>schema_name <span class="kw">in </span>catalog_manager.schema_names(<span class="kw-2">&amp;</span>catalog_name, <span class="prelude-val">None</span>).<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#175 id=175 data-nosnippet>175</a> <span class="kw">let </span>opts = <span class="kw">if let </span><span class="prelude-val">Some</span>(table_metadata_manager) = <span class="kw-2">&amp;</span>table_metadata_manager {
<a href=#176 id=176 data-nosnippet>176</a> table_metadata_manager
<a href=#177 id=177 data-nosnippet>177</a> .schema_manager()
<a href=#178 id=178 data-nosnippet>178</a> .get(SchemaNameKey::new(<span class="kw-2">&amp;</span>catalog_name, <span class="kw-2">&amp;</span>schema_name))
<a href=#179 id=179 data-nosnippet>179</a> .<span class="kw">await
<a href=#180 id=180 data-nosnippet>180</a> </span>.context(TableMetadataManagerSnafu)<span class="question-mark">?
<a href=#181 id=181 data-nosnippet>181</a> </span><span class="comment">// information_schema is not available from this
<a href=#182 id=182 data-nosnippet>182</a> // table_metadata_manager and we return None
<a href=#183 id=183 data-nosnippet>183</a> </span>.map(|schema_opts| <span class="macro">format!</span>(<span class="string">"{}"</span>, schema_opts.into_inner()))
<a href=#184 id=184 data-nosnippet>184</a> } <span class="kw">else </span>{
<a href=#185 id=185 data-nosnippet>185</a> <span class="prelude-val">None
<a href=#186 id=186 data-nosnippet>186</a> </span>};
<a href=#187 id=187 data-nosnippet>187</a>
<a href=#188 id=188 data-nosnippet>188</a> <span class="self">self</span>.add_schema(
<a href=#189 id=189 data-nosnippet>189</a> <span class="kw-2">&amp;</span>predicates,
<a href=#190 id=190 data-nosnippet>190</a> <span class="kw-2">&amp;</span>catalog_name,
<a href=#191 id=191 data-nosnippet>191</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#192 id=192 data-nosnippet>192</a> opts.as_deref().unwrap_or(<span class="string">""</span>),
<a href=#193 id=193 data-nosnippet>193</a> );
<a href=#194 id=194 data-nosnippet>194</a> }
<a href=#195 id=195 data-nosnippet>195</a>
<a href=#196 id=196 data-nosnippet>196</a> <span class="self">self</span>.finish()
<a href=#197 id=197 data-nosnippet>197</a> }
<a href=#198 id=198 data-nosnippet>198</a>
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">fn </span>add_schema(
<a href=#200 id=200 data-nosnippet>200</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#201 id=201 data-nosnippet>201</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#202 id=202 data-nosnippet>202</a> catalog_name: <span class="kw-2">&amp;</span>str,
<a href=#203 id=203 data-nosnippet>203</a> schema_name: <span class="kw-2">&amp;</span>str,
<a href=#204 id=204 data-nosnippet>204</a> schema_options: <span class="kw-2">&amp;</span>str,
<a href=#205 id=205 data-nosnippet>205</a> ) {
<a href=#206 id=206 data-nosnippet>206</a> <span class="kw">let </span>row = [
<a href=#207 id=207 data-nosnippet>207</a> (CATALOG_NAME, <span class="kw-2">&amp;</span>Value::from(catalog_name)),
<a href=#208 id=208 data-nosnippet>208</a> (SCHEMA_NAME, <span class="kw-2">&amp;</span>Value::from(schema_name)),
<a href=#209 id=209 data-nosnippet>209</a> (DEFAULT_CHARACTER_SET_NAME, <span class="kw-2">&amp;</span>Value::from(<span class="string">"utf8"</span>)),
<a href=#210 id=210 data-nosnippet>210</a> (DEFAULT_COLLATION_NAME, <span class="kw-2">&amp;</span>Value::from(<span class="string">"utf8_bin"</span>)),
<a href=#211 id=211 data-nosnippet>211</a> (SCHEMA_OPTS, <span class="kw-2">&amp;</span>Value::from(schema_options)),
<a href=#212 id=212 data-nosnippet>212</a> ];
<a href=#213 id=213 data-nosnippet>213</a>
<a href=#214 id=214 data-nosnippet>214</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#215 id=215 data-nosnippet>215</a> <span class="kw">return</span>;
<a href=#216 id=216 data-nosnippet>216</a> }
<a href=#217 id=217 data-nosnippet>217</a>
<a href=#218 id=218 data-nosnippet>218</a> <span class="self">self</span>.catalog_names.push(<span class="prelude-val">Some</span>(catalog_name));
<a href=#219 id=219 data-nosnippet>219</a> <span class="self">self</span>.schema_names.push(<span class="prelude-val">Some</span>(schema_name));
<a href=#220 id=220 data-nosnippet>220</a> <span class="self">self</span>.charset_names.push(<span class="prelude-val">Some</span>(<span class="string">"utf8"</span>));
<a href=#221 id=221 data-nosnippet>221</a> <span class="self">self</span>.collation_names.push(<span class="prelude-val">Some</span>(<span class="string">"utf8_bin"</span>));
<a href=#222 id=222 data-nosnippet>222</a> <span class="self">self</span>.sql_paths.push(<span class="prelude-val">None</span>);
<a href=#223 id=223 data-nosnippet>223</a> <span class="self">self</span>.schema_options.push(<span class="prelude-val">Some</span>(schema_options));
<a href=#224 id=224 data-nosnippet>224</a> }
<a href=#225 id=225 data-nosnippet>225</a>
<a href=#226 id=226 data-nosnippet>226</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#227 id=227 data-nosnippet>227</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#228 id=228 data-nosnippet>228</a> Arc::new(<span class="self">self</span>.catalog_names.finish()),
<a href=#229 id=229 data-nosnippet>229</a> Arc::new(<span class="self">self</span>.schema_names.finish()),
<a href=#230 id=230 data-nosnippet>230</a> Arc::new(<span class="self">self</span>.charset_names.finish()),
<a href=#231 id=231 data-nosnippet>231</a> Arc::new(<span class="self">self</span>.collation_names.finish()),
<a href=#232 id=232 data-nosnippet>232</a> Arc::new(<span class="self">self</span>.sql_paths.finish()),
<a href=#233 id=233 data-nosnippet>233</a> Arc::new(<span class="self">self</span>.schema_options.finish()),
<a href=#234 id=234 data-nosnippet>234</a> ];
<a href=#235 id=235 data-nosnippet>235</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#236 id=236 data-nosnippet>236</a> }
<a href=#237 id=237 data-nosnippet>237</a>}
<a href=#238 id=238 data-nosnippet>238</a>
<a href=#239 id=239 data-nosnippet>239</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaSchemata {
<a href=#240 id=240 data-nosnippet>240</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#241 id=241 data-nosnippet>241</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#242 id=242 data-nosnippet>242</a> }
<a href=#243 id=243 data-nosnippet>243</a>
<a href=#244 id=244 data-nosnippet>244</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#247 id=247 data-nosnippet>247</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#248 id=248 data-nosnippet>248</a> schema,
<a href=#249 id=249 data-nosnippet>249</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#250 id=250 data-nosnippet>250</a> builder
<a href=#251 id=251 data-nosnippet>251</a> .make_schemata(<span class="prelude-val">None</span>)
<a href=#252 id=252 data-nosnippet>252</a> .<span class="kw">await
<a href=#253 id=253 data-nosnippet>253</a> </span>.map(|x| x.into_df_record_batch())
<a href=#254 id=254 data-nosnippet>254</a> .map_err(Into::into)
<a href=#255 id=255 data-nosnippet>255</a> }),
<a href=#256 id=256 data-nosnippet>256</a> ))
<a href=#257 id=257 data-nosnippet>257</a> }
<a href=#258 id=258 data-nosnippet>258</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,343 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/ssts.rs`."><title>ssts.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>ssts.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_catalog::consts::{
<a href=#18 id=18 data-nosnippet>18</a> INFORMATION_SCHEMA_SSTS_INDEX_META_TABLE_ID, INFORMATION_SCHEMA_SSTS_MANIFEST_TABLE_ID,
<a href=#19 id=19 data-nosnippet>19</a> INFORMATION_SCHEMA_SSTS_STORAGE_TABLE_ID,
<a href=#20 id=20 data-nosnippet>20</a>};
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_recordbatch::SendableRecordBatchStream;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_recordbatch::adapter::AsyncRecordBatchStreamAdapter;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>datafusion::physical_plan::ExecutionPlan;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datatypes::schema::SchemaRef;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>snafu::ResultExt;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>store_api::sst_entry::{ManifestSstEntry, PuffinIndexMetaEntry, StorageSstEntry};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#29 id=29 data-nosnippet>29</a>
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span><span class="kw">crate</span>::error::{ProjectSchemaSnafu, <span class="prelude-ty">Result</span>};
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::{
<a href=#33 id=33 data-nosnippet>33</a> DatanodeInspectKind, DatanodeInspectRequest, InformationTable, SSTS_INDEX_META, SSTS_MANIFEST,
<a href=#34 id=34 data-nosnippet>34</a> SSTS_STORAGE,
<a href=#35 id=35 data-nosnippet>35</a>};
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::utils;
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">fn </span>projected_schema(schema: <span class="kw-2">&amp;</span>SchemaRef, request: <span class="kw-2">&amp;</span>ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SchemaRef&gt; {
<a href=#39 id=39 data-nosnippet>39</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(p) = request.projection.as_deref() {
<a href=#40 id=40 data-nosnippet>40</a> <span class="prelude-val">Ok</span>(Arc::new(schema.try_project(p).context(ProjectSchemaSnafu)<span class="question-mark">?</span>))
<a href=#41 id=41 data-nosnippet>41</a> } <span class="kw">else </span>{
<a href=#42 id=42 data-nosnippet>42</a> <span class="prelude-val">Ok</span>(schema.clone())
<a href=#43 id=43 data-nosnippet>43</a> }
<a href=#44 id=44 data-nosnippet>44</a>}
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">fn </span>inspect_plan(
<a href=#47 id=47 data-nosnippet>47</a> catalog_manager: <span class="kw-2">&amp;</span>Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#48 id=48 data-nosnippet>48</a> kind: DatanodeInspectKind,
<a href=#49 id=49 data-nosnippet>49</a> schema: <span class="kw-2">&amp;</span>SchemaRef,
<a href=#50 id=50 data-nosnippet>50</a> request: ScanRequest,
<a href=#51 id=51 data-nosnippet>51</a>) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;&gt; {
<a href=#52 id=52 data-nosnippet>52</a> <span class="kw">let </span>projected_schema = projected_schema(schema, <span class="kw-2">&amp;</span>request)<span class="question-mark">?</span>;
<a href=#53 id=53 data-nosnippet>53</a> <span class="kw">let </span>info_ext = utils::information_extension(catalog_manager)<span class="question-mark">?</span>;
<a href=#54 id=54 data-nosnippet>54</a> <span class="kw">let </span>req = DatanodeInspectRequest {
<a href=#55 id=55 data-nosnippet>55</a> kind,
<a href=#56 id=56 data-nosnippet>56</a> scan: request,
<a href=#57 id=57 data-nosnippet>57</a> };
<a href=#58 id=58 data-nosnippet>58</a>
<a href=#59 id=59 data-nosnippet>59</a> info_ext.inspect_datanode_plan(req, projected_schema)
<a href=#60 id=60 data-nosnippet>60</a>}
<a href=#61 id=61 data-nosnippet>61</a>
<a href=#62 id=62 data-nosnippet>62</a><span class="doccomment">/// Information schema table for sst manifest.
<a href=#63 id=63 data-nosnippet>63</a></span><span class="kw">pub struct </span>InformationSchemaSstsManifest {
<a href=#64 id=64 data-nosnippet>64</a> schema: SchemaRef,
<a href=#65 id=65 data-nosnippet>65</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#66 id=66 data-nosnippet>66</a>}
<a href=#67 id=67 data-nosnippet>67</a>
<a href=#68 id=68 data-nosnippet>68</a><span class="kw">impl </span>InformationSchemaSstsManifest {
<a href=#69 id=69 data-nosnippet>69</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#70 id=70 data-nosnippet>70</a> <span class="self">Self </span>{
<a href=#71 id=71 data-nosnippet>71</a> schema: ManifestSstEntry::schema(),
<a href=#72 id=72 data-nosnippet>72</a> catalog_manager,
<a href=#73 id=73 data-nosnippet>73</a> }
<a href=#74 id=74 data-nosnippet>74</a> }
<a href=#75 id=75 data-nosnippet>75</a>}
<a href=#76 id=76 data-nosnippet>76</a>
<a href=#77 id=77 data-nosnippet>77</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaSstsManifest {
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#79 id=79 data-nosnippet>79</a> INFORMATION_SCHEMA_SSTS_MANIFEST_TABLE_ID
<a href=#80 id=80 data-nosnippet>80</a> }
<a href=#81 id=81 data-nosnippet>81</a>
<a href=#82 id=82 data-nosnippet>82</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#83 id=83 data-nosnippet>83</a> SSTS_MANIFEST
<a href=#84 id=84 data-nosnippet>84</a> }
<a href=#85 id=85 data-nosnippet>85</a>
<a href=#86 id=86 data-nosnippet>86</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#87 id=87 data-nosnippet>87</a> <span class="self">self</span>.schema.clone()
<a href=#88 id=88 data-nosnippet>88</a> }
<a href=#89 id=89 data-nosnippet>89</a>
<a href=#90 id=90 data-nosnippet>90</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">let </span>schema = projected_schema(<span class="kw-2">&amp;</span><span class="self">self</span>.schema, <span class="kw-2">&amp;</span>request)<span class="question-mark">?</span>;
<a href=#92 id=92 data-nosnippet>92</a> <span class="kw">let </span>info_ext = utils::information_extension(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#93 id=93 data-nosnippet>93</a> <span class="kw">let </span>req = DatanodeInspectRequest {
<a href=#94 id=94 data-nosnippet>94</a> kind: DatanodeInspectKind::SstManifest,
<a href=#95 id=95 data-nosnippet>95</a> scan: request,
<a href=#96 id=96 data-nosnippet>96</a> };
<a href=#97 id=97 data-nosnippet>97</a>
<a href=#98 id=98 data-nosnippet>98</a> <span class="kw">let </span>future = <span class="kw">async move </span>{
<a href=#99 id=99 data-nosnippet>99</a> info_ext
<a href=#100 id=100 data-nosnippet>100</a> .inspect_datanode(req)
<a href=#101 id=101 data-nosnippet>101</a> .<span class="kw">await
<a href=#102 id=102 data-nosnippet>102</a> </span>.map_err(BoxedError::new)
<a href=#103 id=103 data-nosnippet>103</a> .context(common_recordbatch::error::ExternalSnafu)
<a href=#104 id=104 data-nosnippet>104</a> };
<a href=#105 id=105 data-nosnippet>105</a> <span class="prelude-val">Ok</span>(Box::pin(AsyncRecordBatchStreamAdapter::new(
<a href=#106 id=106 data-nosnippet>106</a> schema,
<a href=#107 id=107 data-nosnippet>107</a> Box::pin(future),
<a href=#108 id=108 data-nosnippet>108</a> )))
<a href=#109 id=109 data-nosnippet>109</a> }
<a href=#110 id=110 data-nosnippet>110</a>
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">fn </span>scan_plan(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;&gt; {
<a href=#112 id=112 data-nosnippet>112</a> inspect_plan(
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager,
<a href=#114 id=114 data-nosnippet>114</a> DatanodeInspectKind::SstManifest,
<a href=#115 id=115 data-nosnippet>115</a> <span class="kw-2">&amp;</span><span class="self">self</span>.schema,
<a href=#116 id=116 data-nosnippet>116</a> request,
<a href=#117 id=117 data-nosnippet>117</a> )
<a href=#118 id=118 data-nosnippet>118</a> }
<a href=#119 id=119 data-nosnippet>119</a>}
<a href=#120 id=120 data-nosnippet>120</a>
<a href=#121 id=121 data-nosnippet>121</a><span class="doccomment">/// Information schema table for sst storage.
<a href=#122 id=122 data-nosnippet>122</a></span><span class="kw">pub struct </span>InformationSchemaSstsStorage {
<a href=#123 id=123 data-nosnippet>123</a> schema: SchemaRef,
<a href=#124 id=124 data-nosnippet>124</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#125 id=125 data-nosnippet>125</a>}
<a href=#126 id=126 data-nosnippet>126</a>
<a href=#127 id=127 data-nosnippet>127</a><span class="kw">impl </span>InformationSchemaSstsStorage {
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#129 id=129 data-nosnippet>129</a> <span class="self">Self </span>{
<a href=#130 id=130 data-nosnippet>130</a> schema: StorageSstEntry::schema(),
<a href=#131 id=131 data-nosnippet>131</a> catalog_manager,
<a href=#132 id=132 data-nosnippet>132</a> }
<a href=#133 id=133 data-nosnippet>133</a> }
<a href=#134 id=134 data-nosnippet>134</a>}
<a href=#135 id=135 data-nosnippet>135</a>
<a href=#136 id=136 data-nosnippet>136</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaSstsStorage {
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#138 id=138 data-nosnippet>138</a> INFORMATION_SCHEMA_SSTS_STORAGE_TABLE_ID
<a href=#139 id=139 data-nosnippet>139</a> }
<a href=#140 id=140 data-nosnippet>140</a>
<a href=#141 id=141 data-nosnippet>141</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#142 id=142 data-nosnippet>142</a> SSTS_STORAGE
<a href=#143 id=143 data-nosnippet>143</a> }
<a href=#144 id=144 data-nosnippet>144</a>
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#146 id=146 data-nosnippet>146</a> <span class="self">self</span>.schema.clone()
<a href=#147 id=147 data-nosnippet>147</a> }
<a href=#148 id=148 data-nosnippet>148</a>
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">let </span>schema = projected_schema(<span class="kw-2">&amp;</span><span class="self">self</span>.schema, <span class="kw-2">&amp;</span>request)<span class="question-mark">?</span>;
<a href=#151 id=151 data-nosnippet>151</a>
<a href=#152 id=152 data-nosnippet>152</a> <span class="kw">let </span>info_ext = utils::information_extension(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">let </span>req = DatanodeInspectRequest {
<a href=#154 id=154 data-nosnippet>154</a> kind: DatanodeInspectKind::SstStorage,
<a href=#155 id=155 data-nosnippet>155</a> scan: request,
<a href=#156 id=156 data-nosnippet>156</a> };
<a href=#157 id=157 data-nosnippet>157</a>
<a href=#158 id=158 data-nosnippet>158</a> <span class="kw">let </span>future = <span class="kw">async move </span>{
<a href=#159 id=159 data-nosnippet>159</a> info_ext
<a href=#160 id=160 data-nosnippet>160</a> .inspect_datanode(req)
<a href=#161 id=161 data-nosnippet>161</a> .<span class="kw">await
<a href=#162 id=162 data-nosnippet>162</a> </span>.map_err(BoxedError::new)
<a href=#163 id=163 data-nosnippet>163</a> .context(common_recordbatch::error::ExternalSnafu)
<a href=#164 id=164 data-nosnippet>164</a> };
<a href=#165 id=165 data-nosnippet>165</a> <span class="prelude-val">Ok</span>(Box::pin(AsyncRecordBatchStreamAdapter::new(
<a href=#166 id=166 data-nosnippet>166</a> schema,
<a href=#167 id=167 data-nosnippet>167</a> Box::pin(future),
<a href=#168 id=168 data-nosnippet>168</a> )))
<a href=#169 id=169 data-nosnippet>169</a> }
<a href=#170 id=170 data-nosnippet>170</a>
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">fn </span>scan_plan(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;&gt; {
<a href=#172 id=172 data-nosnippet>172</a> inspect_plan(
<a href=#173 id=173 data-nosnippet>173</a> <span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager,
<a href=#174 id=174 data-nosnippet>174</a> DatanodeInspectKind::SstStorage,
<a href=#175 id=175 data-nosnippet>175</a> <span class="kw-2">&amp;</span><span class="self">self</span>.schema,
<a href=#176 id=176 data-nosnippet>176</a> request,
<a href=#177 id=177 data-nosnippet>177</a> )
<a href=#178 id=178 data-nosnippet>178</a> }
<a href=#179 id=179 data-nosnippet>179</a>}
<a href=#180 id=180 data-nosnippet>180</a>
<a href=#181 id=181 data-nosnippet>181</a><span class="doccomment">/// Information schema table for index metadata.
<a href=#182 id=182 data-nosnippet>182</a></span><span class="kw">pub struct </span>InformationSchemaSstsIndexMeta {
<a href=#183 id=183 data-nosnippet>183</a> schema: SchemaRef,
<a href=#184 id=184 data-nosnippet>184</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#185 id=185 data-nosnippet>185</a>}
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a><span class="kw">impl </span>InformationSchemaSstsIndexMeta {
<a href=#188 id=188 data-nosnippet>188</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#189 id=189 data-nosnippet>189</a> <span class="self">Self </span>{
<a href=#190 id=190 data-nosnippet>190</a> schema: PuffinIndexMetaEntry::schema(),
<a href=#191 id=191 data-nosnippet>191</a> catalog_manager,
<a href=#192 id=192 data-nosnippet>192</a> }
<a href=#193 id=193 data-nosnippet>193</a> }
<a href=#194 id=194 data-nosnippet>194</a>}
<a href=#195 id=195 data-nosnippet>195</a>
<a href=#196 id=196 data-nosnippet>196</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaSstsIndexMeta {
<a href=#197 id=197 data-nosnippet>197</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#198 id=198 data-nosnippet>198</a> INFORMATION_SCHEMA_SSTS_INDEX_META_TABLE_ID
<a href=#199 id=199 data-nosnippet>199</a> }
<a href=#200 id=200 data-nosnippet>200</a>
<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#202 id=202 data-nosnippet>202</a> SSTS_INDEX_META
<a href=#203 id=203 data-nosnippet>203</a> }
<a href=#204 id=204 data-nosnippet>204</a>
<a href=#205 id=205 data-nosnippet>205</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#206 id=206 data-nosnippet>206</a> <span class="self">self</span>.schema.clone()
<a href=#207 id=207 data-nosnippet>207</a> }
<a href=#208 id=208 data-nosnippet>208</a>
<a href=#209 id=209 data-nosnippet>209</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">let </span>schema = projected_schema(<span class="kw-2">&amp;</span><span class="self">self</span>.schema, <span class="kw-2">&amp;</span>request)<span class="question-mark">?</span>;
<a href=#211 id=211 data-nosnippet>211</a>
<a href=#212 id=212 data-nosnippet>212</a> <span class="kw">let </span>info_ext = utils::information_extension(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">let </span>req = DatanodeInspectRequest {
<a href=#214 id=214 data-nosnippet>214</a> kind: DatanodeInspectKind::SstIndexMeta,
<a href=#215 id=215 data-nosnippet>215</a> scan: request,
<a href=#216 id=216 data-nosnippet>216</a> };
<a href=#217 id=217 data-nosnippet>217</a>
<a href=#218 id=218 data-nosnippet>218</a> <span class="kw">let </span>future = <span class="kw">async move </span>{
<a href=#219 id=219 data-nosnippet>219</a> info_ext
<a href=#220 id=220 data-nosnippet>220</a> .inspect_datanode(req)
<a href=#221 id=221 data-nosnippet>221</a> .<span class="kw">await
<a href=#222 id=222 data-nosnippet>222</a> </span>.map_err(BoxedError::new)
<a href=#223 id=223 data-nosnippet>223</a> .context(common_recordbatch::error::ExternalSnafu)
<a href=#224 id=224 data-nosnippet>224</a> };
<a href=#225 id=225 data-nosnippet>225</a> <span class="prelude-val">Ok</span>(Box::pin(AsyncRecordBatchStreamAdapter::new(
<a href=#226 id=226 data-nosnippet>226</a> schema,
<a href=#227 id=227 data-nosnippet>227</a> Box::pin(future),
<a href=#228 id=228 data-nosnippet>228</a> )))
<a href=#229 id=229 data-nosnippet>229</a> }
<a href=#230 id=230 data-nosnippet>230</a>
<a href=#231 id=231 data-nosnippet>231</a> <span class="kw">fn </span>scan_plan(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;&gt; {
<a href=#232 id=232 data-nosnippet>232</a> inspect_plan(
<a href=#233 id=233 data-nosnippet>233</a> <span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager,
<a href=#234 id=234 data-nosnippet>234</a> DatanodeInspectKind::SstIndexMeta,
<a href=#235 id=235 data-nosnippet>235</a> <span class="kw-2">&amp;</span><span class="self">self</span>.schema,
<a href=#236 id=236 data-nosnippet>236</a> request,
<a href=#237 id=237 data-nosnippet>237</a> )
<a href=#238 id=238 data-nosnippet>238</a> }
<a href=#239 id=239 data-nosnippet>239</a>}
<a href=#240 id=240 data-nosnippet>240</a>
<a href=#241 id=241 data-nosnippet>241</a><span class="attr">#[cfg(test)]
<a href=#242 id=242 data-nosnippet>242</a></span><span class="kw">mod </span>tests {
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">use </span>cache::{build_fundamental_cache_registry, with_default_composite_cache_registry};
<a href=#244 id=244 data-nosnippet>244</a> <span class="kw">use </span>common_catalog::consts::{DEFAULT_CATALOG_NAME, INFORMATION_SCHEMA_NAME};
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw">use </span>common_meta::cache::{CacheRegistryBuilder, LayeredCacheRegistryBuilder};
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">use </span>common_meta::cluster::NodeInfo;
<a href=#247 id=247 data-nosnippet>247</a> <span class="kw">use </span>common_meta::datanode::RegionStat;
<a href=#248 id=248 data-nosnippet>248</a> <span class="kw">use </span>common_meta::key::flow::flow_state::FlowStat;
<a href=#249 id=249 data-nosnippet>249</a> <span class="kw">use </span>common_meta::kv_backend::memory::MemoryKvBackend;
<a href=#250 id=250 data-nosnippet>250</a> <span class="kw">use </span>common_procedure::ProcedureInfo;
<a href=#251 id=251 data-nosnippet>251</a> <span class="kw">use </span>common_recordbatch::{RecordBatches, SendableRecordBatchStream};
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw">use </span>datafusion::physical_plan::empty::EmptyExec;
<a href=#253 id=253 data-nosnippet>253</a>
<a href=#254 id=254 data-nosnippet>254</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#255 id=255 data-nosnippet>255</a> <span class="kw">use </span><span class="kw">crate</span>::error::Error;
<a href=#256 id=256 data-nosnippet>256</a> <span class="kw">use </span><span class="kw">crate</span>::information_schema::InformationExtension;
<a href=#257 id=257 data-nosnippet>257</a> <span class="kw">use </span><span class="kw">crate</span>::kvbackend::KvBackendCatalogManagerBuilder;
<a href=#258 id=258 data-nosnippet>258</a>
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">struct </span>PlanInformationExtension;
<a href=#260 id=260 data-nosnippet>260</a>
<a href=#261 id=261 data-nosnippet>261</a> <span class="attr">#[async_trait::async_trait]
<a href=#262 id=262 data-nosnippet>262</a> </span><span class="kw">impl </span>InformationExtension <span class="kw">for </span>PlanInformationExtension {
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">type </span>Error = Error;
<a href=#264 id=264 data-nosnippet>264</a>
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">async fn </span>nodes(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Vec&lt;NodeInfo&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#266 id=266 data-nosnippet>266</a> <span class="prelude-val">Ok</span>(<span class="macro">vec!</span>[])
<a href=#267 id=267 data-nosnippet>267</a> }
<a href=#268 id=268 data-nosnippet>268</a>
<a href=#269 id=269 data-nosnippet>269</a> <span class="kw">async fn </span>procedures(
<a href=#270 id=270 data-nosnippet>270</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#271 id=271 data-nosnippet>271</a> ) -&gt; std::result::Result&lt;Vec&lt;(String, ProcedureInfo)&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#272 id=272 data-nosnippet>272</a> <span class="prelude-val">Ok</span>(<span class="macro">vec!</span>[])
<a href=#273 id=273 data-nosnippet>273</a> }
<a href=#274 id=274 data-nosnippet>274</a>
<a href=#275 id=275 data-nosnippet>275</a> <span class="kw">async fn </span>region_stats(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Vec&lt;RegionStat&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#276 id=276 data-nosnippet>276</a> <span class="prelude-val">Ok</span>(<span class="macro">vec!</span>[])
<a href=#277 id=277 data-nosnippet>277</a> }
<a href=#278 id=278 data-nosnippet>278</a>
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">async fn </span>flow_stats(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;FlowStat&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#280 id=280 data-nosnippet>280</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
<a href=#281 id=281 data-nosnippet>281</a> }
<a href=#282 id=282 data-nosnippet>282</a>
<a href=#283 id=283 data-nosnippet>283</a> <span class="kw">async fn </span>inspect_datanode(
<a href=#284 id=284 data-nosnippet>284</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#285 id=285 data-nosnippet>285</a> _request: DatanodeInspectRequest,
<a href=#286 id=286 data-nosnippet>286</a> ) -&gt; std::result::Result&lt;SendableRecordBatchStream, <span class="self">Self</span>::Error&gt; {
<a href=#287 id=287 data-nosnippet>287</a> <span class="prelude-val">Ok</span>(RecordBatches::empty().as_stream())
<a href=#288 id=288 data-nosnippet>288</a> }
<a href=#289 id=289 data-nosnippet>289</a>
<a href=#290 id=290 data-nosnippet>290</a> <span class="kw">fn </span>inspect_datanode_plan(
<a href=#291 id=291 data-nosnippet>291</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#292 id=292 data-nosnippet>292</a> _request: DatanodeInspectRequest,
<a href=#293 id=293 data-nosnippet>293</a> schema: SchemaRef,
<a href=#294 id=294 data-nosnippet>294</a> ) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>ExecutionPlan&gt;&gt;, <span class="self">Self</span>::Error&gt; {
<a href=#295 id=295 data-nosnippet>295</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(Arc::new(EmptyExec::new(
<a href=#296 id=296 data-nosnippet>296</a> schema.arrow_schema().clone(),
<a href=#297 id=297 data-nosnippet>297</a> ))))
<a href=#298 id=298 data-nosnippet>298</a> }
<a href=#299 id=299 data-nosnippet>299</a> }
<a href=#300 id=300 data-nosnippet>300</a>
<a href=#301 id=301 data-nosnippet>301</a> <span class="attr">#[tokio::test]
<a href=#302 id=302 data-nosnippet>302</a> </span><span class="kw">async fn </span>ssts_manifest_uses_information_extension_scan_plan() {
<a href=#303 id=303 data-nosnippet>303</a> <span class="kw">let </span>backend = Arc::new(MemoryKvBackend::default());
<a href=#304 id=304 data-nosnippet>304</a> <span class="kw">let </span>layered_cache_builder = LayeredCacheRegistryBuilder::default()
<a href=#305 id=305 data-nosnippet>305</a> .add_cache_registry(CacheRegistryBuilder::default().build());
<a href=#306 id=306 data-nosnippet>306</a> <span class="kw">let </span>fundamental_cache_registry = build_fundamental_cache_registry(backend.clone());
<a href=#307 id=307 data-nosnippet>307</a> <span class="kw">let </span>layered_cache_registry = Arc::new(
<a href=#308 id=308 data-nosnippet>308</a> with_default_composite_cache_registry(
<a href=#309 id=309 data-nosnippet>309</a> layered_cache_builder.add_cache_registry(fundamental_cache_registry),
<a href=#310 id=310 data-nosnippet>310</a> )
<a href=#311 id=311 data-nosnippet>311</a> .unwrap()
<a href=#312 id=312 data-nosnippet>312</a> .build(),
<a href=#313 id=313 data-nosnippet>313</a> );
<a href=#314 id=314 data-nosnippet>314</a>
<a href=#315 id=315 data-nosnippet>315</a> <span class="kw">let </span>catalog_manager = KvBackendCatalogManagerBuilder::new(
<a href=#316 id=316 data-nosnippet>316</a> Arc::new(PlanInformationExtension),
<a href=#317 id=317 data-nosnippet>317</a> backend,
<a href=#318 id=318 data-nosnippet>318</a> layered_cache_registry,
<a href=#319 id=319 data-nosnippet>319</a> )
<a href=#320 id=320 data-nosnippet>320</a> .build();
<a href=#321 id=321 data-nosnippet>321</a>
<a href=#322 id=322 data-nosnippet>322</a> <span class="kw">let </span>table = catalog_manager
<a href=#323 id=323 data-nosnippet>323</a> .table(
<a href=#324 id=324 data-nosnippet>324</a> DEFAULT_CATALOG_NAME,
<a href=#325 id=325 data-nosnippet>325</a> INFORMATION_SCHEMA_NAME,
<a href=#326 id=326 data-nosnippet>326</a> SSTS_MANIFEST,
<a href=#327 id=327 data-nosnippet>327</a> <span class="prelude-val">None</span>,
<a href=#328 id=328 data-nosnippet>328</a> )
<a href=#329 id=329 data-nosnippet>329</a> .<span class="kw">await
<a href=#330 id=330 data-nosnippet>330</a> </span>.unwrap()
<a href=#331 id=331 data-nosnippet>331</a> .unwrap();
<a href=#332 id=332 data-nosnippet>332</a>
<a href=#333 id=333 data-nosnippet>333</a> <span class="kw">let </span>request = ScanRequest {
<a href=#334 id=334 data-nosnippet>334</a> projection: <span class="prelude-val">Some</span>(<span class="macro">vec!</span>[<span class="number">0</span>]),
<a href=#335 id=335 data-nosnippet>335</a> ..Default::default()
<a href=#336 id=336 data-nosnippet>336</a> };
<a href=#337 id=337 data-nosnippet>337</a> <span class="kw">let </span>plan = table.scan_to_plan(request).unwrap().unwrap();
<a href=#338 id=338 data-nosnippet>338</a>
<a href=#339 id=339 data-nosnippet>339</a> <span class="macro">assert!</span>(plan.as_ref().is::&lt;EmptyExec&gt;());
<a href=#340 id=340 data-nosnippet>340</a> <span class="macro">assert_eq!</span>(<span class="number">1</span>, plan.schema().fields().len());
<a href=#341 id=341 data-nosnippet>341</a> }
<a href=#342 id=342 data-nosnippet>342</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,441 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/statistics.rs`."><title>statistics.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>statistics.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_STATISTICS_TABLE_ID;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, ScalarVectorBuilder, VectorRef};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, FulltextBackend, Schema, SchemaRef};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datatypes::value::Value;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::vectors::{Int64VectorBuilder, StringVectorBuilder};
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>futures::TryStreamExt;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>snafu::{OptionExt, ResultExt};
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>store_api::sst_entry::{
<a href=#33 id=33 data-nosnippet>33</a> PUFFIN_INDEX_TYPE_BLOOM_FILTER, PUFFIN_INDEX_TYPE_FULLTEXT_BLOOM,
<a href=#34 id=34 data-nosnippet>34</a> PUFFIN_INDEX_TYPE_FULLTEXT_TANTIVY, PUFFIN_INDEX_TYPE_INVERTED,
<a href=#35 id=35 data-nosnippet>35</a>};
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#40 id=40 data-nosnippet>40</a> CreateRecordBatchSnafu, InternalSnafu, <span class="prelude-ty">Result</span>, UpgradeWeakCatalogManagerRefSnafu,
<a href=#41 id=41 data-nosnippet>41</a>};
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::key_column_usage::{
<a href=#43 id=43 data-nosnippet>43</a> CONSTRAINT_NAME_FULLTEXT_INDEX, CONSTRAINT_NAME_INVERTED_INDEX, CONSTRAINT_NAME_PRI,
<a href=#44 id=44 data-nosnippet>44</a> CONSTRAINT_NAME_SKIPPING_INDEX, CONSTRAINT_NAME_TIME_INDEX,
<a href=#45 id=45 data-nosnippet>45</a>};
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{
<a href=#47 id=47 data-nosnippet>47</a> InformationTable, Predicates, STATISTICS, primary_key_encoding_index_type,
<a href=#48 id=48 data-nosnippet>48</a>};
<a href=#49 id=49 data-nosnippet>49</a>
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">pub const </span>TABLE_CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"table_catalog"</span>;
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">pub const </span>TABLE_SCHEMA: <span class="kw-2">&amp;</span>str = <span class="string">"table_schema"</span>;
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">pub const </span>TABLE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_name"</span>;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">pub const </span>NON_UNIQUE: <span class="kw-2">&amp;</span>str = <span class="string">"non_unique"</span>;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">pub const </span>INDEX_SCHEMA: <span class="kw-2">&amp;</span>str = <span class="string">"index_schema"</span>;
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">pub const </span>INDEX_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"index_name"</span>;
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">pub const </span>SEQ_IN_INDEX: <span class="kw-2">&amp;</span>str = <span class="string">"seq_in_index"</span>;
<a href=#57 id=57 data-nosnippet>57</a><span class="kw">pub const </span>COLUMN_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"column_name"</span>;
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">pub const </span>COLLATION: <span class="kw-2">&amp;</span>str = <span class="string">"collation"</span>;
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">pub const </span>CARDINALITY: <span class="kw-2">&amp;</span>str = <span class="string">"cardinality"</span>;
<a href=#60 id=60 data-nosnippet>60</a><span class="kw">pub const </span>SUB_PART: <span class="kw-2">&amp;</span>str = <span class="string">"sub_part"</span>;
<a href=#61 id=61 data-nosnippet>61</a><span class="kw">pub const </span>PACKED: <span class="kw-2">&amp;</span>str = <span class="string">"packed"</span>;
<a href=#62 id=62 data-nosnippet>62</a><span class="kw">pub const </span>NULLABLE: <span class="kw-2">&amp;</span>str = <span class="string">"nullable"</span>;
<a href=#63 id=63 data-nosnippet>63</a><span class="kw">pub const </span>INDEX_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"index_type"</span>;
<a href=#64 id=64 data-nosnippet>64</a><span class="kw">pub const </span>COMMENT: <span class="kw-2">&amp;</span>str = <span class="string">"comment"</span>;
<a href=#65 id=65 data-nosnippet>65</a><span class="kw">pub const </span>INDEX_COMMENT: <span class="kw-2">&amp;</span>str = <span class="string">"index_comment"</span>;
<a href=#66 id=66 data-nosnippet>66</a><span class="kw">pub const </span>IS_VISIBLE: <span class="kw-2">&amp;</span>str = <span class="string">"is_visible"</span>;
<a href=#67 id=67 data-nosnippet>67</a><span class="kw">pub const </span>EXPRESSION: <span class="kw-2">&amp;</span>str = <span class="string">"expression"</span>;
<a href=#68 id=68 data-nosnippet>68</a><span class="kw">pub const </span>GREPTIME_INDEX_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"greptime_index_type"</span>;
<a href=#69 id=69 data-nosnippet>69</a>
<a href=#70 id=70 data-nosnippet>70</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#71 id=71 data-nosnippet>71</a><span class="kw">const </span>MYSQL_DEFAULT_CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"def"</span>;
<a href=#72 id=72 data-nosnippet>72</a><span class="kw">const </span>ASCENDING_COLLATION: <span class="kw-2">&amp;</span>str = <span class="string">"A"</span>;
<a href=#73 id=73 data-nosnippet>73</a><span class="kw">const </span>YES: <span class="kw-2">&amp;</span>str = <span class="string">"YES"</span>;
<a href=#74 id=74 data-nosnippet>74</a><span class="kw">const </span>EMPTY: <span class="kw-2">&amp;</span>str = <span class="string">""</span>;
<a href=#75 id=75 data-nosnippet>75</a><span class="kw">const </span>PRIMARY: <span class="kw-2">&amp;</span>str = <span class="string">"PRIMARY"</span>;
<a href=#76 id=76 data-nosnippet>76</a><span class="kw">const </span>TIME: <span class="kw-2">&amp;</span>str = <span class="string">"TIME"</span>;
<a href=#77 id=77 data-nosnippet>77</a><span class="kw">const </span>FULLTEXT: <span class="kw-2">&amp;</span>str = <span class="string">"FULLTEXT"</span>;
<a href=#78 id=78 data-nosnippet>78</a><span class="kw">const </span>INVERTED: <span class="kw-2">&amp;</span>str = <span class="string">"INVERTED"</span>;
<a href=#79 id=79 data-nosnippet>79</a><span class="kw">const </span>SKIPPING: <span class="kw-2">&amp;</span>str = <span class="string">"SKIPPING"</span>;
<a href=#80 id=80 data-nosnippet>80</a><span class="kw">const </span>SECONDARY_INDEX_SEQ: i64 = <span class="number">1</span>;
<a href=#81 id=81 data-nosnippet>81</a>
<a href=#82 id=82 data-nosnippet>82</a><span class="doccomment">/// The `information_schema.statistics` table provides index metadata in a
<a href=#83 id=83 data-nosnippet>83</a>/// MySQL-compatible shape.
<a href=#84 id=84 data-nosnippet>84</a></span><span class="attr">#[derive(Debug)]
<a href=#85 id=85 data-nosnippet>85</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaStatistics {
<a href=#86 id=86 data-nosnippet>86</a> schema: SchemaRef,
<a href=#87 id=87 data-nosnippet>87</a> catalog_name: String,
<a href=#88 id=88 data-nosnippet>88</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#89 id=89 data-nosnippet>89</a>}
<a href=#90 id=90 data-nosnippet>90</a>
<a href=#91 id=91 data-nosnippet>91</a><span class="kw">impl </span>InformationSchemaStatistics {
<a href=#92 id=92 data-nosnippet>92</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_name: String, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#93 id=93 data-nosnippet>93</a> <span class="self">Self </span>{
<a href=#94 id=94 data-nosnippet>94</a> schema: <span class="self">Self</span>::schema(),
<a href=#95 id=95 data-nosnippet>95</a> catalog_name,
<a href=#96 id=96 data-nosnippet>96</a> catalog_manager,
<a href=#97 id=97 data-nosnippet>97</a> }
<a href=#98 id=98 data-nosnippet>98</a> }
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#101 id=101 data-nosnippet>101</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#102 id=102 data-nosnippet>102</a> ColumnSchema::new(TABLE_CATALOG, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#103 id=103 data-nosnippet>103</a> ColumnSchema::new(TABLE_SCHEMA, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#104 id=104 data-nosnippet>104</a> ColumnSchema::new(TABLE_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#105 id=105 data-nosnippet>105</a> ColumnSchema::new(NON_UNIQUE, ConcreteDataType::int64_datatype(), <span class="bool-val">false</span>),
<a href=#106 id=106 data-nosnippet>106</a> ColumnSchema::new(INDEX_SCHEMA, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#107 id=107 data-nosnippet>107</a> ColumnSchema::new(INDEX_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#108 id=108 data-nosnippet>108</a> ColumnSchema::new(SEQ_IN_INDEX, ConcreteDataType::int64_datatype(), <span class="bool-val">false</span>),
<a href=#109 id=109 data-nosnippet>109</a> ColumnSchema::new(COLUMN_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#110 id=110 data-nosnippet>110</a> ColumnSchema::new(COLLATION, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#111 id=111 data-nosnippet>111</a> ColumnSchema::new(CARDINALITY, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#112 id=112 data-nosnippet>112</a> ColumnSchema::new(SUB_PART, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#113 id=113 data-nosnippet>113</a> ColumnSchema::new(PACKED, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#114 id=114 data-nosnippet>114</a> ColumnSchema::new(NULLABLE, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#115 id=115 data-nosnippet>115</a> ColumnSchema::new(INDEX_TYPE, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#116 id=116 data-nosnippet>116</a> ColumnSchema::new(COMMENT, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#117 id=117 data-nosnippet>117</a> ColumnSchema::new(INDEX_COMMENT, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#118 id=118 data-nosnippet>118</a> ColumnSchema::new(IS_VISIBLE, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#119 id=119 data-nosnippet>119</a> ColumnSchema::new(EXPRESSION, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#120 id=120 data-nosnippet>120</a> ColumnSchema::new(
<a href=#121 id=121 data-nosnippet>121</a> GREPTIME_INDEX_TYPE,
<a href=#122 id=122 data-nosnippet>122</a> ConcreteDataType::string_datatype(),
<a href=#123 id=123 data-nosnippet>123</a> <span class="bool-val">true</span>,
<a href=#124 id=124 data-nosnippet>124</a> ),
<a href=#125 id=125 data-nosnippet>125</a> ]))
<a href=#126 id=126 data-nosnippet>126</a> }
<a href=#127 id=127 data-nosnippet>127</a>
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaStatisticsBuilder {
<a href=#129 id=129 data-nosnippet>129</a> InformationSchemaStatisticsBuilder::new(
<a href=#130 id=130 data-nosnippet>130</a> <span class="self">self</span>.schema.clone(),
<a href=#131 id=131 data-nosnippet>131</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#132 id=132 data-nosnippet>132</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#133 id=133 data-nosnippet>133</a> )
<a href=#134 id=134 data-nosnippet>134</a> }
<a href=#135 id=135 data-nosnippet>135</a>}
<a href=#136 id=136 data-nosnippet>136</a>
<a href=#137 id=137 data-nosnippet>137</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaStatistics {
<a href=#138 id=138 data-nosnippet>138</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#139 id=139 data-nosnippet>139</a> INFORMATION_SCHEMA_STATISTICS_TABLE_ID
<a href=#140 id=140 data-nosnippet>140</a> }
<a href=#141 id=141 data-nosnippet>141</a>
<a href=#142 id=142 data-nosnippet>142</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#143 id=143 data-nosnippet>143</a> STATISTICS
<a href=#144 id=144 data-nosnippet>144</a> }
<a href=#145 id=145 data-nosnippet>145</a>
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#147 id=147 data-nosnippet>147</a> <span class="self">self</span>.schema.clone()
<a href=#148 id=148 data-nosnippet>148</a> }
<a href=#149 id=149 data-nosnippet>149</a>
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#152 id=152 data-nosnippet>152</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#154 id=154 data-nosnippet>154</a> schema,
<a href=#155 id=155 data-nosnippet>155</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#156 id=156 data-nosnippet>156</a> builder
<a href=#157 id=157 data-nosnippet>157</a> .make_statistics(<span class="prelude-val">Some</span>(request))
<a href=#158 id=158 data-nosnippet>158</a> .<span class="kw">await
<a href=#159 id=159 data-nosnippet>159</a> </span>.map(|x| x.into_df_record_batch())
<a href=#160 id=160 data-nosnippet>160</a> .map_err(Into::into)
<a href=#161 id=161 data-nosnippet>161</a> }),
<a href=#162 id=162 data-nosnippet>162</a> ));
<a href=#163 id=163 data-nosnippet>163</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#164 id=164 data-nosnippet>164</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#165 id=165 data-nosnippet>165</a> .map_err(BoxedError::new)
<a href=#166 id=166 data-nosnippet>166</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#167 id=167 data-nosnippet>167</a> ))
<a href=#168 id=168 data-nosnippet>168</a> }
<a href=#169 id=169 data-nosnippet>169</a>}
<a href=#170 id=170 data-nosnippet>170</a>
<a href=#171 id=171 data-nosnippet>171</a><span class="kw">struct </span>InformationSchemaStatisticsBuilder {
<a href=#172 id=172 data-nosnippet>172</a> schema: SchemaRef,
<a href=#173 id=173 data-nosnippet>173</a> catalog_name: String,
<a href=#174 id=174 data-nosnippet>174</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#175 id=175 data-nosnippet>175</a>
<a href=#176 id=176 data-nosnippet>176</a> table_catalogs: StringVectorBuilder,
<a href=#177 id=177 data-nosnippet>177</a> table_schemas: StringVectorBuilder,
<a href=#178 id=178 data-nosnippet>178</a> table_names: StringVectorBuilder,
<a href=#179 id=179 data-nosnippet>179</a> non_unique: Int64VectorBuilder,
<a href=#180 id=180 data-nosnippet>180</a> index_schemas: StringVectorBuilder,
<a href=#181 id=181 data-nosnippet>181</a> index_names: StringVectorBuilder,
<a href=#182 id=182 data-nosnippet>182</a> seq_in_index: Int64VectorBuilder,
<a href=#183 id=183 data-nosnippet>183</a> column_names: StringVectorBuilder,
<a href=#184 id=184 data-nosnippet>184</a> collations: StringVectorBuilder,
<a href=#185 id=185 data-nosnippet>185</a> cardinalities: Int64VectorBuilder,
<a href=#186 id=186 data-nosnippet>186</a> sub_parts: Int64VectorBuilder,
<a href=#187 id=187 data-nosnippet>187</a> packed: StringVectorBuilder,
<a href=#188 id=188 data-nosnippet>188</a> nullable: StringVectorBuilder,
<a href=#189 id=189 data-nosnippet>189</a> index_types: StringVectorBuilder,
<a href=#190 id=190 data-nosnippet>190</a> comments: StringVectorBuilder,
<a href=#191 id=191 data-nosnippet>191</a> index_comments: StringVectorBuilder,
<a href=#192 id=192 data-nosnippet>192</a> is_visible: StringVectorBuilder,
<a href=#193 id=193 data-nosnippet>193</a> expressions: StringVectorBuilder,
<a href=#194 id=194 data-nosnippet>194</a> greptime_index_types: StringVectorBuilder,
<a href=#195 id=195 data-nosnippet>195</a>}
<a href=#196 id=196 data-nosnippet>196</a>
<a href=#197 id=197 data-nosnippet>197</a><span class="kw">impl </span>InformationSchemaStatisticsBuilder {
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">fn </span>new(
<a href=#199 id=199 data-nosnippet>199</a> schema: SchemaRef,
<a href=#200 id=200 data-nosnippet>200</a> catalog_name: String,
<a href=#201 id=201 data-nosnippet>201</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#202 id=202 data-nosnippet>202</a> ) -&gt; <span class="self">Self </span>{
<a href=#203 id=203 data-nosnippet>203</a> <span class="self">Self </span>{
<a href=#204 id=204 data-nosnippet>204</a> schema,
<a href=#205 id=205 data-nosnippet>205</a> catalog_name,
<a href=#206 id=206 data-nosnippet>206</a> catalog_manager,
<a href=#207 id=207 data-nosnippet>207</a> table_catalogs: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#208 id=208 data-nosnippet>208</a> table_schemas: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#209 id=209 data-nosnippet>209</a> table_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#210 id=210 data-nosnippet>210</a> non_unique: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#211 id=211 data-nosnippet>211</a> index_schemas: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#212 id=212 data-nosnippet>212</a> index_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#213 id=213 data-nosnippet>213</a> seq_in_index: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#214 id=214 data-nosnippet>214</a> column_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#215 id=215 data-nosnippet>215</a> collations: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#216 id=216 data-nosnippet>216</a> cardinalities: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#217 id=217 data-nosnippet>217</a> sub_parts: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#218 id=218 data-nosnippet>218</a> packed: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#219 id=219 data-nosnippet>219</a> nullable: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#220 id=220 data-nosnippet>220</a> index_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#221 id=221 data-nosnippet>221</a> comments: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#222 id=222 data-nosnippet>222</a> index_comments: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#223 id=223 data-nosnippet>223</a> is_visible: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#224 id=224 data-nosnippet>224</a> expressions: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#225 id=225 data-nosnippet>225</a> greptime_index_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#226 id=226 data-nosnippet>226</a> }
<a href=#227 id=227 data-nosnippet>227</a> }
<a href=#228 id=228 data-nosnippet>228</a>
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">async fn </span>make_statistics(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#230 id=230 data-nosnippet>230</a> <span class="kw">let </span>catalog_name = <span class="self">self</span>.catalog_name.clone();
<a href=#231 id=231 data-nosnippet>231</a> <span class="kw">let </span>catalog_manager = <span class="self">self
<a href=#232 id=232 data-nosnippet>232</a> </span>.catalog_manager
<a href=#233 id=233 data-nosnippet>233</a> .upgrade()
<a href=#234 id=234 data-nosnippet>234</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#235 id=235 data-nosnippet>235</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#236 id=236 data-nosnippet>236</a>
<a href=#237 id=237 data-nosnippet>237</a> <span class="kw">for </span>schema_name <span class="kw">in </span>catalog_manager.schema_names(<span class="kw-2">&amp;</span>catalog_name, <span class="prelude-val">None</span>).<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#238 id=238 data-nosnippet>238</a> <span class="kw">let </span><span class="kw-2">mut </span>stream = catalog_manager.tables(<span class="kw-2">&amp;</span>catalog_name, <span class="kw-2">&amp;</span>schema_name, <span class="prelude-val">None</span>);
<a href=#239 id=239 data-nosnippet>239</a>
<a href=#240 id=240 data-nosnippet>240</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(table) = stream.try_next().<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#241 id=241 data-nosnippet>241</a> <span class="kw">let </span>table_info = table.table_info();
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">let </span>table_name = <span class="kw-2">&amp;</span>table_info.name;
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">let </span>keys = <span class="kw-2">&amp;</span>table_info.meta.primary_key_indices;
<a href=#244 id=244 data-nosnippet>244</a> <span class="kw">let </span>schema = table.schema();
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw">let </span>primary_key_encoding =
<a href=#246 id=246 data-nosnippet>246</a> primary_key_encoding_index_type(<span class="kw-2">&amp;</span>table_info.meta.options.extra_options);
<a href=#247 id=247 data-nosnippet>247</a>
<a href=#248 id=248 data-nosnippet>248</a> <span class="kw">for </span>(primary_key_seq, idx) <span class="kw">in </span>keys.iter().enumerate() {
<a href=#249 id=249 data-nosnippet>249</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(column) = schema.column_schemas().get(<span class="kw-2">*</span>idx) {
<a href=#250 id=250 data-nosnippet>250</a> <span class="self">self</span>.add_statistics(
<a href=#251 id=251 data-nosnippet>251</a> <span class="kw-2">&amp;</span>predicates,
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#253 id=253 data-nosnippet>253</a> table_name,
<a href=#254 id=254 data-nosnippet>254</a> <span class="number">0</span>,
<a href=#255 id=255 data-nosnippet>255</a> CONSTRAINT_NAME_PRI,
<a href=#256 id=256 data-nosnippet>256</a> primary_key_seq <span class="kw">as </span>i64 + <span class="number">1</span>,
<a href=#257 id=257 data-nosnippet>257</a> column,
<a href=#258 id=258 data-nosnippet>258</a> PRIMARY,
<a href=#259 id=259 data-nosnippet>259</a> primary_key_encoding,
<a href=#260 id=260 data-nosnippet>260</a> );
<a href=#261 id=261 data-nosnippet>261</a> }
<a href=#262 id=262 data-nosnippet>262</a> }
<a href=#263 id=263 data-nosnippet>263</a>
<a href=#264 id=264 data-nosnippet>264</a> <span class="kw">for </span>column <span class="kw">in </span>schema.column_schemas() {
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">if </span>column.is_time_index() {
<a href=#266 id=266 data-nosnippet>266</a> <span class="self">self</span>.add_statistics(
<a href=#267 id=267 data-nosnippet>267</a> <span class="kw-2">&amp;</span>predicates,
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#269 id=269 data-nosnippet>269</a> table_name,
<a href=#270 id=270 data-nosnippet>270</a> <span class="number">1</span>,
<a href=#271 id=271 data-nosnippet>271</a> CONSTRAINT_NAME_TIME_INDEX,
<a href=#272 id=272 data-nosnippet>272</a> <span class="number">1</span>,
<a href=#273 id=273 data-nosnippet>273</a> column,
<a href=#274 id=274 data-nosnippet>274</a> TIME,
<a href=#275 id=275 data-nosnippet>275</a> EMPTY,
<a href=#276 id=276 data-nosnippet>276</a> );
<a href=#277 id=277 data-nosnippet>277</a> }
<a href=#278 id=278 data-nosnippet>278</a> <span class="kw">if </span>column.is_inverted_indexed() {
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">let </span>index_name =
<a href=#280 id=280 data-nosnippet>280</a> column_index_name(CONSTRAINT_NAME_INVERTED_INDEX, <span class="kw-2">&amp;</span>column.name);
<a href=#281 id=281 data-nosnippet>281</a> <span class="self">self</span>.add_statistics(
<a href=#282 id=282 data-nosnippet>282</a> <span class="kw-2">&amp;</span>predicates,
<a href=#283 id=283 data-nosnippet>283</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#284 id=284 data-nosnippet>284</a> table_name,
<a href=#285 id=285 data-nosnippet>285</a> <span class="number">1</span>,
<a href=#286 id=286 data-nosnippet>286</a> <span class="kw-2">&amp;</span>index_name,
<a href=#287 id=287 data-nosnippet>287</a> SECONDARY_INDEX_SEQ,
<a href=#288 id=288 data-nosnippet>288</a> column,
<a href=#289 id=289 data-nosnippet>289</a> INVERTED,
<a href=#290 id=290 data-nosnippet>290</a> PUFFIN_INDEX_TYPE_INVERTED,
<a href=#291 id=291 data-nosnippet>291</a> );
<a href=#292 id=292 data-nosnippet>292</a> }
<a href=#293 id=293 data-nosnippet>293</a> <span class="kw">if let </span><span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(options)) = column.fulltext_options()
<a href=#294 id=294 data-nosnippet>294</a> &amp;&amp; options.enable
<a href=#295 id=295 data-nosnippet>295</a> {
<a href=#296 id=296 data-nosnippet>296</a> <span class="kw">let </span>greptime_index_type = <span class="kw">match </span>options.backend {
<a href=#297 id=297 data-nosnippet>297</a> FulltextBackend::Bloom =&gt; PUFFIN_INDEX_TYPE_FULLTEXT_BLOOM,
<a href=#298 id=298 data-nosnippet>298</a> FulltextBackend::Tantivy =&gt; PUFFIN_INDEX_TYPE_FULLTEXT_TANTIVY,
<a href=#299 id=299 data-nosnippet>299</a> };
<a href=#300 id=300 data-nosnippet>300</a> <span class="kw">let </span>index_name =
<a href=#301 id=301 data-nosnippet>301</a> column_index_name(CONSTRAINT_NAME_FULLTEXT_INDEX, <span class="kw-2">&amp;</span>column.name);
<a href=#302 id=302 data-nosnippet>302</a> <span class="self">self</span>.add_statistics(
<a href=#303 id=303 data-nosnippet>303</a> <span class="kw-2">&amp;</span>predicates,
<a href=#304 id=304 data-nosnippet>304</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#305 id=305 data-nosnippet>305</a> table_name,
<a href=#306 id=306 data-nosnippet>306</a> <span class="number">1</span>,
<a href=#307 id=307 data-nosnippet>307</a> <span class="kw-2">&amp;</span>index_name,
<a href=#308 id=308 data-nosnippet>308</a> SECONDARY_INDEX_SEQ,
<a href=#309 id=309 data-nosnippet>309</a> column,
<a href=#310 id=310 data-nosnippet>310</a> FULLTEXT,
<a href=#311 id=311 data-nosnippet>311</a> greptime_index_type,
<a href=#312 id=312 data-nosnippet>312</a> );
<a href=#313 id=313 data-nosnippet>313</a> }
<a href=#314 id=314 data-nosnippet>314</a> <span class="kw">if </span>column.is_skipping_indexed() {
<a href=#315 id=315 data-nosnippet>315</a> <span class="kw">let </span>index_name =
<a href=#316 id=316 data-nosnippet>316</a> column_index_name(CONSTRAINT_NAME_SKIPPING_INDEX, <span class="kw-2">&amp;</span>column.name);
<a href=#317 id=317 data-nosnippet>317</a> <span class="self">self</span>.add_statistics(
<a href=#318 id=318 data-nosnippet>318</a> <span class="kw-2">&amp;</span>predicates,
<a href=#319 id=319 data-nosnippet>319</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#320 id=320 data-nosnippet>320</a> table_name,
<a href=#321 id=321 data-nosnippet>321</a> <span class="number">1</span>,
<a href=#322 id=322 data-nosnippet>322</a> <span class="kw-2">&amp;</span>index_name,
<a href=#323 id=323 data-nosnippet>323</a> SECONDARY_INDEX_SEQ,
<a href=#324 id=324 data-nosnippet>324</a> column,
<a href=#325 id=325 data-nosnippet>325</a> SKIPPING,
<a href=#326 id=326 data-nosnippet>326</a> PUFFIN_INDEX_TYPE_BLOOM_FILTER,
<a href=#327 id=327 data-nosnippet>327</a> );
<a href=#328 id=328 data-nosnippet>328</a> }
<a href=#329 id=329 data-nosnippet>329</a> }
<a href=#330 id=330 data-nosnippet>330</a> }
<a href=#331 id=331 data-nosnippet>331</a> }
<a href=#332 id=332 data-nosnippet>332</a>
<a href=#333 id=333 data-nosnippet>333</a> <span class="self">self</span>.finish()
<a href=#334 id=334 data-nosnippet>334</a> }
<a href=#335 id=335 data-nosnippet>335</a>
<a href=#336 id=336 data-nosnippet>336</a> <span class="attr">#[allow(clippy::too_many_arguments)]
<a href=#337 id=337 data-nosnippet>337</a> </span><span class="kw">fn </span>add_statistics(
<a href=#338 id=338 data-nosnippet>338</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#339 id=339 data-nosnippet>339</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#340 id=340 data-nosnippet>340</a> table_schema: <span class="kw-2">&amp;</span>str,
<a href=#341 id=341 data-nosnippet>341</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#342 id=342 data-nosnippet>342</a> non_unique: i64,
<a href=#343 id=343 data-nosnippet>343</a> index_name: <span class="kw-2">&amp;</span>str,
<a href=#344 id=344 data-nosnippet>344</a> seq_in_index: i64,
<a href=#345 id=345 data-nosnippet>345</a> column: <span class="kw-2">&amp;</span>ColumnSchema,
<a href=#346 id=346 data-nosnippet>346</a> index_type: <span class="kw-2">&amp;</span>str,
<a href=#347 id=347 data-nosnippet>347</a> greptime_index_type: <span class="kw-2">&amp;</span>str,
<a href=#348 id=348 data-nosnippet>348</a> ) {
<a href=#349 id=349 data-nosnippet>349</a> <span class="comment">// MySQL's `information_schema.statistics.nullable` is `YES` or `''`,
<a href=#350 id=350 data-nosnippet>350</a> // unlike `columns.is_nullable` which is `YES`/`NO`.
<a href=#351 id=351 data-nosnippet>351</a> </span><span class="kw">let </span>nullable = <span class="kw">if </span>column.is_nullable() { YES } <span class="kw">else </span>{ EMPTY };
<a href=#352 id=352 data-nosnippet>352</a> <span class="kw">let </span>row = [
<a href=#353 id=353 data-nosnippet>353</a> (TABLE_CATALOG, <span class="kw-2">&amp;</span>Value::from(MYSQL_DEFAULT_CATALOG)),
<a href=#354 id=354 data-nosnippet>354</a> (TABLE_SCHEMA, <span class="kw-2">&amp;</span>Value::from(table_schema)),
<a href=#355 id=355 data-nosnippet>355</a> (TABLE_NAME, <span class="kw-2">&amp;</span>Value::from(table_name)),
<a href=#356 id=356 data-nosnippet>356</a> (NON_UNIQUE, <span class="kw-2">&amp;</span>Value::from(non_unique)),
<a href=#357 id=357 data-nosnippet>357</a> (INDEX_SCHEMA, <span class="kw-2">&amp;</span>Value::from(table_schema)),
<a href=#358 id=358 data-nosnippet>358</a> (INDEX_NAME, <span class="kw-2">&amp;</span>Value::from(index_name)),
<a href=#359 id=359 data-nosnippet>359</a> (SEQ_IN_INDEX, <span class="kw-2">&amp;</span>Value::from(seq_in_index)),
<a href=#360 id=360 data-nosnippet>360</a> (COLUMN_NAME, <span class="kw-2">&amp;</span>Value::from(column.name.as_str())),
<a href=#361 id=361 data-nosnippet>361</a> (NULLABLE, <span class="kw-2">&amp;</span>Value::from(nullable)),
<a href=#362 id=362 data-nosnippet>362</a> (INDEX_TYPE, <span class="kw-2">&amp;</span>Value::from(index_type)),
<a href=#363 id=363 data-nosnippet>363</a> (GREPTIME_INDEX_TYPE, <span class="kw-2">&amp;</span>Value::from(greptime_index_type)),
<a href=#364 id=364 data-nosnippet>364</a> ];
<a href=#365 id=365 data-nosnippet>365</a>
<a href=#366 id=366 data-nosnippet>366</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#367 id=367 data-nosnippet>367</a> <span class="kw">return</span>;
<a href=#368 id=368 data-nosnippet>368</a> }
<a href=#369 id=369 data-nosnippet>369</a>
<a href=#370 id=370 data-nosnippet>370</a> <span class="self">self</span>.table_catalogs.push(<span class="prelude-val">Some</span>(MYSQL_DEFAULT_CATALOG));
<a href=#371 id=371 data-nosnippet>371</a> <span class="self">self</span>.table_schemas.push(<span class="prelude-val">Some</span>(table_schema));
<a href=#372 id=372 data-nosnippet>372</a> <span class="self">self</span>.table_names.push(<span class="prelude-val">Some</span>(table_name));
<a href=#373 id=373 data-nosnippet>373</a> <span class="self">self</span>.non_unique.push(<span class="prelude-val">Some</span>(non_unique));
<a href=#374 id=374 data-nosnippet>374</a> <span class="self">self</span>.index_schemas.push(<span class="prelude-val">Some</span>(table_schema));
<a href=#375 id=375 data-nosnippet>375</a> <span class="self">self</span>.index_names.push(<span class="prelude-val">Some</span>(index_name));
<a href=#376 id=376 data-nosnippet>376</a> <span class="self">self</span>.seq_in_index.push(<span class="prelude-val">Some</span>(seq_in_index));
<a href=#377 id=377 data-nosnippet>377</a> <span class="self">self</span>.column_names.push(<span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>column.name));
<a href=#378 id=378 data-nosnippet>378</a> <span class="self">self</span>.collations.push(<span class="prelude-val">Some</span>(ASCENDING_COLLATION));
<a href=#379 id=379 data-nosnippet>379</a> <span class="self">self</span>.cardinalities.push(<span class="prelude-val">None</span>);
<a href=#380 id=380 data-nosnippet>380</a> <span class="self">self</span>.sub_parts.push(<span class="prelude-val">None</span>);
<a href=#381 id=381 data-nosnippet>381</a> <span class="self">self</span>.packed.push(<span class="prelude-val">None</span>);
<a href=#382 id=382 data-nosnippet>382</a> <span class="self">self</span>.nullable.push(<span class="prelude-val">Some</span>(nullable));
<a href=#383 id=383 data-nosnippet>383</a> <span class="self">self</span>.index_types.push(<span class="prelude-val">Some</span>(index_type));
<a href=#384 id=384 data-nosnippet>384</a> <span class="self">self</span>.comments.push(<span class="prelude-val">Some</span>(EMPTY));
<a href=#385 id=385 data-nosnippet>385</a> <span class="self">self</span>.index_comments.push(<span class="prelude-val">Some</span>(EMPTY));
<a href=#386 id=386 data-nosnippet>386</a> <span class="self">self</span>.is_visible.push(<span class="prelude-val">Some</span>(YES));
<a href=#387 id=387 data-nosnippet>387</a> <span class="self">self</span>.expressions.push(<span class="prelude-val">None</span>);
<a href=#388 id=388 data-nosnippet>388</a> <span class="self">self</span>.greptime_index_types.push(<span class="prelude-val">Some</span>(greptime_index_type));
<a href=#389 id=389 data-nosnippet>389</a> }
<a href=#390 id=390 data-nosnippet>390</a>
<a href=#391 id=391 data-nosnippet>391</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#392 id=392 data-nosnippet>392</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#393 id=393 data-nosnippet>393</a> Arc::new(<span class="self">self</span>.table_catalogs.finish()),
<a href=#394 id=394 data-nosnippet>394</a> Arc::new(<span class="self">self</span>.table_schemas.finish()),
<a href=#395 id=395 data-nosnippet>395</a> Arc::new(<span class="self">self</span>.table_names.finish()),
<a href=#396 id=396 data-nosnippet>396</a> Arc::new(<span class="self">self</span>.non_unique.finish()),
<a href=#397 id=397 data-nosnippet>397</a> Arc::new(<span class="self">self</span>.index_schemas.finish()),
<a href=#398 id=398 data-nosnippet>398</a> Arc::new(<span class="self">self</span>.index_names.finish()),
<a href=#399 id=399 data-nosnippet>399</a> Arc::new(<span class="self">self</span>.seq_in_index.finish()),
<a href=#400 id=400 data-nosnippet>400</a> Arc::new(<span class="self">self</span>.column_names.finish()),
<a href=#401 id=401 data-nosnippet>401</a> Arc::new(<span class="self">self</span>.collations.finish()),
<a href=#402 id=402 data-nosnippet>402</a> Arc::new(<span class="self">self</span>.cardinalities.finish()),
<a href=#403 id=403 data-nosnippet>403</a> Arc::new(<span class="self">self</span>.sub_parts.finish()),
<a href=#404 id=404 data-nosnippet>404</a> Arc::new(<span class="self">self</span>.packed.finish()),
<a href=#405 id=405 data-nosnippet>405</a> Arc::new(<span class="self">self</span>.nullable.finish()),
<a href=#406 id=406 data-nosnippet>406</a> Arc::new(<span class="self">self</span>.index_types.finish()),
<a href=#407 id=407 data-nosnippet>407</a> Arc::new(<span class="self">self</span>.comments.finish()),
<a href=#408 id=408 data-nosnippet>408</a> Arc::new(<span class="self">self</span>.index_comments.finish()),
<a href=#409 id=409 data-nosnippet>409</a> Arc::new(<span class="self">self</span>.is_visible.finish()),
<a href=#410 id=410 data-nosnippet>410</a> Arc::new(<span class="self">self</span>.expressions.finish()),
<a href=#411 id=411 data-nosnippet>411</a> Arc::new(<span class="self">self</span>.greptime_index_types.finish()),
<a href=#412 id=412 data-nosnippet>412</a> ];
<a href=#413 id=413 data-nosnippet>413</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#414 id=414 data-nosnippet>414</a> }
<a href=#415 id=415 data-nosnippet>415</a>}
<a href=#416 id=416 data-nosnippet>416</a>
<a href=#417 id=417 data-nosnippet>417</a><span class="kw">fn </span>column_index_name(index_name: <span class="kw-2">&amp;</span>str, column_name: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#418 id=418 data-nosnippet>418</a> <span class="macro">format!</span>(<span class="string">"{}_{}"</span>, index_name.replace(<span class="string">' '</span>, <span class="string">"_"</span>), column_name)
<a href=#419 id=419 data-nosnippet>419</a>}
<a href=#420 id=420 data-nosnippet>420</a>
<a href=#421 id=421 data-nosnippet>421</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaStatistics {
<a href=#422 id=422 data-nosnippet>422</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#423 id=423 data-nosnippet>423</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#424 id=424 data-nosnippet>424</a> }
<a href=#425 id=425 data-nosnippet>425</a>
<a href=#426 id=426 data-nosnippet>426</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#427 id=427 data-nosnippet>427</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#428 id=428 data-nosnippet>428</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#429 id=429 data-nosnippet>429</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#430 id=430 data-nosnippet>430</a> schema,
<a href=#431 id=431 data-nosnippet>431</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#432 id=432 data-nosnippet>432</a> builder
<a href=#433 id=433 data-nosnippet>433</a> .make_statistics(<span class="prelude-val">None</span>)
<a href=#434 id=434 data-nosnippet>434</a> .<span class="kw">await
<a href=#435 id=435 data-nosnippet>435</a> </span>.map(|x| x.into_df_record_batch())
<a href=#436 id=436 data-nosnippet>436</a> .map_err(Into::into)
<a href=#437 id=437 data-nosnippet>437</a> }),
<a href=#438 id=438 data-nosnippet>438</a> ))
<a href=#439 id=439 data-nosnippet>439</a> }
<a href=#440 id=440 data-nosnippet>440</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,282 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/table_constraints.rs`."><title>table_constraints.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>table_constraints.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_TABLE_CONSTRAINTS_TABLE_ID;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, MutableVector};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datatypes::scalars::ScalarVectorBuilder;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::value::Value;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datatypes::vectors::{StringVector, StringVectorBuilder, VectorRef};
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>futures::TryStreamExt;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>snafu::{OptionExt, ResultExt};
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#34 id=34 data-nosnippet>34</a>
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#37 id=37 data-nosnippet>37</a> CreateRecordBatchSnafu, InternalSnafu, <span class="prelude-ty">Result</span>, UpgradeWeakCatalogManagerRefSnafu,
<a href=#38 id=38 data-nosnippet>38</a>};
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::Predicates;
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::key_column_usage::{
<a href=#41 id=41 data-nosnippet>41</a> CONSTRAINT_NAME_PRI, CONSTRAINT_NAME_TIME_INDEX,
<a href=#42 id=42 data-nosnippet>42</a>};
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{InformationTable, TABLE_CONSTRAINTS};
<a href=#44 id=44 data-nosnippet>44</a>
<a href=#45 id=45 data-nosnippet>45</a><span class="doccomment">/// The `TABLE_CONSTRAINTS` table describes which tables have constraints.
<a href=#46 id=46 data-nosnippet>46</a></span><span class="attr">#[derive(Debug)]
<a href=#47 id=47 data-nosnippet>47</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaTableConstraints {
<a href=#48 id=48 data-nosnippet>48</a> schema: SchemaRef,
<a href=#49 id=49 data-nosnippet>49</a> catalog_name: String,
<a href=#50 id=50 data-nosnippet>50</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#51 id=51 data-nosnippet>51</a>}
<a href=#52 id=52 data-nosnippet>52</a>
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">const </span>CONSTRAINT_CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"constraint_catalog"</span>;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">const </span>CONSTRAINT_SCHEMA: <span class="kw-2">&amp;</span>str = <span class="string">"constraint_schema"</span>;
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">const </span>CONSTRAINT_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"constraint_name"</span>;
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">const </span>TABLE_SCHEMA: <span class="kw-2">&amp;</span>str = <span class="string">"table_schema"</span>;
<a href=#57 id=57 data-nosnippet>57</a><span class="kw">const </span>TABLE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_name"</span>;
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">const </span>CONSTRAINT_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"constraint_type"</span>;
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">const </span>ENFORCED: <span class="kw-2">&amp;</span>str = <span class="string">"enforced"</span>;
<a href=#60 id=60 data-nosnippet>60</a>
<a href=#61 id=61 data-nosnippet>61</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#62 id=62 data-nosnippet>62</a>
<a href=#63 id=63 data-nosnippet>63</a><span class="kw">const </span>TIME_INDEX_CONSTRAINT_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"TIME INDEX"</span>;
<a href=#64 id=64 data-nosnippet>64</a><span class="kw">const </span>PRI_KEY_CONSTRAINT_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"PRIMARY KEY"</span>;
<a href=#65 id=65 data-nosnippet>65</a>
<a href=#66 id=66 data-nosnippet>66</a><span class="kw">impl </span>InformationSchemaTableConstraints {
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_name: String, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#68 id=68 data-nosnippet>68</a> <span class="self">Self </span>{
<a href=#69 id=69 data-nosnippet>69</a> schema: <span class="self">Self</span>::schema(),
<a href=#70 id=70 data-nosnippet>70</a> catalog_name,
<a href=#71 id=71 data-nosnippet>71</a> catalog_manager,
<a href=#72 id=72 data-nosnippet>72</a> }
<a href=#73 id=73 data-nosnippet>73</a> }
<a href=#74 id=74 data-nosnippet>74</a>
<a href=#75 id=75 data-nosnippet>75</a> <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#76 id=76 data-nosnippet>76</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#77 id=77 data-nosnippet>77</a> ColumnSchema::new(
<a href=#78 id=78 data-nosnippet>78</a> CONSTRAINT_CATALOG,
<a href=#79 id=79 data-nosnippet>79</a> ConcreteDataType::string_datatype(),
<a href=#80 id=80 data-nosnippet>80</a> <span class="bool-val">false</span>,
<a href=#81 id=81 data-nosnippet>81</a> ),
<a href=#82 id=82 data-nosnippet>82</a> ColumnSchema::new(
<a href=#83 id=83 data-nosnippet>83</a> CONSTRAINT_SCHEMA,
<a href=#84 id=84 data-nosnippet>84</a> ConcreteDataType::string_datatype(),
<a href=#85 id=85 data-nosnippet>85</a> <span class="bool-val">false</span>,
<a href=#86 id=86 data-nosnippet>86</a> ),
<a href=#87 id=87 data-nosnippet>87</a> ColumnSchema::new(CONSTRAINT_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#88 id=88 data-nosnippet>88</a> ColumnSchema::new(TABLE_SCHEMA, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#89 id=89 data-nosnippet>89</a> ColumnSchema::new(TABLE_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#90 id=90 data-nosnippet>90</a> ColumnSchema::new(CONSTRAINT_TYPE, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#91 id=91 data-nosnippet>91</a> ColumnSchema::new(ENFORCED, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#92 id=92 data-nosnippet>92</a> ]))
<a href=#93 id=93 data-nosnippet>93</a> }
<a href=#94 id=94 data-nosnippet>94</a>
<a href=#95 id=95 data-nosnippet>95</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaTableConstraintsBuilder {
<a href=#96 id=96 data-nosnippet>96</a> InformationSchemaTableConstraintsBuilder::new(
<a href=#97 id=97 data-nosnippet>97</a> <span class="self">self</span>.schema.clone(),
<a href=#98 id=98 data-nosnippet>98</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#99 id=99 data-nosnippet>99</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#100 id=100 data-nosnippet>100</a> )
<a href=#101 id=101 data-nosnippet>101</a> }
<a href=#102 id=102 data-nosnippet>102</a>}
<a href=#103 id=103 data-nosnippet>103</a>
<a href=#104 id=104 data-nosnippet>104</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaTableConstraints {
<a href=#105 id=105 data-nosnippet>105</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#106 id=106 data-nosnippet>106</a> INFORMATION_SCHEMA_TABLE_CONSTRAINTS_TABLE_ID
<a href=#107 id=107 data-nosnippet>107</a> }
<a href=#108 id=108 data-nosnippet>108</a>
<a href=#109 id=109 data-nosnippet>109</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#110 id=110 data-nosnippet>110</a> TABLE_CONSTRAINTS
<a href=#111 id=111 data-nosnippet>111</a> }
<a href=#112 id=112 data-nosnippet>112</a>
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#114 id=114 data-nosnippet>114</a> <span class="self">self</span>.schema.clone()
<a href=#115 id=115 data-nosnippet>115</a> }
<a href=#116 id=116 data-nosnippet>116</a>
<a href=#117 id=117 data-nosnippet>117</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#119 id=119 data-nosnippet>119</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#120 id=120 data-nosnippet>120</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#121 id=121 data-nosnippet>121</a> schema,
<a href=#122 id=122 data-nosnippet>122</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#123 id=123 data-nosnippet>123</a> builder
<a href=#124 id=124 data-nosnippet>124</a> .make_table_constraints(<span class="prelude-val">Some</span>(request))
<a href=#125 id=125 data-nosnippet>125</a> .<span class="kw">await
<a href=#126 id=126 data-nosnippet>126</a> </span>.map(|x| x.into_df_record_batch())
<a href=#127 id=127 data-nosnippet>127</a> .map_err(Into::into)
<a href=#128 id=128 data-nosnippet>128</a> }),
<a href=#129 id=129 data-nosnippet>129</a> ));
<a href=#130 id=130 data-nosnippet>130</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#131 id=131 data-nosnippet>131</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#132 id=132 data-nosnippet>132</a> .map_err(BoxedError::new)
<a href=#133 id=133 data-nosnippet>133</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#134 id=134 data-nosnippet>134</a> ))
<a href=#135 id=135 data-nosnippet>135</a> }
<a href=#136 id=136 data-nosnippet>136</a>}
<a href=#137 id=137 data-nosnippet>137</a>
<a href=#138 id=138 data-nosnippet>138</a><span class="kw">struct </span>InformationSchemaTableConstraintsBuilder {
<a href=#139 id=139 data-nosnippet>139</a> schema: SchemaRef,
<a href=#140 id=140 data-nosnippet>140</a> catalog_name: String,
<a href=#141 id=141 data-nosnippet>141</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#142 id=142 data-nosnippet>142</a>
<a href=#143 id=143 data-nosnippet>143</a> constraint_schemas: StringVectorBuilder,
<a href=#144 id=144 data-nosnippet>144</a> constraint_names: StringVectorBuilder,
<a href=#145 id=145 data-nosnippet>145</a> table_schemas: StringVectorBuilder,
<a href=#146 id=146 data-nosnippet>146</a> table_names: StringVectorBuilder,
<a href=#147 id=147 data-nosnippet>147</a> constraint_types: StringVectorBuilder,
<a href=#148 id=148 data-nosnippet>148</a>}
<a href=#149 id=149 data-nosnippet>149</a>
<a href=#150 id=150 data-nosnippet>150</a><span class="kw">impl </span>InformationSchemaTableConstraintsBuilder {
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">fn </span>new(
<a href=#152 id=152 data-nosnippet>152</a> schema: SchemaRef,
<a href=#153 id=153 data-nosnippet>153</a> catalog_name: String,
<a href=#154 id=154 data-nosnippet>154</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#155 id=155 data-nosnippet>155</a> ) -&gt; <span class="self">Self </span>{
<a href=#156 id=156 data-nosnippet>156</a> <span class="self">Self </span>{
<a href=#157 id=157 data-nosnippet>157</a> schema,
<a href=#158 id=158 data-nosnippet>158</a> catalog_name,
<a href=#159 id=159 data-nosnippet>159</a> catalog_manager,
<a href=#160 id=160 data-nosnippet>160</a> constraint_schemas: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#161 id=161 data-nosnippet>161</a> constraint_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#162 id=162 data-nosnippet>162</a> table_schemas: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#163 id=163 data-nosnippet>163</a> table_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#164 id=164 data-nosnippet>164</a> constraint_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#165 id=165 data-nosnippet>165</a> }
<a href=#166 id=166 data-nosnippet>166</a> }
<a href=#167 id=167 data-nosnippet>167</a>
<a href=#168 id=168 data-nosnippet>168</a> <span class="doccomment">/// Construct the `information_schema.table_constraints` virtual table
<a href=#169 id=169 data-nosnippet>169</a> </span><span class="kw">async fn </span>make_table_constraints(
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#171 id=171 data-nosnippet>171</a> request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;,
<a href=#172 id=172 data-nosnippet>172</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#173 id=173 data-nosnippet>173</a> <span class="kw">let </span>catalog_name = <span class="self">self</span>.catalog_name.clone();
<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">let </span>catalog_manager = <span class="self">self
<a href=#175 id=175 data-nosnippet>175</a> </span>.catalog_manager
<a href=#176 id=176 data-nosnippet>176</a> .upgrade()
<a href=#177 id=177 data-nosnippet>177</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#179 id=179 data-nosnippet>179</a>
<a href=#180 id=180 data-nosnippet>180</a> <span class="kw">for </span>schema_name <span class="kw">in </span>catalog_manager.schema_names(<span class="kw-2">&amp;</span>catalog_name, <span class="prelude-val">None</span>).<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#181 id=181 data-nosnippet>181</a> <span class="kw">let </span><span class="kw-2">mut </span>stream = catalog_manager.tables(<span class="kw-2">&amp;</span>catalog_name, <span class="kw-2">&amp;</span>schema_name, <span class="prelude-val">None</span>);
<a href=#182 id=182 data-nosnippet>182</a>
<a href=#183 id=183 data-nosnippet>183</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(table) = stream.try_next().<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">let </span>keys = <span class="kw-2">&amp;</span>table.table_info().meta.primary_key_indices;
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">let </span>schema = table.schema();
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">if </span>schema.timestamp_index().is_some() {
<a href=#188 id=188 data-nosnippet>188</a> <span class="self">self</span>.add_table_constraint(
<a href=#189 id=189 data-nosnippet>189</a> <span class="kw-2">&amp;</span>predicates,
<a href=#190 id=190 data-nosnippet>190</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#191 id=191 data-nosnippet>191</a> CONSTRAINT_NAME_TIME_INDEX,
<a href=#192 id=192 data-nosnippet>192</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#193 id=193 data-nosnippet>193</a> <span class="kw-2">&amp;</span>table.table_info().name,
<a href=#194 id=194 data-nosnippet>194</a> TIME_INDEX_CONSTRAINT_TYPE,
<a href=#195 id=195 data-nosnippet>195</a> );
<a href=#196 id=196 data-nosnippet>196</a> }
<a href=#197 id=197 data-nosnippet>197</a>
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">if </span>!keys.is_empty() {
<a href=#199 id=199 data-nosnippet>199</a> <span class="self">self</span>.add_table_constraint(
<a href=#200 id=200 data-nosnippet>200</a> <span class="kw-2">&amp;</span>predicates,
<a href=#201 id=201 data-nosnippet>201</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#202 id=202 data-nosnippet>202</a> CONSTRAINT_NAME_PRI,
<a href=#203 id=203 data-nosnippet>203</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#204 id=204 data-nosnippet>204</a> <span class="kw-2">&amp;</span>table.table_info().name,
<a href=#205 id=205 data-nosnippet>205</a> PRI_KEY_CONSTRAINT_TYPE,
<a href=#206 id=206 data-nosnippet>206</a> );
<a href=#207 id=207 data-nosnippet>207</a> }
<a href=#208 id=208 data-nosnippet>208</a> }
<a href=#209 id=209 data-nosnippet>209</a> }
<a href=#210 id=210 data-nosnippet>210</a>
<a href=#211 id=211 data-nosnippet>211</a> <span class="self">self</span>.finish()
<a href=#212 id=212 data-nosnippet>212</a> }
<a href=#213 id=213 data-nosnippet>213</a>
<a href=#214 id=214 data-nosnippet>214</a> <span class="kw">fn </span>add_table_constraint(
<a href=#215 id=215 data-nosnippet>215</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#216 id=216 data-nosnippet>216</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#217 id=217 data-nosnippet>217</a> constraint_schema: <span class="kw-2">&amp;</span>str,
<a href=#218 id=218 data-nosnippet>218</a> constraint_name: <span class="kw-2">&amp;</span>str,
<a href=#219 id=219 data-nosnippet>219</a> table_schema: <span class="kw-2">&amp;</span>str,
<a href=#220 id=220 data-nosnippet>220</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#221 id=221 data-nosnippet>221</a> constraint_type: <span class="kw-2">&amp;</span>str,
<a href=#222 id=222 data-nosnippet>222</a> ) {
<a href=#223 id=223 data-nosnippet>223</a> <span class="kw">let </span>row = [
<a href=#224 id=224 data-nosnippet>224</a> (CONSTRAINT_SCHEMA, <span class="kw-2">&amp;</span>Value::from(constraint_schema)),
<a href=#225 id=225 data-nosnippet>225</a> (CONSTRAINT_NAME, <span class="kw-2">&amp;</span>Value::from(constraint_name)),
<a href=#226 id=226 data-nosnippet>226</a> (TABLE_SCHEMA, <span class="kw-2">&amp;</span>Value::from(table_schema)),
<a href=#227 id=227 data-nosnippet>227</a> (TABLE_NAME, <span class="kw-2">&amp;</span>Value::from(table_name)),
<a href=#228 id=228 data-nosnippet>228</a> (CONSTRAINT_TYPE, <span class="kw-2">&amp;</span>Value::from(constraint_type)),
<a href=#229 id=229 data-nosnippet>229</a> ];
<a href=#230 id=230 data-nosnippet>230</a>
<a href=#231 id=231 data-nosnippet>231</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">return</span>;
<a href=#233 id=233 data-nosnippet>233</a> }
<a href=#234 id=234 data-nosnippet>234</a>
<a href=#235 id=235 data-nosnippet>235</a> <span class="self">self</span>.constraint_schemas.push(<span class="prelude-val">Some</span>(constraint_schema));
<a href=#236 id=236 data-nosnippet>236</a> <span class="self">self</span>.constraint_names.push(<span class="prelude-val">Some</span>(constraint_name));
<a href=#237 id=237 data-nosnippet>237</a> <span class="self">self</span>.table_schemas.push(<span class="prelude-val">Some</span>(table_schema));
<a href=#238 id=238 data-nosnippet>238</a> <span class="self">self</span>.table_names.push(<span class="prelude-val">Some</span>(table_name));
<a href=#239 id=239 data-nosnippet>239</a> <span class="self">self</span>.constraint_types.push(<span class="prelude-val">Some</span>(constraint_type));
<a href=#240 id=240 data-nosnippet>240</a> }
<a href=#241 id=241 data-nosnippet>241</a>
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">let </span>rows_num = <span class="self">self</span>.constraint_names.len();
<a href=#244 id=244 data-nosnippet>244</a>
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw">let </span>constraint_catalogs = Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"def"</span>; rows_num]));
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">let </span>enforceds = Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"YES"</span>; rows_num]));
<a href=#247 id=247 data-nosnippet>247</a>
<a href=#248 id=248 data-nosnippet>248</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#249 id=249 data-nosnippet>249</a> constraint_catalogs,
<a href=#250 id=250 data-nosnippet>250</a> Arc::new(<span class="self">self</span>.constraint_schemas.finish()),
<a href=#251 id=251 data-nosnippet>251</a> Arc::new(<span class="self">self</span>.constraint_names.finish()),
<a href=#252 id=252 data-nosnippet>252</a> Arc::new(<span class="self">self</span>.table_schemas.finish()),
<a href=#253 id=253 data-nosnippet>253</a> Arc::new(<span class="self">self</span>.table_names.finish()),
<a href=#254 id=254 data-nosnippet>254</a> Arc::new(<span class="self">self</span>.constraint_types.finish()),
<a href=#255 id=255 data-nosnippet>255</a> enforceds,
<a href=#256 id=256 data-nosnippet>256</a> ];
<a href=#257 id=257 data-nosnippet>257</a>
<a href=#258 id=258 data-nosnippet>258</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#259 id=259 data-nosnippet>259</a> }
<a href=#260 id=260 data-nosnippet>260</a>}
<a href=#261 id=261 data-nosnippet>261</a>
<a href=#262 id=262 data-nosnippet>262</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaTableConstraints {
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#264 id=264 data-nosnippet>264</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#265 id=265 data-nosnippet>265</a> }
<a href=#266 id=266 data-nosnippet>266</a>
<a href=#267 id=267 data-nosnippet>267</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#269 id=269 data-nosnippet>269</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#270 id=270 data-nosnippet>270</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#271 id=271 data-nosnippet>271</a> schema,
<a href=#272 id=272 data-nosnippet>272</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#273 id=273 data-nosnippet>273</a> builder
<a href=#274 id=274 data-nosnippet>274</a> .make_table_constraints(<span class="prelude-val">None</span>)
<a href=#275 id=275 data-nosnippet>275</a> .<span class="kw">await
<a href=#276 id=276 data-nosnippet>276</a> </span>.map(|x| x.into_df_record_batch())
<a href=#277 id=277 data-nosnippet>277</a> .map_err(Into::into)
<a href=#278 id=278 data-nosnippet>278</a> }),
<a href=#279 id=279 data-nosnippet>279</a> ))
<a href=#280 id=280 data-nosnippet>280</a> }
<a href=#281 id=281 data-nosnippet>281</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,63 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/table_names.rs`."><title>table_names.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>table_names.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! All table names in `information_schema`.
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a></span><span class="kw">pub const </span>TABLES: <span class="kw-2">&amp;</span>str = <span class="string">"tables"</span>;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">pub const </span>COLUMNS: <span class="kw-2">&amp;</span>str = <span class="string">"columns"</span>;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">pub const </span>ENGINES: <span class="kw-2">&amp;</span>str = <span class="string">"engines"</span>;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">pub const </span>COLUMN_PRIVILEGES: <span class="kw-2">&amp;</span>str = <span class="string">"column_privileges"</span>;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">pub const </span>COLUMN_STATISTICS: <span class="kw-2">&amp;</span>str = <span class="string">"column_statistics"</span>;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">pub const </span>BUILD_INFO: <span class="kw-2">&amp;</span>str = <span class="string">"build_info"</span>;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">pub const </span>CHARACTER_SETS: <span class="kw-2">&amp;</span>str = <span class="string">"character_sets"</span>;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">pub const </span>COLLATIONS: <span class="kw-2">&amp;</span>str = <span class="string">"collations"</span>;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">pub const </span>COLLATION_CHARACTER_SET_APPLICABILITY: <span class="kw-2">&amp;</span>str = <span class="string">"collation_character_set_applicability"</span>;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">pub const </span>CHECK_CONSTRAINTS: <span class="kw-2">&amp;</span>str = <span class="string">"check_constraints"</span>;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">pub const </span>EVENTS: <span class="kw-2">&amp;</span>str = <span class="string">"events"</span>;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">pub const </span>FILES: <span class="kw-2">&amp;</span>str = <span class="string">"files"</span>;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">pub const </span>SCHEMATA: <span class="kw-2">&amp;</span>str = <span class="string">"schemata"</span>;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">pub const </span>KEY_COLUMN_USAGE: <span class="kw-2">&amp;</span>str = <span class="string">"key_column_usage"</span>;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">pub const </span>OPTIMIZER_TRACE: <span class="kw-2">&amp;</span>str = <span class="string">"optimizer_trace"</span>;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">pub const </span>PARAMETERS: <span class="kw-2">&amp;</span>str = <span class="string">"parameters"</span>;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">pub const </span>PROFILING: <span class="kw-2">&amp;</span>str = <span class="string">"profiling"</span>;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">pub const </span>REFERENTIAL_CONSTRAINTS: <span class="kw-2">&amp;</span>str = <span class="string">"referential_constraints"</span>;
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">pub const </span>ROUTINES: <span class="kw-2">&amp;</span>str = <span class="string">"routines"</span>;
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">pub const </span>SCHEMA_PRIVILEGES: <span class="kw-2">&amp;</span>str = <span class="string">"schema_privileges"</span>;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">pub const </span>TABLE_PRIVILEGES: <span class="kw-2">&amp;</span>str = <span class="string">"table_privileges"</span>;
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">pub const </span>TRIGGERS: <span class="kw-2">&amp;</span>str = <span class="string">"triggers"</span>;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">pub const </span>GLOBAL_STATUS: <span class="kw-2">&amp;</span>str = <span class="string">"global_status"</span>;
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">pub const </span>SESSION_STATUS: <span class="kw-2">&amp;</span>str = <span class="string">"session_status"</span>;
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">pub const </span>PARTITIONS: <span class="kw-2">&amp;</span>str = <span class="string">"partitions"</span>;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">pub const </span>REGION_PEERS: <span class="kw-2">&amp;</span>str = <span class="string">"region_peers"</span>;
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">pub const </span>TABLE_CONSTRAINTS: <span class="kw-2">&amp;</span>str = <span class="string">"table_constraints"</span>;
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">pub const </span>CLUSTER_INFO: <span class="kw-2">&amp;</span>str = <span class="string">"cluster_info"</span>;
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">pub const </span>VIEWS: <span class="kw-2">&amp;</span>str = <span class="string">"views"</span>;
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">pub const </span>FLOWS: <span class="kw-2">&amp;</span>str = <span class="string">"flows"</span>;
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">pub const </span>FLOW_STATISTICS: <span class="kw-2">&amp;</span>str = <span class="string">"flow_statistics"</span>;
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">pub const </span>PROCEDURE_INFO: <span class="kw-2">&amp;</span>str = <span class="string">"procedure_info"</span>;
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">pub const </span>REGION_INFO: <span class="kw-2">&amp;</span>str = <span class="string">"region_info"</span>;
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">pub const </span>REGION_STATISTICS: <span class="kw-2">&amp;</span>str = <span class="string">"region_statistics"</span>;
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">pub const </span>PROCESS_LIST: <span class="kw-2">&amp;</span>str = <span class="string">"process_list"</span>;
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">pub const </span>SSTS_MANIFEST: <span class="kw-2">&amp;</span>str = <span class="string">"ssts_manifest"</span>;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">pub const </span>SSTS_STORAGE: <span class="kw-2">&amp;</span>str = <span class="string">"ssts_storage"</span>;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">pub const </span>SSTS_INDEX_META: <span class="kw-2">&amp;</span>str = <span class="string">"ssts_index_meta"</span>;
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">pub const </span>TABLE_SEMANTICS: <span class="kw-2">&amp;</span>str = <span class="string">"table_semantics"</span>;
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">pub const </span>STATISTICS: <span class="kw-2">&amp;</span>str = <span class="string">"statistics"</span>;
<a href=#57 id=57 data-nosnippet>57</a><span class="kw">pub const </span>RECYCLE_BIN: <span class="kw-2">&amp;</span>str = <span class="string">"recycle_bin"</span>;
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">pub const </span>PLUGINS: <span class="kw-2">&amp;</span>str = <span class="string">"plugins"</span>;
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">pub const </span>USER_PRIVILEGES: <span class="kw-2">&amp;</span>str = <span class="string">"user_privileges"</span>;
<a href=#60 id=60 data-nosnippet>60</a><span class="doccomment">/// MySQL's session list. GreptimeDB reports its own sessions through [`PROCESS_LIST`];
<a href=#61 id=61 data-nosnippet>61</a>/// this table only exists so MySQL tooling finds the name and column shape it expects.
<a href=#62 id=62 data-nosnippet>62</a></span><span class="kw">pub const </span>PROCESSLIST: <span class="kw-2">&amp;</span>str = <span class="string">"processlist"</span>;
</code></pre></div></section></main></body></html>
@@ -0,0 +1,549 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/table_semantics.rs`."><title>table_semantics.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>table_semantics.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! `information_schema.table_semantics`: the queryable view over the table
<a href=#16 id=16 data-nosnippet>16</a>//! semantic layer. One row per table that is part of it, so a consumer can
<a href=#17 id=17 data-nosnippet>17</a>//! discover the observability concept a table stands for with a single SQL
<a href=#18 id=18 data-nosnippet>18</a>//! query instead of parsing every table's `create_options`.
<a href=#19 id=19 data-nosnippet>19</a>//!
<a href=#20 id=20 data-nosnippet>20</a>//! The few signal-agnostic keys are promoted to their own columns
<a href=#21 id=21 data-nosnippet>21</a>//! (`signal_type` / `source` / `source_version` / `pipeline` /
<a href=#22 id=22 data-nosnippet>22</a>//! `metadata_quality`); the remaining signal-specific keys are folded into a
<a href=#23 id=23 data-nosnippet>23</a>//! `semantic_options` JSON string, keyed by the option name with the
<a href=#24 id=24 data-nosnippet>24</a>//! `greptime.semantic.` prefix stripped.
<a href=#25 id=25 data-nosnippet>25</a>//!
<a href=#26 id=26 data-nosnippet>26</a>//! `entity_declarations` reports the entities the table contributes to the
<a href=#27 id=27 data-nosnippet>27</a>//! graph, including the ones the conventions derive with no option set — so a
<a href=#28 id=28 data-nosnippet>28</a>//! table with no semantic option still gets a row. It shows the outcome, not
<a href=#29 id=29 data-nosnippet>29</a>//! the reasoning: a declaration dropped for naming a missing column is simply
<a href=#30 id=30 data-nosnippet>30</a>//! absent, and only the log says why.
<a href=#31 id=31 data-nosnippet>31</a>
<a href=#32 id=32 data-nosnippet>32</a></span><span class="kw">use </span>std::collections::BTreeMap;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#34 id=34 data-nosnippet>34</a>
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_TABLE_SEMANTICS_TABLE_ID;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, ScalarVectorBuilder, VectorRef};
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">use </span>datatypes::value::Value;
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">use </span>datatypes::vectors::{StringVectorBuilder, UInt32VectorBuilder};
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">use </span>futures::TryStreamExt;
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">use </span>serde::Serialize;
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">use </span>snafu::{OptionExt, ResultExt};
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">use </span>table::metadata::TableInfo;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">use </span>table::requests::{
<a href=#54 id=54 data-nosnippet>54</a> SEMANTIC_METRIC_METADATA_QUALITY, SEMANTIC_PIPELINE, SEMANTIC_PREFIX, SEMANTIC_SIGNAL_TYPE,
<a href=#55 id=55 data-nosnippet>55</a> SEMANTIC_SOURCE, SEMANTIC_SOURCE_VERSION, is_semantic_option_key,
<a href=#56 id=56 data-nosnippet>56</a>};
<a href=#57 id=57 data-nosnippet>57</a>
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#60 id=60 data-nosnippet>60</a> CreateRecordBatchSnafu, InternalSnafu, <span class="prelude-ty">Result</span>, UpgradeWeakCatalogManagerRefSnafu,
<a href=#61 id=61 data-nosnippet>61</a>};
<a href=#62 id=62 data-nosnippet>62</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{InformationTable, Predicates, TABLE_SEMANTICS};
<a href=#63 id=63 data-nosnippet>63</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::semantic_graph::{EntityGraphProviderRef, TableEntityDeclaration};
<a href=#64 id=64 data-nosnippet>64</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::utils;
<a href=#65 id=65 data-nosnippet>65</a>
<a href=#66 id=66 data-nosnippet>66</a><span class="kw">pub const </span>TABLE_CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"table_catalog"</span>;
<a href=#67 id=67 data-nosnippet>67</a><span class="kw">pub const </span>TABLE_SCHEMA: <span class="kw-2">&amp;</span>str = <span class="string">"table_schema"</span>;
<a href=#68 id=68 data-nosnippet>68</a><span class="kw">pub const </span>TABLE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_name"</span>;
<a href=#69 id=69 data-nosnippet>69</a><span class="kw">pub const </span>TABLE_ID: <span class="kw-2">&amp;</span>str = <span class="string">"table_id"</span>;
<a href=#70 id=70 data-nosnippet>70</a><span class="kw">pub const </span>SIGNAL_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"signal_type"</span>;
<a href=#71 id=71 data-nosnippet>71</a><span class="kw">pub const </span>SOURCE: <span class="kw-2">&amp;</span>str = <span class="string">"source"</span>;
<a href=#72 id=72 data-nosnippet>72</a><span class="kw">pub const </span>SOURCE_VERSION: <span class="kw-2">&amp;</span>str = <span class="string">"source_version"</span>;
<a href=#73 id=73 data-nosnippet>73</a><span class="kw">pub const </span>PIPELINE: <span class="kw-2">&amp;</span>str = <span class="string">"pipeline"</span>;
<a href=#74 id=74 data-nosnippet>74</a><span class="kw">pub const </span>METADATA_QUALITY: <span class="kw-2">&amp;</span>str = <span class="string">"metadata_quality"</span>;
<a href=#75 id=75 data-nosnippet>75</a><span class="kw">pub const </span>SEMANTIC_OPTIONS: <span class="kw-2">&amp;</span>str = <span class="string">"semantic_options"</span>;
<a href=#76 id=76 data-nosnippet>76</a><span class="kw">pub const </span>ENTITY_DECLARATIONS: <span class="kw-2">&amp;</span>str = <span class="string">"entity_declarations"</span>;
<a href=#77 id=77 data-nosnippet>77</a>
<a href=#78 id=78 data-nosnippet>78</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#79 id=79 data-nosnippet>79</a>
<a href=#80 id=80 data-nosnippet>80</a><span class="kw">fn </span>optional_value(v: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt;) -&gt; Value {
<a href=#81 id=81 data-nosnippet>81</a> v.map(Value::from).unwrap_or(Value::Null)
<a href=#82 id=82 data-nosnippet>82</a>}
<a href=#83 id=83 data-nosnippet>83</a>
<a href=#84 id=84 data-nosnippet>84</a><span class="doccomment">/// The JSON form of one declaration in the `entity_declarations` column.
<a href=#85 id=85 data-nosnippet>85</a></span><span class="attr">#[derive(Serialize)]
<a href=#86 id=86 data-nosnippet>86</a></span><span class="kw">struct </span>DeclarationEntry {
<a href=#87 id=87 data-nosnippet>87</a> entity_type: String,
<a href=#88 id=88 data-nosnippet>88</a> origin: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str,
<a href=#89 id=89 data-nosnippet>89</a> id: Vec&lt;String&gt;,
<a href=#90 id=90 data-nosnippet>90</a> <span class="attr">#[serde(skip_serializing_if = <span class="string">"Option::is_none"</span>)]
<a href=#91 id=91 data-nosnippet>91</a> </span>id_qualifier: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#92 id=92 data-nosnippet>92</a> <span class="attr">#[serde(skip_serializing_if = <span class="string">"Vec::is_empty"</span>)]
<a href=#93 id=93 data-nosnippet>93</a> </span>superseded_by: Vec&lt;String&gt;,
<a href=#94 id=94 data-nosnippet>94</a> <span class="attr">#[serde(skip_serializing_if = <span class="string">"Vec::is_empty"</span>)]
<a href=#95 id=95 data-nosnippet>95</a> </span>descriptive: Vec&lt;String&gt;,
<a href=#96 id=96 data-nosnippet>96</a> <span class="attr">#[serde(skip_serializing_if = <span class="string">"Vec::is_empty"</span>)]
<a href=#97 id=97 data-nosnippet>97</a> </span>scope: Vec&lt;String&gt;,
<a href=#98 id=98 data-nosnippet>98</a>}
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a><span class="kw">impl </span>From&lt;TableEntityDeclaration&gt; <span class="kw">for </span>DeclarationEntry {
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">fn </span>from(declaration: TableEntityDeclaration) -&gt; <span class="self">Self </span>{
<a href=#102 id=102 data-nosnippet>102</a> <span class="self">Self </span>{
<a href=#103 id=103 data-nosnippet>103</a> entity_type: declaration.entity_type,
<a href=#104 id=104 data-nosnippet>104</a> origin: declaration.origin.as_str(),
<a href=#105 id=105 data-nosnippet>105</a> id: declaration.id_columns,
<a href=#106 id=106 data-nosnippet>106</a> id_qualifier: declaration.id_qualifier,
<a href=#107 id=107 data-nosnippet>107</a> superseded_by: declaration.superseded_by_columns,
<a href=#108 id=108 data-nosnippet>108</a> descriptive: declaration.descriptive_columns,
<a href=#109 id=109 data-nosnippet>109</a> scope: declaration.scope_columns,
<a href=#110 id=110 data-nosnippet>110</a> }
<a href=#111 id=111 data-nosnippet>111</a> }
<a href=#112 id=112 data-nosnippet>112</a>}
<a href=#113 id=113 data-nosnippet>113</a>
<a href=#114 id=114 data-nosnippet>114</a><span class="kw">fn </span>entity_declarations_json(declarations: Vec&lt;TableEntityDeclaration&gt;) -&gt; <span class="prelude-ty">Option</span>&lt;String&gt; {
<a href=#115 id=115 data-nosnippet>115</a> <span class="kw">if </span>declarations.is_empty() {
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw">return </span><span class="prelude-val">None</span>;
<a href=#117 id=117 data-nosnippet>117</a> }
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">let </span>entries: Vec&lt;DeclarationEntry&gt; = declarations.into_iter().map(Into::into).collect();
<a href=#119 id=119 data-nosnippet>119</a> <span class="comment">// Fold a failure into `None` rather than panicking the query path, as the
<a href=#120 id=120 data-nosnippet>120</a> // options tail does.
<a href=#121 id=121 data-nosnippet>121</a> </span>serde_json::to_string(<span class="kw-2">&amp;</span>entries).ok()
<a href=#122 id=122 data-nosnippet>122</a>}
<a href=#123 id=123 data-nosnippet>123</a>
<a href=#124 id=124 data-nosnippet>124</a><span class="doccomment">/// The semantic projection of a single table: the signal-agnostic keys promoted
<a href=#125 id=125 data-nosnippet>125</a>/// to columns, plus a JSON tail for the rest. Borrows from the table's options.
<a href=#126 id=126 data-nosnippet>126</a></span><span class="attr">#[derive(Default)]
<a href=#127 id=127 data-nosnippet>127</a></span><span class="kw">struct </span>SemanticRow&lt;<span class="lifetime">'a</span>&gt; {
<a href=#128 id=128 data-nosnippet>128</a> signal_type: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span><span class="lifetime">'a </span>str&gt;,
<a href=#129 id=129 data-nosnippet>129</a> source: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span><span class="lifetime">'a </span>str&gt;,
<a href=#130 id=130 data-nosnippet>130</a> source_version: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span><span class="lifetime">'a </span>str&gt;,
<a href=#131 id=131 data-nosnippet>131</a> pipeline: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span><span class="lifetime">'a </span>str&gt;,
<a href=#132 id=132 data-nosnippet>132</a> metadata_quality: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span><span class="lifetime">'a </span>str&gt;,
<a href=#133 id=133 data-nosnippet>133</a> options_json: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#134 id=134 data-nosnippet>134</a>}
<a href=#135 id=135 data-nosnippet>135</a>
<a href=#136 id=136 data-nosnippet>136</a><span class="kw">impl</span>&lt;<span class="lifetime">'a</span>&gt; SemanticRow&lt;<span class="lifetime">'a</span>&gt; {
<a href=#137 id=137 data-nosnippet>137</a> <span class="doccomment">/// Projects a table's options onto the semantic schema, or `None` when the
<a href=#138 id=138 data-nosnippet>138</a> /// table carries no semantic key at all.
<a href=#139 id=139 data-nosnippet>139</a> </span><span class="kw">fn </span>extract(table_info: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>TableInfo) -&gt; <span class="prelude-ty">Option</span>&lt;<span class="self">Self</span>&gt; {
<a href=#140 id=140 data-nosnippet>140</a> <span class="kw">let </span><span class="kw-2">mut </span>signal_type = <span class="prelude-val">None</span>;
<a href=#141 id=141 data-nosnippet>141</a> <span class="kw">let </span><span class="kw-2">mut </span>source = <span class="prelude-val">None</span>;
<a href=#142 id=142 data-nosnippet>142</a> <span class="kw">let </span><span class="kw-2">mut </span>source_version = <span class="prelude-val">None</span>;
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">let </span><span class="kw-2">mut </span>pipeline = <span class="prelude-val">None</span>;
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">let </span><span class="kw-2">mut </span>metadata_quality = <span class="prelude-val">None</span>;
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">let </span><span class="kw-2">mut </span>rest = BTreeMap::new();
<a href=#146 id=146 data-nosnippet>146</a>
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">for </span>(key, value) <span class="kw">in </span><span class="kw-2">&amp;</span>table_info.meta.options.extra_options {
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">if </span>!is_semantic_option_key(key) {
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">continue</span>;
<a href=#150 id=150 data-nosnippet>150</a> }
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">match </span>key.as_str() {
<a href=#152 id=152 data-nosnippet>152</a> SEMANTIC_SIGNAL_TYPE =&gt; signal_type = <span class="prelude-val">Some</span>(value.as_str()),
<a href=#153 id=153 data-nosnippet>153</a> SEMANTIC_SOURCE =&gt; source = <span class="prelude-val">Some</span>(value.as_str()),
<a href=#154 id=154 data-nosnippet>154</a> SEMANTIC_SOURCE_VERSION =&gt; source_version = <span class="prelude-val">Some</span>(value.as_str()),
<a href=#155 id=155 data-nosnippet>155</a> SEMANTIC_PIPELINE =&gt; pipeline = <span class="prelude-val">Some</span>(value.as_str()),
<a href=#156 id=156 data-nosnippet>156</a> SEMANTIC_METRIC_METADATA_QUALITY =&gt; metadata_quality = <span class="prelude-val">Some</span>(value.as_str()),
<a href=#157 id=157 data-nosnippet>157</a> <span class="kw">_ </span>=&gt; {
<a href=#158 id=158 data-nosnippet>158</a> <span class="kw">let </span>short = key.strip_prefix(SEMANTIC_PREFIX).unwrap_or(key);
<a href=#159 id=159 data-nosnippet>159</a> rest.insert(short, value.as_str());
<a href=#160 id=160 data-nosnippet>160</a> }
<a href=#161 id=161 data-nosnippet>161</a> }
<a href=#162 id=162 data-nosnippet>162</a> }
<a href=#163 id=163 data-nosnippet>163</a>
<a href=#164 id=164 data-nosnippet>164</a> <span class="kw">let </span>has_any = signal_type.is_some()
<a href=#165 id=165 data-nosnippet>165</a> || source.is_some()
<a href=#166 id=166 data-nosnippet>166</a> || source_version.is_some()
<a href=#167 id=167 data-nosnippet>167</a> || pipeline.is_some()
<a href=#168 id=168 data-nosnippet>168</a> || metadata_quality.is_some()
<a href=#169 id=169 data-nosnippet>169</a> || !rest.is_empty();
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw">if </span>!has_any {
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">return </span><span class="prelude-val">None</span>;
<a href=#172 id=172 data-nosnippet>172</a> }
<a href=#173 id=173 data-nosnippet>173</a>
<a href=#174 id=174 data-nosnippet>174</a> <span class="comment">// `rest` is a `BTreeMap`, so the JSON keys come out sorted and the output
<a href=#175 id=175 data-nosnippet>175</a> // is stable across runs. Serializing a string map can't realistically fail,
<a href=#176 id=176 data-nosnippet>176</a> // but fold a failure into `None` rather than panicking the query path.
<a href=#177 id=177 data-nosnippet>177</a> </span><span class="kw">let </span>options_json = (!rest.is_empty())
<a href=#178 id=178 data-nosnippet>178</a> .then(|| serde_json::to_string(<span class="kw-2">&amp;</span>rest).ok())
<a href=#179 id=179 data-nosnippet>179</a> .flatten();
<a href=#180 id=180 data-nosnippet>180</a>
<a href=#181 id=181 data-nosnippet>181</a> <span class="prelude-val">Some</span>(<span class="self">Self </span>{
<a href=#182 id=182 data-nosnippet>182</a> signal_type,
<a href=#183 id=183 data-nosnippet>183</a> source,
<a href=#184 id=184 data-nosnippet>184</a> source_version,
<a href=#185 id=185 data-nosnippet>185</a> pipeline,
<a href=#186 id=186 data-nosnippet>186</a> metadata_quality,
<a href=#187 id=187 data-nosnippet>187</a> options_json,
<a href=#188 id=188 data-nosnippet>188</a> })
<a href=#189 id=189 data-nosnippet>189</a> }
<a href=#190 id=190 data-nosnippet>190</a>}
<a href=#191 id=191 data-nosnippet>191</a>
<a href=#192 id=192 data-nosnippet>192</a><span class="attr">#[derive(Debug)]
<a href=#193 id=193 data-nosnippet>193</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaTableSemantics {
<a href=#194 id=194 data-nosnippet>194</a> schema: SchemaRef,
<a href=#195 id=195 data-nosnippet>195</a> catalog_name: String,
<a href=#196 id=196 data-nosnippet>196</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#197 id=197 data-nosnippet>197</a>}
<a href=#198 id=198 data-nosnippet>198</a>
<a href=#199 id=199 data-nosnippet>199</a><span class="kw">impl </span>InformationSchemaTableSemantics {
<a href=#200 id=200 data-nosnippet>200</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_name: String, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#201 id=201 data-nosnippet>201</a> <span class="self">Self </span>{
<a href=#202 id=202 data-nosnippet>202</a> schema: <span class="self">Self</span>::schema(),
<a href=#203 id=203 data-nosnippet>203</a> catalog_name,
<a href=#204 id=204 data-nosnippet>204</a> catalog_manager,
<a href=#205 id=205 data-nosnippet>205</a> }
<a href=#206 id=206 data-nosnippet>206</a> }
<a href=#207 id=207 data-nosnippet>207</a>
<a href=#208 id=208 data-nosnippet>208</a> <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#209 id=209 data-nosnippet>209</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#210 id=210 data-nosnippet>210</a> ColumnSchema::new(TABLE_CATALOG, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#211 id=211 data-nosnippet>211</a> ColumnSchema::new(TABLE_SCHEMA, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#212 id=212 data-nosnippet>212</a> ColumnSchema::new(TABLE_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#213 id=213 data-nosnippet>213</a> ColumnSchema::new(TABLE_ID, ConcreteDataType::uint32_datatype(), <span class="bool-val">false</span>),
<a href=#214 id=214 data-nosnippet>214</a> ColumnSchema::new(SIGNAL_TYPE, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#215 id=215 data-nosnippet>215</a> ColumnSchema::new(SOURCE, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#216 id=216 data-nosnippet>216</a> ColumnSchema::new(SOURCE_VERSION, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#217 id=217 data-nosnippet>217</a> ColumnSchema::new(PIPELINE, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#218 id=218 data-nosnippet>218</a> ColumnSchema::new(METADATA_QUALITY, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#219 id=219 data-nosnippet>219</a> ColumnSchema::new(SEMANTIC_OPTIONS, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#220 id=220 data-nosnippet>220</a> ColumnSchema::new(
<a href=#221 id=221 data-nosnippet>221</a> ENTITY_DECLARATIONS,
<a href=#222 id=222 data-nosnippet>222</a> ConcreteDataType::string_datatype(),
<a href=#223 id=223 data-nosnippet>223</a> <span class="bool-val">true</span>,
<a href=#224 id=224 data-nosnippet>224</a> ),
<a href=#225 id=225 data-nosnippet>225</a> ]))
<a href=#226 id=226 data-nosnippet>226</a> }
<a href=#227 id=227 data-nosnippet>227</a>
<a href=#228 id=228 data-nosnippet>228</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaSemanticTablesBuilder {
<a href=#229 id=229 data-nosnippet>229</a> InformationSchemaSemanticTablesBuilder::new(
<a href=#230 id=230 data-nosnippet>230</a> <span class="self">self</span>.schema.clone(),
<a href=#231 id=231 data-nosnippet>231</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#232 id=232 data-nosnippet>232</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#233 id=233 data-nosnippet>233</a> )
<a href=#234 id=234 data-nosnippet>234</a> }
<a href=#235 id=235 data-nosnippet>235</a>}
<a href=#236 id=236 data-nosnippet>236</a>
<a href=#237 id=237 data-nosnippet>237</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaTableSemantics {
<a href=#238 id=238 data-nosnippet>238</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#239 id=239 data-nosnippet>239</a> INFORMATION_SCHEMA_TABLE_SEMANTICS_TABLE_ID
<a href=#240 id=240 data-nosnippet>240</a> }
<a href=#241 id=241 data-nosnippet>241</a>
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#243 id=243 data-nosnippet>243</a> TABLE_SEMANTICS
<a href=#244 id=244 data-nosnippet>244</a> }
<a href=#245 id=245 data-nosnippet>245</a>
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#247 id=247 data-nosnippet>247</a> <span class="self">self</span>.schema.clone()
<a href=#248 id=248 data-nosnippet>248</a> }
<a href=#249 id=249 data-nosnippet>249</a>
<a href=#250 id=250 data-nosnippet>250</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#251 id=251 data-nosnippet>251</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#253 id=253 data-nosnippet>253</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#254 id=254 data-nosnippet>254</a> schema,
<a href=#255 id=255 data-nosnippet>255</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#256 id=256 data-nosnippet>256</a> builder
<a href=#257 id=257 data-nosnippet>257</a> .make_tables(<span class="prelude-val">Some</span>(request))
<a href=#258 id=258 data-nosnippet>258</a> .<span class="kw">await
<a href=#259 id=259 data-nosnippet>259</a> </span>.map(|x| x.into_df_record_batch())
<a href=#260 id=260 data-nosnippet>260</a> .map_err(|err| datafusion::error::DataFusionError::External(Box::new(err)))
<a href=#261 id=261 data-nosnippet>261</a> }),
<a href=#262 id=262 data-nosnippet>262</a> ));
<a href=#263 id=263 data-nosnippet>263</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#264 id=264 data-nosnippet>264</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#265 id=265 data-nosnippet>265</a> .map_err(BoxedError::new)
<a href=#266 id=266 data-nosnippet>266</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#267 id=267 data-nosnippet>267</a> ))
<a href=#268 id=268 data-nosnippet>268</a> }
<a href=#269 id=269 data-nosnippet>269</a>}
<a href=#270 id=270 data-nosnippet>270</a>
<a href=#271 id=271 data-nosnippet>271</a><span class="kw">struct </span>InformationSchemaSemanticTablesBuilder {
<a href=#272 id=272 data-nosnippet>272</a> schema: SchemaRef,
<a href=#273 id=273 data-nosnippet>273</a> catalog_name: String,
<a href=#274 id=274 data-nosnippet>274</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#275 id=275 data-nosnippet>275</a>
<a href=#276 id=276 data-nosnippet>276</a> catalog_names: StringVectorBuilder,
<a href=#277 id=277 data-nosnippet>277</a> schema_names: StringVectorBuilder,
<a href=#278 id=278 data-nosnippet>278</a> table_names: StringVectorBuilder,
<a href=#279 id=279 data-nosnippet>279</a> table_ids: UInt32VectorBuilder,
<a href=#280 id=280 data-nosnippet>280</a> signal_types: StringVectorBuilder,
<a href=#281 id=281 data-nosnippet>281</a> sources: StringVectorBuilder,
<a href=#282 id=282 data-nosnippet>282</a> source_versions: StringVectorBuilder,
<a href=#283 id=283 data-nosnippet>283</a> pipelines: StringVectorBuilder,
<a href=#284 id=284 data-nosnippet>284</a> metadata_qualities: StringVectorBuilder,
<a href=#285 id=285 data-nosnippet>285</a> semantic_options: StringVectorBuilder,
<a href=#286 id=286 data-nosnippet>286</a> entity_declarations: StringVectorBuilder,
<a href=#287 id=287 data-nosnippet>287</a>}
<a href=#288 id=288 data-nosnippet>288</a>
<a href=#289 id=289 data-nosnippet>289</a><span class="kw">impl </span>InformationSchemaSemanticTablesBuilder {
<a href=#290 id=290 data-nosnippet>290</a> <span class="kw">fn </span>new(
<a href=#291 id=291 data-nosnippet>291</a> schema: SchemaRef,
<a href=#292 id=292 data-nosnippet>292</a> catalog_name: String,
<a href=#293 id=293 data-nosnippet>293</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#294 id=294 data-nosnippet>294</a> ) -&gt; <span class="self">Self </span>{
<a href=#295 id=295 data-nosnippet>295</a> <span class="self">Self </span>{
<a href=#296 id=296 data-nosnippet>296</a> schema,
<a href=#297 id=297 data-nosnippet>297</a> catalog_name,
<a href=#298 id=298 data-nosnippet>298</a> catalog_manager,
<a href=#299 id=299 data-nosnippet>299</a> catalog_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#300 id=300 data-nosnippet>300</a> schema_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#301 id=301 data-nosnippet>301</a> table_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#302 id=302 data-nosnippet>302</a> table_ids: UInt32VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#303 id=303 data-nosnippet>303</a> signal_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#304 id=304 data-nosnippet>304</a> sources: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#305 id=305 data-nosnippet>305</a> source_versions: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#306 id=306 data-nosnippet>306</a> pipelines: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#307 id=307 data-nosnippet>307</a> metadata_qualities: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#308 id=308 data-nosnippet>308</a> semantic_options: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#309 id=309 data-nosnippet>309</a> entity_declarations: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#310 id=310 data-nosnippet>310</a> }
<a href=#311 id=311 data-nosnippet>311</a> }
<a href=#312 id=312 data-nosnippet>312</a>
<a href=#313 id=313 data-nosnippet>313</a> <span class="kw">async fn </span>make_tables(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#314 id=314 data-nosnippet>314</a> <span class="kw">let </span>catalog_name = <span class="self">self</span>.catalog_name.clone();
<a href=#315 id=315 data-nosnippet>315</a> <span class="kw">let </span>catalog_manager = <span class="self">self
<a href=#316 id=316 data-nosnippet>316</a> </span>.catalog_manager
<a href=#317 id=317 data-nosnippet>317</a> .upgrade()
<a href=#318 id=318 data-nosnippet>318</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#319 id=319 data-nosnippet>319</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#320 id=320 data-nosnippet>320</a> <span class="comment">// Resolved once for the whole scan: the lookup downcasts the catalog
<a href=#321 id=321 data-nosnippet>321</a> // manager, while the per-table call behind it is pure metadata work.
<a href=#322 id=322 data-nosnippet>322</a> </span><span class="kw">let </span>graph_provider = utils::entity_graph_provider(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#323 id=323 data-nosnippet>323</a>
<a href=#324 id=324 data-nosnippet>324</a> <span class="kw">for </span>schema_name <span class="kw">in </span>catalog_manager.schema_names(<span class="kw-2">&amp;</span>catalog_name, <span class="prelude-val">None</span>).<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#325 id=325 data-nosnippet>325</a> <span class="kw">let </span><span class="kw-2">mut </span>table_stream = catalog_manager.tables(<span class="kw-2">&amp;</span>catalog_name, <span class="kw-2">&amp;</span>schema_name, <span class="prelude-val">None</span>);
<a href=#326 id=326 data-nosnippet>326</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(table) = table_stream.try_next().<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#327 id=327 data-nosnippet>327</a> <span class="self">self</span>.add_table(
<a href=#328 id=328 data-nosnippet>328</a> <span class="kw-2">&amp;</span>predicates,
<a href=#329 id=329 data-nosnippet>329</a> <span class="kw-2">&amp;</span>catalog_name,
<a href=#330 id=330 data-nosnippet>330</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#331 id=331 data-nosnippet>331</a> table.table_info(),
<a href=#332 id=332 data-nosnippet>332</a> graph_provider.as_ref(),
<a href=#333 id=333 data-nosnippet>333</a> );
<a href=#334 id=334 data-nosnippet>334</a> }
<a href=#335 id=335 data-nosnippet>335</a> }
<a href=#336 id=336 data-nosnippet>336</a>
<a href=#337 id=337 data-nosnippet>337</a> <span class="self">self</span>.finish()
<a href=#338 id=338 data-nosnippet>338</a> }
<a href=#339 id=339 data-nosnippet>339</a>
<a href=#340 id=340 data-nosnippet>340</a> <span class="kw">fn </span>add_table(
<a href=#341 id=341 data-nosnippet>341</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#342 id=342 data-nosnippet>342</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#343 id=343 data-nosnippet>343</a> catalog_name: <span class="kw-2">&amp;</span>str,
<a href=#344 id=344 data-nosnippet>344</a> schema_name: <span class="kw-2">&amp;</span>str,
<a href=#345 id=345 data-nosnippet>345</a> table_info: Arc&lt;TableInfo&gt;,
<a href=#346 id=346 data-nosnippet>346</a> graph_provider: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>EntityGraphProviderRef&gt;,
<a href=#347 id=347 data-nosnippet>347</a> ) {
<a href=#348 id=348 data-nosnippet>348</a> <span class="kw">let </span>semantic_row = SemanticRow::extract(<span class="kw-2">&amp;</span>table_info);
<a href=#349 id=349 data-nosnippet>349</a> <span class="kw">let </span>carries_options = semantic_row.is_some();
<a href=#350 id=350 data-nosnippet>350</a> <span class="kw">let </span>row = semantic_row.unwrap_or_default();
<a href=#351 id=351 data-nosnippet>351</a>
<a href=#352 id=352 data-nosnippet>352</a> <span class="kw">let </span>table_name = table_info.name.as_ref();
<a href=#353 id=353 data-nosnippet>353</a> <span class="kw">let </span>catalog_v = Value::from(catalog_name);
<a href=#354 id=354 data-nosnippet>354</a> <span class="kw">let </span>schema_v = Value::from(schema_name);
<a href=#355 id=355 data-nosnippet>355</a> <span class="kw">let </span>name_v = Value::from(table_name);
<a href=#356 id=356 data-nosnippet>356</a> <span class="kw">let </span>signal_v = optional_value(row.signal_type);
<a href=#357 id=357 data-nosnippet>357</a> <span class="kw">let </span>source_v = optional_value(row.source);
<a href=#358 id=358 data-nosnippet>358</a> <span class="kw">let </span>source_version_v = optional_value(row.source_version);
<a href=#359 id=359 data-nosnippet>359</a> <span class="kw">let </span>pipeline_v = optional_value(row.pipeline);
<a href=#360 id=360 data-nosnippet>360</a> <span class="kw">let </span>quality_v = optional_value(row.metadata_quality);
<a href=#361 id=361 data-nosnippet>361</a> <span class="kw">let </span>predicate_row = [
<a href=#362 id=362 data-nosnippet>362</a> (TABLE_CATALOG, <span class="kw-2">&amp;</span>catalog_v),
<a href=#363 id=363 data-nosnippet>363</a> (TABLE_SCHEMA, <span class="kw-2">&amp;</span>schema_v),
<a href=#364 id=364 data-nosnippet>364</a> (TABLE_NAME, <span class="kw-2">&amp;</span>name_v),
<a href=#365 id=365 data-nosnippet>365</a> (SIGNAL_TYPE, <span class="kw-2">&amp;</span>signal_v),
<a href=#366 id=366 data-nosnippet>366</a> (SOURCE, <span class="kw-2">&amp;</span>source_v),
<a href=#367 id=367 data-nosnippet>367</a> (SOURCE_VERSION, <span class="kw-2">&amp;</span>source_version_v),
<a href=#368 id=368 data-nosnippet>368</a> (PIPELINE, <span class="kw-2">&amp;</span>pipeline_v),
<a href=#369 id=369 data-nosnippet>369</a> (METADATA_QUALITY, <span class="kw-2">&amp;</span>quality_v),
<a href=#370 id=370 data-nosnippet>370</a> ];
<a href=#371 id=371 data-nosnippet>371</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>predicate_row) {
<a href=#372 id=372 data-nosnippet>372</a> <span class="kw">return</span>;
<a href=#373 id=373 data-nosnippet>373</a> }
<a href=#374 id=374 data-nosnippet>374</a>
<a href=#375 id=375 data-nosnippet>375</a> <span class="kw">let </span>declarations_json = graph_provider
<a href=#376 id=376 data-nosnippet>376</a> .map(|provider| provider.table_declarations(<span class="kw-2">&amp;</span>table_info))
<a href=#377 id=377 data-nosnippet>377</a> .and_then(entity_declarations_json);
<a href=#378 id=378 data-nosnippet>378</a> <span class="kw">if </span>!carries_options &amp;&amp; declarations_json.is_none() {
<a href=#379 id=379 data-nosnippet>379</a> <span class="kw">return</span>;
<a href=#380 id=380 data-nosnippet>380</a> }
<a href=#381 id=381 data-nosnippet>381</a>
<a href=#382 id=382 data-nosnippet>382</a> <span class="self">self</span>.catalog_names.push(<span class="prelude-val">Some</span>(catalog_name));
<a href=#383 id=383 data-nosnippet>383</a> <span class="self">self</span>.schema_names.push(<span class="prelude-val">Some</span>(schema_name));
<a href=#384 id=384 data-nosnippet>384</a> <span class="self">self</span>.table_names.push(<span class="prelude-val">Some</span>(table_name));
<a href=#385 id=385 data-nosnippet>385</a> <span class="self">self</span>.table_ids.push(<span class="prelude-val">Some</span>(table_info.table_id()));
<a href=#386 id=386 data-nosnippet>386</a> <span class="self">self</span>.signal_types.push(row.signal_type);
<a href=#387 id=387 data-nosnippet>387</a> <span class="self">self</span>.sources.push(row.source);
<a href=#388 id=388 data-nosnippet>388</a> <span class="self">self</span>.source_versions.push(row.source_version);
<a href=#389 id=389 data-nosnippet>389</a> <span class="self">self</span>.pipelines.push(row.pipeline);
<a href=#390 id=390 data-nosnippet>390</a> <span class="self">self</span>.metadata_qualities.push(row.metadata_quality);
<a href=#391 id=391 data-nosnippet>391</a> <span class="self">self</span>.semantic_options.push(row.options_json.as_deref());
<a href=#392 id=392 data-nosnippet>392</a> <span class="self">self</span>.entity_declarations.push(declarations_json.as_deref());
<a href=#393 id=393 data-nosnippet>393</a> }
<a href=#394 id=394 data-nosnippet>394</a>
<a href=#395 id=395 data-nosnippet>395</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#396 id=396 data-nosnippet>396</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#397 id=397 data-nosnippet>397</a> Arc::new(<span class="self">self</span>.catalog_names.finish()),
<a href=#398 id=398 data-nosnippet>398</a> Arc::new(<span class="self">self</span>.schema_names.finish()),
<a href=#399 id=399 data-nosnippet>399</a> Arc::new(<span class="self">self</span>.table_names.finish()),
<a href=#400 id=400 data-nosnippet>400</a> Arc::new(<span class="self">self</span>.table_ids.finish()),
<a href=#401 id=401 data-nosnippet>401</a> Arc::new(<span class="self">self</span>.signal_types.finish()),
<a href=#402 id=402 data-nosnippet>402</a> Arc::new(<span class="self">self</span>.sources.finish()),
<a href=#403 id=403 data-nosnippet>403</a> Arc::new(<span class="self">self</span>.source_versions.finish()),
<a href=#404 id=404 data-nosnippet>404</a> Arc::new(<span class="self">self</span>.pipelines.finish()),
<a href=#405 id=405 data-nosnippet>405</a> Arc::new(<span class="self">self</span>.metadata_qualities.finish()),
<a href=#406 id=406 data-nosnippet>406</a> Arc::new(<span class="self">self</span>.semantic_options.finish()),
<a href=#407 id=407 data-nosnippet>407</a> Arc::new(<span class="self">self</span>.entity_declarations.finish()),
<a href=#408 id=408 data-nosnippet>408</a> ];
<a href=#409 id=409 data-nosnippet>409</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#410 id=410 data-nosnippet>410</a> }
<a href=#411 id=411 data-nosnippet>411</a>}
<a href=#412 id=412 data-nosnippet>412</a>
<a href=#413 id=413 data-nosnippet>413</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaTableSemantics {
<a href=#414 id=414 data-nosnippet>414</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#415 id=415 data-nosnippet>415</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#416 id=416 data-nosnippet>416</a> }
<a href=#417 id=417 data-nosnippet>417</a>
<a href=#418 id=418 data-nosnippet>418</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#419 id=419 data-nosnippet>419</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#420 id=420 data-nosnippet>420</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#421 id=421 data-nosnippet>421</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#422 id=422 data-nosnippet>422</a> schema,
<a href=#423 id=423 data-nosnippet>423</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#424 id=424 data-nosnippet>424</a> builder
<a href=#425 id=425 data-nosnippet>425</a> .make_tables(<span class="prelude-val">None</span>)
<a href=#426 id=426 data-nosnippet>426</a> .<span class="kw">await
<a href=#427 id=427 data-nosnippet>427</a> </span>.map(|x| x.into_df_record_batch())
<a href=#428 id=428 data-nosnippet>428</a> .map_err(Into::into)
<a href=#429 id=429 data-nosnippet>429</a> }),
<a href=#430 id=430 data-nosnippet>430</a> ))
<a href=#431 id=431 data-nosnippet>431</a> }
<a href=#432 id=432 data-nosnippet>432</a>}
<a href=#433 id=433 data-nosnippet>433</a>
<a href=#434 id=434 data-nosnippet>434</a><span class="attr">#[cfg(test)]
<a href=#435 id=435 data-nosnippet>435</a></span><span class="kw">mod </span>tests {
<a href=#436 id=436 data-nosnippet>436</a> <span class="kw">use </span>std::collections::HashMap;
<a href=#437 id=437 data-nosnippet>437</a>
<a href=#438 id=438 data-nosnippet>438</a> <span class="kw">use </span>common_catalog::consts::{DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME, MITO_ENGINE};
<a href=#439 id=439 data-nosnippet>439</a> <span class="kw">use </span>datatypes::schema::SchemaBuilder;
<a href=#440 id=440 data-nosnippet>440</a> <span class="kw">use </span>table::metadata::{TableInfoBuilder, TableMeta, TableType};
<a href=#441 id=441 data-nosnippet>441</a> <span class="kw">use </span>table::requests::{
<a href=#442 id=442 data-nosnippet>442</a> SEMANTIC_METRIC_TYPE, SEMANTIC_METRIC_UNIT, SEMANTIC_SOURCE_VERSION, TableOptions,
<a href=#443 id=443 data-nosnippet>443</a> };
<a href=#444 id=444 data-nosnippet>444</a>
<a href=#445 id=445 data-nosnippet>445</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#446 id=446 data-nosnippet>446</a>
<a href=#447 id=447 data-nosnippet>447</a> <span class="kw">fn </span>table_info(extra: <span class="kw-2">&amp;</span>[(<span class="kw-2">&amp;</span>str, <span class="kw-2">&amp;</span>str)]) -&gt; TableInfo {
<a href=#448 id=448 data-nosnippet>448</a> <span class="kw">let </span>schema = Arc::new(
<a href=#449 id=449 data-nosnippet>449</a> SchemaBuilder::try_from_columns(<span class="macro">vec!</span>[ColumnSchema::new(
<a href=#450 id=450 data-nosnippet>450</a> <span class="string">"ts"</span>,
<a href=#451 id=451 data-nosnippet>451</a> ConcreteDataType::timestamp_millisecond_datatype(),
<a href=#452 id=452 data-nosnippet>452</a> <span class="bool-val">false</span>,
<a href=#453 id=453 data-nosnippet>453</a> )])
<a href=#454 id=454 data-nosnippet>454</a> .unwrap()
<a href=#455 id=455 data-nosnippet>455</a> .build()
<a href=#456 id=456 data-nosnippet>456</a> .unwrap(),
<a href=#457 id=457 data-nosnippet>457</a> );
<a href=#458 id=458 data-nosnippet>458</a> <span class="kw">let </span>options = TableOptions {
<a href=#459 id=459 data-nosnippet>459</a> extra_options: extra
<a href=#460 id=460 data-nosnippet>460</a> .iter()
<a href=#461 id=461 data-nosnippet>461</a> .map(|(k, v)| (k.to_string(), v.to_string()))
<a href=#462 id=462 data-nosnippet>462</a> .collect::&lt;HashMap&lt;<span class="kw">_</span>, <span class="kw">_</span>&gt;&gt;(),
<a href=#463 id=463 data-nosnippet>463</a> ..Default::default()
<a href=#464 id=464 data-nosnippet>464</a> };
<a href=#465 id=465 data-nosnippet>465</a> <span class="kw">let </span>meta = TableMeta {
<a href=#466 id=466 data-nosnippet>466</a> schema,
<a href=#467 id=467 data-nosnippet>467</a> primary_key_indices: <span class="macro">vec!</span>[],
<a href=#468 id=468 data-nosnippet>468</a> value_indices: <span class="macro">vec!</span>[],
<a href=#469 id=469 data-nosnippet>469</a> engine: MITO_ENGINE.to_string(),
<a href=#470 id=470 data-nosnippet>470</a> next_column_id: <span class="number">1</span>,
<a href=#471 id=471 data-nosnippet>471</a> options,
<a href=#472 id=472 data-nosnippet>472</a> created_on: Default::default(),
<a href=#473 id=473 data-nosnippet>473</a> updated_on: Default::default(),
<a href=#474 id=474 data-nosnippet>474</a> partition_key_indices: <span class="macro">vec!</span>[],
<a href=#475 id=475 data-nosnippet>475</a> column_ids: <span class="macro">vec!</span>[],
<a href=#476 id=476 data-nosnippet>476</a> };
<a href=#477 id=477 data-nosnippet>477</a> TableInfoBuilder::default()
<a href=#478 id=478 data-nosnippet>478</a> .table_id(<span class="number">1</span>)
<a href=#479 id=479 data-nosnippet>479</a> .name(<span class="string">"t"</span>)
<a href=#480 id=480 data-nosnippet>480</a> .catalog_name(DEFAULT_CATALOG_NAME)
<a href=#481 id=481 data-nosnippet>481</a> .schema_name(DEFAULT_SCHEMA_NAME)
<a href=#482 id=482 data-nosnippet>482</a> .table_version(<span class="number">0</span>)
<a href=#483 id=483 data-nosnippet>483</a> .table_type(TableType::Base)
<a href=#484 id=484 data-nosnippet>484</a> .meta(meta)
<a href=#485 id=485 data-nosnippet>485</a> .build()
<a href=#486 id=486 data-nosnippet>486</a> .unwrap()
<a href=#487 id=487 data-nosnippet>487</a> }
<a href=#488 id=488 data-nosnippet>488</a>
<a href=#489 id=489 data-nosnippet>489</a> <span class="attr">#[test]
<a href=#490 id=490 data-nosnippet>490</a> </span><span class="kw">fn </span>extract_promotes_core_keys_and_folds_the_rest() {
<a href=#491 id=491 data-nosnippet>491</a> <span class="kw">let </span>info = table_info(<span class="kw-2">&amp;</span>[
<a href=#492 id=492 data-nosnippet>492</a> (SEMANTIC_SIGNAL_TYPE, <span class="string">"metric"</span>),
<a href=#493 id=493 data-nosnippet>493</a> (SEMANTIC_SOURCE, <span class="string">"opentelemetry"</span>),
<a href=#494 id=494 data-nosnippet>494</a> (SEMANTIC_SOURCE_VERSION, <span class="string">"2.0"</span>),
<a href=#495 id=495 data-nosnippet>495</a> (SEMANTIC_PIPELINE, <span class="string">"greptime_metric_v1"</span>),
<a href=#496 id=496 data-nosnippet>496</a> (SEMANTIC_METRIC_METADATA_QUALITY, <span class="string">"declared"</span>),
<a href=#497 id=497 data-nosnippet>497</a> (SEMANTIC_METRIC_TYPE, <span class="string">"counter"</span>),
<a href=#498 id=498 data-nosnippet>498</a> (SEMANTIC_METRIC_UNIT, <span class="string">"By"</span>),
<a href=#499 id=499 data-nosnippet>499</a> <span class="comment">// A non-semantic option must be ignored entirely.
<a href=#500 id=500 data-nosnippet>500</a> </span>(<span class="string">"ttl"</span>, <span class="string">"7d"</span>),
<a href=#501 id=501 data-nosnippet>501</a> ]);
<a href=#502 id=502 data-nosnippet>502</a>
<a href=#503 id=503 data-nosnippet>503</a> <span class="kw">let </span>row = SemanticRow::extract(<span class="kw-2">&amp;</span>info).unwrap();
<a href=#504 id=504 data-nosnippet>504</a> <span class="macro">assert_eq!</span>(row.signal_type, <span class="prelude-val">Some</span>(<span class="string">"metric"</span>));
<a href=#505 id=505 data-nosnippet>505</a> <span class="macro">assert_eq!</span>(row.source, <span class="prelude-val">Some</span>(<span class="string">"opentelemetry"</span>));
<a href=#506 id=506 data-nosnippet>506</a> <span class="macro">assert_eq!</span>(row.source_version, <span class="prelude-val">Some</span>(<span class="string">"2.0"</span>));
<a href=#507 id=507 data-nosnippet>507</a> <span class="macro">assert_eq!</span>(row.pipeline, <span class="prelude-val">Some</span>(<span class="string">"greptime_metric_v1"</span>));
<a href=#508 id=508 data-nosnippet>508</a> <span class="macro">assert_eq!</span>(row.metadata_quality, <span class="prelude-val">Some</span>(<span class="string">"declared"</span>));
<a href=#509 id=509 data-nosnippet>509</a> <span class="comment">// Promoted keys stay out of the JSON tail; remaining keys are sorted and
<a href=#510 id=510 data-nosnippet>510</a> // prefix-stripped.
<a href=#511 id=511 data-nosnippet>511</a> </span><span class="macro">assert_eq!</span>(
<a href=#512 id=512 data-nosnippet>512</a> row.options_json.as_deref(),
<a href=#513 id=513 data-nosnippet>513</a> <span class="prelude-val">Some</span>(<span class="string">r#"{"metric.type":"counter","metric.unit":"By"}"#</span>)
<a href=#514 id=514 data-nosnippet>514</a> );
<a href=#515 id=515 data-nosnippet>515</a> }
<a href=#516 id=516 data-nosnippet>516</a>
<a href=#517 id=517 data-nosnippet>517</a> <span class="attr">#[test]
<a href=#518 id=518 data-nosnippet>518</a> </span><span class="kw">fn </span>extract_skips_untagged_table() {
<a href=#519 id=519 data-nosnippet>519</a> <span class="kw">let </span>info = table_info(<span class="kw-2">&amp;</span>[(<span class="string">"ttl"</span>, <span class="string">"7d"</span>)]);
<a href=#520 id=520 data-nosnippet>520</a> <span class="macro">assert!</span>(SemanticRow::extract(<span class="kw-2">&amp;</span>info).is_none());
<a href=#521 id=521 data-nosnippet>521</a> }
<a href=#522 id=522 data-nosnippet>522</a>
<a href=#523 id=523 data-nosnippet>523</a> <span class="attr">#[test]
<a href=#524 id=524 data-nosnippet>524</a> </span><span class="kw">fn </span>extract_omits_json_when_only_core_keys_present() {
<a href=#525 id=525 data-nosnippet>525</a> <span class="kw">let </span>info = table_info(<span class="kw-2">&amp;</span>[(SEMANTIC_SIGNAL_TYPE, <span class="string">"log"</span>)]);
<a href=#526 id=526 data-nosnippet>526</a> <span class="kw">let </span>row = SemanticRow::extract(<span class="kw-2">&amp;</span>info).unwrap();
<a href=#527 id=527 data-nosnippet>527</a> <span class="macro">assert_eq!</span>(row.signal_type, <span class="prelude-val">Some</span>(<span class="string">"log"</span>));
<a href=#528 id=528 data-nosnippet>528</a> <span class="macro">assert!</span>(row.source.is_none());
<a href=#529 id=529 data-nosnippet>529</a> <span class="macro">assert!</span>(row.options_json.is_none());
<a href=#530 id=530 data-nosnippet>530</a> }
<a href=#531 id=531 data-nosnippet>531</a>
<a href=#532 id=532 data-nosnippet>532</a> <span class="attr">#[test]
<a href=#533 id=533 data-nosnippet>533</a> </span><span class="kw">fn </span>extract_folds_entity_keys_into_json_tail() {
<a href=#534 id=534 data-nosnippet>534</a> <span class="comment">// Entity keys are not promoted columns; they surface verbatim (prefix-
<a href=#535 id=535 data-nosnippet>535</a> // stripped, sorted) in the JSON tail with no code change to this table.
<a href=#536 id=536 data-nosnippet>536</a> </span><span class="kw">let </span>info = table_info(<span class="kw-2">&amp;</span>[
<a href=#537 id=537 data-nosnippet>537</a> (SEMANTIC_SIGNAL_TYPE, <span class="string">"trace"</span>),
<a href=#538 id=538 data-nosnippet>538</a> (<span class="string">"greptime.semantic.entity.service.id"</span>, <span class="string">"service_name"</span>),
<a href=#539 id=539 data-nosnippet>539</a> (<span class="string">"greptime.semantic.entity.host.id"</span>, <span class="string">"host_id"</span>),
<a href=#540 id=540 data-nosnippet>540</a> ]);
<a href=#541 id=541 data-nosnippet>541</a> <span class="kw">let </span>row = SemanticRow::extract(<span class="kw-2">&amp;</span>info).unwrap();
<a href=#542 id=542 data-nosnippet>542</a> <span class="macro">assert_eq!</span>(row.signal_type, <span class="prelude-val">Some</span>(<span class="string">"trace"</span>));
<a href=#543 id=543 data-nosnippet>543</a> <span class="macro">assert_eq!</span>(
<a href=#544 id=544 data-nosnippet>544</a> row.options_json.as_deref(),
<a href=#545 id=545 data-nosnippet>545</a> <span class="prelude-val">Some</span>(<span class="string">r#"{"entity.host.id":"host_id","entity.service.id":"service_name"}"#</span>)
<a href=#546 id=546 data-nosnippet>546</a> );
<a href=#547 id=547 data-nosnippet>547</a> }
<a href=#548 id=548 data-nosnippet>548</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,470 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/tables.rs`."><title>tables.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>tables.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>core::pin::pin;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_catalog::consts::{INFORMATION_SCHEMA_TABLES_TABLE_ID, MITO_ENGINE};
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_meta::datanode::RegionStat;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_telemetry::error;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, ScalarVectorBuilder, VectorRef};
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>datatypes::value::Value;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>datatypes::vectors::{
<a href=#33 id=33 data-nosnippet>33</a> StringVectorBuilder, TimestampSecondVectorBuilder, UInt32VectorBuilder, UInt64VectorBuilder,
<a href=#34 id=34 data-nosnippet>34</a>};
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span>futures::StreamExt;
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>snafu::{OptionExt, ResultExt};
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span>table::metadata::{TableInfo, TableType};
<a href=#39 id=39 data-nosnippet>39</a>
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#42 id=42 data-nosnippet>42</a> CreateRecordBatchSnafu, FindRegionRoutesSnafu, InternalSnafu, <span class="prelude-ty">Result</span>,
<a href=#43 id=43 data-nosnippet>43</a> UpgradeWeakCatalogManagerRefSnafu,
<a href=#44 id=44 data-nosnippet>44</a>};
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">use </span><span class="kw">crate</span>::kvbackend::KvBackendCatalogManager;
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{InformationTable, Predicates, TABLES};
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::utils;
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">pub const </span>TABLE_CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"table_catalog"</span>;
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">pub const </span>TABLE_SCHEMA: <span class="kw-2">&amp;</span>str = <span class="string">"table_schema"</span>;
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">pub const </span>TABLE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_name"</span>;
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">pub const </span>TABLE_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"table_type"</span>;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">pub const </span>VERSION: <span class="kw-2">&amp;</span>str = <span class="string">"version"</span>;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">pub const </span>ROW_FORMAT: <span class="kw-2">&amp;</span>str = <span class="string">"row_format"</span>;
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">pub const </span>TABLE_ROWS: <span class="kw-2">&amp;</span>str = <span class="string">"table_rows"</span>;
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">pub const </span>DATA_LENGTH: <span class="kw-2">&amp;</span>str = <span class="string">"data_length"</span>;
<a href=#57 id=57 data-nosnippet>57</a><span class="kw">pub const </span>INDEX_LENGTH: <span class="kw-2">&amp;</span>str = <span class="string">"index_length"</span>;
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">pub const </span>MAX_DATA_LENGTH: <span class="kw-2">&amp;</span>str = <span class="string">"max_data_length"</span>;
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">pub const </span>AVG_ROW_LENGTH: <span class="kw-2">&amp;</span>str = <span class="string">"avg_row_length"</span>;
<a href=#60 id=60 data-nosnippet>60</a><span class="kw">pub const </span>DATA_FREE: <span class="kw-2">&amp;</span>str = <span class="string">"data_free"</span>;
<a href=#61 id=61 data-nosnippet>61</a><span class="kw">pub const </span>AUTO_INCREMENT: <span class="kw-2">&amp;</span>str = <span class="string">"auto_increment"</span>;
<a href=#62 id=62 data-nosnippet>62</a><span class="kw">pub const </span>CREATE_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"create_time"</span>;
<a href=#63 id=63 data-nosnippet>63</a><span class="kw">pub const </span>UPDATE_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"update_time"</span>;
<a href=#64 id=64 data-nosnippet>64</a><span class="kw">pub const </span>CHECK_TIME: <span class="kw-2">&amp;</span>str = <span class="string">"check_time"</span>;
<a href=#65 id=65 data-nosnippet>65</a><span class="kw">pub const </span>TABLE_COLLATION: <span class="kw-2">&amp;</span>str = <span class="string">"table_collation"</span>;
<a href=#66 id=66 data-nosnippet>66</a><span class="kw">pub const </span>CHECKSUM: <span class="kw-2">&amp;</span>str = <span class="string">"checksum"</span>;
<a href=#67 id=67 data-nosnippet>67</a><span class="kw">pub const </span>CREATE_OPTIONS: <span class="kw-2">&amp;</span>str = <span class="string">"create_options"</span>;
<a href=#68 id=68 data-nosnippet>68</a><span class="kw">pub const </span>TABLE_COMMENT: <span class="kw-2">&amp;</span>str = <span class="string">"table_comment"</span>;
<a href=#69 id=69 data-nosnippet>69</a><span class="kw">pub const </span>MAX_INDEX_LENGTH: <span class="kw-2">&amp;</span>str = <span class="string">"max_index_length"</span>;
<a href=#70 id=70 data-nosnippet>70</a><span class="kw">pub const </span>TEMPORARY: <span class="kw-2">&amp;</span>str = <span class="string">"temporary"</span>;
<a href=#71 id=71 data-nosnippet>71</a><span class="kw">const </span>TABLE_ID: <span class="kw-2">&amp;</span>str = <span class="string">"table_id"</span>;
<a href=#72 id=72 data-nosnippet>72</a><span class="kw">pub const </span>ENGINE: <span class="kw-2">&amp;</span>str = <span class="string">"engine"</span>;
<a href=#73 id=73 data-nosnippet>73</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#74 id=74 data-nosnippet>74</a>
<a href=#75 id=75 data-nosnippet>75</a><span class="attr">#[derive(Debug)]
<a href=#76 id=76 data-nosnippet>76</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaTables {
<a href=#77 id=77 data-nosnippet>77</a> schema: SchemaRef,
<a href=#78 id=78 data-nosnippet>78</a> catalog_name: String,
<a href=#79 id=79 data-nosnippet>79</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#80 id=80 data-nosnippet>80</a>}
<a href=#81 id=81 data-nosnippet>81</a>
<a href=#82 id=82 data-nosnippet>82</a><span class="kw">impl </span>InformationSchemaTables {
<a href=#83 id=83 data-nosnippet>83</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_name: String, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#84 id=84 data-nosnippet>84</a> <span class="self">Self </span>{
<a href=#85 id=85 data-nosnippet>85</a> schema: <span class="self">Self</span>::schema(),
<a href=#86 id=86 data-nosnippet>86</a> catalog_name,
<a href=#87 id=87 data-nosnippet>87</a> catalog_manager,
<a href=#88 id=88 data-nosnippet>88</a> }
<a href=#89 id=89 data-nosnippet>89</a> }
<a href=#90 id=90 data-nosnippet>90</a>
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#92 id=92 data-nosnippet>92</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#93 id=93 data-nosnippet>93</a> ColumnSchema::new(TABLE_CATALOG, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#94 id=94 data-nosnippet>94</a> ColumnSchema::new(TABLE_SCHEMA, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#95 id=95 data-nosnippet>95</a> ColumnSchema::new(TABLE_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#96 id=96 data-nosnippet>96</a> ColumnSchema::new(TABLE_TYPE, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#97 id=97 data-nosnippet>97</a> ColumnSchema::new(TABLE_ID, ConcreteDataType::uint32_datatype(), <span class="bool-val">true</span>),
<a href=#98 id=98 data-nosnippet>98</a> ColumnSchema::new(DATA_LENGTH, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#99 id=99 data-nosnippet>99</a> ColumnSchema::new(MAX_DATA_LENGTH, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#100 id=100 data-nosnippet>100</a> ColumnSchema::new(INDEX_LENGTH, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#101 id=101 data-nosnippet>101</a> ColumnSchema::new(MAX_INDEX_LENGTH, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#102 id=102 data-nosnippet>102</a> ColumnSchema::new(AVG_ROW_LENGTH, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#103 id=103 data-nosnippet>103</a> ColumnSchema::new(ENGINE, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#104 id=104 data-nosnippet>104</a> ColumnSchema::new(VERSION, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#105 id=105 data-nosnippet>105</a> ColumnSchema::new(ROW_FORMAT, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#106 id=106 data-nosnippet>106</a> ColumnSchema::new(TABLE_ROWS, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#107 id=107 data-nosnippet>107</a> ColumnSchema::new(DATA_FREE, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#108 id=108 data-nosnippet>108</a> ColumnSchema::new(AUTO_INCREMENT, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#109 id=109 data-nosnippet>109</a> ColumnSchema::new(
<a href=#110 id=110 data-nosnippet>110</a> CREATE_TIME,
<a href=#111 id=111 data-nosnippet>111</a> ConcreteDataType::timestamp_second_datatype(),
<a href=#112 id=112 data-nosnippet>112</a> <span class="bool-val">true</span>,
<a href=#113 id=113 data-nosnippet>113</a> ),
<a href=#114 id=114 data-nosnippet>114</a> ColumnSchema::new(
<a href=#115 id=115 data-nosnippet>115</a> UPDATE_TIME,
<a href=#116 id=116 data-nosnippet>116</a> ConcreteDataType::timestamp_second_datatype(),
<a href=#117 id=117 data-nosnippet>117</a> <span class="bool-val">true</span>,
<a href=#118 id=118 data-nosnippet>118</a> ),
<a href=#119 id=119 data-nosnippet>119</a> ColumnSchema::new(
<a href=#120 id=120 data-nosnippet>120</a> CHECK_TIME,
<a href=#121 id=121 data-nosnippet>121</a> ConcreteDataType::timestamp_second_datatype(),
<a href=#122 id=122 data-nosnippet>122</a> <span class="bool-val">true</span>,
<a href=#123 id=123 data-nosnippet>123</a> ),
<a href=#124 id=124 data-nosnippet>124</a> ColumnSchema::new(TABLE_COLLATION, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#125 id=125 data-nosnippet>125</a> ColumnSchema::new(CHECKSUM, ConcreteDataType::uint64_datatype(), <span class="bool-val">true</span>),
<a href=#126 id=126 data-nosnippet>126</a> ColumnSchema::new(CREATE_OPTIONS, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#127 id=127 data-nosnippet>127</a> ColumnSchema::new(TABLE_COMMENT, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#128 id=128 data-nosnippet>128</a> ColumnSchema::new(TEMPORARY, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#129 id=129 data-nosnippet>129</a> ]))
<a href=#130 id=130 data-nosnippet>130</a> }
<a href=#131 id=131 data-nosnippet>131</a>
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaTablesBuilder {
<a href=#133 id=133 data-nosnippet>133</a> InformationSchemaTablesBuilder::new(
<a href=#134 id=134 data-nosnippet>134</a> <span class="self">self</span>.schema.clone(),
<a href=#135 id=135 data-nosnippet>135</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#136 id=136 data-nosnippet>136</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#137 id=137 data-nosnippet>137</a> )
<a href=#138 id=138 data-nosnippet>138</a> }
<a href=#139 id=139 data-nosnippet>139</a>}
<a href=#140 id=140 data-nosnippet>140</a>
<a href=#141 id=141 data-nosnippet>141</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaTables {
<a href=#142 id=142 data-nosnippet>142</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#143 id=143 data-nosnippet>143</a> INFORMATION_SCHEMA_TABLES_TABLE_ID
<a href=#144 id=144 data-nosnippet>144</a> }
<a href=#145 id=145 data-nosnippet>145</a>
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#147 id=147 data-nosnippet>147</a> TABLES
<a href=#148 id=148 data-nosnippet>148</a> }
<a href=#149 id=149 data-nosnippet>149</a>
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#151 id=151 data-nosnippet>151</a> <span class="self">self</span>.schema.clone()
<a href=#152 id=152 data-nosnippet>152</a> }
<a href=#153 id=153 data-nosnippet>153</a>
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#157 id=157 data-nosnippet>157</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#158 id=158 data-nosnippet>158</a> schema,
<a href=#159 id=159 data-nosnippet>159</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#160 id=160 data-nosnippet>160</a> builder
<a href=#161 id=161 data-nosnippet>161</a> .make_tables(<span class="prelude-val">Some</span>(request))
<a href=#162 id=162 data-nosnippet>162</a> .<span class="kw">await
<a href=#163 id=163 data-nosnippet>163</a> </span>.map(|x| x.into_df_record_batch())
<a href=#164 id=164 data-nosnippet>164</a> .map_err(|err| datafusion::error::DataFusionError::External(Box::new(err)))
<a href=#165 id=165 data-nosnippet>165</a> }),
<a href=#166 id=166 data-nosnippet>166</a> ));
<a href=#167 id=167 data-nosnippet>167</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#168 id=168 data-nosnippet>168</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#169 id=169 data-nosnippet>169</a> .map_err(BoxedError::new)
<a href=#170 id=170 data-nosnippet>170</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#171 id=171 data-nosnippet>171</a> ))
<a href=#172 id=172 data-nosnippet>172</a> }
<a href=#173 id=173 data-nosnippet>173</a>}
<a href=#174 id=174 data-nosnippet>174</a>
<a href=#175 id=175 data-nosnippet>175</a><span class="doccomment">/// Builds the `information_schema.TABLE` table row by row
<a href=#176 id=176 data-nosnippet>176</a>///
<a href=#177 id=177 data-nosnippet>177</a>/// Columns are based on &lt;https://www.postgresql.org/docs/current/infoschema-columns.html&gt;
<a href=#178 id=178 data-nosnippet>178</a></span><span class="kw">struct </span>InformationSchemaTablesBuilder {
<a href=#179 id=179 data-nosnippet>179</a> schema: SchemaRef,
<a href=#180 id=180 data-nosnippet>180</a> catalog_name: String,
<a href=#181 id=181 data-nosnippet>181</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#182 id=182 data-nosnippet>182</a>
<a href=#183 id=183 data-nosnippet>183</a> catalog_names: StringVectorBuilder,
<a href=#184 id=184 data-nosnippet>184</a> schema_names: StringVectorBuilder,
<a href=#185 id=185 data-nosnippet>185</a> table_names: StringVectorBuilder,
<a href=#186 id=186 data-nosnippet>186</a> table_types: StringVectorBuilder,
<a href=#187 id=187 data-nosnippet>187</a> table_ids: UInt32VectorBuilder,
<a href=#188 id=188 data-nosnippet>188</a> version: UInt64VectorBuilder,
<a href=#189 id=189 data-nosnippet>189</a> row_format: StringVectorBuilder,
<a href=#190 id=190 data-nosnippet>190</a> table_rows: UInt64VectorBuilder,
<a href=#191 id=191 data-nosnippet>191</a> data_length: UInt64VectorBuilder,
<a href=#192 id=192 data-nosnippet>192</a> max_data_length: UInt64VectorBuilder,
<a href=#193 id=193 data-nosnippet>193</a> index_length: UInt64VectorBuilder,
<a href=#194 id=194 data-nosnippet>194</a> avg_row_length: UInt64VectorBuilder,
<a href=#195 id=195 data-nosnippet>195</a> max_index_length: UInt64VectorBuilder,
<a href=#196 id=196 data-nosnippet>196</a> data_free: UInt64VectorBuilder,
<a href=#197 id=197 data-nosnippet>197</a> auto_increment: UInt64VectorBuilder,
<a href=#198 id=198 data-nosnippet>198</a> create_time: TimestampSecondVectorBuilder,
<a href=#199 id=199 data-nosnippet>199</a> update_time: TimestampSecondVectorBuilder,
<a href=#200 id=200 data-nosnippet>200</a> check_time: TimestampSecondVectorBuilder,
<a href=#201 id=201 data-nosnippet>201</a> table_collation: StringVectorBuilder,
<a href=#202 id=202 data-nosnippet>202</a> checksum: UInt64VectorBuilder,
<a href=#203 id=203 data-nosnippet>203</a> create_options: StringVectorBuilder,
<a href=#204 id=204 data-nosnippet>204</a> table_comment: StringVectorBuilder,
<a href=#205 id=205 data-nosnippet>205</a> engines: StringVectorBuilder,
<a href=#206 id=206 data-nosnippet>206</a> temporary: StringVectorBuilder,
<a href=#207 id=207 data-nosnippet>207</a>}
<a href=#208 id=208 data-nosnippet>208</a>
<a href=#209 id=209 data-nosnippet>209</a><span class="kw">impl </span>InformationSchemaTablesBuilder {
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">fn </span>new(
<a href=#211 id=211 data-nosnippet>211</a> schema: SchemaRef,
<a href=#212 id=212 data-nosnippet>212</a> catalog_name: String,
<a href=#213 id=213 data-nosnippet>213</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#214 id=214 data-nosnippet>214</a> ) -&gt; <span class="self">Self </span>{
<a href=#215 id=215 data-nosnippet>215</a> <span class="self">Self </span>{
<a href=#216 id=216 data-nosnippet>216</a> schema,
<a href=#217 id=217 data-nosnippet>217</a> catalog_name,
<a href=#218 id=218 data-nosnippet>218</a> catalog_manager,
<a href=#219 id=219 data-nosnippet>219</a> catalog_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#220 id=220 data-nosnippet>220</a> schema_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#221 id=221 data-nosnippet>221</a> table_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#222 id=222 data-nosnippet>222</a> table_types: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#223 id=223 data-nosnippet>223</a> table_ids: UInt32VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#224 id=224 data-nosnippet>224</a> data_length: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#225 id=225 data-nosnippet>225</a> max_data_length: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#226 id=226 data-nosnippet>226</a> index_length: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#227 id=227 data-nosnippet>227</a> avg_row_length: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#228 id=228 data-nosnippet>228</a> engines: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#229 id=229 data-nosnippet>229</a> version: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#230 id=230 data-nosnippet>230</a> row_format: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#231 id=231 data-nosnippet>231</a> table_rows: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#232 id=232 data-nosnippet>232</a> max_index_length: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#233 id=233 data-nosnippet>233</a> data_free: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#234 id=234 data-nosnippet>234</a> auto_increment: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#235 id=235 data-nosnippet>235</a> create_time: TimestampSecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#236 id=236 data-nosnippet>236</a> update_time: TimestampSecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#237 id=237 data-nosnippet>237</a> check_time: TimestampSecondVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#238 id=238 data-nosnippet>238</a> table_collation: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#239 id=239 data-nosnippet>239</a> checksum: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#240 id=240 data-nosnippet>240</a> create_options: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#241 id=241 data-nosnippet>241</a> table_comment: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#242 id=242 data-nosnippet>242</a> temporary: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#243 id=243 data-nosnippet>243</a> }
<a href=#244 id=244 data-nosnippet>244</a> }
<a href=#245 id=245 data-nosnippet>245</a>
<a href=#246 id=246 data-nosnippet>246</a> <span class="doccomment">/// Construct the `information_schema.tables` virtual table
<a href=#247 id=247 data-nosnippet>247</a> </span><span class="kw">async fn </span>make_tables(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#248 id=248 data-nosnippet>248</a> <span class="kw">let </span>catalog_name = <span class="self">self</span>.catalog_name.clone();
<a href=#249 id=249 data-nosnippet>249</a> <span class="kw">let </span>catalog_manager = <span class="self">self
<a href=#250 id=250 data-nosnippet>250</a> </span>.catalog_manager
<a href=#251 id=251 data-nosnippet>251</a> .upgrade()
<a href=#252 id=252 data-nosnippet>252</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#253 id=253 data-nosnippet>253</a> <span class="kw">let </span>partition_manager = catalog_manager
<a href=#254 id=254 data-nosnippet>254</a> .as_any()
<a href=#255 id=255 data-nosnippet>255</a> .downcast_ref::&lt;KvBackendCatalogManager&gt;()
<a href=#256 id=256 data-nosnippet>256</a> .map(|catalog_manager| catalog_manager.partition_manager());
<a href=#257 id=257 data-nosnippet>257</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#258 id=258 data-nosnippet>258</a>
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">let </span>information_extension = utils::information_extension(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_manager)<span class="question-mark">?</span>;
<a href=#260 id=260 data-nosnippet>260</a>
<a href=#261 id=261 data-nosnippet>261</a> <span class="comment">// TODO(dennis): `region_stats` API is not stable in distributed cluster because of network issue etc.
<a href=#262 id=262 data-nosnippet>262</a> // But we don't want the statements such as `show tables` fail,
<a href=#263 id=263 data-nosnippet>263</a> // so using `unwrap_or_else` here instead of `?` operator.
<a href=#264 id=264 data-nosnippet>264</a> </span><span class="kw">let </span>region_stats = {
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">let </span><span class="kw-2">mut </span>x = information_extension
<a href=#266 id=266 data-nosnippet>266</a> .region_stats()
<a href=#267 id=267 data-nosnippet>267</a> .<span class="kw">await
<a href=#268 id=268 data-nosnippet>268</a> </span>.unwrap_or_else(|e| {
<a href=#269 id=269 data-nosnippet>269</a> <span class="macro">error!</span>(e; <span class="string">"Failed to find region stats in information_schema, fallback to all empty"</span>);
<a href=#270 id=270 data-nosnippet>270</a> <span class="macro">vec!</span>[]
<a href=#271 id=271 data-nosnippet>271</a> });
<a href=#272 id=272 data-nosnippet>272</a> x.sort_unstable_by_key(|x| x.id);
<a href=#273 id=273 data-nosnippet>273</a> x
<a href=#274 id=274 data-nosnippet>274</a> };
<a href=#275 id=275 data-nosnippet>275</a>
<a href=#276 id=276 data-nosnippet>276</a> <span class="kw">for </span>schema_name <span class="kw">in </span>catalog_manager.schema_names(<span class="kw-2">&amp;</span>catalog_name, <span class="prelude-val">None</span>).<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#277 id=277 data-nosnippet>277</a> <span class="kw">let </span>table_stream = catalog_manager.tables(<span class="kw-2">&amp;</span>catalog_name, <span class="kw-2">&amp;</span>schema_name, <span class="prelude-val">None</span>);
<a href=#278 id=278 data-nosnippet>278</a>
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">const </span>BATCH_SIZE: usize = <span class="number">128</span>;
<a href=#280 id=280 data-nosnippet>280</a> <span class="comment">// Split tables into chunks
<a href=#281 id=281 data-nosnippet>281</a> </span><span class="kw">let </span><span class="kw-2">mut </span>table_chunks = <span class="macro">pin!</span>(table_stream.ready_chunks(BATCH_SIZE));
<a href=#282 id=282 data-nosnippet>282</a>
<a href=#283 id=283 data-nosnippet>283</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(tables) = table_chunks.next().<span class="kw">await </span>{
<a href=#284 id=284 data-nosnippet>284</a> <span class="kw">let </span>tables = tables.into_iter().collect::&lt;<span class="prelude-ty">Result</span>&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;&gt;()<span class="question-mark">?</span>;
<a href=#285 id=285 data-nosnippet>285</a> <span class="kw">let </span>mito_or_physical_table_ids = tables
<a href=#286 id=286 data-nosnippet>286</a> .iter()
<a href=#287 id=287 data-nosnippet>287</a> .filter(|table| {
<a href=#288 id=288 data-nosnippet>288</a> table.table_info().meta.engine == MITO_ENGINE
<a href=#289 id=289 data-nosnippet>289</a> || table.table_info().is_physical_table()
<a href=#290 id=290 data-nosnippet>290</a> })
<a href=#291 id=291 data-nosnippet>291</a> .map(|table| table.table_info().ident.table_id)
<a href=#292 id=292 data-nosnippet>292</a> .collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;();
<a href=#293 id=293 data-nosnippet>293</a>
<a href=#294 id=294 data-nosnippet>294</a> <span class="kw">let </span>table_routes = <span class="kw">if let </span><span class="prelude-val">Some</span>(partition_manager) = <span class="kw-2">&amp;</span>partition_manager {
<a href=#295 id=295 data-nosnippet>295</a> partition_manager
<a href=#296 id=296 data-nosnippet>296</a> .batch_find_region_routes(<span class="kw-2">&amp;</span>mito_or_physical_table_ids)
<a href=#297 id=297 data-nosnippet>297</a> .<span class="kw">await
<a href=#298 id=298 data-nosnippet>298</a> </span>.context(FindRegionRoutesSnafu)<span class="question-mark">?
<a href=#299 id=299 data-nosnippet>299</a> </span>} <span class="kw">else </span>{
<a href=#300 id=300 data-nosnippet>300</a> mito_or_physical_table_ids
<a href=#301 id=301 data-nosnippet>301</a> .into_iter()
<a href=#302 id=302 data-nosnippet>302</a> .map(|id| (id, <span class="macro">vec!</span>[]))
<a href=#303 id=303 data-nosnippet>303</a> .collect()
<a href=#304 id=304 data-nosnippet>304</a> };
<a href=#305 id=305 data-nosnippet>305</a>
<a href=#306 id=306 data-nosnippet>306</a> <span class="kw">for </span>table <span class="kw">in </span>tables {
<a href=#307 id=307 data-nosnippet>307</a> <span class="kw">let </span>table_region_stats =
<a href=#308 id=308 data-nosnippet>308</a> <span class="kw">match </span>table_routes.get(<span class="kw-2">&amp;</span>table.table_info().ident.table_id) {
<a href=#309 id=309 data-nosnippet>309</a> <span class="prelude-val">Some</span>(routes) =&gt; routes
<a href=#310 id=310 data-nosnippet>310</a> .iter()
<a href=#311 id=311 data-nosnippet>311</a> .flat_map(|route| {
<a href=#312 id=312 data-nosnippet>312</a> <span class="kw">let </span>region_id = route.region.id;
<a href=#313 id=313 data-nosnippet>313</a> region_stats
<a href=#314 id=314 data-nosnippet>314</a> .binary_search_by_key(<span class="kw-2">&amp;</span>region_id, |x| x.id)
<a href=#315 id=315 data-nosnippet>315</a> .map(|i| <span class="kw-2">&amp;</span>region_stats[i])
<a href=#316 id=316 data-nosnippet>316</a> })
<a href=#317 id=317 data-nosnippet>317</a> .collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;(),
<a href=#318 id=318 data-nosnippet>318</a> <span class="prelude-val">None </span>=&gt; <span class="macro">vec!</span>[],
<a href=#319 id=319 data-nosnippet>319</a> };
<a href=#320 id=320 data-nosnippet>320</a>
<a href=#321 id=321 data-nosnippet>321</a> <span class="self">self</span>.add_table(
<a href=#322 id=322 data-nosnippet>322</a> <span class="kw-2">&amp;</span>predicates,
<a href=#323 id=323 data-nosnippet>323</a> <span class="kw-2">&amp;</span>catalog_name,
<a href=#324 id=324 data-nosnippet>324</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#325 id=325 data-nosnippet>325</a> table.table_info(),
<a href=#326 id=326 data-nosnippet>326</a> table.table_type(),
<a href=#327 id=327 data-nosnippet>327</a> <span class="kw-2">&amp;</span>table_region_stats,
<a href=#328 id=328 data-nosnippet>328</a> );
<a href=#329 id=329 data-nosnippet>329</a> }
<a href=#330 id=330 data-nosnippet>330</a> }
<a href=#331 id=331 data-nosnippet>331</a> }
<a href=#332 id=332 data-nosnippet>332</a>
<a href=#333 id=333 data-nosnippet>333</a> <span class="self">self</span>.finish()
<a href=#334 id=334 data-nosnippet>334</a> }
<a href=#335 id=335 data-nosnippet>335</a>
<a href=#336 id=336 data-nosnippet>336</a> <span class="attr">#[allow(clippy::too_many_arguments)]
<a href=#337 id=337 data-nosnippet>337</a> </span><span class="kw">fn </span>add_table(
<a href=#338 id=338 data-nosnippet>338</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#339 id=339 data-nosnippet>339</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#340 id=340 data-nosnippet>340</a> catalog_name: <span class="kw-2">&amp;</span>str,
<a href=#341 id=341 data-nosnippet>341</a> schema_name: <span class="kw-2">&amp;</span>str,
<a href=#342 id=342 data-nosnippet>342</a> table_info: Arc&lt;TableInfo&gt;,
<a href=#343 id=343 data-nosnippet>343</a> table_type: TableType,
<a href=#344 id=344 data-nosnippet>344</a> region_stats: <span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span>RegionStat],
<a href=#345 id=345 data-nosnippet>345</a> ) {
<a href=#346 id=346 data-nosnippet>346</a> <span class="kw">let </span>table_name = table_info.name.as_ref();
<a href=#347 id=347 data-nosnippet>347</a> <span class="kw">let </span>table_id = table_info.table_id();
<a href=#348 id=348 data-nosnippet>348</a> <span class="kw">let </span>engine = table_info.meta.engine.as_ref();
<a href=#349 id=349 data-nosnippet>349</a>
<a href=#350 id=350 data-nosnippet>350</a> <span class="kw">let </span>table_type_text = <span class="kw">match </span>table_type {
<a href=#351 id=351 data-nosnippet>351</a> TableType::Base =&gt; <span class="string">"BASE TABLE"</span>,
<a href=#352 id=352 data-nosnippet>352</a> TableType::View =&gt; <span class="string">"VIEW"</span>,
<a href=#353 id=353 data-nosnippet>353</a> TableType::Temporary =&gt; <span class="string">"LOCAL TEMPORARY"</span>,
<a href=#354 id=354 data-nosnippet>354</a> };
<a href=#355 id=355 data-nosnippet>355</a>
<a href=#356 id=356 data-nosnippet>356</a> <span class="kw">let </span>row = [
<a href=#357 id=357 data-nosnippet>357</a> (TABLE_CATALOG, <span class="kw-2">&amp;</span>Value::from(catalog_name)),
<a href=#358 id=358 data-nosnippet>358</a> (TABLE_ID, <span class="kw-2">&amp;</span>Value::from(table_id)),
<a href=#359 id=359 data-nosnippet>359</a> (TABLE_SCHEMA, <span class="kw-2">&amp;</span>Value::from(schema_name)),
<a href=#360 id=360 data-nosnippet>360</a> (ENGINE, <span class="kw-2">&amp;</span>Value::from(engine)),
<a href=#361 id=361 data-nosnippet>361</a> (TABLE_NAME, <span class="kw-2">&amp;</span>Value::from(table_name)),
<a href=#362 id=362 data-nosnippet>362</a> (TABLE_TYPE, <span class="kw-2">&amp;</span>Value::from(table_type_text)),
<a href=#363 id=363 data-nosnippet>363</a> ];
<a href=#364 id=364 data-nosnippet>364</a>
<a href=#365 id=365 data-nosnippet>365</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#366 id=366 data-nosnippet>366</a> <span class="kw">return</span>;
<a href=#367 id=367 data-nosnippet>367</a> }
<a href=#368 id=368 data-nosnippet>368</a>
<a href=#369 id=369 data-nosnippet>369</a> <span class="self">self</span>.catalog_names.push(<span class="prelude-val">Some</span>(catalog_name));
<a href=#370 id=370 data-nosnippet>370</a> <span class="self">self</span>.schema_names.push(<span class="prelude-val">Some</span>(schema_name));
<a href=#371 id=371 data-nosnippet>371</a> <span class="self">self</span>.table_names.push(<span class="prelude-val">Some</span>(table_name));
<a href=#372 id=372 data-nosnippet>372</a> <span class="self">self</span>.table_types.push(<span class="prelude-val">Some</span>(table_type_text));
<a href=#373 id=373 data-nosnippet>373</a> <span class="self">self</span>.table_ids.push(<span class="prelude-val">Some</span>(table_id));
<a href=#374 id=374 data-nosnippet>374</a>
<a href=#375 id=375 data-nosnippet>375</a> <span class="kw">let </span>data_length: u64 = region_stats.iter().map(|stat| stat.sst_size).sum();
<a href=#376 id=376 data-nosnippet>376</a> <span class="kw">let </span>table_rows: u64 = region_stats.iter().map(|stat| stat.num_rows).sum();
<a href=#377 id=377 data-nosnippet>377</a> <span class="kw">let </span>index_length: u64 = region_stats.iter().map(|stat| stat.index_size).sum();
<a href=#378 id=378 data-nosnippet>378</a>
<a href=#379 id=379 data-nosnippet>379</a> <span class="kw">let </span>total_data_length: u64 = data_length
<a href=#380 id=380 data-nosnippet>380</a> + region_stats
<a href=#381 id=381 data-nosnippet>381</a> .iter()
<a href=#382 id=382 data-nosnippet>382</a> .map(|stat| stat.memtable_size)
<a href=#383 id=383 data-nosnippet>383</a> .sum::&lt;u64&gt;();
<a href=#384 id=384 data-nosnippet>384</a> <span class="kw">let </span>avg_row_length = total_data_length.checked_div(table_rows).unwrap_or(<span class="number">0</span>);
<a href=#385 id=385 data-nosnippet>385</a>
<a href=#386 id=386 data-nosnippet>386</a> <span class="self">self</span>.data_length.push(<span class="prelude-val">Some</span>(data_length));
<a href=#387 id=387 data-nosnippet>387</a> <span class="self">self</span>.index_length.push(<span class="prelude-val">Some</span>(index_length));
<a href=#388 id=388 data-nosnippet>388</a> <span class="self">self</span>.table_rows.push(<span class="prelude-val">Some</span>(table_rows));
<a href=#389 id=389 data-nosnippet>389</a> <span class="self">self</span>.avg_row_length.push(<span class="prelude-val">Some</span>(avg_row_length));
<a href=#390 id=390 data-nosnippet>390</a>
<a href=#391 id=391 data-nosnippet>391</a> <span class="comment">// TODO(sunng87): use real data for these fields
<a href=#392 id=392 data-nosnippet>392</a> </span><span class="self">self</span>.max_data_length.push(<span class="prelude-val">Some</span>(<span class="number">0</span>));
<a href=#393 id=393 data-nosnippet>393</a> <span class="self">self</span>.checksum.push(<span class="prelude-val">Some</span>(<span class="number">0</span>));
<a href=#394 id=394 data-nosnippet>394</a> <span class="self">self</span>.max_index_length.push(<span class="prelude-val">Some</span>(<span class="number">0</span>));
<a href=#395 id=395 data-nosnippet>395</a> <span class="self">self</span>.data_free.push(<span class="prelude-val">Some</span>(<span class="number">0</span>));
<a href=#396 id=396 data-nosnippet>396</a> <span class="self">self</span>.auto_increment.push(<span class="prelude-val">Some</span>(<span class="number">0</span>));
<a href=#397 id=397 data-nosnippet>397</a> <span class="self">self</span>.row_format.push(<span class="prelude-val">Some</span>(<span class="string">"Fixed"</span>));
<a href=#398 id=398 data-nosnippet>398</a> <span class="self">self</span>.table_collation.push(<span class="prelude-val">Some</span>(<span class="string">"utf8_bin"</span>));
<a href=#399 id=399 data-nosnippet>399</a> <span class="self">self</span>.update_time
<a href=#400 id=400 data-nosnippet>400</a> .push(<span class="prelude-val">Some</span>(table_info.meta.updated_on.timestamp().into()));
<a href=#401 id=401 data-nosnippet>401</a> <span class="self">self</span>.check_time.push(<span class="prelude-val">None</span>);
<a href=#402 id=402 data-nosnippet>402</a> <span class="comment">// use mariadb default table version number here
<a href=#403 id=403 data-nosnippet>403</a> </span><span class="self">self</span>.version.push(<span class="prelude-val">Some</span>(<span class="number">11</span>));
<a href=#404 id=404 data-nosnippet>404</a> <span class="self">self</span>.table_comment.push(table_info.desc.as_deref());
<a href=#405 id=405 data-nosnippet>405</a> <span class="self">self</span>.create_options
<a href=#406 id=406 data-nosnippet>406</a> .push(<span class="prelude-val">Some</span>(table_info.meta.options.to_string().as_ref()));
<a href=#407 id=407 data-nosnippet>407</a> <span class="self">self</span>.create_time
<a href=#408 id=408 data-nosnippet>408</a> .push(<span class="prelude-val">Some</span>(table_info.meta.created_on.timestamp().into()));
<a href=#409 id=409 data-nosnippet>409</a>
<a href=#410 id=410 data-nosnippet>410</a> <span class="self">self</span>.temporary
<a href=#411 id=411 data-nosnippet>411</a> .push(<span class="kw">if </span><span class="macro">matches!</span>(table_type, TableType::Temporary) {
<a href=#412 id=412 data-nosnippet>412</a> <span class="prelude-val">Some</span>(<span class="string">"Y"</span>)
<a href=#413 id=413 data-nosnippet>413</a> } <span class="kw">else </span>{
<a href=#414 id=414 data-nosnippet>414</a> <span class="prelude-val">Some</span>(<span class="string">"N"</span>)
<a href=#415 id=415 data-nosnippet>415</a> });
<a href=#416 id=416 data-nosnippet>416</a> <span class="self">self</span>.engines.push(<span class="prelude-val">Some</span>(engine));
<a href=#417 id=417 data-nosnippet>417</a> }
<a href=#418 id=418 data-nosnippet>418</a>
<a href=#419 id=419 data-nosnippet>419</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#420 id=420 data-nosnippet>420</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#421 id=421 data-nosnippet>421</a> Arc::new(<span class="self">self</span>.catalog_names.finish()),
<a href=#422 id=422 data-nosnippet>422</a> Arc::new(<span class="self">self</span>.schema_names.finish()),
<a href=#423 id=423 data-nosnippet>423</a> Arc::new(<span class="self">self</span>.table_names.finish()),
<a href=#424 id=424 data-nosnippet>424</a> Arc::new(<span class="self">self</span>.table_types.finish()),
<a href=#425 id=425 data-nosnippet>425</a> Arc::new(<span class="self">self</span>.table_ids.finish()),
<a href=#426 id=426 data-nosnippet>426</a> Arc::new(<span class="self">self</span>.data_length.finish()),
<a href=#427 id=427 data-nosnippet>427</a> Arc::new(<span class="self">self</span>.max_data_length.finish()),
<a href=#428 id=428 data-nosnippet>428</a> Arc::new(<span class="self">self</span>.index_length.finish()),
<a href=#429 id=429 data-nosnippet>429</a> Arc::new(<span class="self">self</span>.max_index_length.finish()),
<a href=#430 id=430 data-nosnippet>430</a> Arc::new(<span class="self">self</span>.avg_row_length.finish()),
<a href=#431 id=431 data-nosnippet>431</a> Arc::new(<span class="self">self</span>.engines.finish()),
<a href=#432 id=432 data-nosnippet>432</a> Arc::new(<span class="self">self</span>.version.finish()),
<a href=#433 id=433 data-nosnippet>433</a> Arc::new(<span class="self">self</span>.row_format.finish()),
<a href=#434 id=434 data-nosnippet>434</a> Arc::new(<span class="self">self</span>.table_rows.finish()),
<a href=#435 id=435 data-nosnippet>435</a> Arc::new(<span class="self">self</span>.data_free.finish()),
<a href=#436 id=436 data-nosnippet>436</a> Arc::new(<span class="self">self</span>.auto_increment.finish()),
<a href=#437 id=437 data-nosnippet>437</a> Arc::new(<span class="self">self</span>.create_time.finish()),
<a href=#438 id=438 data-nosnippet>438</a> Arc::new(<span class="self">self</span>.update_time.finish()),
<a href=#439 id=439 data-nosnippet>439</a> Arc::new(<span class="self">self</span>.check_time.finish()),
<a href=#440 id=440 data-nosnippet>440</a> Arc::new(<span class="self">self</span>.table_collation.finish()),
<a href=#441 id=441 data-nosnippet>441</a> Arc::new(<span class="self">self</span>.checksum.finish()),
<a href=#442 id=442 data-nosnippet>442</a> Arc::new(<span class="self">self</span>.create_options.finish()),
<a href=#443 id=443 data-nosnippet>443</a> Arc::new(<span class="self">self</span>.table_comment.finish()),
<a href=#444 id=444 data-nosnippet>444</a> Arc::new(<span class="self">self</span>.temporary.finish()),
<a href=#445 id=445 data-nosnippet>445</a> ];
<a href=#446 id=446 data-nosnippet>446</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#447 id=447 data-nosnippet>447</a> }
<a href=#448 id=448 data-nosnippet>448</a>}
<a href=#449 id=449 data-nosnippet>449</a>
<a href=#450 id=450 data-nosnippet>450</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaTables {
<a href=#451 id=451 data-nosnippet>451</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#452 id=452 data-nosnippet>452</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#453 id=453 data-nosnippet>453</a> }
<a href=#454 id=454 data-nosnippet>454</a>
<a href=#455 id=455 data-nosnippet>455</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#456 id=456 data-nosnippet>456</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#457 id=457 data-nosnippet>457</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#458 id=458 data-nosnippet>458</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#459 id=459 data-nosnippet>459</a> schema,
<a href=#460 id=460 data-nosnippet>460</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#461 id=461 data-nosnippet>461</a> builder
<a href=#462 id=462 data-nosnippet>462</a> .make_tables(<span class="prelude-val">None</span>)
<a href=#463 id=463 data-nosnippet>463</a> .<span class="kw">await
<a href=#464 id=464 data-nosnippet>464</a> </span>.map(|x| x.into_df_record_batch())
<a href=#465 id=465 data-nosnippet>465</a> .map_err(Into::into)
<a href=#466 id=466 data-nosnippet>466</a> }),
<a href=#467 id=467 data-nosnippet>467</a> ))
<a href=#468 id=468 data-nosnippet>468</a> }
<a href=#469 id=469 data-nosnippet>469</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,289 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/information_schema/views.rs`."><title>views.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/information_schema/</div>views.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_catalog::consts::INFORMATION_SCHEMA_VIEW_TABLE_ID;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datatypes::prelude::{ConcreteDataType, ScalarVectorBuilder, VectorRef};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datatypes::value::Value;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datatypes::vectors::StringVectorBuilder;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>futures::TryStreamExt;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>snafu::{OptionExt, ResultExt};
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>table::metadata::TableType;
<a href=#34 id=34 data-nosnippet>34</a>
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#37 id=37 data-nosnippet>37</a> CastManagerSnafu, CreateRecordBatchSnafu, GetViewCacheSnafu, InternalSnafu, <span class="prelude-ty">Result</span>,
<a href=#38 id=38 data-nosnippet>38</a> UpgradeWeakCatalogManagerRefSnafu, ViewInfoNotFoundSnafu,
<a href=#39 id=39 data-nosnippet>39</a>};
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">use </span><span class="kw">crate</span>::kvbackend::KvBackendCatalogManager;
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::information_schema::{InformationTable, Predicates, VIEWS};
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">const </span>INIT_CAPACITY: usize = <span class="number">42</span>;
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">pub const </span>TABLE_CATALOG: <span class="kw-2">&amp;</span>str = <span class="string">"table_catalog"</span>;
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">pub const </span>TABLE_SCHEMA: <span class="kw-2">&amp;</span>str = <span class="string">"table_schema"</span>;
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">pub const </span>TABLE_NAME: <span class="kw-2">&amp;</span>str = <span class="string">"table_name"</span>;
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">pub const </span>VIEW_DEFINITION: <span class="kw-2">&amp;</span>str = <span class="string">"view_definition"</span>;
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">pub const </span>CHECK_OPTION: <span class="kw-2">&amp;</span>str = <span class="string">"check_option"</span>;
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">pub const </span>IS_UPDATABLE: <span class="kw-2">&amp;</span>str = <span class="string">"is_updatable"</span>;
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">pub const </span>DEFINER: <span class="kw-2">&amp;</span>str = <span class="string">"definer"</span>;
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">pub const </span>SECURITY_TYPE: <span class="kw-2">&amp;</span>str = <span class="string">"security_type"</span>;
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">pub const </span>CHARACTER_SET_CLIENT: <span class="kw-2">&amp;</span>str = <span class="string">"character_set_client"</span>;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">pub const </span>COLLATION_CONNECTION: <span class="kw-2">&amp;</span>str = <span class="string">"collation_connection"</span>;
<a href=#54 id=54 data-nosnippet>54</a>
<a href=#55 id=55 data-nosnippet>55</a><span class="doccomment">/// The `information_schema.views` to provides information about views in databases.
<a href=#56 id=56 data-nosnippet>56</a></span><span class="attr">#[derive(Debug)]
<a href=#57 id=57 data-nosnippet>57</a></span><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>InformationSchemaViews {
<a href=#58 id=58 data-nosnippet>58</a> schema: SchemaRef,
<a href=#59 id=59 data-nosnippet>59</a> catalog_name: String,
<a href=#60 id=60 data-nosnippet>60</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#61 id=61 data-nosnippet>61</a>}
<a href=#62 id=62 data-nosnippet>62</a>
<a href=#63 id=63 data-nosnippet>63</a><span class="kw">impl </span>InformationSchemaViews {
<a href=#64 id=64 data-nosnippet>64</a> <span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>new(catalog_name: String, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#65 id=65 data-nosnippet>65</a> <span class="self">Self </span>{
<a href=#66 id=66 data-nosnippet>66</a> schema: <span class="self">Self</span>::schema(),
<a href=#67 id=67 data-nosnippet>67</a> catalog_name,
<a href=#68 id=68 data-nosnippet>68</a> catalog_manager,
<a href=#69 id=69 data-nosnippet>69</a> }
<a href=#70 id=70 data-nosnippet>70</a> }
<a href=#71 id=71 data-nosnippet>71</a>
<a href=#72 id=72 data-nosnippet>72</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>schema() -&gt; SchemaRef {
<a href=#73 id=73 data-nosnippet>73</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#74 id=74 data-nosnippet>74</a> ColumnSchema::new(TABLE_CATALOG, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#75 id=75 data-nosnippet>75</a> ColumnSchema::new(TABLE_SCHEMA, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#76 id=76 data-nosnippet>76</a> ColumnSchema::new(TABLE_NAME, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#77 id=77 data-nosnippet>77</a> ColumnSchema::new(VIEW_DEFINITION, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#78 id=78 data-nosnippet>78</a> ColumnSchema::new(CHECK_OPTION, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#79 id=79 data-nosnippet>79</a> ColumnSchema::new(IS_UPDATABLE, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#80 id=80 data-nosnippet>80</a> ColumnSchema::new(DEFINER, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#81 id=81 data-nosnippet>81</a> ColumnSchema::new(SECURITY_TYPE, ConcreteDataType::string_datatype(), <span class="bool-val">true</span>),
<a href=#82 id=82 data-nosnippet>82</a> ColumnSchema::new(
<a href=#83 id=83 data-nosnippet>83</a> CHARACTER_SET_CLIENT,
<a href=#84 id=84 data-nosnippet>84</a> ConcreteDataType::string_datatype(),
<a href=#85 id=85 data-nosnippet>85</a> <span class="bool-val">true</span>,
<a href=#86 id=86 data-nosnippet>86</a> ),
<a href=#87 id=87 data-nosnippet>87</a> ColumnSchema::new(
<a href=#88 id=88 data-nosnippet>88</a> COLLATION_CONNECTION,
<a href=#89 id=89 data-nosnippet>89</a> ConcreteDataType::string_datatype(),
<a href=#90 id=90 data-nosnippet>90</a> <span class="bool-val">true</span>,
<a href=#91 id=91 data-nosnippet>91</a> ),
<a href=#92 id=92 data-nosnippet>92</a> ]))
<a href=#93 id=93 data-nosnippet>93</a> }
<a href=#94 id=94 data-nosnippet>94</a>
<a href=#95 id=95 data-nosnippet>95</a> <span class="kw">fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; InformationSchemaViewsBuilder {
<a href=#96 id=96 data-nosnippet>96</a> InformationSchemaViewsBuilder::new(
<a href=#97 id=97 data-nosnippet>97</a> <span class="self">self</span>.schema.clone(),
<a href=#98 id=98 data-nosnippet>98</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#99 id=99 data-nosnippet>99</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#100 id=100 data-nosnippet>100</a> )
<a href=#101 id=101 data-nosnippet>101</a> }
<a href=#102 id=102 data-nosnippet>102</a>}
<a href=#103 id=103 data-nosnippet>103</a>
<a href=#104 id=104 data-nosnippet>104</a><span class="kw">impl </span>InformationTable <span class="kw">for </span>InformationSchemaViews {
<a href=#105 id=105 data-nosnippet>105</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#106 id=106 data-nosnippet>106</a> INFORMATION_SCHEMA_VIEW_TABLE_ID
<a href=#107 id=107 data-nosnippet>107</a> }
<a href=#108 id=108 data-nosnippet>108</a>
<a href=#109 id=109 data-nosnippet>109</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#110 id=110 data-nosnippet>110</a> VIEWS
<a href=#111 id=111 data-nosnippet>111</a> }
<a href=#112 id=112 data-nosnippet>112</a>
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#114 id=114 data-nosnippet>114</a> <span class="self">self</span>.schema.clone()
<a href=#115 id=115 data-nosnippet>115</a> }
<a href=#116 id=116 data-nosnippet>116</a>
<a href=#117 id=117 data-nosnippet>117</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#119 id=119 data-nosnippet>119</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#120 id=120 data-nosnippet>120</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#121 id=121 data-nosnippet>121</a> schema,
<a href=#122 id=122 data-nosnippet>122</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#123 id=123 data-nosnippet>123</a> builder
<a href=#124 id=124 data-nosnippet>124</a> .make_views(<span class="prelude-val">Some</span>(request))
<a href=#125 id=125 data-nosnippet>125</a> .<span class="kw">await
<a href=#126 id=126 data-nosnippet>126</a> </span>.map(|x| x.into_df_record_batch())
<a href=#127 id=127 data-nosnippet>127</a> .map_err(|err| datafusion::error::DataFusionError::External(Box::new(err)))
<a href=#128 id=128 data-nosnippet>128</a> }),
<a href=#129 id=129 data-nosnippet>129</a> ));
<a href=#130 id=130 data-nosnippet>130</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#131 id=131 data-nosnippet>131</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#132 id=132 data-nosnippet>132</a> .map_err(BoxedError::new)
<a href=#133 id=133 data-nosnippet>133</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#134 id=134 data-nosnippet>134</a> ))
<a href=#135 id=135 data-nosnippet>135</a> }
<a href=#136 id=136 data-nosnippet>136</a>}
<a href=#137 id=137 data-nosnippet>137</a>
<a href=#138 id=138 data-nosnippet>138</a><span class="doccomment">/// Builds the `information_schema.VIEWS` table row by row
<a href=#139 id=139 data-nosnippet>139</a>///
<a href=#140 id=140 data-nosnippet>140</a>/// Columns are based on &lt;https://dev.mysql.com/doc/refman/8.4/en/information-schema-views-table.html&gt;
<a href=#141 id=141 data-nosnippet>141</a></span><span class="kw">struct </span>InformationSchemaViewsBuilder {
<a href=#142 id=142 data-nosnippet>142</a> schema: SchemaRef,
<a href=#143 id=143 data-nosnippet>143</a> catalog_name: String,
<a href=#144 id=144 data-nosnippet>144</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#145 id=145 data-nosnippet>145</a>
<a href=#146 id=146 data-nosnippet>146</a> catalog_names: StringVectorBuilder,
<a href=#147 id=147 data-nosnippet>147</a> schema_names: StringVectorBuilder,
<a href=#148 id=148 data-nosnippet>148</a> table_names: StringVectorBuilder,
<a href=#149 id=149 data-nosnippet>149</a> view_definitions: StringVectorBuilder,
<a href=#150 id=150 data-nosnippet>150</a> check_options: StringVectorBuilder,
<a href=#151 id=151 data-nosnippet>151</a> is_updatable: StringVectorBuilder,
<a href=#152 id=152 data-nosnippet>152</a> definer: StringVectorBuilder,
<a href=#153 id=153 data-nosnippet>153</a> security_type: StringVectorBuilder,
<a href=#154 id=154 data-nosnippet>154</a> character_set_client: StringVectorBuilder,
<a href=#155 id=155 data-nosnippet>155</a> collation_connection: StringVectorBuilder,
<a href=#156 id=156 data-nosnippet>156</a>}
<a href=#157 id=157 data-nosnippet>157</a>
<a href=#158 id=158 data-nosnippet>158</a><span class="kw">impl </span>InformationSchemaViewsBuilder {
<a href=#159 id=159 data-nosnippet>159</a> <span class="kw">fn </span>new(
<a href=#160 id=160 data-nosnippet>160</a> schema: SchemaRef,
<a href=#161 id=161 data-nosnippet>161</a> catalog_name: String,
<a href=#162 id=162 data-nosnippet>162</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#163 id=163 data-nosnippet>163</a> ) -&gt; <span class="self">Self </span>{
<a href=#164 id=164 data-nosnippet>164</a> <span class="self">Self </span>{
<a href=#165 id=165 data-nosnippet>165</a> schema,
<a href=#166 id=166 data-nosnippet>166</a> catalog_name,
<a href=#167 id=167 data-nosnippet>167</a> catalog_manager,
<a href=#168 id=168 data-nosnippet>168</a> catalog_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#169 id=169 data-nosnippet>169</a> schema_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#170 id=170 data-nosnippet>170</a> table_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#171 id=171 data-nosnippet>171</a> view_definitions: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#172 id=172 data-nosnippet>172</a> check_options: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#173 id=173 data-nosnippet>173</a> is_updatable: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#174 id=174 data-nosnippet>174</a> definer: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#175 id=175 data-nosnippet>175</a> security_type: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#176 id=176 data-nosnippet>176</a> character_set_client: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#177 id=177 data-nosnippet>177</a> collation_connection: StringVectorBuilder::with_capacity(INIT_CAPACITY),
<a href=#178 id=178 data-nosnippet>178</a> }
<a href=#179 id=179 data-nosnippet>179</a> }
<a href=#180 id=180 data-nosnippet>180</a>
<a href=#181 id=181 data-nosnippet>181</a> <span class="doccomment">/// Construct the `information_schema.views` virtual table
<a href=#182 id=182 data-nosnippet>182</a> </span><span class="kw">async fn </span>make_views(<span class="kw-2">&amp;mut </span><span class="self">self</span>, request: <span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#183 id=183 data-nosnippet>183</a> <span class="kw">let </span>catalog_name = <span class="self">self</span>.catalog_name.clone();
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">let </span>catalog_manager = <span class="self">self
<a href=#185 id=185 data-nosnippet>185</a> </span>.catalog_manager
<a href=#186 id=186 data-nosnippet>186</a> .upgrade()
<a href=#187 id=187 data-nosnippet>187</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#188 id=188 data-nosnippet>188</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span>request);
<a href=#189 id=189 data-nosnippet>189</a> <span class="kw">let </span>view_info_cache = catalog_manager
<a href=#190 id=190 data-nosnippet>190</a> .as_any()
<a href=#191 id=191 data-nosnippet>191</a> .downcast_ref::&lt;KvBackendCatalogManager&gt;()
<a href=#192 id=192 data-nosnippet>192</a> .context(CastManagerSnafu)<span class="question-mark">?
<a href=#193 id=193 data-nosnippet>193</a> </span>.view_info_cache()<span class="question-mark">?</span>;
<a href=#194 id=194 data-nosnippet>194</a>
<a href=#195 id=195 data-nosnippet>195</a> <span class="kw">for </span>schema_name <span class="kw">in </span>catalog_manager.schema_names(<span class="kw-2">&amp;</span>catalog_name, <span class="prelude-val">None</span>).<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">let </span><span class="kw-2">mut </span>stream = catalog_manager.tables(<span class="kw-2">&amp;</span>catalog_name, <span class="kw-2">&amp;</span>schema_name, <span class="prelude-val">None</span>);
<a href=#197 id=197 data-nosnippet>197</a>
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(table) = stream.try_next().<span class="kw">await</span><span class="question-mark">? </span>{
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">let </span>table_info = table.table_info();
<a href=#200 id=200 data-nosnippet>200</a> <span class="kw">if </span>table_info.table_type == TableType::View {
<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">let </span>view_info = view_info_cache
<a href=#202 id=202 data-nosnippet>202</a> .get(table_info.ident.table_id)
<a href=#203 id=203 data-nosnippet>203</a> .<span class="kw">await
<a href=#204 id=204 data-nosnippet>204</a> </span>.context(GetViewCacheSnafu)<span class="question-mark">?
<a href=#205 id=205 data-nosnippet>205</a> </span>.context(ViewInfoNotFoundSnafu {
<a href=#206 id=206 data-nosnippet>206</a> name: <span class="kw-2">&amp;</span>table_info.name,
<a href=#207 id=207 data-nosnippet>207</a> })<span class="question-mark">?</span>;
<a href=#208 id=208 data-nosnippet>208</a> <span class="self">self</span>.add_view(
<a href=#209 id=209 data-nosnippet>209</a> <span class="kw-2">&amp;</span>predicates,
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw-2">&amp;</span>catalog_name,
<a href=#211 id=211 data-nosnippet>211</a> <span class="kw-2">&amp;</span>schema_name,
<a href=#212 id=212 data-nosnippet>212</a> <span class="kw-2">&amp;</span>table_info.name,
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw-2">&amp;</span>view_info.definition,
<a href=#214 id=214 data-nosnippet>214</a> )
<a href=#215 id=215 data-nosnippet>215</a> }
<a href=#216 id=216 data-nosnippet>216</a> }
<a href=#217 id=217 data-nosnippet>217</a> }
<a href=#218 id=218 data-nosnippet>218</a>
<a href=#219 id=219 data-nosnippet>219</a> <span class="self">self</span>.finish()
<a href=#220 id=220 data-nosnippet>220</a> }
<a href=#221 id=221 data-nosnippet>221</a>
<a href=#222 id=222 data-nosnippet>222</a> <span class="kw">fn </span>add_view(
<a href=#223 id=223 data-nosnippet>223</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#224 id=224 data-nosnippet>224</a> predicates: <span class="kw-2">&amp;</span>Predicates,
<a href=#225 id=225 data-nosnippet>225</a> catalog_name: <span class="kw-2">&amp;</span>str,
<a href=#226 id=226 data-nosnippet>226</a> schema_name: <span class="kw-2">&amp;</span>str,
<a href=#227 id=227 data-nosnippet>227</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#228 id=228 data-nosnippet>228</a> definition: <span class="kw-2">&amp;</span>str,
<a href=#229 id=229 data-nosnippet>229</a> ) {
<a href=#230 id=230 data-nosnippet>230</a> <span class="kw">let </span>row = [
<a href=#231 id=231 data-nosnippet>231</a> (TABLE_CATALOG, <span class="kw-2">&amp;</span>Value::from(catalog_name)),
<a href=#232 id=232 data-nosnippet>232</a> (TABLE_SCHEMA, <span class="kw-2">&amp;</span>Value::from(schema_name)),
<a href=#233 id=233 data-nosnippet>233</a> (TABLE_NAME, <span class="kw-2">&amp;</span>Value::from(table_name)),
<a href=#234 id=234 data-nosnippet>234</a> ];
<a href=#235 id=235 data-nosnippet>235</a>
<a href=#236 id=236 data-nosnippet>236</a> <span class="kw">if </span>!predicates.eval(<span class="kw-2">&amp;</span>row) {
<a href=#237 id=237 data-nosnippet>237</a> <span class="kw">return</span>;
<a href=#238 id=238 data-nosnippet>238</a> }
<a href=#239 id=239 data-nosnippet>239</a> <span class="self">self</span>.catalog_names.push(<span class="prelude-val">Some</span>(catalog_name));
<a href=#240 id=240 data-nosnippet>240</a> <span class="self">self</span>.schema_names.push(<span class="prelude-val">Some</span>(schema_name));
<a href=#241 id=241 data-nosnippet>241</a> <span class="self">self</span>.table_names.push(<span class="prelude-val">Some</span>(table_name));
<a href=#242 id=242 data-nosnippet>242</a> <span class="self">self</span>.view_definitions.push(<span class="prelude-val">Some</span>(definition));
<a href=#243 id=243 data-nosnippet>243</a> <span class="self">self</span>.check_options.push(<span class="prelude-val">None</span>);
<a href=#244 id=244 data-nosnippet>244</a> <span class="comment">// View is not updatable, statements such UPDATE , DELETE , and INSERT are illegal and are rejected.
<a href=#245 id=245 data-nosnippet>245</a> </span><span class="self">self</span>.is_updatable.push(<span class="prelude-val">Some</span>(<span class="string">"NO"</span>));
<a href=#246 id=246 data-nosnippet>246</a> <span class="self">self</span>.definer.push(<span class="prelude-val">None</span>);
<a href=#247 id=247 data-nosnippet>247</a> <span class="self">self</span>.security_type.push(<span class="prelude-val">None</span>);
<a href=#248 id=248 data-nosnippet>248</a> <span class="self">self</span>.character_set_client.push(<span class="prelude-val">Some</span>(<span class="string">"utf8"</span>));
<a href=#249 id=249 data-nosnippet>249</a> <span class="self">self</span>.collation_connection.push(<span class="prelude-val">Some</span>(<span class="string">"utf8_bin"</span>));
<a href=#250 id=250 data-nosnippet>250</a> }
<a href=#251 id=251 data-nosnippet>251</a>
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw">fn </span>finish(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#253 id=253 data-nosnippet>253</a> <span class="kw">let </span>columns: Vec&lt;VectorRef&gt; = <span class="macro">vec!</span>[
<a href=#254 id=254 data-nosnippet>254</a> Arc::new(<span class="self">self</span>.catalog_names.finish()),
<a href=#255 id=255 data-nosnippet>255</a> Arc::new(<span class="self">self</span>.schema_names.finish()),
<a href=#256 id=256 data-nosnippet>256</a> Arc::new(<span class="self">self</span>.table_names.finish()),
<a href=#257 id=257 data-nosnippet>257</a> Arc::new(<span class="self">self</span>.view_definitions.finish()),
<a href=#258 id=258 data-nosnippet>258</a> Arc::new(<span class="self">self</span>.check_options.finish()),
<a href=#259 id=259 data-nosnippet>259</a> Arc::new(<span class="self">self</span>.is_updatable.finish()),
<a href=#260 id=260 data-nosnippet>260</a> Arc::new(<span class="self">self</span>.definer.finish()),
<a href=#261 id=261 data-nosnippet>261</a> Arc::new(<span class="self">self</span>.security_type.finish()),
<a href=#262 id=262 data-nosnippet>262</a> Arc::new(<span class="self">self</span>.character_set_client.finish()),
<a href=#263 id=263 data-nosnippet>263</a> Arc::new(<span class="self">self</span>.collation_connection.finish()),
<a href=#264 id=264 data-nosnippet>264</a> ];
<a href=#265 id=265 data-nosnippet>265</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), columns).context(CreateRecordBatchSnafu)
<a href=#266 id=266 data-nosnippet>266</a> }
<a href=#267 id=267 data-nosnippet>267</a>}
<a href=#268 id=268 data-nosnippet>268</a>
<a href=#269 id=269 data-nosnippet>269</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>InformationSchemaViews {
<a href=#270 id=270 data-nosnippet>270</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#271 id=271 data-nosnippet>271</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#272 id=272 data-nosnippet>272</a> }
<a href=#273 id=273 data-nosnippet>273</a>
<a href=#274 id=274 data-nosnippet>274</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#275 id=275 data-nosnippet>275</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#276 id=276 data-nosnippet>276</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#277 id=277 data-nosnippet>277</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#278 id=278 data-nosnippet>278</a> schema,
<a href=#279 id=279 data-nosnippet>279</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#280 id=280 data-nosnippet>280</a> builder
<a href=#281 id=281 data-nosnippet>281</a> .make_views(<span class="prelude-val">None</span>)
<a href=#282 id=282 data-nosnippet>282</a> .<span class="kw">await
<a href=#283 id=283 data-nosnippet>283</a> </span>.map(|x| x.into_df_record_batch())
<a href=#284 id=284 data-nosnippet>284</a> .map_err(Into::into)
<a href=#285 id=285 data-nosnippet>285</a> }),
<a href=#286 id=286 data-nosnippet>286</a> ))
<a href=#287 id=287 data-nosnippet>287</a> }
<a href=#288 id=288 data-nosnippet>288</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,217 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/memory_table.rs`."><title>memory_table.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/</div>memory_table.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">mod </span>table_columns;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>std::sync::Arc;
<a href=#18 id=18 data-nosnippet>18</a>
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>arrow_schema::SchemaRef <span class="kw">as </span>ArrowSchemaRef;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_recordbatch::{RecordBatch, SendableRecordBatchStream};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>datafusion::physical_plan::SendableRecordBatchStream <span class="kw">as </span>DfSendableRecordBatchStream;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datafusion::physical_plan::streaming::PartitionStream <span class="kw">as </span>DfPartitionStream;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datatypes::schema::SchemaRef;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datatypes::vectors::VectorRef;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>snafu::ResultExt;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#31 id=31 data-nosnippet>31</a>
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span><span class="kw">crate</span>::error::{CreateRecordBatchSnafu, InternalSnafu, <span class="prelude-ty">Result</span>};
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::SystemTable;
<a href=#34 id=34 data-nosnippet>34</a>
<a href=#35 id=35 data-nosnippet>35</a><span class="doccomment">/// A memory table with specified schema and columns.
<a href=#36 id=36 data-nosnippet>36</a></span><span class="attr">#[derive(Debug)]
<a href=#37 id=37 data-nosnippet>37</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>MemoryTable {
<a href=#38 id=38 data-nosnippet>38</a> <span class="kw">pub</span>(<span class="kw">crate</span>) table_id: TableId,
<a href=#39 id=39 data-nosnippet>39</a> <span class="kw">pub</span>(<span class="kw">crate</span>) table_name: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str,
<a href=#40 id=40 data-nosnippet>40</a> <span class="kw">pub</span>(<span class="kw">crate</span>) schema: SchemaRef,
<a href=#41 id=41 data-nosnippet>41</a> <span class="kw">pub</span>(<span class="kw">crate</span>) columns: Vec&lt;VectorRef&gt;,
<a href=#42 id=42 data-nosnippet>42</a>}
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">impl </span>MemoryTable {
<a href=#45 id=45 data-nosnippet>45</a> <span class="doccomment">/// Creates a memory table with table id, name, schema and columns.
<a href=#46 id=46 data-nosnippet>46</a> </span><span class="kw">pub fn </span>new(
<a href=#47 id=47 data-nosnippet>47</a> table_id: TableId,
<a href=#48 id=48 data-nosnippet>48</a> table_name: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str,
<a href=#49 id=49 data-nosnippet>49</a> schema: SchemaRef,
<a href=#50 id=50 data-nosnippet>50</a> columns: Vec&lt;VectorRef&gt;,
<a href=#51 id=51 data-nosnippet>51</a> ) -&gt; <span class="self">Self </span>{
<a href=#52 id=52 data-nosnippet>52</a> <span class="self">Self </span>{
<a href=#53 id=53 data-nosnippet>53</a> table_id,
<a href=#54 id=54 data-nosnippet>54</a> table_name,
<a href=#55 id=55 data-nosnippet>55</a> schema,
<a href=#56 id=56 data-nosnippet>56</a> columns,
<a href=#57 id=57 data-nosnippet>57</a> }
<a href=#58 id=58 data-nosnippet>58</a> }
<a href=#59 id=59 data-nosnippet>59</a>
<a href=#60 id=60 data-nosnippet>60</a> <span class="kw">pub fn </span>builder(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; MemoryTableBuilder {
<a href=#61 id=61 data-nosnippet>61</a> MemoryTableBuilder::new(<span class="self">self</span>.schema.clone(), <span class="self">self</span>.columns.clone())
<a href=#62 id=62 data-nosnippet>62</a> }
<a href=#63 id=63 data-nosnippet>63</a>}
<a href=#64 id=64 data-nosnippet>64</a>
<a href=#65 id=65 data-nosnippet>65</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>MemoryTableBuilder {
<a href=#66 id=66 data-nosnippet>66</a> schema: SchemaRef,
<a href=#67 id=67 data-nosnippet>67</a> columns: Vec&lt;VectorRef&gt;,
<a href=#68 id=68 data-nosnippet>68</a>}
<a href=#69 id=69 data-nosnippet>69</a>
<a href=#70 id=70 data-nosnippet>70</a><span class="kw">impl </span>MemoryTableBuilder {
<a href=#71 id=71 data-nosnippet>71</a> <span class="kw">fn </span>new(schema: SchemaRef, columns: Vec&lt;VectorRef&gt;) -&gt; <span class="self">Self </span>{
<a href=#72 id=72 data-nosnippet>72</a> <span class="self">Self </span>{ schema, columns }
<a href=#73 id=73 data-nosnippet>73</a> }
<a href=#74 id=74 data-nosnippet>74</a>
<a href=#75 id=75 data-nosnippet>75</a> <span class="doccomment">/// Construct the `information_schema.{table_name}` virtual table
<a href=#76 id=76 data-nosnippet>76</a> </span><span class="kw">pub async fn </span>memory_records(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;RecordBatch&gt; {
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">if </span><span class="self">self</span>.columns.is_empty() {
<a href=#78 id=78 data-nosnippet>78</a> <span class="prelude-val">Ok</span>(RecordBatch::new_empty(<span class="self">self</span>.schema.clone()))
<a href=#79 id=79 data-nosnippet>79</a> } <span class="kw">else </span>{
<a href=#80 id=80 data-nosnippet>80</a> RecordBatch::new(<span class="self">self</span>.schema.clone(), std::mem::take(<span class="kw-2">&amp;mut </span><span class="self">self</span>.columns))
<a href=#81 id=81 data-nosnippet>81</a> .context(CreateRecordBatchSnafu)
<a href=#82 id=82 data-nosnippet>82</a> }
<a href=#83 id=83 data-nosnippet>83</a> }
<a href=#84 id=84 data-nosnippet>84</a>}
<a href=#85 id=85 data-nosnippet>85</a>
<a href=#86 id=86 data-nosnippet>86</a><span class="kw">impl </span>DfPartitionStream <span class="kw">for </span>MemoryTable {
<a href=#87 id=87 data-nosnippet>87</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>ArrowSchemaRef {
<a href=#88 id=88 data-nosnippet>88</a> <span class="self">self</span>.schema.arrow_schema()
<a href=#89 id=89 data-nosnippet>89</a> }
<a href=#90 id=90 data-nosnippet>90</a>
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">fn </span>execute(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: Arc&lt;TaskContext&gt;) -&gt; DfSendableRecordBatchStream {
<a href=#92 id=92 data-nosnippet>92</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#93 id=93 data-nosnippet>93</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#94 id=94 data-nosnippet>94</a> Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#95 id=95 data-nosnippet>95</a> schema,
<a href=#96 id=96 data-nosnippet>96</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#97 id=97 data-nosnippet>97</a> builder
<a href=#98 id=98 data-nosnippet>98</a> .memory_records()
<a href=#99 id=99 data-nosnippet>99</a> .<span class="kw">await
<a href=#100 id=100 data-nosnippet>100</a> </span>.map(|x| x.into_df_record_batch())
<a href=#101 id=101 data-nosnippet>101</a> .map_err(Into::into)
<a href=#102 id=102 data-nosnippet>102</a> }),
<a href=#103 id=103 data-nosnippet>103</a> ))
<a href=#104 id=104 data-nosnippet>104</a> }
<a href=#105 id=105 data-nosnippet>105</a>}
<a href=#106 id=106 data-nosnippet>106</a>
<a href=#107 id=107 data-nosnippet>107</a><span class="kw">impl </span>SystemTable <span class="kw">for </span>MemoryTable {
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#109 id=109 data-nosnippet>109</a> <span class="self">self</span>.table_id
<a href=#110 id=110 data-nosnippet>110</a> }
<a href=#111 id=111 data-nosnippet>111</a>
<a href=#112 id=112 data-nosnippet>112</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#113 id=113 data-nosnippet>113</a> <span class="self">self</span>.table_name
<a href=#114 id=114 data-nosnippet>114</a> }
<a href=#115 id=115 data-nosnippet>115</a>
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#117 id=117 data-nosnippet>117</a> <span class="self">self</span>.schema.clone()
<a href=#118 id=118 data-nosnippet>118</a> }
<a href=#119 id=119 data-nosnippet>119</a>
<a href=#120 id=120 data-nosnippet>120</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, _request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#121 id=121 data-nosnippet>121</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#122 id=122 data-nosnippet>122</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = <span class="self">self</span>.builder();
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#124 id=124 data-nosnippet>124</a> schema,
<a href=#125 id=125 data-nosnippet>125</a> futures::stream::once(<span class="kw">async move </span>{
<a href=#126 id=126 data-nosnippet>126</a> builder
<a href=#127 id=127 data-nosnippet>127</a> .memory_records()
<a href=#128 id=128 data-nosnippet>128</a> .<span class="kw">await
<a href=#129 id=129 data-nosnippet>129</a> </span>.map(|x| x.into_df_record_batch())
<a href=#130 id=130 data-nosnippet>130</a> .map_err(Into::into)
<a href=#131 id=131 data-nosnippet>131</a> }),
<a href=#132 id=132 data-nosnippet>132</a> ));
<a href=#133 id=133 data-nosnippet>133</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#134 id=134 data-nosnippet>134</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#135 id=135 data-nosnippet>135</a> .map_err(BoxedError::new)
<a href=#136 id=136 data-nosnippet>136</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#137 id=137 data-nosnippet>137</a> ))
<a href=#138 id=138 data-nosnippet>138</a> }
<a href=#139 id=139 data-nosnippet>139</a>}
<a href=#140 id=140 data-nosnippet>140</a>
<a href=#141 id=141 data-nosnippet>141</a><span class="attr">#[cfg(test)]
<a href=#142 id=142 data-nosnippet>142</a></span><span class="kw">mod </span>tests {
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">use </span>std::sync::Arc;
<a href=#144 id=144 data-nosnippet>144</a>
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">use </span>common_recordbatch::RecordBatches;
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">use </span>datatypes::prelude::ConcreteDataType;
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema};
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">use </span>datatypes::vectors::StringVector;
<a href=#149 id=149 data-nosnippet>149</a>
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">use </span><span class="kw">crate</span>::system_schema::SystemTable;
<a href=#152 id=152 data-nosnippet>152</a>
<a href=#153 id=153 data-nosnippet>153</a> <span class="attr">#[tokio::test]
<a href=#154 id=154 data-nosnippet>154</a> </span><span class="kw">async fn </span>test_memory_table() {
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">let </span>schema = Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#156 id=156 data-nosnippet>156</a> ColumnSchema::new(<span class="string">"a"</span>, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#157 id=157 data-nosnippet>157</a> ColumnSchema::new(<span class="string">"b"</span>, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#158 id=158 data-nosnippet>158</a> ]));
<a href=#159 id=159 data-nosnippet>159</a>
<a href=#160 id=160 data-nosnippet>160</a> <span class="kw">let </span>table = MemoryTable::new(
<a href=#161 id=161 data-nosnippet>161</a> <span class="number">42</span>,
<a href=#162 id=162 data-nosnippet>162</a> <span class="string">"test"</span>,
<a href=#163 id=163 data-nosnippet>163</a> schema.clone(),
<a href=#164 id=164 data-nosnippet>164</a> <span class="macro">vec!</span>[
<a href=#165 id=165 data-nosnippet>165</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"a1"</span>, <span class="string">"a2"</span>])),
<a href=#166 id=166 data-nosnippet>166</a> Arc::new(StringVector::from(<span class="macro">vec!</span>[<span class="string">"b1"</span>, <span class="string">"b2"</span>])),
<a href=#167 id=167 data-nosnippet>167</a> ],
<a href=#168 id=168 data-nosnippet>168</a> );
<a href=#169 id=169 data-nosnippet>169</a>
<a href=#170 id=170 data-nosnippet>170</a> <span class="macro">assert_eq!</span>(<span class="number">42</span>, table.table_id());
<a href=#171 id=171 data-nosnippet>171</a> <span class="macro">assert_eq!</span>(<span class="string">"test"</span>, table.table_name);
<a href=#172 id=172 data-nosnippet>172</a> <span class="macro">assert_eq!</span>(schema, SystemTable::schema(<span class="kw-2">&amp;</span>table));
<a href=#173 id=173 data-nosnippet>173</a>
<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">let </span>stream = table.to_stream(ScanRequest::default()).unwrap();
<a href=#175 id=175 data-nosnippet>175</a>
<a href=#176 id=176 data-nosnippet>176</a> <span class="kw">let </span>batches = RecordBatches::try_collect(stream).<span class="kw">await</span>.unwrap();
<a href=#177 id=177 data-nosnippet>177</a>
<a href=#178 id=178 data-nosnippet>178</a> <span class="macro">assert_eq!</span>(
<a href=#179 id=179 data-nosnippet>179</a> <span class="string">"\
<a href=#180 id=180 data-nosnippet>180</a>+----+----+
<a href=#181 id=181 data-nosnippet>181</a>| a | b |
<a href=#182 id=182 data-nosnippet>182</a>+----+----+
<a href=#183 id=183 data-nosnippet>183</a>| a1 | b1 |
<a href=#184 id=184 data-nosnippet>184</a>| a2 | b2 |
<a href=#185 id=185 data-nosnippet>185</a>+----+----+"</span>,
<a href=#186 id=186 data-nosnippet>186</a> batches.pretty_print().unwrap()
<a href=#187 id=187 data-nosnippet>187</a> );
<a href=#188 id=188 data-nosnippet>188</a> }
<a href=#189 id=189 data-nosnippet>189</a>
<a href=#190 id=190 data-nosnippet>190</a> <span class="attr">#[tokio::test]
<a href=#191 id=191 data-nosnippet>191</a> </span><span class="kw">async fn </span>test_empty_memory_table() {
<a href=#192 id=192 data-nosnippet>192</a> <span class="kw">let </span>schema = Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#193 id=193 data-nosnippet>193</a> ColumnSchema::new(<span class="string">"a"</span>, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#194 id=194 data-nosnippet>194</a> ColumnSchema::new(<span class="string">"b"</span>, ConcreteDataType::string_datatype(), <span class="bool-val">false</span>),
<a href=#195 id=195 data-nosnippet>195</a> ]));
<a href=#196 id=196 data-nosnippet>196</a>
<a href=#197 id=197 data-nosnippet>197</a> <span class="kw">let </span>table = MemoryTable::new(<span class="number">42</span>, <span class="string">"test"</span>, schema.clone(), <span class="macro">vec!</span>[]);
<a href=#198 id=198 data-nosnippet>198</a>
<a href=#199 id=199 data-nosnippet>199</a> <span class="macro">assert_eq!</span>(<span class="number">42</span>, table.table_id());
<a href=#200 id=200 data-nosnippet>200</a> <span class="macro">assert_eq!</span>(<span class="string">"test"</span>, table.table_name());
<a href=#201 id=201 data-nosnippet>201</a> <span class="macro">assert_eq!</span>(schema, SystemTable::schema(<span class="kw-2">&amp;</span>table));
<a href=#202 id=202 data-nosnippet>202</a>
<a href=#203 id=203 data-nosnippet>203</a> <span class="kw">let </span>stream = table.to_stream(ScanRequest::default()).unwrap();
<a href=#204 id=204 data-nosnippet>204</a>
<a href=#205 id=205 data-nosnippet>205</a> <span class="kw">let </span>batches = RecordBatches::try_collect(stream).<span class="kw">await</span>.unwrap();
<a href=#206 id=206 data-nosnippet>206</a>
<a href=#207 id=207 data-nosnippet>207</a> <span class="macro">assert_eq!</span>(
<a href=#208 id=208 data-nosnippet>208</a> <span class="string">"\
<a href=#209 id=209 data-nosnippet>209</a>+---+---+
<a href=#210 id=210 data-nosnippet>210</a>| a | b |
<a href=#211 id=211 data-nosnippet>211</a>+---+---+
<a href=#212 id=212 data-nosnippet>212</a>+---+---+"</span>,
<a href=#213 id=213 data-nosnippet>213</a> batches.pretty_print().unwrap()
<a href=#214 id=214 data-nosnippet>214</a> );
<a href=#215 id=215 data-nosnippet>215</a> }
<a href=#216 id=216 data-nosnippet>216</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,51 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/memory_table/table_columns.rs`."><title>table_columns.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/memory_table/</div>table_columns.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="attr">#[macro_export]
<a href=#16 id=16 data-nosnippet>16</a></span><span class="macro">macro_rules!</span> memory_table_cols{
<a href=#17 id=17 data-nosnippet>17</a> ([$(<span class="macro-nonterminal">$colname</span>:ident),<span class="kw-2">*</span>], <span class="macro-nonterminal">$t</span>:expr) =&gt; {
<a href=#18 id=18 data-nosnippet>18</a> <span class="kw">let </span>t = <span class="kw-2">&amp;</span><span class="macro-nonterminal">$t</span>;
<a href=#19 id=19 data-nosnippet>19</a> $(
<a href=#20 id=20 data-nosnippet>20</a> <span class="kw">let </span><span class="kw-2">mut </span><span class="macro-nonterminal">$colname </span>= Vec::with_capacity(t.len());
<a href=#21 id=21 data-nosnippet>21</a> )*
<a href=#22 id=22 data-nosnippet>22</a> <span class="macro">paste::paste!</span>{
<a href=#23 id=23 data-nosnippet>23</a> <span class="kw">for </span><span class="kw-2">&amp;</span>($([&lt;r_ <span class="macro-nonterminal">$colname</span>&gt;]),<span class="kw-2">*</span>) <span class="kw">in </span>t {
<a href=#24 id=24 data-nosnippet>24</a> $(
<a href=#25 id=25 data-nosnippet>25</a> <span class="macro-nonterminal">$colname</span>.push([&lt;r_ <span class="macro-nonterminal">$colname</span>&gt;]);
<a href=#26 id=26 data-nosnippet>26</a> )*
<a href=#27 id=27 data-nosnippet>27</a> }
<a href=#28 id=28 data-nosnippet>28</a> }
<a href=#29 id=29 data-nosnippet>29</a> };
<a href=#30 id=30 data-nosnippet>30</a>}
<a href=#31 id=31 data-nosnippet>31</a>
<a href=#32 id=32 data-nosnippet>32</a><span class="attr">#[cfg(test)]
<a href=#33 id=33 data-nosnippet>33</a></span><span class="kw">mod </span>tests {
<a href=#34 id=34 data-nosnippet>34</a>
<a href=#35 id=35 data-nosnippet>35</a> <span class="attr">#[test]
<a href=#36 id=36 data-nosnippet>36</a> </span><span class="kw">fn </span>test_memory_table_columns() {
<a href=#37 id=37 data-nosnippet>37</a> <span class="macro">memory_table_cols!</span>(
<a href=#38 id=38 data-nosnippet>38</a> [oid, typname, typlen],
<a href=#39 id=39 data-nosnippet>39</a> [
<a href=#40 id=40 data-nosnippet>40</a> (<span class="number">1</span>, <span class="string">"String"</span>, -<span class="number">1</span>),
<a href=#41 id=41 data-nosnippet>41</a> (<span class="number">2</span>, <span class="string">"Binary"</span>, -<span class="number">1</span>),
<a href=#42 id=42 data-nosnippet>42</a> (<span class="number">3</span>, <span class="string">"Time"</span>, <span class="number">8</span>),
<a href=#43 id=43 data-nosnippet>43</a> (<span class="number">4</span>, <span class="string">"Datetime"</span>, <span class="number">8</span>)
<a href=#44 id=44 data-nosnippet>44</a> ]
<a href=#45 id=45 data-nosnippet>45</a> );
<a href=#46 id=46 data-nosnippet>46</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>oid[..], <span class="kw-2">&amp;</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]);
<a href=#47 id=47 data-nosnippet>47</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>typname[..], <span class="kw-2">&amp;</span>[<span class="string">"String"</span>, <span class="string">"Binary"</span>, <span class="string">"Time"</span>, <span class="string">"Datetime"</span>]);
<a href=#48 id=48 data-nosnippet>48</a> <span class="macro">assert_eq!</span>(<span class="kw-2">&amp;</span>typlen[..], <span class="kw-2">&amp;</span>[-<span class="number">1</span>, -<span class="number">1</span>, <span class="number">8</span>, <span class="number">8</span>]);
<a href=#49 id=49 data-nosnippet>49</a> }
<a href=#50 id=50 data-nosnippet>50</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,60 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/numbers_table_provider.rs`."><title>numbers_table_provider.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/</div>numbers_table_provider.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="attr">#[cfg(any(test, feature = <span class="string">"testing"</span>, debug_assertions))]
<a href=#16 id=16 data-nosnippet>16</a></span><span class="kw">use </span>common_catalog::consts::NUMBERS_TABLE_ID;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>table::TableRef;
<a href=#18 id=18 data-nosnippet>18</a><span class="attr">#[cfg(any(test, feature = <span class="string">"testing"</span>, debug_assertions))]
<a href=#19 id=19 data-nosnippet>19</a></span><span class="kw">use </span>table::table::numbers::NUMBERS_TABLE_NAME;
<a href=#20 id=20 data-nosnippet>20</a><span class="attr">#[cfg(any(test, feature = <span class="string">"testing"</span>, debug_assertions))]
<a href=#21 id=21 data-nosnippet>21</a></span><span class="kw">use </span>table::table::numbers::NumbersTable;
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a><span class="comment">// NumbersTableProvider is a dedicated provider for feature-gating the numbers table.
<a href=#24 id=24 data-nosnippet>24</a></span><span class="attr">#[derive(Clone)]
<a href=#25 id=25 data-nosnippet>25</a></span><span class="kw">pub struct </span>NumbersTableProvider;
<a href=#26 id=26 data-nosnippet>26</a>
<a href=#27 id=27 data-nosnippet>27</a><span class="attr">#[cfg(any(test, feature = <span class="string">"testing"</span>, debug_assertions))]
<a href=#28 id=28 data-nosnippet>28</a></span><span class="kw">impl </span>NumbersTableProvider {
<a href=#29 id=29 data-nosnippet>29</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>table_exists(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str) -&gt; bool {
<a href=#30 id=30 data-nosnippet>30</a> name == NUMBERS_TABLE_NAME
<a href=#31 id=31 data-nosnippet>31</a> }
<a href=#32 id=32 data-nosnippet>32</a>
<a href=#33 id=33 data-nosnippet>33</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>table_names(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Vec&lt;String&gt; {
<a href=#34 id=34 data-nosnippet>34</a> <span class="macro">vec!</span>[NUMBERS_TABLE_NAME.to_string()]
<a href=#35 id=35 data-nosnippet>35</a> }
<a href=#36 id=36 data-nosnippet>36</a>
<a href=#37 id=37 data-nosnippet>37</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>table(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;TableRef&gt; {
<a href=#38 id=38 data-nosnippet>38</a> <span class="kw">if </span>name == NUMBERS_TABLE_NAME {
<a href=#39 id=39 data-nosnippet>39</a> <span class="prelude-val">Some</span>(NumbersTable::table(NUMBERS_TABLE_ID))
<a href=#40 id=40 data-nosnippet>40</a> } <span class="kw">else </span>{
<a href=#41 id=41 data-nosnippet>41</a> <span class="prelude-val">None
<a href=#42 id=42 data-nosnippet>42</a> </span>}
<a href=#43 id=43 data-nosnippet>43</a> }
<a href=#44 id=44 data-nosnippet>44</a>}
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a><span class="attr">#[cfg(not(any(test, feature = <span class="string">"testing"</span>, debug_assertions)))]
<a href=#47 id=47 data-nosnippet>47</a></span><span class="kw">impl </span>NumbersTableProvider {
<a href=#48 id=48 data-nosnippet>48</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>table_exists(<span class="kw-2">&amp;</span><span class="self">self</span>, _name: <span class="kw-2">&amp;</span>str) -&gt; bool {
<a href=#49 id=49 data-nosnippet>49</a> <span class="bool-val">false
<a href=#50 id=50 data-nosnippet>50</a> </span>}
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>table_names(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Vec&lt;String&gt; {
<a href=#53 id=53 data-nosnippet>53</a> <span class="macro">vec!</span>[]
<a href=#54 id=54 data-nosnippet>54</a> }
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>table(<span class="kw-2">&amp;</span><span class="self">self</span>, _name: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;TableRef&gt; {
<a href=#57 id=57 data-nosnippet>57</a> <span class="prelude-val">None
<a href=#58 id=58 data-nosnippet>58</a> </span>}
<a href=#59 id=59 data-nosnippet>59</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,315 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/pg_catalog.rs`."><title>pg_catalog.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/</div>pg_catalog.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::collections::HashMap;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::sync::{Arc, Weak};
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>arrow_schema::SchemaRef;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>async_trait::async_trait;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_catalog::consts::{DEFAULT_CATALOG_NAME, PG_CATALOG_NAME, PG_CATALOG_TABLE_ID_START};
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_recordbatch::SendableRecordBatchStream;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_recordbatch::adapter::RecordBatchStreamAdapter;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_telemetry::warn;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>datafusion::datasource::TableType;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>datafusion::error::DataFusionError;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>datafusion::execution::TaskContext;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>datafusion::physical_plan::stream::RecordBatchStreamAdapter <span class="kw">as </span>DfRecordBatchStreamAdapter;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>datafusion_pg_catalog::pg_catalog::catalog_info::CatalogInfo;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>datafusion_pg_catalog::pg_catalog::context::EmptyContextProvider;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>datafusion_pg_catalog::pg_catalog::{
<a href=#32 id=32 data-nosnippet>32</a> PG_CATALOG_TABLES, PgCatalogSchemaProvider, PgCatalogStaticTables, PgCatalogTable,
<a href=#33 id=33 data-nosnippet>33</a>};
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span>snafu::ResultExt;
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span>store_api::storage::ScanRequest;
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>table::TableRef;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>table::metadata::TableId;
<a href=#38 id=38 data-nosnippet>38</a>
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">use </span><span class="kw">crate</span>::error::{InternalSnafu, ProjectSchemaSnafu, <span class="prelude-ty">Result</span>};
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::{
<a href=#42 id=42 data-nosnippet>42</a> SystemSchemaProvider, SystemSchemaProviderInner, SystemTable, SystemTableRef,
<a href=#43 id=43 data-nosnippet>43</a>};
<a href=#44 id=44 data-nosnippet>44</a>
<a href=#45 id=45 data-nosnippet>45</a><span class="doccomment">/// [`PGCatalogProvider`] is the provider for a schema named `pg_catalog`, it is not a catalog.
<a href=#46 id=46 data-nosnippet>46</a></span><span class="kw">pub struct </span>PGCatalogProvider {
<a href=#47 id=47 data-nosnippet>47</a> catalog_name: String,
<a href=#48 id=48 data-nosnippet>48</a> inner: PgCatalogSchemaProvider&lt;CatalogManagerWrapper, EmptyContextProvider&gt;,
<a href=#49 id=49 data-nosnippet>49</a> tables: HashMap&lt;String, TableRef&gt;,
<a href=#50 id=50 data-nosnippet>50</a> table_ids: HashMap&lt;<span class="kw-2">&amp;</span><span class="lifetime">'static </span>str, u32&gt;,
<a href=#51 id=51 data-nosnippet>51</a>}
<a href=#52 id=52 data-nosnippet>52</a>
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">impl </span>SystemSchemaProvider <span class="kw">for </span>PGCatalogProvider {
<a href=#54 id=54 data-nosnippet>54</a> <span class="kw">fn </span>tables(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>HashMap&lt;String, TableRef&gt; {
<a href=#55 id=55 data-nosnippet>55</a> <span class="macro">assert!</span>(!<span class="self">self</span>.tables.is_empty());
<a href=#56 id=56 data-nosnippet>56</a>
<a href=#57 id=57 data-nosnippet>57</a> <span class="kw-2">&amp;</span><span class="self">self</span>.tables
<a href=#58 id=58 data-nosnippet>58</a> }
<a href=#59 id=59 data-nosnippet>59</a>}
<a href=#60 id=60 data-nosnippet>60</a>
<a href=#61 id=61 data-nosnippet>61</a><span class="kw">impl </span>PGCatalogProvider {
<a href=#62 id=62 data-nosnippet>62</a> <span class="kw">pub fn </span>new(catalog_name: String, catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;) -&gt; <span class="self">Self </span>{
<a href=#63 id=63 data-nosnippet>63</a> <span class="comment">// safe to expect/unwrap because it contains only schema read, this can
<a href=#64 id=64 data-nosnippet>64</a> // be ensured by sqlness tests
<a href=#65 id=65 data-nosnippet>65</a> </span><span class="kw">let </span>static_tables =
<a href=#66 id=66 data-nosnippet>66</a> PgCatalogStaticTables::try_new().expect(<span class="string">"Failed to initialize static tables"</span>);
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">let </span>inner = PgCatalogSchemaProvider::try_new(
<a href=#68 id=68 data-nosnippet>68</a> CatalogManagerWrapper {
<a href=#69 id=69 data-nosnippet>69</a> catalog_name: catalog_name.clone(),
<a href=#70 id=70 data-nosnippet>70</a> catalog_manager,
<a href=#71 id=71 data-nosnippet>71</a> },
<a href=#72 id=72 data-nosnippet>72</a> Arc::new(static_tables),
<a href=#73 id=73 data-nosnippet>73</a> EmptyContextProvider,
<a href=#74 id=74 data-nosnippet>74</a> )
<a href=#75 id=75 data-nosnippet>75</a> .expect(<span class="string">"Failed to initialize PgCatalogSchemaProvider"</span>);
<a href=#76 id=76 data-nosnippet>76</a>
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">let </span>table_ids: HashMap&lt;<span class="kw">_</span>, <span class="kw">_</span>&gt; = (PG_CATALOG_TABLE_ID_START..)
<a href=#78 id=78 data-nosnippet>78</a> .zip(PG_CATALOG_TABLES.iter())
<a href=#79 id=79 data-nosnippet>79</a> .map(|(id, name)| (<span class="kw-2">*</span>name, id))
<a href=#80 id=80 data-nosnippet>80</a> .collect();
<a href=#81 id=81 data-nosnippet>81</a>
<a href=#82 id=82 data-nosnippet>82</a> <span class="kw">let </span><span class="kw-2">mut </span>provider = <span class="self">Self </span>{
<a href=#83 id=83 data-nosnippet>83</a> catalog_name,
<a href=#84 id=84 data-nosnippet>84</a> inner,
<a href=#85 id=85 data-nosnippet>85</a> tables: HashMap::new(),
<a href=#86 id=86 data-nosnippet>86</a> table_ids,
<a href=#87 id=87 data-nosnippet>87</a> };
<a href=#88 id=88 data-nosnippet>88</a> provider.build_tables();
<a href=#89 id=89 data-nosnippet>89</a> provider
<a href=#90 id=90 data-nosnippet>90</a> }
<a href=#91 id=91 data-nosnippet>91</a>
<a href=#92 id=92 data-nosnippet>92</a> <span class="kw">fn </span>build_tables(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#93 id=93 data-nosnippet>93</a> <span class="comment">// SECURITY NOTE:
<a href=#94 id=94 data-nosnippet>94</a> // Must follow the same security rules as [`InformationSchemaProvider::build_tables`].
<a href=#95 id=95 data-nosnippet>95</a> </span><span class="kw">let </span><span class="kw-2">mut </span>tables = HashMap::new();
<a href=#96 id=96 data-nosnippet>96</a> <span class="comment">// It's safe to unwrap here because we are sure that the constants have been handle correctly inside system_table.
<a href=#97 id=97 data-nosnippet>97</a> </span><span class="kw">for </span>name <span class="kw">in </span>PG_CATALOG_TABLES {
<a href=#98 id=98 data-nosnippet>98</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table) = <span class="self">self</span>.build_table(name) {
<a href=#99 id=99 data-nosnippet>99</a> tables.insert(name.to_string(), table);
<a href=#100 id=100 data-nosnippet>100</a> }
<a href=#101 id=101 data-nosnippet>101</a> }
<a href=#102 id=102 data-nosnippet>102</a>
<a href=#103 id=103 data-nosnippet>103</a> <span class="self">self</span>.tables = tables;
<a href=#104 id=104 data-nosnippet>104</a> }
<a href=#105 id=105 data-nosnippet>105</a>}
<a href=#106 id=106 data-nosnippet>106</a>
<a href=#107 id=107 data-nosnippet>107</a><span class="kw">impl </span>SystemSchemaProviderInner <span class="kw">for </span>PGCatalogProvider {
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">fn </span>schema_name() -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#109 id=109 data-nosnippet>109</a> PG_CATALOG_NAME
<a href=#110 id=110 data-nosnippet>110</a> }
<a href=#111 id=111 data-nosnippet>111</a>
<a href=#112 id=112 data-nosnippet>112</a> <span class="kw">fn </span>system_table(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;SystemTableRef&gt; {
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">if let </span><span class="prelude-val">Some</span>((table_name, table_id)) = <span class="self">self</span>.table_ids.get_key_value(name) {
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">let </span>table = <span class="self">self</span>.inner.build_table_by_name(name).expect(name);
<a href=#115 id=115 data-nosnippet>115</a>
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table) = table {
<a href=#117 id=117 data-nosnippet>117</a> <span class="kw">if let </span><span class="prelude-val">Ok</span>(system_table) = DFTableProviderAsSystemTable::try_new(
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw-2">*</span>table_id,
<a href=#119 id=119 data-nosnippet>119</a> table_name,
<a href=#120 id=120 data-nosnippet>120</a> table::metadata::TableType::Temporary,
<a href=#121 id=121 data-nosnippet>121</a> table,
<a href=#122 id=122 data-nosnippet>122</a> ) {
<a href=#123 id=123 data-nosnippet>123</a> <span class="prelude-val">Some</span>(Arc::new(system_table))
<a href=#124 id=124 data-nosnippet>124</a> } <span class="kw">else </span>{
<a href=#125 id=125 data-nosnippet>125</a> <span class="macro">warn!</span>(<span class="string">"failed to create pg_catalog system table {}"</span>, name);
<a href=#126 id=126 data-nosnippet>126</a> <span class="prelude-val">None
<a href=#127 id=127 data-nosnippet>127</a> </span>}
<a href=#128 id=128 data-nosnippet>128</a> } <span class="kw">else </span>{
<a href=#129 id=129 data-nosnippet>129</a> <span class="prelude-val">None
<a href=#130 id=130 data-nosnippet>130</a> </span>}
<a href=#131 id=131 data-nosnippet>131</a> } <span class="kw">else </span>{
<a href=#132 id=132 data-nosnippet>132</a> <span class="prelude-val">None
<a href=#133 id=133 data-nosnippet>133</a> </span>}
<a href=#134 id=134 data-nosnippet>134</a> }
<a href=#135 id=135 data-nosnippet>135</a>
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw">fn </span>catalog_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw-2">&amp;</span><span class="self">self</span>.catalog_name
<a href=#138 id=138 data-nosnippet>138</a> }
<a href=#139 id=139 data-nosnippet>139</a>}
<a href=#140 id=140 data-nosnippet>140</a>
<a href=#141 id=141 data-nosnippet>141</a><span class="attr">#[derive(Clone)]
<a href=#142 id=142 data-nosnippet>142</a></span><span class="kw">pub struct </span>CatalogManagerWrapper {
<a href=#143 id=143 data-nosnippet>143</a> catalog_name: String,
<a href=#144 id=144 data-nosnippet>144</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#145 id=145 data-nosnippet>145</a>}
<a href=#146 id=146 data-nosnippet>146</a>
<a href=#147 id=147 data-nosnippet>147</a><span class="kw">impl </span>CatalogManagerWrapper {
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">fn </span>catalog_manager(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Arc&lt;<span class="kw">dyn </span>CatalogManager&gt;, DataFusionError&gt; {
<a href=#149 id=149 data-nosnippet>149</a> <span class="self">self</span>.catalog_manager.upgrade().ok_or_else(|| {
<a href=#150 id=150 data-nosnippet>150</a> DataFusionError::Internal(<span class="string">"Failed to access catalog manager"</span>.to_string())
<a href=#151 id=151 data-nosnippet>151</a> })
<a href=#152 id=152 data-nosnippet>152</a> }
<a href=#153 id=153 data-nosnippet>153</a>}
<a href=#154 id=154 data-nosnippet>154</a>
<a href=#155 id=155 data-nosnippet>155</a><span class="kw">impl </span>std::fmt::Debug <span class="kw">for </span>CatalogManagerWrapper {
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>std::fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; std::fmt::Result {
<a href=#157 id=157 data-nosnippet>157</a> f.debug_struct(<span class="string">"CatalogManagerWrapper"</span>).finish()
<a href=#158 id=158 data-nosnippet>158</a> }
<a href=#159 id=159 data-nosnippet>159</a>}
<a href=#160 id=160 data-nosnippet>160</a>
<a href=#161 id=161 data-nosnippet>161</a><span class="attr">#[async_trait]
<a href=#162 id=162 data-nosnippet>162</a></span><span class="kw">impl </span>CatalogInfo <span class="kw">for </span>CatalogManagerWrapper {
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">async fn </span>catalog_names(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Vec&lt;String&gt;, DataFusionError&gt; {
<a href=#164 id=164 data-nosnippet>164</a> <span class="kw">if </span><span class="self">self</span>.catalog_name == DEFAULT_CATALOG_NAME {
<a href=#165 id=165 data-nosnippet>165</a> CatalogManager::catalog_names(<span class="self">self</span>.catalog_manager()<span class="question-mark">?</span>.as_ref())
<a href=#166 id=166 data-nosnippet>166</a> .<span class="kw">await
<a href=#167 id=167 data-nosnippet>167</a> </span>.map_err(|e| DataFusionError::External(Box::new(e)))
<a href=#168 id=168 data-nosnippet>168</a> } <span class="kw">else </span>{
<a href=#169 id=169 data-nosnippet>169</a> <span class="prelude-val">Ok</span>(<span class="macro">vec!</span>[<span class="self">self</span>.catalog_name.clone()])
<a href=#170 id=170 data-nosnippet>170</a> }
<a href=#171 id=171 data-nosnippet>171</a> }
<a href=#172 id=172 data-nosnippet>172</a>
<a href=#173 id=173 data-nosnippet>173</a> <span class="kw">async fn </span>schema_names(
<a href=#174 id=174 data-nosnippet>174</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#175 id=175 data-nosnippet>175</a> catalog_name: <span class="kw-2">&amp;</span>str,
<a href=#176 id=176 data-nosnippet>176</a> ) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;Vec&lt;String&gt;&gt;, DataFusionError&gt; {
<a href=#177 id=177 data-nosnippet>177</a> <span class="self">self</span>.catalog_manager()<span class="question-mark">?
<a href=#178 id=178 data-nosnippet>178</a> </span>.schema_names(catalog_name, <span class="prelude-val">None</span>)
<a href=#179 id=179 data-nosnippet>179</a> .<span class="kw">await
<a href=#180 id=180 data-nosnippet>180</a> </span>.map(<span class="prelude-val">Some</span>)
<a href=#181 id=181 data-nosnippet>181</a> .map_err(|e| DataFusionError::External(Box::new(e)))
<a href=#182 id=182 data-nosnippet>182</a> }
<a href=#183 id=183 data-nosnippet>183</a>
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">async fn </span>table_names(
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#186 id=186 data-nosnippet>186</a> catalog_name: <span class="kw-2">&amp;</span>str,
<a href=#187 id=187 data-nosnippet>187</a> schema_name: <span class="kw-2">&amp;</span>str,
<a href=#188 id=188 data-nosnippet>188</a> ) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;Vec&lt;String&gt;&gt;, DataFusionError&gt; {
<a href=#189 id=189 data-nosnippet>189</a> <span class="self">self</span>.catalog_manager()<span class="question-mark">?
<a href=#190 id=190 data-nosnippet>190</a> </span>.table_names(catalog_name, schema_name, <span class="prelude-val">None</span>)
<a href=#191 id=191 data-nosnippet>191</a> .<span class="kw">await
<a href=#192 id=192 data-nosnippet>192</a> </span>.map(<span class="prelude-val">Some</span>)
<a href=#193 id=193 data-nosnippet>193</a> .map_err(|e| DataFusionError::External(Box::new(e)))
<a href=#194 id=194 data-nosnippet>194</a> }
<a href=#195 id=195 data-nosnippet>195</a>
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">async fn </span>table_schema(
<a href=#197 id=197 data-nosnippet>197</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#198 id=198 data-nosnippet>198</a> catalog_name: <span class="kw-2">&amp;</span>str,
<a href=#199 id=199 data-nosnippet>199</a> schema_name: <span class="kw-2">&amp;</span>str,
<a href=#200 id=200 data-nosnippet>200</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#201 id=201 data-nosnippet>201</a> ) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;SchemaRef&gt;, DataFusionError&gt; {
<a href=#202 id=202 data-nosnippet>202</a> <span class="kw">let </span>table = <span class="self">self
<a href=#203 id=203 data-nosnippet>203</a> </span>.catalog_manager()<span class="question-mark">?
<a href=#204 id=204 data-nosnippet>204</a> </span>.table(catalog_name, schema_name, table_name, <span class="prelude-val">None</span>)
<a href=#205 id=205 data-nosnippet>205</a> .<span class="kw">await
<a href=#206 id=206 data-nosnippet>206</a> </span>.map_err(|e| DataFusionError::External(Box::new(e)))<span class="question-mark">?</span>;
<a href=#207 id=207 data-nosnippet>207</a>
<a href=#208 id=208 data-nosnippet>208</a> <span class="prelude-val">Ok</span>(table.map(|t| t.schema().arrow_schema().clone()))
<a href=#209 id=209 data-nosnippet>209</a> }
<a href=#210 id=210 data-nosnippet>210</a>
<a href=#211 id=211 data-nosnippet>211</a> <span class="kw">async fn </span>table_type(
<a href=#212 id=212 data-nosnippet>212</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#213 id=213 data-nosnippet>213</a> catalog_name: <span class="kw-2">&amp;</span>str,
<a href=#214 id=214 data-nosnippet>214</a> schema_name: <span class="kw-2">&amp;</span>str,
<a href=#215 id=215 data-nosnippet>215</a> table_name: <span class="kw-2">&amp;</span>str,
<a href=#216 id=216 data-nosnippet>216</a> ) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;TableType&gt;, DataFusionError&gt; {
<a href=#217 id=217 data-nosnippet>217</a> <span class="kw">let </span>table = <span class="self">self
<a href=#218 id=218 data-nosnippet>218</a> </span>.catalog_manager()<span class="question-mark">?
<a href=#219 id=219 data-nosnippet>219</a> </span>.table(catalog_name, schema_name, table_name, <span class="prelude-val">None</span>)
<a href=#220 id=220 data-nosnippet>220</a> .<span class="kw">await
<a href=#221 id=221 data-nosnippet>221</a> </span>.map_err(|e| DataFusionError::External(Box::new(e)))<span class="question-mark">?</span>;
<a href=#222 id=222 data-nosnippet>222</a>
<a href=#223 id=223 data-nosnippet>223</a> <span class="prelude-val">Ok</span>(table.map(|t| t.table_type().into()))
<a href=#224 id=224 data-nosnippet>224</a> }
<a href=#225 id=225 data-nosnippet>225</a>}
<a href=#226 id=226 data-nosnippet>226</a>
<a href=#227 id=227 data-nosnippet>227</a><span class="kw">struct </span>DFTableProviderAsSystemTable {
<a href=#228 id=228 data-nosnippet>228</a> <span class="kw">pub </span>table_id: TableId,
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">pub </span>table_name: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str,
<a href=#230 id=230 data-nosnippet>230</a> <span class="kw">pub </span>table_type: table::metadata::TableType,
<a href=#231 id=231 data-nosnippet>231</a> <span class="kw">pub </span>schema: Arc&lt;datatypes::schema::Schema&gt;,
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">pub </span>table_provider: PgCatalogTable,
<a href=#233 id=233 data-nosnippet>233</a>}
<a href=#234 id=234 data-nosnippet>234</a>
<a href=#235 id=235 data-nosnippet>235</a><span class="kw">impl </span>DFTableProviderAsSystemTable {
<a href=#236 id=236 data-nosnippet>236</a> <span class="kw">pub fn </span>try_new(
<a href=#237 id=237 data-nosnippet>237</a> table_id: TableId,
<a href=#238 id=238 data-nosnippet>238</a> table_name: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str,
<a href=#239 id=239 data-nosnippet>239</a> table_type: table::metadata::TableType,
<a href=#240 id=240 data-nosnippet>240</a> table_provider: PgCatalogTable,
<a href=#241 id=241 data-nosnippet>241</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>&gt; {
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">let </span>arrow_schema = table_provider.schema();
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">let </span>schema = Arc::new(arrow_schema.try_into().context(ProjectSchemaSnafu)<span class="question-mark">?</span>);
<a href=#244 id=244 data-nosnippet>244</a> <span class="prelude-val">Ok</span>(<span class="self">Self </span>{
<a href=#245 id=245 data-nosnippet>245</a> table_id,
<a href=#246 id=246 data-nosnippet>246</a> table_name,
<a href=#247 id=247 data-nosnippet>247</a> table_type,
<a href=#248 id=248 data-nosnippet>248</a> schema,
<a href=#249 id=249 data-nosnippet>249</a> table_provider,
<a href=#250 id=250 data-nosnippet>250</a> })
<a href=#251 id=251 data-nosnippet>251</a> }
<a href=#252 id=252 data-nosnippet>252</a>}
<a href=#253 id=253 data-nosnippet>253</a>
<a href=#254 id=254 data-nosnippet>254</a><span class="kw">impl </span>SystemTable <span class="kw">for </span>DFTableProviderAsSystemTable {
<a href=#255 id=255 data-nosnippet>255</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#256 id=256 data-nosnippet>256</a> <span class="self">self</span>.table_id
<a href=#257 id=257 data-nosnippet>257</a> }
<a href=#258 id=258 data-nosnippet>258</a>
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#260 id=260 data-nosnippet>260</a> <span class="self">self</span>.table_name
<a href=#261 id=261 data-nosnippet>261</a> }
<a href=#262 id=262 data-nosnippet>262</a>
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Arc&lt;datatypes::schema::Schema&gt; {
<a href=#264 id=264 data-nosnippet>264</a> <span class="self">self</span>.schema.clone()
<a href=#265 id=265 data-nosnippet>265</a> }
<a href=#266 id=266 data-nosnippet>266</a>
<a href=#267 id=267 data-nosnippet>267</a> <span class="kw">fn </span>table_type(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; table::metadata::TableType {
<a href=#268 id=268 data-nosnippet>268</a> <span class="self">self</span>.table_type
<a href=#269 id=269 data-nosnippet>269</a> }
<a href=#270 id=270 data-nosnippet>270</a>
<a href=#271 id=271 data-nosnippet>271</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, _request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#272 id=272 data-nosnippet>272</a> <span class="kw">match </span><span class="kw-2">&amp;</span><span class="self">self</span>.table_provider {
<a href=#273 id=273 data-nosnippet>273</a> PgCatalogTable::Static(table) =&gt; {
<a href=#274 id=274 data-nosnippet>274</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#275 id=275 data-nosnippet>275</a> <span class="kw">let </span>data = table
<a href=#276 id=276 data-nosnippet>276</a> .data()
<a href=#277 id=277 data-nosnippet>277</a> .iter()
<a href=#278 id=278 data-nosnippet>278</a> .map(|rb| <span class="prelude-val">Ok</span>(rb.clone()))
<a href=#279 id=279 data-nosnippet>279</a> .collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;();
<a href=#280 id=280 data-nosnippet>280</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#281 id=281 data-nosnippet>281</a> schema,
<a href=#282 id=282 data-nosnippet>282</a> futures::stream::iter(data),
<a href=#283 id=283 data-nosnippet>283</a> ));
<a href=#284 id=284 data-nosnippet>284</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#285 id=285 data-nosnippet>285</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#286 id=286 data-nosnippet>286</a> .map_err(BoxedError::new)
<a href=#287 id=287 data-nosnippet>287</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#288 id=288 data-nosnippet>288</a> ))
<a href=#289 id=289 data-nosnippet>289</a> }
<a href=#290 id=290 data-nosnippet>290</a>
<a href=#291 id=291 data-nosnippet>291</a> PgCatalogTable::Dynamic(table) =&gt; {
<a href=#292 id=292 data-nosnippet>292</a> <span class="kw">let </span>stream = table.execute(Arc::new(TaskContext::default()));
<a href=#293 id=293 data-nosnippet>293</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#294 id=294 data-nosnippet>294</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#295 id=295 data-nosnippet>295</a> .map_err(BoxedError::new)
<a href=#296 id=296 data-nosnippet>296</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#297 id=297 data-nosnippet>297</a> ))
<a href=#298 id=298 data-nosnippet>298</a> }
<a href=#299 id=299 data-nosnippet>299</a>
<a href=#300 id=300 data-nosnippet>300</a> PgCatalogTable::Empty(<span class="kw">_</span>) =&gt; {
<a href=#301 id=301 data-nosnippet>301</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.arrow_schema().clone();
<a href=#302 id=302 data-nosnippet>302</a> <span class="kw">let </span>stream = Box::pin(DfRecordBatchStreamAdapter::new(
<a href=#303 id=303 data-nosnippet>303</a> schema,
<a href=#304 id=304 data-nosnippet>304</a> futures::stream::iter(<span class="macro">vec!</span>[]),
<a href=#305 id=305 data-nosnippet>305</a> ));
<a href=#306 id=306 data-nosnippet>306</a> <span class="prelude-val">Ok</span>(Box::pin(
<a href=#307 id=307 data-nosnippet>307</a> RecordBatchStreamAdapter::try_new(stream)
<a href=#308 id=308 data-nosnippet>308</a> .map_err(BoxedError::new)
<a href=#309 id=309 data-nosnippet>309</a> .context(InternalSnafu)<span class="question-mark">?</span>,
<a href=#310 id=310 data-nosnippet>310</a> ))
<a href=#311 id=311 data-nosnippet>311</a> }
<a href=#312 id=312 data-nosnippet>312</a> }
<a href=#313 id=313 data-nosnippet>313</a> }
<a href=#314 id=314 data-nosnippet>314</a>}
</code></pre></div></section></main></body></html>
+590
View File
@@ -0,0 +1,590 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/predicate.rs`."><title>predicate.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/</div>predicate.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>arrow::array::StringArray;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>arrow::compute::kernels::comparison;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>datafusion::common::ScalarValue;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>datafusion::logical_expr::expr::Like;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>datafusion::logical_expr::{Expr, Operator};
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>datatypes::value::Value;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>store_api::storage::ScanRequest;
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">type </span>ColumnName = String;
<a href=#24 id=24 data-nosnippet>24</a><span class="doccomment">/// Predicate to filter `information_schema` tables stream,
<a href=#25 id=25 data-nosnippet>25</a>/// we only support these simple predicates currently.
<a href=#26 id=26 data-nosnippet>26</a>/// TODO(dennis): supports more predicate types.
<a href=#27 id=27 data-nosnippet>27</a></span><span class="attr">#[derive(Clone, PartialEq, Eq, Debug)]
<a href=#28 id=28 data-nosnippet>28</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">enum </span>Predicate {
<a href=#29 id=29 data-nosnippet>29</a> Eq(ColumnName, Value),
<a href=#30 id=30 data-nosnippet>30</a> Like(ColumnName, String, bool),
<a href=#31 id=31 data-nosnippet>31</a> NotEq(ColumnName, Value),
<a href=#32 id=32 data-nosnippet>32</a> InList(ColumnName, Vec&lt;Value&gt;),
<a href=#33 id=33 data-nosnippet>33</a> And(Box&lt;Predicate&gt;, Box&lt;Predicate&gt;),
<a href=#34 id=34 data-nosnippet>34</a> Or(Box&lt;Predicate&gt;, Box&lt;Predicate&gt;),
<a href=#35 id=35 data-nosnippet>35</a> Not(Box&lt;Predicate&gt;),
<a href=#36 id=36 data-nosnippet>36</a>}
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">impl </span>Predicate {
<a href=#39 id=39 data-nosnippet>39</a> <span class="doccomment">/// Evaluate the predicate with the row, returns:
<a href=#40 id=40 data-nosnippet>40</a> /// - `None` when the predicate can't evaluate with the row.
<a href=#41 id=41 data-nosnippet>41</a> /// - `Some(true)` when the predicate is satisfied,
<a href=#42 id=42 data-nosnippet>42</a> /// - `Some(false)` when the predicate is not satisfied,
<a href=#43 id=43 data-nosnippet>43</a> </span><span class="kw">fn </span>eval(<span class="kw-2">&amp;</span><span class="self">self</span>, row: <span class="kw-2">&amp;</span>[(<span class="kw-2">&amp;</span>str, <span class="kw-2">&amp;</span>Value)]) -&gt; <span class="prelude-ty">Option</span>&lt;bool&gt; {
<a href=#44 id=44 data-nosnippet>44</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#45 id=45 data-nosnippet>45</a> Predicate::Eq(c, v) =&gt; {
<a href=#46 id=46 data-nosnippet>46</a> <span class="kw">for </span>(column, value) <span class="kw">in </span>row {
<a href=#47 id=47 data-nosnippet>47</a> <span class="kw">if </span>c != column {
<a href=#48 id=48 data-nosnippet>48</a> <span class="kw">continue</span>;
<a href=#49 id=49 data-nosnippet>49</a> }
<a href=#50 id=50 data-nosnippet>50</a> <span class="kw">return </span><span class="prelude-val">Some</span>(v == <span class="kw-2">*</span>value);
<a href=#51 id=51 data-nosnippet>51</a> }
<a href=#52 id=52 data-nosnippet>52</a> }
<a href=#53 id=53 data-nosnippet>53</a> Predicate::Like(c, pattern, case_insensitive) =&gt; {
<a href=#54 id=54 data-nosnippet>54</a> <span class="kw">for </span>(column, value) <span class="kw">in </span>row {
<a href=#55 id=55 data-nosnippet>55</a> <span class="kw">if </span>c != column {
<a href=#56 id=56 data-nosnippet>56</a> <span class="kw">continue</span>;
<a href=#57 id=57 data-nosnippet>57</a> }
<a href=#58 id=58 data-nosnippet>58</a>
<a href=#59 id=59 data-nosnippet>59</a> <span class="kw">let </span>Value::String(bs) = value <span class="kw">else </span>{
<a href=#60 id=60 data-nosnippet>60</a> <span class="kw">continue</span>;
<a href=#61 id=61 data-nosnippet>61</a> };
<a href=#62 id=62 data-nosnippet>62</a>
<a href=#63 id=63 data-nosnippet>63</a> <span class="kw">return </span>like_utf8(bs.as_utf8(), pattern, case_insensitive);
<a href=#64 id=64 data-nosnippet>64</a> }
<a href=#65 id=65 data-nosnippet>65</a> }
<a href=#66 id=66 data-nosnippet>66</a> Predicate::NotEq(c, v) =&gt; {
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">for </span>(column, value) <span class="kw">in </span>row {
<a href=#68 id=68 data-nosnippet>68</a> <span class="kw">if </span>c != column {
<a href=#69 id=69 data-nosnippet>69</a> <span class="kw">continue</span>;
<a href=#70 id=70 data-nosnippet>70</a> }
<a href=#71 id=71 data-nosnippet>71</a> <span class="kw">return </span><span class="prelude-val">Some</span>(v != <span class="kw-2">*</span>value);
<a href=#72 id=72 data-nosnippet>72</a> }
<a href=#73 id=73 data-nosnippet>73</a> }
<a href=#74 id=74 data-nosnippet>74</a> Predicate::InList(c, values) =&gt; {
<a href=#75 id=75 data-nosnippet>75</a> <span class="kw">for </span>(column, value) <span class="kw">in </span>row {
<a href=#76 id=76 data-nosnippet>76</a> <span class="kw">if </span>c != column {
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">continue</span>;
<a href=#78 id=78 data-nosnippet>78</a> }
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw">return </span><span class="prelude-val">Some</span>(values.iter().any(|v| v == <span class="kw-2">*</span>value));
<a href=#80 id=80 data-nosnippet>80</a> }
<a href=#81 id=81 data-nosnippet>81</a> }
<a href=#82 id=82 data-nosnippet>82</a> Predicate::And(left, right) =&gt; {
<a href=#83 id=83 data-nosnippet>83</a> <span class="kw">let </span>left = left.eval(row);
<a href=#84 id=84 data-nosnippet>84</a>
<a href=#85 id=85 data-nosnippet>85</a> <span class="comment">// short-circuit
<a href=#86 id=86 data-nosnippet>86</a> </span><span class="kw">if </span><span class="macro">matches!</span>(left, <span class="prelude-val">Some</span>(<span class="bool-val">false</span>)) {
<a href=#87 id=87 data-nosnippet>87</a> <span class="kw">return </span><span class="prelude-val">Some</span>(<span class="bool-val">false</span>);
<a href=#88 id=88 data-nosnippet>88</a> }
<a href=#89 id=89 data-nosnippet>89</a>
<a href=#90 id=90 data-nosnippet>90</a> <span class="kw">return match </span>(left, right.eval(row)) {
<a href=#91 id=91 data-nosnippet>91</a> (<span class="prelude-val">Some</span>(left), <span class="prelude-val">Some</span>(right)) =&gt; <span class="prelude-val">Some</span>(left &amp;&amp; right),
<a href=#92 id=92 data-nosnippet>92</a> (<span class="prelude-val">None</span>, <span class="prelude-val">Some</span>(<span class="bool-val">false</span>)) =&gt; <span class="prelude-val">Some</span>(<span class="bool-val">false</span>),
<a href=#93 id=93 data-nosnippet>93</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
<a href=#94 id=94 data-nosnippet>94</a> };
<a href=#95 id=95 data-nosnippet>95</a> }
<a href=#96 id=96 data-nosnippet>96</a> Predicate::Or(left, right) =&gt; {
<a href=#97 id=97 data-nosnippet>97</a> <span class="kw">let </span>left = left.eval(row);
<a href=#98 id=98 data-nosnippet>98</a>
<a href=#99 id=99 data-nosnippet>99</a> <span class="comment">// short-circuit
<a href=#100 id=100 data-nosnippet>100</a> </span><span class="kw">if </span><span class="macro">matches!</span>(left, <span class="prelude-val">Some</span>(<span class="bool-val">true</span>)) {
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">return </span><span class="prelude-val">Some</span>(<span class="bool-val">true</span>);
<a href=#102 id=102 data-nosnippet>102</a> }
<a href=#103 id=103 data-nosnippet>103</a>
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">return match </span>(left, right.eval(row)) {
<a href=#105 id=105 data-nosnippet>105</a> (<span class="prelude-val">Some</span>(left), <span class="prelude-val">Some</span>(right)) =&gt; <span class="prelude-val">Some</span>(left || right),
<a href=#106 id=106 data-nosnippet>106</a> (<span class="prelude-val">None</span>, <span class="prelude-val">Some</span>(<span class="bool-val">true</span>)) =&gt; <span class="prelude-val">Some</span>(<span class="bool-val">true</span>),
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
<a href=#108 id=108 data-nosnippet>108</a> };
<a href=#109 id=109 data-nosnippet>109</a> }
<a href=#110 id=110 data-nosnippet>110</a> Predicate::Not(p) =&gt; {
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">return </span><span class="prelude-val">Some</span>(!p.eval(row)<span class="question-mark">?</span>);
<a href=#112 id=112 data-nosnippet>112</a> }
<a href=#113 id=113 data-nosnippet>113</a> }
<a href=#114 id=114 data-nosnippet>114</a>
<a href=#115 id=115 data-nosnippet>115</a> <span class="comment">// Can't evaluate predicate with the row
<a href=#116 id=116 data-nosnippet>116</a> </span><span class="prelude-val">None
<a href=#117 id=117 data-nosnippet>117</a> </span>}
<a href=#118 id=118 data-nosnippet>118</a>
<a href=#119 id=119 data-nosnippet>119</a> <span class="doccomment">/// Try to create a predicate from datafusion [`Expr`], return None if fails.
<a href=#120 id=120 data-nosnippet>120</a> </span><span class="kw">fn </span>from_expr(expr: Expr) -&gt; <span class="prelude-ty">Option</span>&lt;Predicate&gt; {
<a href=#121 id=121 data-nosnippet>121</a> <span class="kw">match </span>expr {
<a href=#122 id=122 data-nosnippet>122</a> <span class="comment">// NOT expr
<a href=#123 id=123 data-nosnippet>123</a> </span>Expr::Not(expr) =&gt; <span class="prelude-val">Some</span>(Predicate::Not(Box::new(<span class="self">Self</span>::from_expr(<span class="kw-2">*</span>expr)<span class="question-mark">?</span>))),
<a href=#124 id=124 data-nosnippet>124</a> <span class="comment">// expr LIKE pattern
<a href=#125 id=125 data-nosnippet>125</a> </span>Expr::Like(Like {
<a href=#126 id=126 data-nosnippet>126</a> negated,
<a href=#127 id=127 data-nosnippet>127</a> expr,
<a href=#128 id=128 data-nosnippet>128</a> pattern,
<a href=#129 id=129 data-nosnippet>129</a> case_insensitive,
<a href=#130 id=130 data-nosnippet>130</a> ..
<a href=#131 id=131 data-nosnippet>131</a> }) <span class="kw">if </span>is_column(<span class="kw-2">&amp;</span>expr) &amp;&amp; is_string_literal(<span class="kw-2">&amp;</span>pattern) =&gt; {
<a href=#132 id=132 data-nosnippet>132</a> <span class="comment">// Safety: ensured by gurad
<a href=#133 id=133 data-nosnippet>133</a> </span><span class="kw">let </span>Expr::Column(c) = <span class="kw-2">*</span>expr <span class="kw">else </span>{
<a href=#134 id=134 data-nosnippet>134</a> <span class="macro">unreachable!</span>();
<a href=#135 id=135 data-nosnippet>135</a> };
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw">let </span>Expr::Literal(ScalarValue::Utf8(<span class="prelude-val">Some</span>(pattern)), <span class="kw">_</span>) = <span class="kw-2">*</span>pattern <span class="kw">else </span>{
<a href=#137 id=137 data-nosnippet>137</a> <span class="macro">unreachable!</span>();
<a href=#138 id=138 data-nosnippet>138</a> };
<a href=#139 id=139 data-nosnippet>139</a>
<a href=#140 id=140 data-nosnippet>140</a> <span class="kw">let </span>p = Predicate::Like(c.name, pattern, case_insensitive);
<a href=#141 id=141 data-nosnippet>141</a>
<a href=#142 id=142 data-nosnippet>142</a> <span class="kw">if </span>negated {
<a href=#143 id=143 data-nosnippet>143</a> <span class="prelude-val">Some</span>(Predicate::Not(Box::new(p)))
<a href=#144 id=144 data-nosnippet>144</a> } <span class="kw">else </span>{
<a href=#145 id=145 data-nosnippet>145</a> <span class="prelude-val">Some</span>(p)
<a href=#146 id=146 data-nosnippet>146</a> }
<a href=#147 id=147 data-nosnippet>147</a> }
<a href=#148 id=148 data-nosnippet>148</a> <span class="comment">// left OP right
<a href=#149 id=149 data-nosnippet>149</a> </span>Expr::BinaryExpr(bin) =&gt; <span class="kw">match </span>(<span class="kw-2">*</span>bin.left, bin.op, <span class="kw-2">*</span>bin.right) {
<a href=#150 id=150 data-nosnippet>150</a> <span class="comment">// left == right
<a href=#151 id=151 data-nosnippet>151</a> </span>(Expr::Literal(scalar, <span class="kw">_</span>), Operator::Eq, Expr::Column(c))
<a href=#152 id=152 data-nosnippet>152</a> | (Expr::Column(c), Operator::Eq, Expr::Literal(scalar, <span class="kw">_</span>)) =&gt; {
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">let </span><span class="prelude-val">Ok</span>(v) = Value::try_from(scalar) <span class="kw">else </span>{
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">return </span><span class="prelude-val">None</span>;
<a href=#155 id=155 data-nosnippet>155</a> };
<a href=#156 id=156 data-nosnippet>156</a>
<a href=#157 id=157 data-nosnippet>157</a> <span class="prelude-val">Some</span>(Predicate::Eq(c.name, v))
<a href=#158 id=158 data-nosnippet>158</a> }
<a href=#159 id=159 data-nosnippet>159</a> <span class="comment">// left != right
<a href=#160 id=160 data-nosnippet>160</a> </span>(Expr::Literal(scalar, <span class="kw">_</span>), Operator::NotEq, Expr::Column(c))
<a href=#161 id=161 data-nosnippet>161</a> | (Expr::Column(c), Operator::NotEq, Expr::Literal(scalar, <span class="kw">_</span>)) =&gt; {
<a href=#162 id=162 data-nosnippet>162</a> <span class="kw">let </span><span class="prelude-val">Ok</span>(v) = Value::try_from(scalar) <span class="kw">else </span>{
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">return </span><span class="prelude-val">None</span>;
<a href=#164 id=164 data-nosnippet>164</a> };
<a href=#165 id=165 data-nosnippet>165</a>
<a href=#166 id=166 data-nosnippet>166</a> <span class="prelude-val">Some</span>(Predicate::NotEq(c.name, v))
<a href=#167 id=167 data-nosnippet>167</a> }
<a href=#168 id=168 data-nosnippet>168</a> <span class="comment">// left AND right
<a href=#169 id=169 data-nosnippet>169</a> </span>(left, Operator::And, right) =&gt; {
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw">let </span>left = <span class="self">Self</span>::from_expr(left)<span class="question-mark">?</span>;
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">let </span>right = <span class="self">Self</span>::from_expr(right)<span class="question-mark">?</span>;
<a href=#172 id=172 data-nosnippet>172</a>
<a href=#173 id=173 data-nosnippet>173</a> <span class="prelude-val">Some</span>(Predicate::And(Box::new(left), Box::new(right)))
<a href=#174 id=174 data-nosnippet>174</a> }
<a href=#175 id=175 data-nosnippet>175</a> <span class="comment">// left OR right
<a href=#176 id=176 data-nosnippet>176</a> </span>(left, Operator::Or, right) =&gt; {
<a href=#177 id=177 data-nosnippet>177</a> <span class="kw">let </span>left = <span class="self">Self</span>::from_expr(left)<span class="question-mark">?</span>;
<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">let </span>right = <span class="self">Self</span>::from_expr(right)<span class="question-mark">?</span>;
<a href=#179 id=179 data-nosnippet>179</a>
<a href=#180 id=180 data-nosnippet>180</a> <span class="prelude-val">Some</span>(Predicate::Or(Box::new(left), Box::new(right)))
<a href=#181 id=181 data-nosnippet>181</a> }
<a href=#182 id=182 data-nosnippet>182</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
<a href=#183 id=183 data-nosnippet>183</a> },
<a href=#184 id=184 data-nosnippet>184</a> <span class="comment">// [NOT] IN (LIST)
<a href=#185 id=185 data-nosnippet>185</a> </span>Expr::InList(list) =&gt; {
<a href=#186 id=186 data-nosnippet>186</a> <span class="kw">match </span>(<span class="kw-2">*</span>list.expr, list.list, list.negated) {
<a href=#187 id=187 data-nosnippet>187</a> <span class="comment">// column [NOT] IN (v1, v2, v3, ...)
<a href=#188 id=188 data-nosnippet>188</a> </span>(Expr::Column(c), list, negated) <span class="kw">if </span>is_all_scalars(<span class="kw-2">&amp;</span>list) =&gt; {
<a href=#189 id=189 data-nosnippet>189</a> <span class="kw">let </span><span class="kw-2">mut </span>values = Vec::with_capacity(list.len());
<a href=#190 id=190 data-nosnippet>190</a> <span class="kw">for </span>scalar <span class="kw">in </span>list {
<a href=#191 id=191 data-nosnippet>191</a> <span class="comment">// Safety: checked by `is_all_scalars`
<a href=#192 id=192 data-nosnippet>192</a> </span><span class="kw">let </span>Expr::Literal(scalar, <span class="kw">_</span>) = scalar <span class="kw">else </span>{
<a href=#193 id=193 data-nosnippet>193</a> <span class="macro">unreachable!</span>();
<a href=#194 id=194 data-nosnippet>194</a> };
<a href=#195 id=195 data-nosnippet>195</a>
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">let </span><span class="prelude-val">Ok</span>(value) = Value::try_from(scalar) <span class="kw">else </span>{
<a href=#197 id=197 data-nosnippet>197</a> <span class="kw">return </span><span class="prelude-val">None</span>;
<a href=#198 id=198 data-nosnippet>198</a> };
<a href=#199 id=199 data-nosnippet>199</a>
<a href=#200 id=200 data-nosnippet>200</a> values.push(value);
<a href=#201 id=201 data-nosnippet>201</a> }
<a href=#202 id=202 data-nosnippet>202</a>
<a href=#203 id=203 data-nosnippet>203</a> <span class="kw">let </span>predicate = Predicate::InList(c.name, values);
<a href=#204 id=204 data-nosnippet>204</a>
<a href=#205 id=205 data-nosnippet>205</a> <span class="kw">if </span>negated {
<a href=#206 id=206 data-nosnippet>206</a> <span class="prelude-val">Some</span>(Predicate::Not(Box::new(predicate)))
<a href=#207 id=207 data-nosnippet>207</a> } <span class="kw">else </span>{
<a href=#208 id=208 data-nosnippet>208</a> <span class="prelude-val">Some</span>(predicate)
<a href=#209 id=209 data-nosnippet>209</a> }
<a href=#210 id=210 data-nosnippet>210</a> }
<a href=#211 id=211 data-nosnippet>211</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
<a href=#212 id=212 data-nosnippet>212</a> }
<a href=#213 id=213 data-nosnippet>213</a> }
<a href=#214 id=214 data-nosnippet>214</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
<a href=#215 id=215 data-nosnippet>215</a> }
<a href=#216 id=216 data-nosnippet>216</a> }
<a href=#217 id=217 data-nosnippet>217</a>}
<a href=#218 id=218 data-nosnippet>218</a>
<a href=#219 id=219 data-nosnippet>219</a><span class="doccomment">/// Perform SQL left LIKE right, return `None` if fail to evaluate.
<a href=#220 id=220 data-nosnippet>220</a>/// - `s` the target string
<a href=#221 id=221 data-nosnippet>221</a>/// - `pattern` the pattern just like '%abc'
<a href=#222 id=222 data-nosnippet>222</a>/// - `case_insensitive` whether to perform case-insensitive like or not.
<a href=#223 id=223 data-nosnippet>223</a></span><span class="kw">fn </span>like_utf8(s: <span class="kw-2">&amp;</span>str, pattern: <span class="kw-2">&amp;</span>str, case_insensitive: <span class="kw-2">&amp;</span>bool) -&gt; <span class="prelude-ty">Option</span>&lt;bool&gt; {
<a href=#224 id=224 data-nosnippet>224</a> <span class="kw">let </span>array = StringArray::from(<span class="macro">vec!</span>[s]);
<a href=#225 id=225 data-nosnippet>225</a> <span class="kw">let </span>patterns = StringArray::new_scalar(pattern);
<a href=#226 id=226 data-nosnippet>226</a>
<a href=#227 id=227 data-nosnippet>227</a> <span class="kw">let </span><span class="prelude-val">Ok</span>(booleans) = (<span class="kw">if </span><span class="kw-2">*</span>case_insensitive {
<a href=#228 id=228 data-nosnippet>228</a> comparison::ilike(<span class="kw-2">&amp;</span>array, <span class="kw-2">&amp;</span>patterns)
<a href=#229 id=229 data-nosnippet>229</a> } <span class="kw">else </span>{
<a href=#230 id=230 data-nosnippet>230</a> comparison::like(<span class="kw-2">&amp;</span>array, <span class="kw-2">&amp;</span>patterns)
<a href=#231 id=231 data-nosnippet>231</a> }) <span class="kw">else </span>{
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">return </span><span class="prelude-val">None</span>;
<a href=#233 id=233 data-nosnippet>233</a> };
<a href=#234 id=234 data-nosnippet>234</a>
<a href=#235 id=235 data-nosnippet>235</a> <span class="comment">// Safety: at least one value in result
<a href=#236 id=236 data-nosnippet>236</a> </span><span class="prelude-val">Some</span>(booleans.value(<span class="number">0</span>))
<a href=#237 id=237 data-nosnippet>237</a>}
<a href=#238 id=238 data-nosnippet>238</a>
<a href=#239 id=239 data-nosnippet>239</a><span class="kw">fn </span>is_string_literal(expr: <span class="kw-2">&amp;</span>Expr) -&gt; bool {
<a href=#240 id=240 data-nosnippet>240</a> <span class="macro">matches!</span>(expr, Expr::Literal(ScalarValue::Utf8(<span class="prelude-val">Some</span>(<span class="kw">_</span>)), <span class="kw">_</span>))
<a href=#241 id=241 data-nosnippet>241</a>}
<a href=#242 id=242 data-nosnippet>242</a>
<a href=#243 id=243 data-nosnippet>243</a><span class="kw">fn </span>is_column(expr: <span class="kw-2">&amp;</span>Expr) -&gt; bool {
<a href=#244 id=244 data-nosnippet>244</a> <span class="macro">matches!</span>(expr, Expr::Column(<span class="kw">_</span>))
<a href=#245 id=245 data-nosnippet>245</a>}
<a href=#246 id=246 data-nosnippet>246</a>
<a href=#247 id=247 data-nosnippet>247</a><span class="doccomment">/// A list of predicate
<a href=#248 id=248 data-nosnippet>248</a></span><span class="kw">pub struct </span>Predicates {
<a href=#249 id=249 data-nosnippet>249</a> predicates: Vec&lt;Predicate&gt;,
<a href=#250 id=250 data-nosnippet>250</a>}
<a href=#251 id=251 data-nosnippet>251</a>
<a href=#252 id=252 data-nosnippet>252</a><span class="kw">impl </span>Predicates {
<a href=#253 id=253 data-nosnippet>253</a> <span class="doccomment">/// Try its best to create predicates from [`ScanRequest`].
<a href=#254 id=254 data-nosnippet>254</a> </span><span class="kw">pub fn </span>from_scan_request(request: <span class="kw-2">&amp;</span><span class="prelude-ty">Option</span>&lt;ScanRequest&gt;) -&gt; Predicates {
<a href=#255 id=255 data-nosnippet>255</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(request) = request {
<a href=#256 id=256 data-nosnippet>256</a> <span class="kw">let </span><span class="kw-2">mut </span>predicates = Vec::with_capacity(request.filters.len());
<a href=#257 id=257 data-nosnippet>257</a>
<a href=#258 id=258 data-nosnippet>258</a> <span class="kw">for </span>filter <span class="kw">in </span><span class="kw-2">&amp;</span>request.filters {
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(predicate) = Predicate::from_expr(filter.clone()) {
<a href=#260 id=260 data-nosnippet>260</a> predicates.push(predicate);
<a href=#261 id=261 data-nosnippet>261</a> }
<a href=#262 id=262 data-nosnippet>262</a> }
<a href=#263 id=263 data-nosnippet>263</a>
<a href=#264 id=264 data-nosnippet>264</a> <span class="self">Self </span>{ predicates }
<a href=#265 id=265 data-nosnippet>265</a> } <span class="kw">else </span>{
<a href=#266 id=266 data-nosnippet>266</a> <span class="self">Self </span>{
<a href=#267 id=267 data-nosnippet>267</a> predicates: Vec::new(),
<a href=#268 id=268 data-nosnippet>268</a> }
<a href=#269 id=269 data-nosnippet>269</a> }
<a href=#270 id=270 data-nosnippet>270</a> }
<a href=#271 id=271 data-nosnippet>271</a>
<a href=#272 id=272 data-nosnippet>272</a> <span class="doccomment">/// Evaluate the predicates with the row.
<a href=#273 id=273 data-nosnippet>273</a> /// returns true when all the predicates are satisfied or can't be evaluated.
<a href=#274 id=274 data-nosnippet>274</a> </span><span class="kw">pub fn </span>eval(<span class="kw-2">&amp;</span><span class="self">self</span>, row: <span class="kw-2">&amp;</span>[(<span class="kw-2">&amp;</span>str, <span class="kw-2">&amp;</span>Value)]) -&gt; bool {
<a href=#275 id=275 data-nosnippet>275</a> <span class="comment">// fast path
<a href=#276 id=276 data-nosnippet>276</a> </span><span class="kw">if </span><span class="self">self</span>.predicates.is_empty() {
<a href=#277 id=277 data-nosnippet>277</a> <span class="kw">return </span><span class="bool-val">true</span>;
<a href=#278 id=278 data-nosnippet>278</a> }
<a href=#279 id=279 data-nosnippet>279</a>
<a href=#280 id=280 data-nosnippet>280</a> <span class="self">self</span>.predicates
<a href=#281 id=281 data-nosnippet>281</a> .iter()
<a href=#282 id=282 data-nosnippet>282</a> .filter_map(|p| p.eval(row))
<a href=#283 id=283 data-nosnippet>283</a> .all(|b| b)
<a href=#284 id=284 data-nosnippet>284</a> }
<a href=#285 id=285 data-nosnippet>285</a>}
<a href=#286 id=286 data-nosnippet>286</a>
<a href=#287 id=287 data-nosnippet>287</a><span class="doccomment">/// Returns true when the values are all [`DfExpr::Literal`].
<a href=#288 id=288 data-nosnippet>288</a></span><span class="kw">fn </span>is_all_scalars(list: <span class="kw-2">&amp;</span>[Expr]) -&gt; bool {
<a href=#289 id=289 data-nosnippet>289</a> list.iter().all(|v| <span class="macro">matches!</span>(v, Expr::Literal(<span class="kw">_</span>, <span class="kw">_</span>)))
<a href=#290 id=290 data-nosnippet>290</a>}
<a href=#291 id=291 data-nosnippet>291</a>
<a href=#292 id=292 data-nosnippet>292</a><span class="attr">#[cfg(test)]
<a href=#293 id=293 data-nosnippet>293</a></span><span class="kw">mod </span>tests {
<a href=#294 id=294 data-nosnippet>294</a> <span class="kw">use </span>datafusion::common::Column;
<a href=#295 id=295 data-nosnippet>295</a> <span class="kw">use </span>datafusion::logical_expr::expr::InList;
<a href=#296 id=296 data-nosnippet>296</a> <span class="kw">use </span>datafusion::logical_expr::{BinaryExpr, Literal};
<a href=#297 id=297 data-nosnippet>297</a>
<a href=#298 id=298 data-nosnippet>298</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#299 id=299 data-nosnippet>299</a>
<a href=#300 id=300 data-nosnippet>300</a> <span class="attr">#[test]
<a href=#301 id=301 data-nosnippet>301</a> </span><span class="kw">fn </span>test_predicate_eval() {
<a href=#302 id=302 data-nosnippet>302</a> <span class="kw">let </span>a_col = <span class="string">"a"</span>.to_string();
<a href=#303 id=303 data-nosnippet>303</a> <span class="kw">let </span>b_col = <span class="string">"b"</span>.to_string();
<a href=#304 id=304 data-nosnippet>304</a> <span class="kw">let </span>a_value = Value::from(<span class="string">"a_value"</span>);
<a href=#305 id=305 data-nosnippet>305</a> <span class="kw">let </span>b_value = Value::from(<span class="string">"b_value"</span>);
<a href=#306 id=306 data-nosnippet>306</a> <span class="kw">let </span>wrong_value = Value::from(<span class="string">"wrong_value"</span>);
<a href=#307 id=307 data-nosnippet>307</a>
<a href=#308 id=308 data-nosnippet>308</a> <span class="kw">let </span>a_row = [(a_col.as_str(), <span class="kw-2">&amp;</span>a_value)];
<a href=#309 id=309 data-nosnippet>309</a> <span class="kw">let </span>b_row = [(<span class="string">"b"</span>, <span class="kw-2">&amp;</span>wrong_value)];
<a href=#310 id=310 data-nosnippet>310</a> <span class="kw">let </span>wrong_row = [(a_col.as_str(), <span class="kw-2">&amp;</span>wrong_value)];
<a href=#311 id=311 data-nosnippet>311</a>
<a href=#312 id=312 data-nosnippet>312</a> <span class="comment">// Predicate::Eq
<a href=#313 id=313 data-nosnippet>313</a> </span><span class="kw">let </span>p = Predicate::Eq(a_col.clone(), a_value.clone());
<a href=#314 id=314 data-nosnippet>314</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>a_row).unwrap());
<a href=#315 id=315 data-nosnippet>315</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>b_row).is_none());
<a href=#316 id=316 data-nosnippet>316</a> <span class="macro">assert!</span>(!p.eval(<span class="kw-2">&amp;</span>wrong_row).unwrap());
<a href=#317 id=317 data-nosnippet>317</a>
<a href=#318 id=318 data-nosnippet>318</a> <span class="comment">// Predicate::NotEq
<a href=#319 id=319 data-nosnippet>319</a> </span><span class="kw">let </span>p = Predicate::NotEq(a_col.clone(), a_value.clone());
<a href=#320 id=320 data-nosnippet>320</a> <span class="macro">assert!</span>(!p.eval(<span class="kw-2">&amp;</span>a_row).unwrap());
<a href=#321 id=321 data-nosnippet>321</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>b_row).is_none());
<a href=#322 id=322 data-nosnippet>322</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>wrong_row).unwrap());
<a href=#323 id=323 data-nosnippet>323</a>
<a href=#324 id=324 data-nosnippet>324</a> <span class="comment">// Predicate::InList
<a href=#325 id=325 data-nosnippet>325</a> </span><span class="kw">let </span>p = Predicate::InList(a_col.clone(), <span class="macro">vec!</span>[a_value.clone(), b_value.clone()]);
<a href=#326 id=326 data-nosnippet>326</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>a_row).unwrap());
<a href=#327 id=327 data-nosnippet>327</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>b_row).is_none());
<a href=#328 id=328 data-nosnippet>328</a> <span class="macro">assert!</span>(!p.eval(<span class="kw-2">&amp;</span>wrong_row).unwrap());
<a href=#329 id=329 data-nosnippet>329</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>[(<span class="kw-2">&amp;</span>a_col, <span class="kw-2">&amp;</span>b_value)]).unwrap());
<a href=#330 id=330 data-nosnippet>330</a>
<a href=#331 id=331 data-nosnippet>331</a> <span class="kw">let </span>p1 = Predicate::Eq(a_col.clone(), a_value.clone());
<a href=#332 id=332 data-nosnippet>332</a> <span class="kw">let </span>p2 = Predicate::Eq(b_col.clone(), b_value.clone());
<a href=#333 id=333 data-nosnippet>333</a> <span class="kw">let </span>row = [(a_col.as_str(), <span class="kw-2">&amp;</span>a_value), (b_col.as_str(), <span class="kw-2">&amp;</span>b_value)];
<a href=#334 id=334 data-nosnippet>334</a> <span class="kw">let </span>wrong_row = [(a_col.as_str(), <span class="kw-2">&amp;</span>a_value), (b_col.as_str(), <span class="kw-2">&amp;</span>wrong_value)];
<a href=#335 id=335 data-nosnippet>335</a>
<a href=#336 id=336 data-nosnippet>336</a> <span class="comment">//Predicate::And
<a href=#337 id=337 data-nosnippet>337</a> </span><span class="kw">let </span>p = Predicate::And(Box::new(p1.clone()), Box::new(p2.clone()));
<a href=#338 id=338 data-nosnippet>338</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>row).unwrap());
<a href=#339 id=339 data-nosnippet>339</a> <span class="macro">assert!</span>(!p.eval(<span class="kw-2">&amp;</span>wrong_row).unwrap());
<a href=#340 id=340 data-nosnippet>340</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>[]).is_none());
<a href=#341 id=341 data-nosnippet>341</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>[(<span class="string">"c"</span>, <span class="kw-2">&amp;</span>a_value)]).is_none());
<a href=#342 id=342 data-nosnippet>342</a> <span class="macro">assert!</span>(
<a href=#343 id=343 data-nosnippet>343</a> !p.eval(<span class="kw-2">&amp;</span>[(a_col.as_str(), <span class="kw-2">&amp;</span>b_value), (b_col.as_str(), <span class="kw-2">&amp;</span>a_value)])
<a href=#344 id=344 data-nosnippet>344</a> .unwrap()
<a href=#345 id=345 data-nosnippet>345</a> );
<a href=#346 id=346 data-nosnippet>346</a> <span class="macro">assert!</span>(
<a href=#347 id=347 data-nosnippet>347</a> !p.eval(<span class="kw-2">&amp;</span>[(a_col.as_str(), <span class="kw-2">&amp;</span>b_value), (b_col.as_str(), <span class="kw-2">&amp;</span>b_value)])
<a href=#348 id=348 data-nosnippet>348</a> .unwrap()
<a href=#349 id=349 data-nosnippet>349</a> );
<a href=#350 id=350 data-nosnippet>350</a> <span class="macro">assert!</span>(
<a href=#351 id=351 data-nosnippet>351</a> p.eval(<span class="kw-2">&amp;</span>[(a_col.as_ref(), <span class="kw-2">&amp;</span>a_value), (<span class="string">"c"</span>, <span class="kw-2">&amp;</span>a_value)])
<a href=#352 id=352 data-nosnippet>352</a> .is_none()
<a href=#353 id=353 data-nosnippet>353</a> );
<a href=#354 id=354 data-nosnippet>354</a> <span class="macro">assert!</span>(
<a href=#355 id=355 data-nosnippet>355</a> !p.eval(<span class="kw-2">&amp;</span>[(a_col.as_ref(), <span class="kw-2">&amp;</span>b_value), (<span class="string">"c"</span>, <span class="kw-2">&amp;</span>a_value)])
<a href=#356 id=356 data-nosnippet>356</a> .unwrap()
<a href=#357 id=357 data-nosnippet>357</a> );
<a href=#358 id=358 data-nosnippet>358</a>
<a href=#359 id=359 data-nosnippet>359</a> <span class="comment">//Predicate::Or
<a href=#360 id=360 data-nosnippet>360</a> </span><span class="kw">let </span>p = Predicate::Or(Box::new(p1), Box::new(p2));
<a href=#361 id=361 data-nosnippet>361</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>row).unwrap());
<a href=#362 id=362 data-nosnippet>362</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>wrong_row).unwrap());
<a href=#363 id=363 data-nosnippet>363</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>[]).is_none());
<a href=#364 id=364 data-nosnippet>364</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>[(<span class="string">"c"</span>, <span class="kw-2">&amp;</span>a_value)]).is_none());
<a href=#365 id=365 data-nosnippet>365</a> <span class="macro">assert!</span>(
<a href=#366 id=366 data-nosnippet>366</a> !p.eval(<span class="kw-2">&amp;</span>[(a_col.as_str(), <span class="kw-2">&amp;</span>b_value), (b_col.as_str(), <span class="kw-2">&amp;</span>a_value)])
<a href=#367 id=367 data-nosnippet>367</a> .unwrap()
<a href=#368 id=368 data-nosnippet>368</a> );
<a href=#369 id=369 data-nosnippet>369</a> <span class="macro">assert!</span>(
<a href=#370 id=370 data-nosnippet>370</a> p.eval(<span class="kw-2">&amp;</span>[(a_col.as_str(), <span class="kw-2">&amp;</span>b_value), (b_col.as_str(), <span class="kw-2">&amp;</span>b_value)])
<a href=#371 id=371 data-nosnippet>371</a> .unwrap()
<a href=#372 id=372 data-nosnippet>372</a> );
<a href=#373 id=373 data-nosnippet>373</a> <span class="macro">assert!</span>(
<a href=#374 id=374 data-nosnippet>374</a> p.eval(<span class="kw-2">&amp;</span>[(a_col.as_ref(), <span class="kw-2">&amp;</span>a_value), (<span class="string">"c"</span>, <span class="kw-2">&amp;</span>a_value)])
<a href=#375 id=375 data-nosnippet>375</a> .unwrap()
<a href=#376 id=376 data-nosnippet>376</a> );
<a href=#377 id=377 data-nosnippet>377</a> <span class="macro">assert!</span>(
<a href=#378 id=378 data-nosnippet>378</a> p.eval(<span class="kw-2">&amp;</span>[(a_col.as_ref(), <span class="kw-2">&amp;</span>b_value), (<span class="string">"c"</span>, <span class="kw-2">&amp;</span>a_value)])
<a href=#379 id=379 data-nosnippet>379</a> .is_none()
<a href=#380 id=380 data-nosnippet>380</a> );
<a href=#381 id=381 data-nosnippet>381</a> }
<a href=#382 id=382 data-nosnippet>382</a>
<a href=#383 id=383 data-nosnippet>383</a> <span class="attr">#[test]
<a href=#384 id=384 data-nosnippet>384</a> </span><span class="kw">fn </span>test_predicate_like() {
<a href=#385 id=385 data-nosnippet>385</a> <span class="comment">// case insensitive
<a href=#386 id=386 data-nosnippet>386</a> </span><span class="kw">let </span>expr = Expr::Like(Like {
<a href=#387 id=387 data-nosnippet>387</a> negated: <span class="bool-val">false</span>,
<a href=#388 id=388 data-nosnippet>388</a> expr: Box::new(column(<span class="string">"a"</span>)),
<a href=#389 id=389 data-nosnippet>389</a> pattern: Box::new(<span class="string">"%abc"</span>.lit()),
<a href=#390 id=390 data-nosnippet>390</a> case_insensitive: <span class="bool-val">true</span>,
<a href=#391 id=391 data-nosnippet>391</a> escape_char: <span class="prelude-val">None</span>,
<a href=#392 id=392 data-nosnippet>392</a> });
<a href=#393 id=393 data-nosnippet>393</a>
<a href=#394 id=394 data-nosnippet>394</a> <span class="kw">let </span>p = Predicate::from_expr(expr).unwrap();
<a href=#395 id=395 data-nosnippet>395</a> <span class="macro">assert!</span>(
<a href=#396 id=396 data-nosnippet>396</a> <span class="macro">matches!</span>(<span class="kw-2">&amp;</span>p, Predicate::Like(c, pattern, case_insensitive) <span class="kw">if
<a href=#397 id=397 data-nosnippet>397</a> </span>c == <span class="string">"a"
<a href=#398 id=398 data-nosnippet>398</a> </span>&amp;&amp; pattern == <span class="string">"%abc"
<a href=#399 id=399 data-nosnippet>399</a> </span>&amp;&amp; <span class="kw-2">*</span>case_insensitive)
<a href=#400 id=400 data-nosnippet>400</a> );
<a href=#401 id=401 data-nosnippet>401</a>
<a href=#402 id=402 data-nosnippet>402</a> <span class="kw">let </span>match_row = [
<a href=#403 id=403 data-nosnippet>403</a> (<span class="string">"a"</span>, <span class="kw-2">&amp;</span>Value::from(<span class="string">"hello AbC"</span>)),
<a href=#404 id=404 data-nosnippet>404</a> (<span class="string">"b"</span>, <span class="kw-2">&amp;</span>Value::from(<span class="string">"b value"</span>)),
<a href=#405 id=405 data-nosnippet>405</a> ];
<a href=#406 id=406 data-nosnippet>406</a> <span class="kw">let </span>unmatch_row = [(<span class="string">"a"</span>, <span class="kw-2">&amp;</span>Value::from(<span class="string">"bca"</span>)), (<span class="string">"b"</span>, <span class="kw-2">&amp;</span>Value::from(<span class="string">"b value"</span>))];
<a href=#407 id=407 data-nosnippet>407</a>
<a href=#408 id=408 data-nosnippet>408</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>match_row).unwrap());
<a href=#409 id=409 data-nosnippet>409</a> <span class="macro">assert!</span>(!p.eval(<span class="kw-2">&amp;</span>unmatch_row).unwrap());
<a href=#410 id=410 data-nosnippet>410</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>[]).is_none());
<a href=#411 id=411 data-nosnippet>411</a>
<a href=#412 id=412 data-nosnippet>412</a> <span class="comment">// case sensitive
<a href=#413 id=413 data-nosnippet>413</a> </span><span class="kw">let </span>expr = Expr::Like(Like {
<a href=#414 id=414 data-nosnippet>414</a> negated: <span class="bool-val">false</span>,
<a href=#415 id=415 data-nosnippet>415</a> expr: Box::new(column(<span class="string">"a"</span>)),
<a href=#416 id=416 data-nosnippet>416</a> pattern: Box::new(<span class="string">"%abc"</span>.lit()),
<a href=#417 id=417 data-nosnippet>417</a> case_insensitive: <span class="bool-val">false</span>,
<a href=#418 id=418 data-nosnippet>418</a> escape_char: <span class="prelude-val">None</span>,
<a href=#419 id=419 data-nosnippet>419</a> });
<a href=#420 id=420 data-nosnippet>420</a>
<a href=#421 id=421 data-nosnippet>421</a> <span class="kw">let </span>p = Predicate::from_expr(expr).unwrap();
<a href=#422 id=422 data-nosnippet>422</a> <span class="macro">assert!</span>(
<a href=#423 id=423 data-nosnippet>423</a> <span class="macro">matches!</span>(<span class="kw-2">&amp;</span>p, Predicate::Like(c, pattern, case_insensitive) <span class="kw">if
<a href=#424 id=424 data-nosnippet>424</a> </span>c == <span class="string">"a"
<a href=#425 id=425 data-nosnippet>425</a> </span>&amp;&amp; pattern == <span class="string">"%abc"
<a href=#426 id=426 data-nosnippet>426</a> </span>&amp;&amp; !<span class="kw-2">*</span>case_insensitive)
<a href=#427 id=427 data-nosnippet>427</a> );
<a href=#428 id=428 data-nosnippet>428</a> <span class="macro">assert!</span>(!p.eval(<span class="kw-2">&amp;</span>match_row).unwrap());
<a href=#429 id=429 data-nosnippet>429</a> <span class="macro">assert!</span>(!p.eval(<span class="kw-2">&amp;</span>unmatch_row).unwrap());
<a href=#430 id=430 data-nosnippet>430</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>[]).is_none());
<a href=#431 id=431 data-nosnippet>431</a>
<a href=#432 id=432 data-nosnippet>432</a> <span class="comment">// not like
<a href=#433 id=433 data-nosnippet>433</a> </span><span class="kw">let </span>expr = Expr::Like(Like {
<a href=#434 id=434 data-nosnippet>434</a> negated: <span class="bool-val">true</span>,
<a href=#435 id=435 data-nosnippet>435</a> expr: Box::new(column(<span class="string">"a"</span>)),
<a href=#436 id=436 data-nosnippet>436</a> pattern: Box::new(<span class="string">"%abc"</span>.lit()),
<a href=#437 id=437 data-nosnippet>437</a> case_insensitive: <span class="bool-val">true</span>,
<a href=#438 id=438 data-nosnippet>438</a> escape_char: <span class="prelude-val">None</span>,
<a href=#439 id=439 data-nosnippet>439</a> });
<a href=#440 id=440 data-nosnippet>440</a>
<a href=#441 id=441 data-nosnippet>441</a> <span class="kw">let </span>p = Predicate::from_expr(expr).unwrap();
<a href=#442 id=442 data-nosnippet>442</a> <span class="macro">assert!</span>(!p.eval(<span class="kw-2">&amp;</span>match_row).unwrap());
<a href=#443 id=443 data-nosnippet>443</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>unmatch_row).unwrap());
<a href=#444 id=444 data-nosnippet>444</a> <span class="macro">assert!</span>(p.eval(<span class="kw-2">&amp;</span>[]).is_none());
<a href=#445 id=445 data-nosnippet>445</a> }
<a href=#446 id=446 data-nosnippet>446</a>
<a href=#447 id=447 data-nosnippet>447</a> <span class="kw">fn </span>column(name: <span class="kw-2">&amp;</span>str) -&gt; Expr {
<a href=#448 id=448 data-nosnippet>448</a> Expr::Column(Column::from_name(name))
<a href=#449 id=449 data-nosnippet>449</a> }
<a href=#450 id=450 data-nosnippet>450</a>
<a href=#451 id=451 data-nosnippet>451</a> <span class="kw">fn </span>match_string_value(v: <span class="kw-2">&amp;</span>Value, expected: <span class="kw-2">&amp;</span>str) -&gt; bool {
<a href=#452 id=452 data-nosnippet>452</a> <span class="macro">matches!</span>(v, Value::String(bs) <span class="kw">if </span>bs.as_utf8() == expected)
<a href=#453 id=453 data-nosnippet>453</a> }
<a href=#454 id=454 data-nosnippet>454</a>
<a href=#455 id=455 data-nosnippet>455</a> <span class="kw">fn </span>match_string_values(vs: <span class="kw-2">&amp;</span>[Value], expected: <span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span>str]) -&gt; bool {
<a href=#456 id=456 data-nosnippet>456</a> <span class="macro">assert_eq!</span>(vs.len(), expected.len());
<a href=#457 id=457 data-nosnippet>457</a>
<a href=#458 id=458 data-nosnippet>458</a> <span class="kw">let </span><span class="kw-2">mut </span>result = <span class="bool-val">true</span>;
<a href=#459 id=459 data-nosnippet>459</a> <span class="kw">for </span>(i, v) <span class="kw">in </span>vs.iter().enumerate() {
<a href=#460 id=460 data-nosnippet>460</a> result = result &amp;&amp; match_string_value(v, expected[i]);
<a href=#461 id=461 data-nosnippet>461</a> }
<a href=#462 id=462 data-nosnippet>462</a>
<a href=#463 id=463 data-nosnippet>463</a> result
<a href=#464 id=464 data-nosnippet>464</a> }
<a href=#465 id=465 data-nosnippet>465</a>
<a href=#466 id=466 data-nosnippet>466</a> <span class="kw">fn </span>mock_exprs() -&gt; (Expr, Expr) {
<a href=#467 id=467 data-nosnippet>467</a> <span class="kw">let </span>expr1 = Expr::BinaryExpr(BinaryExpr {
<a href=#468 id=468 data-nosnippet>468</a> left: Box::new(column(<span class="string">"a"</span>)),
<a href=#469 id=469 data-nosnippet>469</a> op: Operator::Eq,
<a href=#470 id=470 data-nosnippet>470</a> right: Box::new(<span class="string">"a_value"</span>.lit()),
<a href=#471 id=471 data-nosnippet>471</a> });
<a href=#472 id=472 data-nosnippet>472</a>
<a href=#473 id=473 data-nosnippet>473</a> <span class="kw">let </span>expr2 = Expr::BinaryExpr(BinaryExpr {
<a href=#474 id=474 data-nosnippet>474</a> left: Box::new(column(<span class="string">"b"</span>)),
<a href=#475 id=475 data-nosnippet>475</a> op: Operator::NotEq,
<a href=#476 id=476 data-nosnippet>476</a> right: Box::new(<span class="string">"b_value"</span>.lit()),
<a href=#477 id=477 data-nosnippet>477</a> });
<a href=#478 id=478 data-nosnippet>478</a>
<a href=#479 id=479 data-nosnippet>479</a> (expr1, expr2)
<a href=#480 id=480 data-nosnippet>480</a> }
<a href=#481 id=481 data-nosnippet>481</a>
<a href=#482 id=482 data-nosnippet>482</a> <span class="attr">#[test]
<a href=#483 id=483 data-nosnippet>483</a> </span><span class="kw">fn </span>test_predicate_from_expr() {
<a href=#484 id=484 data-nosnippet>484</a> <span class="kw">let </span>(expr1, expr2) = mock_exprs();
<a href=#485 id=485 data-nosnippet>485</a>
<a href=#486 id=486 data-nosnippet>486</a> <span class="kw">let </span>p1 = Predicate::from_expr(expr1.clone()).unwrap();
<a href=#487 id=487 data-nosnippet>487</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(<span class="kw-2">&amp;</span>p1, Predicate::Eq(column, v) <span class="kw">if </span>column == <span class="string">"a"
<a href=#488 id=488 data-nosnippet>488</a> </span>&amp;&amp; match_string_value(v, <span class="string">"a_value"</span>)));
<a href=#489 id=489 data-nosnippet>489</a>
<a href=#490 id=490 data-nosnippet>490</a> <span class="kw">let </span>p2 = Predicate::from_expr(expr2.clone()).unwrap();
<a href=#491 id=491 data-nosnippet>491</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(<span class="kw-2">&amp;</span>p2, Predicate::NotEq(column, v) <span class="kw">if </span>column == <span class="string">"b"
<a href=#492 id=492 data-nosnippet>492</a> </span>&amp;&amp; match_string_value(v, <span class="string">"b_value"</span>)));
<a href=#493 id=493 data-nosnippet>493</a>
<a href=#494 id=494 data-nosnippet>494</a> <span class="kw">let </span>and_expr = Expr::BinaryExpr(BinaryExpr {
<a href=#495 id=495 data-nosnippet>495</a> left: Box::new(expr1.clone()),
<a href=#496 id=496 data-nosnippet>496</a> op: Operator::And,
<a href=#497 id=497 data-nosnippet>497</a> right: Box::new(expr2.clone()),
<a href=#498 id=498 data-nosnippet>498</a> });
<a href=#499 id=499 data-nosnippet>499</a> <span class="kw">let </span>or_expr = Expr::BinaryExpr(BinaryExpr {
<a href=#500 id=500 data-nosnippet>500</a> left: Box::new(expr1.clone()),
<a href=#501 id=501 data-nosnippet>501</a> op: Operator::Or,
<a href=#502 id=502 data-nosnippet>502</a> right: Box::new(expr2.clone()),
<a href=#503 id=503 data-nosnippet>503</a> });
<a href=#504 id=504 data-nosnippet>504</a> <span class="kw">let </span>not_expr = Expr::Not(Box::new(expr1.clone()));
<a href=#505 id=505 data-nosnippet>505</a>
<a href=#506 id=506 data-nosnippet>506</a> <span class="kw">let </span>and_p = Predicate::from_expr(and_expr).unwrap();
<a href=#507 id=507 data-nosnippet>507</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(and_p, Predicate::And(left, right) <span class="kw">if </span><span class="kw-2">*</span>left == p1 &amp;&amp; <span class="kw-2">*</span>right == p2));
<a href=#508 id=508 data-nosnippet>508</a> <span class="kw">let </span>or_p = Predicate::from_expr(or_expr).unwrap();
<a href=#509 id=509 data-nosnippet>509</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(or_p, Predicate::Or(left, right) <span class="kw">if </span><span class="kw-2">*</span>left == p1 &amp;&amp; <span class="kw-2">*</span>right == p2));
<a href=#510 id=510 data-nosnippet>510</a> <span class="kw">let </span>not_p = Predicate::from_expr(not_expr).unwrap();
<a href=#511 id=511 data-nosnippet>511</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(not_p, Predicate::Not(p) <span class="kw">if </span><span class="kw-2">*</span>p == p1));
<a href=#512 id=512 data-nosnippet>512</a>
<a href=#513 id=513 data-nosnippet>513</a> <span class="kw">let </span>inlist_expr = Expr::InList(InList {
<a href=#514 id=514 data-nosnippet>514</a> expr: Box::new(column(<span class="string">"a"</span>)),
<a href=#515 id=515 data-nosnippet>515</a> list: <span class="macro">vec!</span>[<span class="string">"a1"</span>.lit(), <span class="string">"a2"</span>.lit()],
<a href=#516 id=516 data-nosnippet>516</a> negated: <span class="bool-val">false</span>,
<a href=#517 id=517 data-nosnippet>517</a> });
<a href=#518 id=518 data-nosnippet>518</a>
<a href=#519 id=519 data-nosnippet>519</a> <span class="kw">let </span>inlist_p = Predicate::from_expr(inlist_expr).unwrap();
<a href=#520 id=520 data-nosnippet>520</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(<span class="kw-2">&amp;</span>inlist_p, Predicate::InList(c, values) <span class="kw">if </span>c == <span class="string">"a"
<a href=#521 id=521 data-nosnippet>521</a> </span>&amp;&amp; match_string_values(values, <span class="kw-2">&amp;</span>[<span class="string">"a1"</span>, <span class="string">"a2"</span>])));
<a href=#522 id=522 data-nosnippet>522</a>
<a href=#523 id=523 data-nosnippet>523</a> <span class="kw">let </span>inlist_expr = Expr::InList(InList {
<a href=#524 id=524 data-nosnippet>524</a> expr: Box::new(column(<span class="string">"a"</span>)),
<a href=#525 id=525 data-nosnippet>525</a> list: <span class="macro">vec!</span>[<span class="string">"a1"</span>.lit(), <span class="string">"a2"</span>.lit()],
<a href=#526 id=526 data-nosnippet>526</a> negated: <span class="bool-val">true</span>,
<a href=#527 id=527 data-nosnippet>527</a> });
<a href=#528 id=528 data-nosnippet>528</a> <span class="kw">let </span>inlist_p = Predicate::from_expr(inlist_expr).unwrap();
<a href=#529 id=529 data-nosnippet>529</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(inlist_p, Predicate::Not(p) <span class="kw">if
<a href=#530 id=530 data-nosnippet>530</a> </span><span class="macro">matches!</span>(<span class="kw-2">&amp;*</span>p,
<a href=#531 id=531 data-nosnippet>531</a> Predicate::InList(c, values) <span class="kw">if </span>c == <span class="string">"a"
<a href=#532 id=532 data-nosnippet>532</a> </span>&amp;&amp; match_string_values(values, <span class="kw-2">&amp;</span>[<span class="string">"a1"</span>, <span class="string">"a2"</span>]))));
<a href=#533 id=533 data-nosnippet>533</a> }
<a href=#534 id=534 data-nosnippet>534</a>
<a href=#535 id=535 data-nosnippet>535</a> <span class="attr">#[test]
<a href=#536 id=536 data-nosnippet>536</a> </span><span class="kw">fn </span>test_predicates_from_scan_request() {
<a href=#537 id=537 data-nosnippet>537</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span><span class="prelude-val">None</span>);
<a href=#538 id=538 data-nosnippet>538</a> <span class="macro">assert!</span>(predicates.predicates.is_empty());
<a href=#539 id=539 data-nosnippet>539</a>
<a href=#540 id=540 data-nosnippet>540</a> <span class="kw">let </span>(expr1, expr2) = mock_exprs();
<a href=#541 id=541 data-nosnippet>541</a>
<a href=#542 id=542 data-nosnippet>542</a> <span class="kw">let </span>request = ScanRequest {
<a href=#543 id=543 data-nosnippet>543</a> filters: <span class="macro">vec!</span>[expr1, expr2],
<a href=#544 id=544 data-nosnippet>544</a> ..Default::default()
<a href=#545 id=545 data-nosnippet>545</a> };
<a href=#546 id=546 data-nosnippet>546</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span><span class="prelude-val">Some</span>(request));
<a href=#547 id=547 data-nosnippet>547</a>
<a href=#548 id=548 data-nosnippet>548</a> <span class="macro">assert_eq!</span>(<span class="number">2</span>, predicates.predicates.len());
<a href=#549 id=549 data-nosnippet>549</a> <span class="macro">assert!</span>(
<a href=#550 id=550 data-nosnippet>550</a> <span class="macro">matches!</span>(<span class="kw-2">&amp;</span>predicates.predicates[<span class="number">0</span>], Predicate::Eq(column, v) <span class="kw">if </span>column == <span class="string">"a"
<a href=#551 id=551 data-nosnippet>551</a> </span>&amp;&amp; match_string_value(v, <span class="string">"a_value"</span>))
<a href=#552 id=552 data-nosnippet>552</a> );
<a href=#553 id=553 data-nosnippet>553</a> <span class="macro">assert!</span>(
<a href=#554 id=554 data-nosnippet>554</a> <span class="macro">matches!</span>(<span class="kw-2">&amp;</span>predicates.predicates[<span class="number">1</span>], Predicate::NotEq(column, v) <span class="kw">if </span>column == <span class="string">"b"
<a href=#555 id=555 data-nosnippet>555</a> </span>&amp;&amp; match_string_value(v, <span class="string">"b_value"</span>))
<a href=#556 id=556 data-nosnippet>556</a> );
<a href=#557 id=557 data-nosnippet>557</a> }
<a href=#558 id=558 data-nosnippet>558</a>
<a href=#559 id=559 data-nosnippet>559</a> <span class="attr">#[test]
<a href=#560 id=560 data-nosnippet>560</a> </span><span class="kw">fn </span>test_predicates_eval_row() {
<a href=#561 id=561 data-nosnippet>561</a> <span class="kw">let </span>wrong_row = [
<a href=#562 id=562 data-nosnippet>562</a> (<span class="string">"a"</span>, <span class="kw-2">&amp;</span>Value::from(<span class="string">"a_value"</span>)),
<a href=#563 id=563 data-nosnippet>563</a> (<span class="string">"b"</span>, <span class="kw-2">&amp;</span>Value::from(<span class="string">"b_value"</span>)),
<a href=#564 id=564 data-nosnippet>564</a> (<span class="string">"c"</span>, <span class="kw-2">&amp;</span>Value::from(<span class="string">"c_value"</span>)),
<a href=#565 id=565 data-nosnippet>565</a> ];
<a href=#566 id=566 data-nosnippet>566</a> <span class="kw">let </span>row = [
<a href=#567 id=567 data-nosnippet>567</a> (<span class="string">"a"</span>, <span class="kw-2">&amp;</span>Value::from(<span class="string">"a_value"</span>)),
<a href=#568 id=568 data-nosnippet>568</a> (<span class="string">"b"</span>, <span class="kw-2">&amp;</span>Value::from(<span class="string">"not_b_value"</span>)),
<a href=#569 id=569 data-nosnippet>569</a> (<span class="string">"c"</span>, <span class="kw-2">&amp;</span>Value::from(<span class="string">"c_value"</span>)),
<a href=#570 id=570 data-nosnippet>570</a> ];
<a href=#571 id=571 data-nosnippet>571</a> <span class="kw">let </span>c_row = [(<span class="string">"c"</span>, <span class="kw-2">&amp;</span>Value::from(<span class="string">"c_value"</span>))];
<a href=#572 id=572 data-nosnippet>572</a>
<a href=#573 id=573 data-nosnippet>573</a> <span class="comment">// test empty predicates, always returns true
<a href=#574 id=574 data-nosnippet>574</a> </span><span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span><span class="prelude-val">None</span>);
<a href=#575 id=575 data-nosnippet>575</a> <span class="macro">assert!</span>(predicates.eval(<span class="kw-2">&amp;</span>row));
<a href=#576 id=576 data-nosnippet>576</a> <span class="macro">assert!</span>(predicates.eval(<span class="kw-2">&amp;</span>wrong_row));
<a href=#577 id=577 data-nosnippet>577</a> <span class="macro">assert!</span>(predicates.eval(<span class="kw-2">&amp;</span>c_row));
<a href=#578 id=578 data-nosnippet>578</a>
<a href=#579 id=579 data-nosnippet>579</a> <span class="kw">let </span>(expr1, expr2) = mock_exprs();
<a href=#580 id=580 data-nosnippet>580</a> <span class="kw">let </span>request = ScanRequest {
<a href=#581 id=581 data-nosnippet>581</a> filters: <span class="macro">vec!</span>[expr1, expr2],
<a href=#582 id=582 data-nosnippet>582</a> ..Default::default()
<a href=#583 id=583 data-nosnippet>583</a> };
<a href=#584 id=584 data-nosnippet>584</a> <span class="kw">let </span>predicates = Predicates::from_scan_request(<span class="kw-2">&amp;</span><span class="prelude-val">Some</span>(request));
<a href=#585 id=585 data-nosnippet>585</a> <span class="macro">assert!</span>(predicates.eval(<span class="kw-2">&amp;</span>row));
<a href=#586 id=586 data-nosnippet>586</a> <span class="macro">assert!</span>(!predicates.eval(<span class="kw-2">&amp;</span>wrong_row));
<a href=#587 id=587 data-nosnippet>587</a> <span class="macro">assert!</span>(predicates.eval(<span class="kw-2">&amp;</span>c_row));
<a href=#588 id=588 data-nosnippet>588</a> }
<a href=#589 id=589 data-nosnippet>589</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,480 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/semantic_graph.rs`."><title>semantic_graph.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/</div>semantic_graph.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! The computed entity-graph tables `greptime_private.semantic_entities` and
<a href=#16 id=16 data-nosnippet>16</a>//! `greptime_private.semantic_relationships`.
<a href=#17 id=17 data-nosnippet>17</a>//!
<a href=#18 id=18 data-nosnippet>18</a>//! They live in `greptime_private`, not `information_schema`: scanning them
<a href=#19 id=19 data-nosnippet>19</a>//! triggers read-time derivation over telemetry tables (trace self-joins, ...),
<a href=#20 id=20 data-nosnippet>20</a>//! which breaks the "cheap, metadata-only" expectation users have of
<a href=#21 id=21 data-nosnippet>21</a>//! `information_schema`. `greptime_private` also hosts the physical
<a href=#22 id=22 data-nosnippet>22</a>//! declared-edge table (`semantic_relationships_declared`), whose rows are
<a href=#23 id=23 data-nosnippet>23</a>//! unioned into the computed `semantic_relationships`.
<a href=#24 id=24 data-nosnippet>24</a>//!
<a href=#25 id=25 data-nosnippet>25</a>//! These are thin forwarders: their rows are derived at read time by the injected
<a href=#26 id=26 data-nosnippet>26</a>//! [`EntityGraphProvider`], which enumerates the `table_semantics` declarations,
<a href=#27 id=27 data-nosnippet>27</a>//! builds typed DataFusion derivation plans, and executes them via the query
<a href=#28 id=28 data-nosnippet>28</a>//! engine. When no provider is injected (e.g. before the engine is up, or on a
<a href=#29 id=29 data-nosnippet>29</a>//! non-frontend node) they stream empty. The fixed schemas here must match the
<a href=#30 id=30 data-nosnippet>30</a>//! columns the provider's plans project; JSON columns are `json` (JSONB), whose
<a href=#31 id=31 data-nosnippet>31</a>//! Arrow storage type is `Binary` — the derived batches are rebuilt against the
<a href=#32 id=32 data-nosnippet>32</a>//! declared Arrow schema (which carries the `json` extension metadata) in
<a href=#33 id=33 data-nosnippet>33</a>//! [`SystemTable::to_stream`].
<a href=#34 id=34 data-nosnippet>34</a>
<a href=#35 id=35 data-nosnippet>35</a></span><span class="kw">use </span>std::sync::{Arc, LazyLock, Weak};
<a href=#36 id=36 data-nosnippet>36</a>
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>common_catalog::consts::{
<a href=#38 id=38 data-nosnippet>38</a> CONFIDENCE_COLUMN, DEFAULT_PRIVATE_SCHEMA_NAME, DST_ID_COLUMN, DST_TYPE_COLUMN,
<a href=#39 id=39 data-nosnippet>39</a> DURATION_COUNT_COLUMN, DURATION_MAX_COLUMN, DURATION_SUM_COLUMN, EDGE_ATTRIBUTES_COLUMN,
<a href=#40 id=40 data-nosnippet>40</a> ENTITY_DESCRIPTIVE_COLUMN, ENTITY_ID_ATTRS_COLUMN, ENTITY_ID_COLUMN, ENTITY_SCOPE_COLUMN,
<a href=#41 id=41 data-nosnippet>41</a> ENTITY_TYPE_COLUMN, ERROR_COUNT_COLUMN, FRESH_UNTIL_COLUMN, OBSERVED_AT_COLUMN,
<a href=#42 id=42 data-nosnippet>42</a> PROVENANCE_COLUMN, REL_TYPE_COLUMN, REQUEST_COUNT_COLUMN, SEMANTIC_ENTITIES_TABLE_ID,
<a href=#43 id=43 data-nosnippet>43</a> SEMANTIC_ENTITIES_TABLE_NAME <span class="kw">as </span>SEMANTIC_ENTITIES, SEMANTIC_RELATIONSHIPS_TABLE_ID,
<a href=#44 id=44 data-nosnippet>44</a> SEMANTIC_RELATIONSHIPS_TABLE_NAME <span class="kw">as </span>SEMANTIC_RELATIONSHIPS, SOURCE_TABLES_COLUMN,
<a href=#45 id=45 data-nosnippet>45</a> SRC_ID_COLUMN, SRC_TYPE_COLUMN, UNMATCHED_COUNT_COLUMN, WINDOW_END_COLUMN, WINDOW_START_COLUMN,
<a href=#46 id=46 data-nosnippet>46</a>};
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">use </span>common_recordbatch::adapter::AsyncRecordBatchStreamAdapter;
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">use </span>common_recordbatch::{
<a href=#50 id=50 data-nosnippet>50</a> DfRecordBatch, EmptyRecordBatchStream, RecordBatch, RecordBatchStreamWrapper,
<a href=#51 id=51 data-nosnippet>51</a> SendableRecordBatchStream,
<a href=#52 id=52 data-nosnippet>52</a>};
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">use </span>datatypes::prelude::ConcreteDataType;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema, SchemaRef};
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">use </span>futures::StreamExt;
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">use </span>session::context::QueryContextRef;
<a href=#57 id=57 data-nosnippet>57</a><span class="kw">use </span>snafu::ResultExt;
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">use </span>store_api::storage::{ScanRequest, TableId};
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">use </span>table::TableRef;
<a href=#60 id=60 data-nosnippet>60</a><span class="kw">use </span>table::metadata::TableInfo;
<a href=#61 id=61 data-nosnippet>61</a>
<a href=#62 id=62 data-nosnippet>62</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#63 id=63 data-nosnippet>63</a><span class="kw">use </span><span class="kw">crate</span>::error::{InternalSnafu, <span class="prelude-ty">Result</span>};
<a href=#64 id=64 data-nosnippet>64</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::{SystemSchemaProviderInner, SystemTable, SystemTableRef, utils};
<a href=#65 id=65 data-nosnippet>65</a>
<a href=#66 id=66 data-nosnippet>66</a><span class="kw">pub type </span>EntityGraphProviderRef = Arc&lt;<span class="kw">dyn </span>EntityGraphProvider&gt;;
<a href=#67 id=67 data-nosnippet>67</a>
<a href=#68 id=68 data-nosnippet>68</a><span class="doccomment">/// Where a table's entity declaration came from.
<a href=#69 id=69 data-nosnippet>69</a></span><span class="kw">pub enum </span>DeclarationOrigin {
<a href=#70 id=70 data-nosnippet>70</a> <span class="doccomment">/// A `greptime.semantic.entity.&lt;type&gt;.*` table option.
<a href=#71 id=71 data-nosnippet>71</a> </span>Declared,
<a href=#72 id=72 data-nosnippet>72</a> <span class="doccomment">/// The built-in derivation conventions shipped with the binary.
<a href=#73 id=73 data-nosnippet>73</a> </span>Convention,
<a href=#74 id=74 data-nosnippet>74</a>}
<a href=#75 id=75 data-nosnippet>75</a>
<a href=#76 id=76 data-nosnippet>76</a><span class="kw">impl </span>DeclarationOrigin {
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">pub fn </span>as_str(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#79 id=79 data-nosnippet>79</a> <span class="self">Self</span>::Declared =&gt; <span class="string">"declared"</span>,
<a href=#80 id=80 data-nosnippet>80</a> <span class="self">Self</span>::Convention =&gt; <span class="string">"convention"</span>,
<a href=#81 id=81 data-nosnippet>81</a> }
<a href=#82 id=82 data-nosnippet>82</a> }
<a href=#83 id=83 data-nosnippet>83</a>}
<a href=#84 id=84 data-nosnippet>84</a>
<a href=#85 id=85 data-nosnippet>85</a><span class="doccomment">/// One entity a table declares, as `information_schema.table_semantics`
<a href=#86 id=86 data-nosnippet>86</a>/// reports it. A catalog-side projection of the derivation's own declaration
<a href=#87 id=87 data-nosnippet>87</a>/// type, which lives above this crate.
<a href=#88 id=88 data-nosnippet>88</a></span><span class="kw">pub struct </span>TableEntityDeclaration {
<a href=#89 id=89 data-nosnippet>89</a> <span class="kw">pub </span>entity_type: String,
<a href=#90 id=90 data-nosnippet>90</a> <span class="kw">pub </span>origin: DeclarationOrigin,
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">pub </span>id_columns: Vec&lt;String&gt;,
<a href=#92 id=92 data-nosnippet>92</a> <span class="kw">pub </span>id_qualifier: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#93 id=93 data-nosnippet>93</a> <span class="doccomment">/// Columns whose presence on a row withdraws this declaration for that row.
<a href=#94 id=94 data-nosnippet>94</a> /// Reported because the declaration otherwise reads as unconditional.
<a href=#95 id=95 data-nosnippet>95</a> </span><span class="kw">pub </span>superseded_by_columns: Vec&lt;String&gt;,
<a href=#96 id=96 data-nosnippet>96</a> <span class="kw">pub </span>descriptive_columns: Vec&lt;String&gt;,
<a href=#97 id=97 data-nosnippet>97</a> <span class="kw">pub </span>scope_columns: Vec&lt;String&gt;,
<a href=#98 id=98 data-nosnippet>98</a>}
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a><span class="doccomment">/// Produces the rows of the computed entity-graph tables at read time.
<a href=#101 id=101 data-nosnippet>101</a>///
<a href=#102 id=102 data-nosnippet>102</a>/// Implemented above the query engine (in the frontend) and injected into the
<a href=#103 id=103 data-nosnippet>103</a>/// catalog manager *after* construction — the provider needs the engine, which
<a href=#104 id=104 data-nosnippet>104</a>/// needs the catalog manager — so this late binding breaks the
<a href=#105 id=105 data-nosnippet>105</a>/// `catalog -&gt; query` dependency cycle.
<a href=#106 id=106 data-nosnippet>106</a>///
<a href=#107 id=107 data-nosnippet>107</a>/// `query_ctx` is the outer query's context, captured when the computed table
<a href=#108 id=108 data-nosnippet>108</a>/// is resolved: the derivation must read only sources that context may read
<a href=#109 id=109 data-nosnippet>109</a>/// and execute under it, inheriting the caller's permissions, cancellation and
<a href=#110 id=110 data-nosnippet>110</a>/// deadline (the RFC's derivation contract). `None` (context-less internal
<a href=#111 id=111 data-nosnippet>111</a>/// resolution) keeps the provider's default behaviour.
<a href=#112 id=112 data-nosnippet>112</a></span><span class="attr">#[async_trait::async_trait]
<a href=#113 id=113 data-nosnippet>113</a></span><span class="kw">pub trait </span>EntityGraphProvider: Send + Sync {
<a href=#114 id=114 data-nosnippet>114</a> <span class="doccomment">/// Produces the entity registry (`semantic_entities`) rows for `catalog`.
<a href=#115 id=115 data-nosnippet>115</a> /// `None` means no source table declared an entity.
<a href=#116 id=116 data-nosnippet>116</a> </span><span class="kw">async fn </span>scan_entities(
<a href=#117 id=117 data-nosnippet>117</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#118 id=118 data-nosnippet>118</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#119 id=119 data-nosnippet>119</a> request: ScanRequest,
<a href=#120 id=120 data-nosnippet>120</a> query_ctx: <span class="prelude-ty">Option</span>&lt;QueryContextRef&gt;,
<a href=#121 id=121 data-nosnippet>121</a> ) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;SendableRecordBatchStream&gt;, BoxedError&gt;;
<a href=#122 id=122 data-nosnippet>122</a>
<a href=#123 id=123 data-nosnippet>123</a> <span class="doccomment">/// Produces the relationship set (`semantic_relationships`) rows for `catalog`.
<a href=#124 id=124 data-nosnippet>124</a> </span><span class="kw">async fn </span>scan_relationships(
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#126 id=126 data-nosnippet>126</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#127 id=127 data-nosnippet>127</a> request: ScanRequest,
<a href=#128 id=128 data-nosnippet>128</a> query_ctx: <span class="prelude-ty">Option</span>&lt;QueryContextRef&gt;,
<a href=#129 id=129 data-nosnippet>129</a> ) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;SendableRecordBatchStream&gt;, BoxedError&gt;;
<a href=#130 id=130 data-nosnippet>130</a>
<a href=#131 id=131 data-nosnippet>131</a> <span class="doccomment">/// The entities `table_info` contributes to the graph: its explicit
<a href=#132 id=132 data-nosnippet>132</a> /// declarations merged with the ones the conventions derive. Metadata-only
<a href=#133 id=133 data-nosnippet>133</a> /// by contract — it runs per table on the `table_semantics` scan and must
<a href=#134 id=134 data-nosnippet>134</a> /// not touch the query engine.
<a href=#135 id=135 data-nosnippet>135</a> </span><span class="kw">fn </span>table_declarations(<span class="kw-2">&amp;</span><span class="self">self</span>, table_info: <span class="kw-2">&amp;</span>TableInfo) -&gt; Vec&lt;TableEntityDeclaration&gt;;
<a href=#136 id=136 data-nosnippet>136</a>}
<a href=#137 id=137 data-nosnippet>137</a>
<a href=#138 id=138 data-nosnippet>138</a><span class="doccomment">/// Serves the computed graph tables under `greptime_private`, overlaid on the
<a href=#139 id=139 data-nosnippet>139</a>/// schema's physical tables the same way the `numbers` table overlays `public`
<a href=#140 id=140 data-nosnippet>140</a>/// (the system catalog is consulted before physical table resolution).
<a href=#141 id=141 data-nosnippet>141</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>SemanticGraphTableProvider {
<a href=#142 id=142 data-nosnippet>142</a> catalog_name: String,
<a href=#143 id=143 data-nosnippet>143</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#144 id=144 data-nosnippet>144</a> <span class="doccomment">/// The resolving query's context; captured per resolution (the provider is
<a href=#145 id=145 data-nosnippet>145</a> /// built on demand, never cached), so it cannot leak across sessions.
<a href=#146 id=146 data-nosnippet>146</a> </span>query_ctx: <span class="prelude-ty">Option</span>&lt;QueryContextRef&gt;,
<a href=#147 id=147 data-nosnippet>147</a>}
<a href=#148 id=148 data-nosnippet>148</a>
<a href=#149 id=149 data-nosnippet>149</a><span class="kw">impl </span>SemanticGraphTableProvider {
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new(
<a href=#151 id=151 data-nosnippet>151</a> catalog_name: String,
<a href=#152 id=152 data-nosnippet>152</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#153 id=153 data-nosnippet>153</a> query_ctx: <span class="prelude-ty">Option</span>&lt;QueryContextRef&gt;,
<a href=#154 id=154 data-nosnippet>154</a> ) -&gt; <span class="self">Self </span>{
<a href=#155 id=155 data-nosnippet>155</a> <span class="self">Self </span>{
<a href=#156 id=156 data-nosnippet>156</a> catalog_name,
<a href=#157 id=157 data-nosnippet>157</a> catalog_manager,
<a href=#158 id=158 data-nosnippet>158</a> query_ctx,
<a href=#159 id=159 data-nosnippet>159</a> }
<a href=#160 id=160 data-nosnippet>160</a> }
<a href=#161 id=161 data-nosnippet>161</a>
<a href=#162 id=162 data-nosnippet>162</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>table_names() -&gt; Vec&lt;String&gt; {
<a href=#163 id=163 data-nosnippet>163</a> <span class="macro">vec!</span>[
<a href=#164 id=164 data-nosnippet>164</a> SEMANTIC_ENTITIES.to_string(),
<a href=#165 id=165 data-nosnippet>165</a> SEMANTIC_RELATIONSHIPS.to_string(),
<a href=#166 id=166 data-nosnippet>166</a> ]
<a href=#167 id=167 data-nosnippet>167</a> }
<a href=#168 id=168 data-nosnippet>168</a>
<a href=#169 id=169 data-nosnippet>169</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>table_exists(name: <span class="kw-2">&amp;</span>str) -&gt; bool {
<a href=#170 id=170 data-nosnippet>170</a> name == SEMANTIC_ENTITIES || name == SEMANTIC_RELATIONSHIPS
<a href=#171 id=171 data-nosnippet>171</a> }
<a href=#172 id=172 data-nosnippet>172</a>
<a href=#173 id=173 data-nosnippet>173</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>table(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;TableRef&gt; {
<a href=#174 id=174 data-nosnippet>174</a> <span class="self">self</span>.build_table(name)
<a href=#175 id=175 data-nosnippet>175</a> }
<a href=#176 id=176 data-nosnippet>176</a>}
<a href=#177 id=177 data-nosnippet>177</a>
<a href=#178 id=178 data-nosnippet>178</a><span class="kw">impl </span>SystemSchemaProviderInner <span class="kw">for </span>SemanticGraphTableProvider {
<a href=#179 id=179 data-nosnippet>179</a> <span class="kw">fn </span>catalog_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#180 id=180 data-nosnippet>180</a> <span class="kw-2">&amp;</span><span class="self">self</span>.catalog_name
<a href=#181 id=181 data-nosnippet>181</a> }
<a href=#182 id=182 data-nosnippet>182</a>
<a href=#183 id=183 data-nosnippet>183</a> <span class="kw">fn </span>schema_name() -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#184 id=184 data-nosnippet>184</a> DEFAULT_PRIVATE_SCHEMA_NAME
<a href=#185 id=185 data-nosnippet>185</a> }
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">fn </span>system_table(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;SystemTableRef&gt; {
<a href=#188 id=188 data-nosnippet>188</a> <span class="kw">let </span>kind = <span class="kw">match </span>name {
<a href=#189 id=189 data-nosnippet>189</a> SEMANTIC_ENTITIES =&gt; GraphTableKind::Entities,
<a href=#190 id=190 data-nosnippet>190</a> SEMANTIC_RELATIONSHIPS =&gt; GraphTableKind::Relationships,
<a href=#191 id=191 data-nosnippet>191</a> <span class="kw">_ </span>=&gt; <span class="kw">return </span><span class="prelude-val">None</span>,
<a href=#192 id=192 data-nosnippet>192</a> };
<a href=#193 id=193 data-nosnippet>193</a> <span class="prelude-val">Some</span>(Arc::new(SemanticGraphTable::new(
<a href=#194 id=194 data-nosnippet>194</a> kind,
<a href=#195 id=195 data-nosnippet>195</a> <span class="self">self</span>.catalog_name.clone(),
<a href=#196 id=196 data-nosnippet>196</a> <span class="self">self</span>.catalog_manager.clone(),
<a href=#197 id=197 data-nosnippet>197</a> <span class="self">self</span>.query_ctx.clone(),
<a href=#198 id=198 data-nosnippet>198</a> )) <span class="kw">as _</span>)
<a href=#199 id=199 data-nosnippet>199</a> }
<a href=#200 id=200 data-nosnippet>200</a>}
<a href=#201 id=201 data-nosnippet>201</a>
<a href=#202 id=202 data-nosnippet>202</a><span class="kw">fn </span>ts() -&gt; ConcreteDataType {
<a href=#203 id=203 data-nosnippet>203</a> ConcreteDataType::timestamp_millisecond_datatype()
<a href=#204 id=204 data-nosnippet>204</a>}
<a href=#205 id=205 data-nosnippet>205</a>
<a href=#206 id=206 data-nosnippet>206</a><span class="kw">fn </span>string() -&gt; ConcreteDataType {
<a href=#207 id=207 data-nosnippet>207</a> ConcreteDataType::string_datatype()
<a href=#208 id=208 data-nosnippet>208</a>}
<a href=#209 id=209 data-nosnippet>209</a>
<a href=#210 id=210 data-nosnippet>210</a><span class="kw">fn </span>json() -&gt; ConcreteDataType {
<a href=#211 id=211 data-nosnippet>211</a> ConcreteDataType::json_datatype()
<a href=#212 id=212 data-nosnippet>212</a>}
<a href=#213 id=213 data-nosnippet>213</a>
<a href=#214 id=214 data-nosnippet>214</a><span class="doccomment">/// Schema of `semantic_entities` — the node set of the graph, one row per entity
<a href=#215 id=215 data-nosnippet>215</a>/// observed in a time window. Must match the registry derivation projection.
<a href=#216 id=216 data-nosnippet>216</a>///
<a href=#217 id=217 data-nosnippet>217</a>/// Columns:
<a href=#218 id=218 data-nosnippet>218</a>/// - `observed_at` — TIME INDEX; the 60s time bucket the entity was observed in.
<a href=#219 id=219 data-nosnippet>219</a>/// - `window_start` — start of that observation window.
<a href=#220 id=220 data-nosnippet>220</a>/// - `window_end` — end of the window (`window_start` + 60s).
<a href=#221 id=221 data-nosnippet>221</a>/// - `fresh_until` — time up to which the entity is considered present; equals
<a href=#222 id=222 data-nosnippet>222</a>/// `window_end` for derived rows (the graph is a sliding window, not a
<a href=#223 id=223 data-nosnippet>223</a>/// current-state table: an entity exists in a query window only if it has
<a href=#224 id=224 data-nosnippet>224</a>/// observed evidence there).
<a href=#225 id=225 data-nosnippet>225</a>/// - `entity_type` — the entity's type, e.g. `service`, `host`, `k8s.pod`,
<a href=#226 id=226 data-nosnippet>226</a>/// `process`, `service.instance` (the OTel-style, possibly dotted, type).
<a href=#227 id=227 data-nosnippet>227</a>/// - `entity_id` — canonical identifier: the identifying values in declared
<a href=#228 id=228 data-nosnippet>228</a>/// order, escaped and joined.
<a href=#229 id=229 data-nosnippet>229</a>/// - `entity_id_attrs` — JSON object of the identifying attributes, so a
<a href=#230 id=230 data-nosnippet>230</a>/// consumer holding an id can tell which columns it came from.
<a href=#231 id=231 data-nosnippet>231</a>/// - `scope` — namespace/environment the id is scoped to; empty when none.
<a href=#232 id=232 data-nosnippet>232</a>/// - `descriptive` — JSON snapshot of the entity's descriptive (non-identifying)
<a href=#233 id=233 data-nosnippet>233</a>/// attributes; NULL when no descriptive columns were declared.
<a href=#234 id=234 data-nosnippet>234</a>/// - `source_tables` — JSON array of the telemetry tables that contributed this entity.
<a href=#235 id=235 data-nosnippet>235</a></span><span class="kw">static </span>ENTITIES_SCHEMA: LazyLock&lt;SchemaRef&gt; = LazyLock::new(|| {
<a href=#236 id=236 data-nosnippet>236</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#237 id=237 data-nosnippet>237</a> ColumnSchema::new(OBSERVED_AT_COLUMN, ts(), <span class="bool-val">false</span>).with_time_index(<span class="bool-val">true</span>),
<a href=#238 id=238 data-nosnippet>238</a> ColumnSchema::new(WINDOW_START_COLUMN, ts(), <span class="bool-val">true</span>),
<a href=#239 id=239 data-nosnippet>239</a> ColumnSchema::new(WINDOW_END_COLUMN, ts(), <span class="bool-val">true</span>),
<a href=#240 id=240 data-nosnippet>240</a> ColumnSchema::new(FRESH_UNTIL_COLUMN, ts(), <span class="bool-val">true</span>),
<a href=#241 id=241 data-nosnippet>241</a> ColumnSchema::new(ENTITY_TYPE_COLUMN, string(), <span class="bool-val">false</span>),
<a href=#242 id=242 data-nosnippet>242</a> ColumnSchema::new(ENTITY_ID_COLUMN, string(), <span class="bool-val">false</span>),
<a href=#243 id=243 data-nosnippet>243</a> ColumnSchema::new(ENTITY_ID_ATTRS_COLUMN, json(), <span class="bool-val">true</span>),
<a href=#244 id=244 data-nosnippet>244</a> ColumnSchema::new(ENTITY_SCOPE_COLUMN, string(), <span class="bool-val">true</span>),
<a href=#245 id=245 data-nosnippet>245</a> ColumnSchema::new(ENTITY_DESCRIPTIVE_COLUMN, json(), <span class="bool-val">true</span>),
<a href=#246 id=246 data-nosnippet>246</a> ColumnSchema::new(SOURCE_TABLES_COLUMN, json(), <span class="bool-val">true</span>),
<a href=#247 id=247 data-nosnippet>247</a> ]))
<a href=#248 id=248 data-nosnippet>248</a>});
<a href=#249 id=249 data-nosnippet>249</a>
<a href=#250 id=250 data-nosnippet>250</a><span class="doccomment">/// Schema of `semantic_relationships` — the edge set of the graph, one row per
<a href=#251 id=251 data-nosnippet>251</a>/// edge observed in a time window. This is the 18-column contract every derived
<a href=#252 id=252 data-nosnippet>252</a>/// branch and the declared-edge table must project for the top-level `UNION ALL`.
<a href=#253 id=253 data-nosnippet>253</a>///
<a href=#254 id=254 data-nosnippet>254</a>/// Columns:
<a href=#255 id=255 data-nosnippet>255</a>/// - `observed_at` — TIME INDEX; the 60s time bucket the edge was observed in.
<a href=#256 id=256 data-nosnippet>256</a>/// - `window_start` / `window_end` — the observation window (`window_start` + 60s).
<a href=#257 id=257 data-nosnippet>257</a>/// - `fresh_until` — time up to which the edge is considered live; equals
<a href=#258 id=258 data-nosnippet>258</a>/// `window_end` for derived edges (from `valid_until` for declared edges).
<a href=#259 id=259 data-nosnippet>259</a>/// - `src_type` / `src_id` — type and canonical id of the source endpoint.
<a href=#260 id=260 data-nosnippet>260</a>/// - `dst_type` / `dst_id` — type and canonical id of the destination endpoint.
<a href=#261 id=261 data-nosnippet>261</a>/// - `rel_type` — relationship kind, e.g. `calls`, `runs_on`, `contains`,
<a href=#262 id=262 data-nosnippet>262</a>/// `part_of`, `depends_on` (direction is src → dst; the inverse is a query concern).
<a href=#263 id=263 data-nosnippet>263</a>/// - `provenance` — how the edge was obtained: `trace` (derived from spans),
<a href=#264 id=264 data-nosnippet>264</a>/// `attribute` (shared-identity join), `declared` (hand-inserted), or `agent`
<a href=#265 id=265 data-nosnippet>265</a>/// (agent-inferred). Part of the edge identity, so edges of different provenance
<a href=#266 id=266 data-nosnippet>266</a>/// for the same pair coexist.
<a href=#267 id=267 data-nosnippet>267</a>/// - `confidence` — derivation certainty in `[0, 1]`: `1.0` for paired or
<a href=#268 id=268 data-nosnippet>268</a>/// declared edges, lower for virtual-node or agent-inferred edges. It does
<a href=#269 id=269 data-nosnippet>269</a>/// not correct for trace sampling.
<a href=#270 id=270 data-nosnippet>270</a>/// - `request_count` — RED: number of requests over the window (`calls` edges).
<a href=#271 id=271 data-nosnippet>271</a>/// - `unmatched_count` — client spans on this edge with no server span. The
<a href=#272 id=272 data-nosnippet>272</a>/// other RED columns describe the pairs alone, so this is what separates a
<a href=#273 id=273 data-nosnippet>273</a>/// callee that stopped responding from traffic that stopped arriving.
<a href=#274 id=274 data-nosnippet>274</a>/// - `error_count` — RED: number of errored requests over the window.
<a href=#275 id=275 data-nosnippet>275</a>/// - `duration_sum` — RED: sum of request durations, in seconds, over the window.
<a href=#276 id=276 data-nosnippet>276</a>/// - `duration_count`— RED: number of durations summed (pair with `duration_sum`
<a href=#277 id=277 data-nosnippet>277</a>/// to get an average).
<a href=#278 id=278 data-nosnippet>278</a>/// - `duration_max` — RED: longest single request, in seconds, over the same
<a href=#279 id=279 data-nosnippet>279</a>/// population `duration_sum` covers.
<a href=#280 id=280 data-nosnippet>280</a>/// - `attributes` — JSON of edge attributes, e.g. `connection_type`,
<a href=#281 id=281 data-nosnippet>281</a>/// `db.system`, `peer.service`.
<a href=#282 id=282 data-nosnippet>282</a></span><span class="kw">static </span>RELATIONSHIPS_SCHEMA: LazyLock&lt;SchemaRef&gt; = LazyLock::new(|| {
<a href=#283 id=283 data-nosnippet>283</a> Arc::new(Schema::new(<span class="macro">vec!</span>[
<a href=#284 id=284 data-nosnippet>284</a> ColumnSchema::new(OBSERVED_AT_COLUMN, ts(), <span class="bool-val">false</span>).with_time_index(<span class="bool-val">true</span>),
<a href=#285 id=285 data-nosnippet>285</a> ColumnSchema::new(WINDOW_START_COLUMN, ts(), <span class="bool-val">true</span>),
<a href=#286 id=286 data-nosnippet>286</a> ColumnSchema::new(WINDOW_END_COLUMN, ts(), <span class="bool-val">true</span>),
<a href=#287 id=287 data-nosnippet>287</a> ColumnSchema::new(FRESH_UNTIL_COLUMN, ts(), <span class="bool-val">true</span>),
<a href=#288 id=288 data-nosnippet>288</a> ColumnSchema::new(SRC_TYPE_COLUMN, string(), <span class="bool-val">false</span>),
<a href=#289 id=289 data-nosnippet>289</a> ColumnSchema::new(SRC_ID_COLUMN, string(), <span class="bool-val">false</span>),
<a href=#290 id=290 data-nosnippet>290</a> ColumnSchema::new(DST_TYPE_COLUMN, string(), <span class="bool-val">false</span>),
<a href=#291 id=291 data-nosnippet>291</a> ColumnSchema::new(DST_ID_COLUMN, string(), <span class="bool-val">false</span>),
<a href=#292 id=292 data-nosnippet>292</a> ColumnSchema::new(REL_TYPE_COLUMN, string(), <span class="bool-val">false</span>),
<a href=#293 id=293 data-nosnippet>293</a> ColumnSchema::new(PROVENANCE_COLUMN, string(), <span class="bool-val">false</span>),
<a href=#294 id=294 data-nosnippet>294</a> ColumnSchema::new(
<a href=#295 id=295 data-nosnippet>295</a> CONFIDENCE_COLUMN,
<a href=#296 id=296 data-nosnippet>296</a> ConcreteDataType::float64_datatype(),
<a href=#297 id=297 data-nosnippet>297</a> <span class="bool-val">true</span>,
<a href=#298 id=298 data-nosnippet>298</a> ),
<a href=#299 id=299 data-nosnippet>299</a> ColumnSchema::new(
<a href=#300 id=300 data-nosnippet>300</a> REQUEST_COUNT_COLUMN,
<a href=#301 id=301 data-nosnippet>301</a> ConcreteDataType::int64_datatype(),
<a href=#302 id=302 data-nosnippet>302</a> <span class="bool-val">true</span>,
<a href=#303 id=303 data-nosnippet>303</a> ),
<a href=#304 id=304 data-nosnippet>304</a> ColumnSchema::new(
<a href=#305 id=305 data-nosnippet>305</a> UNMATCHED_COUNT_COLUMN,
<a href=#306 id=306 data-nosnippet>306</a> ConcreteDataType::int64_datatype(),
<a href=#307 id=307 data-nosnippet>307</a> <span class="bool-val">true</span>,
<a href=#308 id=308 data-nosnippet>308</a> ),
<a href=#309 id=309 data-nosnippet>309</a> ColumnSchema::new(ERROR_COUNT_COLUMN, ConcreteDataType::int64_datatype(), <span class="bool-val">true</span>),
<a href=#310 id=310 data-nosnippet>310</a> ColumnSchema::new(
<a href=#311 id=311 data-nosnippet>311</a> DURATION_SUM_COLUMN,
<a href=#312 id=312 data-nosnippet>312</a> ConcreteDataType::float64_datatype(),
<a href=#313 id=313 data-nosnippet>313</a> <span class="bool-val">true</span>,
<a href=#314 id=314 data-nosnippet>314</a> ),
<a href=#315 id=315 data-nosnippet>315</a> ColumnSchema::new(
<a href=#316 id=316 data-nosnippet>316</a> DURATION_COUNT_COLUMN,
<a href=#317 id=317 data-nosnippet>317</a> ConcreteDataType::int64_datatype(),
<a href=#318 id=318 data-nosnippet>318</a> <span class="bool-val">true</span>,
<a href=#319 id=319 data-nosnippet>319</a> ),
<a href=#320 id=320 data-nosnippet>320</a> ColumnSchema::new(
<a href=#321 id=321 data-nosnippet>321</a> DURATION_MAX_COLUMN,
<a href=#322 id=322 data-nosnippet>322</a> ConcreteDataType::float64_datatype(),
<a href=#323 id=323 data-nosnippet>323</a> <span class="bool-val">true</span>,
<a href=#324 id=324 data-nosnippet>324</a> ),
<a href=#325 id=325 data-nosnippet>325</a> ColumnSchema::new(EDGE_ATTRIBUTES_COLUMN, json(), <span class="bool-val">true</span>),
<a href=#326 id=326 data-nosnippet>326</a> ]))
<a href=#327 id=327 data-nosnippet>327</a>});
<a href=#328 id=328 data-nosnippet>328</a>
<a href=#329 id=329 data-nosnippet>329</a><span class="doccomment">/// Which computed table this shell represents, so the two share one forwarder.
<a href=#330 id=330 data-nosnippet>330</a></span><span class="attr">#[derive(Clone, Copy)]
<a href=#331 id=331 data-nosnippet>331</a></span><span class="kw">enum </span>GraphTableKind {
<a href=#332 id=332 data-nosnippet>332</a> Entities,
<a href=#333 id=333 data-nosnippet>333</a> Relationships,
<a href=#334 id=334 data-nosnippet>334</a>}
<a href=#335 id=335 data-nosnippet>335</a>
<a href=#336 id=336 data-nosnippet>336</a><span class="doccomment">/// Forwarder for a computed entity-graph table.
<a href=#337 id=337 data-nosnippet>337</a></span><span class="kw">struct </span>SemanticGraphTable {
<a href=#338 id=338 data-nosnippet>338</a> kind: GraphTableKind,
<a href=#339 id=339 data-nosnippet>339</a> schema: SchemaRef,
<a href=#340 id=340 data-nosnippet>340</a> catalog_name: String,
<a href=#341 id=341 data-nosnippet>341</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#342 id=342 data-nosnippet>342</a> query_ctx: <span class="prelude-ty">Option</span>&lt;QueryContextRef&gt;,
<a href=#343 id=343 data-nosnippet>343</a>}
<a href=#344 id=344 data-nosnippet>344</a>
<a href=#345 id=345 data-nosnippet>345</a><span class="kw">impl </span>SemanticGraphTable {
<a href=#346 id=346 data-nosnippet>346</a> <span class="kw">fn </span>new(
<a href=#347 id=347 data-nosnippet>347</a> kind: GraphTableKind,
<a href=#348 id=348 data-nosnippet>348</a> catalog_name: String,
<a href=#349 id=349 data-nosnippet>349</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#350 id=350 data-nosnippet>350</a> query_ctx: <span class="prelude-ty">Option</span>&lt;QueryContextRef&gt;,
<a href=#351 id=351 data-nosnippet>351</a> ) -&gt; <span class="self">Self </span>{
<a href=#352 id=352 data-nosnippet>352</a> <span class="kw">let </span>schema = <span class="kw">match </span>kind {
<a href=#353 id=353 data-nosnippet>353</a> GraphTableKind::Entities =&gt; ENTITIES_SCHEMA.clone(),
<a href=#354 id=354 data-nosnippet>354</a> GraphTableKind::Relationships =&gt; RELATIONSHIPS_SCHEMA.clone(),
<a href=#355 id=355 data-nosnippet>355</a> };
<a href=#356 id=356 data-nosnippet>356</a> <span class="self">Self </span>{
<a href=#357 id=357 data-nosnippet>357</a> kind,
<a href=#358 id=358 data-nosnippet>358</a> schema,
<a href=#359 id=359 data-nosnippet>359</a> catalog_name,
<a href=#360 id=360 data-nosnippet>360</a> catalog_manager,
<a href=#361 id=361 data-nosnippet>361</a> query_ctx,
<a href=#362 id=362 data-nosnippet>362</a> }
<a href=#363 id=363 data-nosnippet>363</a> }
<a href=#364 id=364 data-nosnippet>364</a>
<a href=#365 id=365 data-nosnippet>365</a> <span class="kw">async fn </span>derive(
<a href=#366 id=366 data-nosnippet>366</a> kind: GraphTableKind,
<a href=#367 id=367 data-nosnippet>367</a> catalog: String,
<a href=#368 id=368 data-nosnippet>368</a> catalog_manager: Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#369 id=369 data-nosnippet>369</a> request: ScanRequest,
<a href=#370 id=370 data-nosnippet>370</a> query_ctx: <span class="prelude-ty">Option</span>&lt;QueryContextRef&gt;,
<a href=#371 id=371 data-nosnippet>371</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;SendableRecordBatchStream&gt;&gt; {
<a href=#372 id=372 data-nosnippet>372</a> <span class="kw">let </span>provider = utils::entity_graph_provider(<span class="kw-2">&amp;</span>catalog_manager)<span class="question-mark">?</span>;
<a href=#373 id=373 data-nosnippet>373</a> <span class="comment">// No provider (engine not up / non-frontend node): stream empty.
<a href=#374 id=374 data-nosnippet>374</a> </span><span class="kw">let </span><span class="prelude-val">Some</span>(provider) = provider <span class="kw">else </span>{
<a href=#375 id=375 data-nosnippet>375</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>);
<a href=#376 id=376 data-nosnippet>376</a> };
<a href=#377 id=377 data-nosnippet>377</a> <span class="kw">match </span>kind {
<a href=#378 id=378 data-nosnippet>378</a> GraphTableKind::Entities =&gt; provider.scan_entities(<span class="kw-2">&amp;</span>catalog, request, query_ctx).<span class="kw">await</span>,
<a href=#379 id=379 data-nosnippet>379</a> GraphTableKind::Relationships =&gt; {
<a href=#380 id=380 data-nosnippet>380</a> provider
<a href=#381 id=381 data-nosnippet>381</a> .scan_relationships(<span class="kw-2">&amp;</span>catalog, request, query_ctx)
<a href=#382 id=382 data-nosnippet>382</a> .<span class="kw">await
<a href=#383 id=383 data-nosnippet>383</a> </span>}
<a href=#384 id=384 data-nosnippet>384</a> }
<a href=#385 id=385 data-nosnippet>385</a> .context(InternalSnafu)
<a href=#386 id=386 data-nosnippet>386</a> }
<a href=#387 id=387 data-nosnippet>387</a>
<a href=#388 id=388 data-nosnippet>388</a> <span class="kw">fn </span>align_schema(
<a href=#389 id=389 data-nosnippet>389</a> stream: SendableRecordBatchStream,
<a href=#390 id=390 data-nosnippet>390</a> schema: SchemaRef,
<a href=#391 id=391 data-nosnippet>391</a> ) -&gt; SendableRecordBatchStream {
<a href=#392 id=392 data-nosnippet>392</a> <span class="kw">let </span>batch_schema = schema.clone();
<a href=#393 id=393 data-nosnippet>393</a> <span class="kw">let </span>arrow_schema = schema.arrow_schema().clone();
<a href=#394 id=394 data-nosnippet>394</a> <span class="kw">let </span>batches = stream.map(<span class="kw">move </span>|batch| {
<a href=#395 id=395 data-nosnippet>395</a> <span class="kw">let </span>batch = batch<span class="question-mark">?</span>;
<a href=#396 id=396 data-nosnippet>396</a> <span class="comment">// The derivation output is structurally identical, but its JSON
<a href=#397 id=397 data-nosnippet>397</a> // fields are plain Binary without the declared extension metadata.
<a href=#398 id=398 data-nosnippet>398</a> </span><span class="kw">let </span>batch = DfRecordBatch::try_new(
<a href=#399 id=399 data-nosnippet>399</a> arrow_schema.clone(),
<a href=#400 id=400 data-nosnippet>400</a> batch.into_df_record_batch().columns().to_vec(),
<a href=#401 id=401 data-nosnippet>401</a> )
<a href=#402 id=402 data-nosnippet>402</a> .context(common_recordbatch::error::NewDfRecordBatchSnafu)<span class="question-mark">?</span>;
<a href=#403 id=403 data-nosnippet>403</a> <span class="prelude-val">Ok</span>(RecordBatch::from_df_record_batch(
<a href=#404 id=404 data-nosnippet>404</a> batch_schema.clone(),
<a href=#405 id=405 data-nosnippet>405</a> batch,
<a href=#406 id=406 data-nosnippet>406</a> ))
<a href=#407 id=407 data-nosnippet>407</a> });
<a href=#408 id=408 data-nosnippet>408</a> Box::pin(RecordBatchStreamWrapper::new(schema, Box::pin(batches)))
<a href=#409 id=409 data-nosnippet>409</a> }
<a href=#410 id=410 data-nosnippet>410</a>}
<a href=#411 id=411 data-nosnippet>411</a>
<a href=#412 id=412 data-nosnippet>412</a><span class="kw">impl </span>SystemTable <span class="kw">for </span>SemanticGraphTable {
<a href=#413 id=413 data-nosnippet>413</a> <span class="kw">fn </span>table_id(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; TableId {
<a href=#414 id=414 data-nosnippet>414</a> <span class="kw">match </span><span class="self">self</span>.kind {
<a href=#415 id=415 data-nosnippet>415</a> GraphTableKind::Entities =&gt; SEMANTIC_ENTITIES_TABLE_ID,
<a href=#416 id=416 data-nosnippet>416</a> GraphTableKind::Relationships =&gt; SEMANTIC_RELATIONSHIPS_TABLE_ID,
<a href=#417 id=417 data-nosnippet>417</a> }
<a href=#418 id=418 data-nosnippet>418</a> }
<a href=#419 id=419 data-nosnippet>419</a>
<a href=#420 id=420 data-nosnippet>420</a> <span class="kw">fn </span>table_name(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str {
<a href=#421 id=421 data-nosnippet>421</a> <span class="kw">match </span><span class="self">self</span>.kind {
<a href=#422 id=422 data-nosnippet>422</a> GraphTableKind::Entities =&gt; SEMANTIC_ENTITIES,
<a href=#423 id=423 data-nosnippet>423</a> GraphTableKind::Relationships =&gt; SEMANTIC_RELATIONSHIPS,
<a href=#424 id=424 data-nosnippet>424</a> }
<a href=#425 id=425 data-nosnippet>425</a> }
<a href=#426 id=426 data-nosnippet>426</a>
<a href=#427 id=427 data-nosnippet>427</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; SchemaRef {
<a href=#428 id=428 data-nosnippet>428</a> <span class="self">self</span>.schema.clone()
<a href=#429 id=429 data-nosnippet>429</a> }
<a href=#430 id=430 data-nosnippet>430</a>
<a href=#431 id=431 data-nosnippet>431</a> <span class="kw">fn </span>to_stream(<span class="kw-2">&amp;</span><span class="self">self</span>, request: ScanRequest) -&gt; <span class="prelude-ty">Result</span>&lt;SendableRecordBatchStream&gt; {
<a href=#432 id=432 data-nosnippet>432</a> <span class="kw">let </span>schema = <span class="self">self</span>.schema.clone();
<a href=#433 id=433 data-nosnippet>433</a> <span class="kw">let </span>kind = <span class="self">self</span>.kind;
<a href=#434 id=434 data-nosnippet>434</a> <span class="kw">let </span>catalog = <span class="self">self</span>.catalog_name.clone();
<a href=#435 id=435 data-nosnippet>435</a> <span class="kw">let </span>catalog_manager = <span class="self">self</span>.catalog_manager.clone();
<a href=#436 id=436 data-nosnippet>436</a> <span class="kw">let </span>query_ctx = <span class="self">self</span>.query_ctx.clone();
<a href=#437 id=437 data-nosnippet>437</a>
<a href=#438 id=438 data-nosnippet>438</a> <span class="kw">let </span>stream_schema = schema.clone();
<a href=#439 id=439 data-nosnippet>439</a> <span class="kw">let </span>stream = <span class="kw">async move </span>{
<a href=#440 id=440 data-nosnippet>440</a> <span class="kw">let </span>stream = <span class="self">Self</span>::derive(kind, catalog, catalog_manager, request, query_ctx)
<a href=#441 id=441 data-nosnippet>441</a> .<span class="kw">await
<a href=#442 id=442 data-nosnippet>442</a> </span>.map_err(BoxedError::new)
<a href=#443 id=443 data-nosnippet>443</a> .context(common_recordbatch::error::ExternalSnafu)<span class="question-mark">?</span>;
<a href=#444 id=444 data-nosnippet>444</a> <span class="prelude-val">Ok</span>(<span class="kw">match </span>stream {
<a href=#445 id=445 data-nosnippet>445</a> <span class="prelude-val">Some</span>(stream) =&gt; <span class="self">Self</span>::align_schema(stream, stream_schema.clone()),
<a href=#446 id=446 data-nosnippet>446</a> <span class="prelude-val">None </span>=&gt; Box::pin(EmptyRecordBatchStream::new(stream_schema.clone())),
<a href=#447 id=447 data-nosnippet>447</a> })
<a href=#448 id=448 data-nosnippet>448</a> };
<a href=#449 id=449 data-nosnippet>449</a>
<a href=#450 id=450 data-nosnippet>450</a> <span class="prelude-val">Ok</span>(Box::pin(AsyncRecordBatchStreamAdapter::new(
<a href=#451 id=451 data-nosnippet>451</a> schema,
<a href=#452 id=452 data-nosnippet>452</a> Box::pin(stream),
<a href=#453 id=453 data-nosnippet>453</a> )))
<a href=#454 id=454 data-nosnippet>454</a> }
<a href=#455 id=455 data-nosnippet>455</a>}
<a href=#456 id=456 data-nosnippet>456</a>
<a href=#457 id=457 data-nosnippet>457</a><span class="attr">#[cfg(test)]
<a href=#458 id=458 data-nosnippet>458</a></span><span class="kw">mod </span>tests {
<a href=#459 id=459 data-nosnippet>459</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#460 id=460 data-nosnippet>460</a>
<a href=#461 id=461 data-nosnippet>461</a> <span class="attr">#[test]
<a href=#462 id=462 data-nosnippet>462</a> </span><span class="kw">fn </span>graph_tables_use_observed_at_as_time_index() {
<a href=#463 id=463 data-nosnippet>463</a> <span class="kw">for </span>schema <span class="kw">in </span>[<span class="kw-2">&amp;*</span>ENTITIES_SCHEMA, <span class="kw-2">&amp;*</span>RELATIONSHIPS_SCHEMA] {
<a href=#464 id=464 data-nosnippet>464</a> <span class="macro">assert_eq!</span>(
<a href=#465 id=465 data-nosnippet>465</a> schema.timestamp_column().map(|column| column.name.as_str()),
<a href=#466 id=466 data-nosnippet>466</a> <span class="prelude-val">Some</span>(<span class="string">"observed_at"</span>)
<a href=#467 id=467 data-nosnippet>467</a> );
<a href=#468 id=468 data-nosnippet>468</a> }
<a href=#469 id=469 data-nosnippet>469</a> }
<a href=#470 id=470 data-nosnippet>470</a>
<a href=#471 id=471 data-nosnippet>471</a> <span class="attr">#[test]
<a href=#472 id=472 data-nosnippet>472</a> </span><span class="kw">fn </span>relationship_schema_does_not_expose_generation_id() {
<a href=#473 id=473 data-nosnippet>473</a> <span class="macro">assert!</span>(
<a href=#474 id=474 data-nosnippet>474</a> RELATIONSHIPS_SCHEMA
<a href=#475 id=475 data-nosnippet>475</a> .column_schema_by_name(<span class="string">"generation_id"</span>)
<a href=#476 id=476 data-nosnippet>476</a> .is_none()
<a href=#477 id=477 data-nosnippet>477</a> );
<a href=#478 id=478 data-nosnippet>478</a> }
<a href=#479 id=479 data-nosnippet>479</a>}
</code></pre></div></section></main></body></html>
+74
View File
@@ -0,0 +1,74 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/utils.rs`."><title>utils.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/</div>utils.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::Weak;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_meta::key::TableMetadataManagerRef;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>snafu::OptionExt;
<a href=#19 id=19 data-nosnippet>19</a>
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManager;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span><span class="kw">crate</span>::error::{GetInformationExtensionSnafu, <span class="prelude-ty">Result</span>, UpgradeWeakCatalogManagerRefSnafu};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span><span class="kw">crate</span>::information_schema::InformationExtensionRef;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span><span class="kw">crate</span>::kvbackend::KvBackendCatalogManager;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span><span class="kw">crate</span>::system_schema::semantic_graph::EntityGraphProviderRef;
<a href=#25 id=25 data-nosnippet>25</a>
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">pub mod </span>tables;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="doccomment">/// Try to get the entity-graph provider from a `[CatalogManager]` weak reference.
<a href=#29 id=29 data-nosnippet>29</a>/// Returns `None` when the manager is not the kv-backed one or the provider has
<a href=#30 id=30 data-nosnippet>30</a>/// not been injected yet (the computed graph tables then stream empty).
<a href=#31 id=31 data-nosnippet>31</a></span><span class="kw">pub fn </span>entity_graph_provider(
<a href=#32 id=32 data-nosnippet>32</a> catalog_manager: <span class="kw-2">&amp;</span>Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#33 id=33 data-nosnippet>33</a>) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;EntityGraphProviderRef&gt;&gt; {
<a href=#34 id=34 data-nosnippet>34</a> <span class="kw">let </span>catalog_manager = catalog_manager
<a href=#35 id=35 data-nosnippet>35</a> .upgrade()
<a href=#36 id=36 data-nosnippet>36</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a> <span class="prelude-val">Ok</span>(catalog_manager
<a href=#39 id=39 data-nosnippet>39</a> .as_any()
<a href=#40 id=40 data-nosnippet>40</a> .downcast_ref::&lt;KvBackendCatalogManager&gt;()
<a href=#41 id=41 data-nosnippet>41</a> .and_then(|manager| manager.entity_graph_provider()))
<a href=#42 id=42 data-nosnippet>42</a>}
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="doccomment">/// Try to get the `[InformationExtension]` from `[CatalogManager]` weak reference.
<a href=#45 id=45 data-nosnippet>45</a></span><span class="kw">pub fn </span>information_extension(
<a href=#46 id=46 data-nosnippet>46</a> catalog_manager: <span class="kw-2">&amp;</span>Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#47 id=47 data-nosnippet>47</a>) -&gt; <span class="prelude-ty">Result</span>&lt;InformationExtensionRef&gt; {
<a href=#48 id=48 data-nosnippet>48</a> <span class="kw">let </span>catalog_manager = catalog_manager
<a href=#49 id=49 data-nosnippet>49</a> .upgrade()
<a href=#50 id=50 data-nosnippet>50</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a> <span class="kw">let </span>information_extension = catalog_manager
<a href=#53 id=53 data-nosnippet>53</a> .as_any()
<a href=#54 id=54 data-nosnippet>54</a> .downcast_ref::&lt;KvBackendCatalogManager&gt;()
<a href=#55 id=55 data-nosnippet>55</a> .map(|manager| manager.information_extension())
<a href=#56 id=56 data-nosnippet>56</a> .context(GetInformationExtensionSnafu)<span class="question-mark">?</span>;
<a href=#57 id=57 data-nosnippet>57</a>
<a href=#58 id=58 data-nosnippet>58</a> <span class="prelude-val">Ok</span>(information_extension)
<a href=#59 id=59 data-nosnippet>59</a>}
<a href=#60 id=60 data-nosnippet>60</a>
<a href=#61 id=61 data-nosnippet>61</a><span class="doccomment">/// Try to get the `[TableMetadataManagerRef]` from `[CatalogManager]` weak reference.
<a href=#62 id=62 data-nosnippet>62</a></span><span class="kw">pub fn </span>table_meta_manager(
<a href=#63 id=63 data-nosnippet>63</a> catalog_manager: <span class="kw-2">&amp;</span>Weak&lt;<span class="kw">dyn </span>CatalogManager&gt;,
<a href=#64 id=64 data-nosnippet>64</a>) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;TableMetadataManagerRef&gt;&gt; {
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">let </span>catalog_manager = catalog_manager
<a href=#66 id=66 data-nosnippet>66</a> .upgrade()
<a href=#67 id=67 data-nosnippet>67</a> .context(UpgradeWeakCatalogManagerRefSnafu)<span class="question-mark">?</span>;
<a href=#68 id=68 data-nosnippet>68</a>
<a href=#69 id=69 data-nosnippet>69</a> <span class="prelude-val">Ok</span>(catalog_manager
<a href=#70 id=70 data-nosnippet>70</a> .as_any()
<a href=#71 id=71 data-nosnippet>71</a> .downcast_ref::&lt;KvBackendCatalogManager&gt;()
<a href=#72 id=72 data-nosnippet>72</a> .map(|manager| manager.table_metadata_manager_ref().clone()))
<a href=#73 id=73 data-nosnippet>73</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,64 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/system_schema/utils/tables.rs`."><title>tables.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/system_schema/utils/</div>tables.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>datatypes::prelude::ConcreteDataType;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>datatypes::schema::ColumnSchema;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">pub fn </span>string_columns(names: <span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span><span class="lifetime">'static </span>str]) -&gt; Vec&lt;ColumnSchema&gt; {
<a href=#19 id=19 data-nosnippet>19</a> names.iter().map(|name| string_column(name)).collect()
<a href=#20 id=20 data-nosnippet>20</a>}
<a href=#21 id=21 data-nosnippet>21</a>
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">pub fn </span>string_column(name: <span class="kw-2">&amp;</span>str) -&gt; ColumnSchema {
<a href=#23 id=23 data-nosnippet>23</a> ColumnSchema::new(
<a href=#24 id=24 data-nosnippet>24</a> str::to_lowercase(name),
<a href=#25 id=25 data-nosnippet>25</a> ConcreteDataType::string_datatype(),
<a href=#26 id=26 data-nosnippet>26</a> <span class="bool-val">false</span>,
<a href=#27 id=27 data-nosnippet>27</a> )
<a href=#28 id=28 data-nosnippet>28</a>}
<a href=#29 id=29 data-nosnippet>29</a>
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">pub fn </span>bigint_column(name: <span class="kw-2">&amp;</span>str) -&gt; ColumnSchema {
<a href=#31 id=31 data-nosnippet>31</a> ColumnSchema::new(
<a href=#32 id=32 data-nosnippet>32</a> str::to_lowercase(name),
<a href=#33 id=33 data-nosnippet>33</a> ConcreteDataType::int64_datatype(),
<a href=#34 id=34 data-nosnippet>34</a> <span class="bool-val">false</span>,
<a href=#35 id=35 data-nosnippet>35</a> )
<a href=#36 id=36 data-nosnippet>36</a>}
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">pub fn </span>timestamp_micro_column(name: <span class="kw-2">&amp;</span>str) -&gt; ColumnSchema {
<a href=#39 id=39 data-nosnippet>39</a> ColumnSchema::new(
<a href=#40 id=40 data-nosnippet>40</a> str::to_lowercase(name),
<a href=#41 id=41 data-nosnippet>41</a> ConcreteDataType::timestamp_microsecond_datatype(),
<a href=#42 id=42 data-nosnippet>42</a> <span class="bool-val">false</span>,
<a href=#43 id=43 data-nosnippet>43</a> )
<a href=#44 id=44 data-nosnippet>44</a>}
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a><span class="attr">#[cfg(test)]
<a href=#47 id=47 data-nosnippet>47</a></span><span class="kw">mod </span>tests {
<a href=#48 id=48 data-nosnippet>48</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#49 id=49 data-nosnippet>49</a>
<a href=#50 id=50 data-nosnippet>50</a> <span class="attr">#[test]
<a href=#51 id=51 data-nosnippet>51</a> </span><span class="kw">fn </span>test_string_columns() {
<a href=#52 id=52 data-nosnippet>52</a> <span class="kw">let </span>columns = [<span class="string">"a"</span>, <span class="string">"b"</span>, <span class="string">"c"</span>];
<a href=#53 id=53 data-nosnippet>53</a> <span class="kw">let </span>column_schemas = string_columns(<span class="kw-2">&amp;</span>columns);
<a href=#54 id=54 data-nosnippet>54</a>
<a href=#55 id=55 data-nosnippet>55</a> <span class="macro">assert_eq!</span>(<span class="number">3</span>, column_schemas.len());
<a href=#56 id=56 data-nosnippet>56</a> <span class="kw">for </span>(i, name) <span class="kw">in </span>columns.iter().enumerate() {
<a href=#57 id=57 data-nosnippet>57</a> <span class="kw">let </span>cs = column_schemas.get(i).unwrap();
<a href=#58 id=58 data-nosnippet>58</a>
<a href=#59 id=59 data-nosnippet>59</a> <span class="macro">assert_eq!</span>(<span class="kw-2">*</span>name, cs.name);
<a href=#60 id=60 data-nosnippet>60</a> <span class="macro">assert_eq!</span>(ConcreteDataType::string_datatype(), cs.data_type);
<a href=#61 id=61 data-nosnippet>61</a> }
<a href=#62 id=62 data-nosnippet>62</a> }
<a href=#63 id=63 data-nosnippet>63</a>}
</code></pre></div></section></main></body></html>
+378
View File
@@ -0,0 +1,378 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/table_source.rs`."><title>table_source.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/</div>table_source.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::collections::HashMap;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::sync::Arc;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_catalog::format_full_table_name;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_query::logical_plan::{SubstraitPlanDecoderRef, rename_logical_plan_columns};
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>datafusion::common::{ResolvedTableReference, TableReference};
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>datafusion::datasource::view::ViewTable;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>datafusion::datasource::{TableProvider, provider_as_source};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>datafusion::logical_expr::TableSource;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>itertools::Itertools;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>session::context::QueryContextRef;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>snafu::{OptionExt, ResultExt, ensure};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>table::metadata::TableType;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>table::table::adapter::DfTableProviderAdapter;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">pub mod </span>dummy_catalog;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>dummy_catalog::DummyCatalogList;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>table::TableRef;
<a href=#32 id=32 data-nosnippet>32</a>
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManagerRef;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#35 id=35 data-nosnippet>35</a> CastManagerSnafu, DecodePlanSnafu, GetViewCacheSnafu, ProjectViewColumnsSnafu,
<a href=#36 id=36 data-nosnippet>36</a> QueryAccessDeniedSnafu, <span class="prelude-ty">Result</span>, TableNotExistSnafu, ViewInfoNotFoundSnafu,
<a href=#37 id=37 data-nosnippet>37</a> ViewPlanColumnsChangedSnafu,
<a href=#38 id=38 data-nosnippet>38</a>};
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span><span class="kw">crate</span>::kvbackend::KvBackendCatalogManager;
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">pub struct </span>DfTableSourceProvider {
<a href=#42 id=42 data-nosnippet>42</a> catalog_manager: CatalogManagerRef,
<a href=#43 id=43 data-nosnippet>43</a> resolved_tables: HashMap&lt;String, Arc&lt;<span class="kw">dyn </span>TableSource&gt;&gt;,
<a href=#44 id=44 data-nosnippet>44</a> disallow_cross_catalog_query: bool,
<a href=#45 id=45 data-nosnippet>45</a> default_catalog: String,
<a href=#46 id=46 data-nosnippet>46</a> default_schema: String,
<a href=#47 id=47 data-nosnippet>47</a> query_ctx: QueryContextRef,
<a href=#48 id=48 data-nosnippet>48</a> plan_decoder: SubstraitPlanDecoderRef,
<a href=#49 id=49 data-nosnippet>49</a> enable_ident_normalization: bool,
<a href=#50 id=50 data-nosnippet>50</a>}
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">impl </span>DfTableSourceProvider {
<a href=#53 id=53 data-nosnippet>53</a> <span class="kw">pub fn </span>new(
<a href=#54 id=54 data-nosnippet>54</a> catalog_manager: CatalogManagerRef,
<a href=#55 id=55 data-nosnippet>55</a> disallow_cross_catalog_query: bool,
<a href=#56 id=56 data-nosnippet>56</a> query_ctx: QueryContextRef,
<a href=#57 id=57 data-nosnippet>57</a> plan_decoder: SubstraitPlanDecoderRef,
<a href=#58 id=58 data-nosnippet>58</a> enable_ident_normalization: bool,
<a href=#59 id=59 data-nosnippet>59</a> ) -&gt; <span class="self">Self </span>{
<a href=#60 id=60 data-nosnippet>60</a> <span class="self">Self </span>{
<a href=#61 id=61 data-nosnippet>61</a> catalog_manager,
<a href=#62 id=62 data-nosnippet>62</a> disallow_cross_catalog_query,
<a href=#63 id=63 data-nosnippet>63</a> resolved_tables: HashMap::new(),
<a href=#64 id=64 data-nosnippet>64</a> default_catalog: query_ctx.current_catalog().to_owned(),
<a href=#65 id=65 data-nosnippet>65</a> default_schema: query_ctx.current_schema(),
<a href=#66 id=66 data-nosnippet>66</a> query_ctx,
<a href=#67 id=67 data-nosnippet>67</a> plan_decoder,
<a href=#68 id=68 data-nosnippet>68</a> enable_ident_normalization,
<a href=#69 id=69 data-nosnippet>69</a> }
<a href=#70 id=70 data-nosnippet>70</a> }
<a href=#71 id=71 data-nosnippet>71</a>
<a href=#72 id=72 data-nosnippet>72</a> <span class="doccomment">/// Returns the query context.
<a href=#73 id=73 data-nosnippet>73</a> </span><span class="kw">pub fn </span>query_ctx(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>QueryContextRef {
<a href=#74 id=74 data-nosnippet>74</a> <span class="kw-2">&amp;</span><span class="self">self</span>.query_ctx
<a href=#75 id=75 data-nosnippet>75</a> }
<a href=#76 id=76 data-nosnippet>76</a>
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">pub fn </span>resolve_table_ref(<span class="kw-2">&amp;</span><span class="self">self</span>, table_ref: TableReference) -&gt; <span class="prelude-ty">Result</span>&lt;ResolvedTableReference&gt; {
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">if </span><span class="self">self</span>.disallow_cross_catalog_query {
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw">match </span><span class="kw-2">&amp;</span>table_ref {
<a href=#80 id=80 data-nosnippet>80</a> TableReference::Bare { .. } | TableReference::Partial { .. } =&gt; {}
<a href=#81 id=81 data-nosnippet>81</a> TableReference::Full {
<a href=#82 id=82 data-nosnippet>82</a> catalog, schema, ..
<a href=#83 id=83 data-nosnippet>83</a> } =&gt; {
<a href=#84 id=84 data-nosnippet>84</a> <span class="macro">ensure!</span>(
<a href=#85 id=85 data-nosnippet>85</a> catalog.as_ref() == <span class="self">self</span>.default_catalog,
<a href=#86 id=86 data-nosnippet>86</a> QueryAccessDeniedSnafu {
<a href=#87 id=87 data-nosnippet>87</a> catalog: catalog.as_ref(),
<a href=#88 id=88 data-nosnippet>88</a> schema: schema.as_ref(),
<a href=#89 id=89 data-nosnippet>89</a> }
<a href=#90 id=90 data-nosnippet>90</a> );
<a href=#91 id=91 data-nosnippet>91</a> }
<a href=#92 id=92 data-nosnippet>92</a> };
<a href=#93 id=93 data-nosnippet>93</a> }
<a href=#94 id=94 data-nosnippet>94</a>
<a href=#95 id=95 data-nosnippet>95</a> <span class="prelude-val">Ok</span>(table_ref.resolve(<span class="kw-2">&amp;</span><span class="self">self</span>.default_catalog, <span class="kw-2">&amp;</span><span class="self">self</span>.default_schema))
<a href=#96 id=96 data-nosnippet>96</a> }
<a href=#97 id=97 data-nosnippet>97</a>
<a href=#98 id=98 data-nosnippet>98</a> <span class="kw">pub async fn </span>resolve_table(
<a href=#99 id=99 data-nosnippet>99</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#100 id=100 data-nosnippet>100</a> table_ref: TableReference,
<a href=#101 id=101 data-nosnippet>101</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;Arc&lt;<span class="kw">dyn </span>TableSource&gt;&gt; {
<a href=#102 id=102 data-nosnippet>102</a> <span class="kw">let </span>table_ref = <span class="self">self</span>.resolve_table_ref(table_ref)<span class="question-mark">?</span>;
<a href=#103 id=103 data-nosnippet>103</a>
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">let </span>resolved_name = table_ref.to_string();
<a href=#105 id=105 data-nosnippet>105</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table) = <span class="self">self</span>.resolved_tables.get(<span class="kw-2">&amp;</span>resolved_name) {
<a href=#106 id=106 data-nosnippet>106</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(table.clone());
<a href=#107 id=107 data-nosnippet>107</a> }
<a href=#108 id=108 data-nosnippet>108</a>
<a href=#109 id=109 data-nosnippet>109</a> <span class="kw">let </span>catalog_name = table_ref.catalog.as_ref();
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">let </span>schema_name = table_ref.schema.as_ref();
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">let </span>table_name = table_ref.table.as_ref();
<a href=#112 id=112 data-nosnippet>112</a>
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">let </span>table = <span class="self">self
<a href=#114 id=114 data-nosnippet>114</a> </span>.catalog_manager
<a href=#115 id=115 data-nosnippet>115</a> .table(catalog_name, schema_name, table_name, <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="self">self</span>.query_ctx))
<a href=#116 id=116 data-nosnippet>116</a> .<span class="kw">await</span><span class="question-mark">?
<a href=#117 id=117 data-nosnippet>117</a> </span>.with_context(|| TableNotExistSnafu {
<a href=#118 id=118 data-nosnippet>118</a> table: format_full_table_name(catalog_name, schema_name, table_name),
<a href=#119 id=119 data-nosnippet>119</a> })<span class="question-mark">?</span>;
<a href=#120 id=120 data-nosnippet>120</a>
<a href=#121 id=121 data-nosnippet>121</a> <span class="kw">let </span>provider: Arc&lt;<span class="kw">dyn </span>TableProvider&gt; = <span class="kw">if </span>table.table_info().table_type == TableType::View {
<a href=#122 id=122 data-nosnippet>122</a> <span class="self">self</span>.create_view_provider(<span class="kw-2">&amp;</span>table).<span class="kw">await</span><span class="question-mark">?
<a href=#123 id=123 data-nosnippet>123</a> </span>} <span class="kw">else </span>{
<a href=#124 id=124 data-nosnippet>124</a> Arc::new(DfTableProviderAdapter::new(table))
<a href=#125 id=125 data-nosnippet>125</a> };
<a href=#126 id=126 data-nosnippet>126</a>
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw">let </span>source = provider_as_source(provider);
<a href=#128 id=128 data-nosnippet>128</a>
<a href=#129 id=129 data-nosnippet>129</a> <span class="kw">let _ </span>= <span class="self">self</span>.resolved_tables.insert(resolved_name, source.clone());
<a href=#130 id=130 data-nosnippet>130</a> <span class="prelude-val">Ok</span>(source)
<a href=#131 id=131 data-nosnippet>131</a> }
<a href=#132 id=132 data-nosnippet>132</a>
<a href=#133 id=133 data-nosnippet>133</a> <span class="kw">async fn </span>create_view_provider(<span class="kw-2">&amp;</span><span class="self">self</span>, table: <span class="kw-2">&amp;</span>TableRef) -&gt; <span class="prelude-ty">Result</span>&lt;Arc&lt;<span class="kw">dyn </span>TableProvider&gt;&gt; {
<a href=#134 id=134 data-nosnippet>134</a> <span class="kw">let </span>catalog_manager = <span class="self">self
<a href=#135 id=135 data-nosnippet>135</a> </span>.catalog_manager
<a href=#136 id=136 data-nosnippet>136</a> .as_any()
<a href=#137 id=137 data-nosnippet>137</a> .downcast_ref::&lt;KvBackendCatalogManager&gt;()
<a href=#138 id=138 data-nosnippet>138</a> .context(CastManagerSnafu)<span class="question-mark">?</span>;
<a href=#139 id=139 data-nosnippet>139</a>
<a href=#140 id=140 data-nosnippet>140</a> <span class="kw">let </span>view_info = catalog_manager
<a href=#141 id=141 data-nosnippet>141</a> .view_info_cache()<span class="question-mark">?
<a href=#142 id=142 data-nosnippet>142</a> </span>.get(table.table_info().ident.table_id)
<a href=#143 id=143 data-nosnippet>143</a> .<span class="kw">await
<a href=#144 id=144 data-nosnippet>144</a> </span>.context(GetViewCacheSnafu)<span class="question-mark">?
<a href=#145 id=145 data-nosnippet>145</a> </span>.context(ViewInfoNotFoundSnafu {
<a href=#146 id=146 data-nosnippet>146</a> name: <span class="kw-2">&amp;</span>table.table_info().name,
<a href=#147 id=147 data-nosnippet>147</a> })<span class="question-mark">?</span>;
<a href=#148 id=148 data-nosnippet>148</a>
<a href=#149 id=149 data-nosnippet>149</a> <span class="comment">// Build the catalog list provider for deserialization.
<a href=#150 id=150 data-nosnippet>150</a> </span><span class="kw">let </span>catalog_list = Arc::new(DummyCatalogList::new(<span class="self">self</span>.catalog_manager.clone()));
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">let </span>logical_plan = <span class="self">self
<a href=#152 id=152 data-nosnippet>152</a> </span>.plan_decoder
<a href=#153 id=153 data-nosnippet>153</a> .decode(view_info.view_info.clone().into(), catalog_list, <span class="bool-val">false</span>)
<a href=#154 id=154 data-nosnippet>154</a> .<span class="kw">await
<a href=#155 id=155 data-nosnippet>155</a> </span>.context(DecodePlanSnafu {
<a href=#156 id=156 data-nosnippet>156</a> name: <span class="kw-2">&amp;</span>table.table_info().name,
<a href=#157 id=157 data-nosnippet>157</a> })<span class="question-mark">?</span>;
<a href=#158 id=158 data-nosnippet>158</a>
<a href=#159 id=159 data-nosnippet>159</a> <span class="kw">let </span>columns: Vec&lt;<span class="kw">_</span>&gt; = view_info.columns.iter().map(|c| c.as_str()).collect();
<a href=#160 id=160 data-nosnippet>160</a>
<a href=#161 id=161 data-nosnippet>161</a> <span class="kw">let </span>original_plan_columns: Vec&lt;<span class="kw">_</span>&gt; =
<a href=#162 id=162 data-nosnippet>162</a> view_info.plan_columns.iter().map(|c| c.as_str()).collect();
<a href=#163 id=163 data-nosnippet>163</a>
<a href=#164 id=164 data-nosnippet>164</a> <span class="kw">let </span>plan_columns: Vec&lt;<span class="kw">_</span>&gt; = logical_plan
<a href=#165 id=165 data-nosnippet>165</a> .schema()
<a href=#166 id=166 data-nosnippet>166</a> .columns()
<a href=#167 id=167 data-nosnippet>167</a> .into_iter()
<a href=#168 id=168 data-nosnippet>168</a> .map(|c| c.name)
<a href=#169 id=169 data-nosnippet>169</a> .collect();
<a href=#170 id=170 data-nosnippet>170</a>
<a href=#171 id=171 data-nosnippet>171</a> <span class="comment">// Only check columns number, because substrait doesn't include aliases currently.
<a href=#172 id=172 data-nosnippet>172</a> // See https://github.com/apache/datafusion/issues/10815#issuecomment-2158666881
<a href=#173 id=173 data-nosnippet>173</a> // and https://github.com/apache/datafusion/issues/6489
<a href=#174 id=174 data-nosnippet>174</a> // TODO(dennis): check column names
<a href=#175 id=175 data-nosnippet>175</a> </span><span class="macro">ensure!</span>(
<a href=#176 id=176 data-nosnippet>176</a> original_plan_columns.len() == plan_columns.len(),
<a href=#177 id=177 data-nosnippet>177</a> ViewPlanColumnsChangedSnafu {
<a href=#178 id=178 data-nosnippet>178</a> origin_names: original_plan_columns.iter().join(<span class="string">","</span>),
<a href=#179 id=179 data-nosnippet>179</a> actual_names: plan_columns.iter().join(<span class="string">","</span>),
<a href=#180 id=180 data-nosnippet>180</a> }
<a href=#181 id=181 data-nosnippet>181</a> );
<a href=#182 id=182 data-nosnippet>182</a>
<a href=#183 id=183 data-nosnippet>183</a> <span class="comment">// We have to do `columns` projection here, because
<a href=#184 id=184 data-nosnippet>184</a> // substrait doesn't include aliases neither for tables nor for columns:
<a href=#185 id=185 data-nosnippet>185</a> // https://github.com/apache/datafusion/issues/10815#issuecomment-2158666881
<a href=#186 id=186 data-nosnippet>186</a> </span><span class="kw">let </span>logical_plan = <span class="kw">if </span>!columns.is_empty() {
<a href=#187 id=187 data-nosnippet>187</a> rename_logical_plan_columns(
<a href=#188 id=188 data-nosnippet>188</a> <span class="self">self</span>.enable_ident_normalization,
<a href=#189 id=189 data-nosnippet>189</a> logical_plan,
<a href=#190 id=190 data-nosnippet>190</a> plan_columns
<a href=#191 id=191 data-nosnippet>191</a> .iter()
<a href=#192 id=192 data-nosnippet>192</a> .map(|c| c.as_str())
<a href=#193 id=193 data-nosnippet>193</a> .zip(columns)
<a href=#194 id=194 data-nosnippet>194</a> .collect(),
<a href=#195 id=195 data-nosnippet>195</a> )
<a href=#196 id=196 data-nosnippet>196</a> .context(ProjectViewColumnsSnafu)<span class="question-mark">?
<a href=#197 id=197 data-nosnippet>197</a> </span>} <span class="kw">else </span>{
<a href=#198 id=198 data-nosnippet>198</a> logical_plan
<a href=#199 id=199 data-nosnippet>199</a> };
<a href=#200 id=200 data-nosnippet>200</a>
<a href=#201 id=201 data-nosnippet>201</a> <span class="prelude-val">Ok</span>(Arc::new(ViewTable::new(
<a href=#202 id=202 data-nosnippet>202</a> logical_plan,
<a href=#203 id=203 data-nosnippet>203</a> <span class="prelude-val">Some</span>(view_info.definition.clone()),
<a href=#204 id=204 data-nosnippet>204</a> )))
<a href=#205 id=205 data-nosnippet>205</a> }
<a href=#206 id=206 data-nosnippet>206</a>}
<a href=#207 id=207 data-nosnippet>207</a>
<a href=#208 id=208 data-nosnippet>208</a><span class="attr">#[cfg(test)]
<a href=#209 id=209 data-nosnippet>209</a></span><span class="kw">mod </span>tests {
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">use </span>common_query::test_util::DummyDecoder;
<a href=#211 id=211 data-nosnippet>211</a> <span class="kw">use </span>session::context::QueryContext;
<a href=#212 id=212 data-nosnippet>212</a>
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#214 id=214 data-nosnippet>214</a> <span class="kw">use </span><span class="kw">crate</span>::kvbackend::KvBackendCatalogManagerBuilder;
<a href=#215 id=215 data-nosnippet>215</a> <span class="kw">use </span><span class="kw">crate</span>::memory::MemoryCatalogManager;
<a href=#216 id=216 data-nosnippet>216</a>
<a href=#217 id=217 data-nosnippet>217</a> <span class="attr">#[test]
<a href=#218 id=218 data-nosnippet>218</a> </span><span class="kw">fn </span>test_validate_table_ref() {
<a href=#219 id=219 data-nosnippet>219</a> <span class="kw">let </span>query_ctx = Arc::new(QueryContext::with(<span class="string">"greptime"</span>, <span class="string">"public"</span>));
<a href=#220 id=220 data-nosnippet>220</a>
<a href=#221 id=221 data-nosnippet>221</a> <span class="kw">let </span>table_provider = DfTableSourceProvider::new(
<a href=#222 id=222 data-nosnippet>222</a> MemoryCatalogManager::with_default_setup(),
<a href=#223 id=223 data-nosnippet>223</a> <span class="bool-val">true</span>,
<a href=#224 id=224 data-nosnippet>224</a> query_ctx.clone(),
<a href=#225 id=225 data-nosnippet>225</a> DummyDecoder::arc(),
<a href=#226 id=226 data-nosnippet>226</a> <span class="bool-val">true</span>,
<a href=#227 id=227 data-nosnippet>227</a> );
<a href=#228 id=228 data-nosnippet>228</a>
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">let </span>table_ref = TableReference::bare(<span class="string">"table_name"</span>);
<a href=#230 id=230 data-nosnippet>230</a> <span class="kw">let </span>result = table_provider.resolve_table_ref(table_ref);
<a href=#231 id=231 data-nosnippet>231</a> <span class="macro">assert!</span>(result.is_ok());
<a href=#232 id=232 data-nosnippet>232</a>
<a href=#233 id=233 data-nosnippet>233</a> <span class="kw">let </span>table_ref = TableReference::partial(<span class="string">"public"</span>, <span class="string">"table_name"</span>);
<a href=#234 id=234 data-nosnippet>234</a> <span class="kw">let </span>result = table_provider.resolve_table_ref(table_ref);
<a href=#235 id=235 data-nosnippet>235</a> <span class="macro">assert!</span>(result.is_ok());
<a href=#236 id=236 data-nosnippet>236</a>
<a href=#237 id=237 data-nosnippet>237</a> <span class="kw">let </span>table_ref = TableReference::partial(<span class="string">"wrong_schema"</span>, <span class="string">"table_name"</span>);
<a href=#238 id=238 data-nosnippet>238</a> <span class="kw">let </span>result = table_provider.resolve_table_ref(table_ref);
<a href=#239 id=239 data-nosnippet>239</a> <span class="macro">assert!</span>(result.is_ok());
<a href=#240 id=240 data-nosnippet>240</a>
<a href=#241 id=241 data-nosnippet>241</a> <span class="kw">let </span>table_ref = TableReference::full(<span class="string">"greptime"</span>, <span class="string">"public"</span>, <span class="string">"table_name"</span>);
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">let </span>result = table_provider.resolve_table_ref(table_ref);
<a href=#243 id=243 data-nosnippet>243</a> <span class="macro">assert!</span>(result.is_ok());
<a href=#244 id=244 data-nosnippet>244</a>
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw">let </span>table_ref = TableReference::full(<span class="string">"wrong_catalog"</span>, <span class="string">"public"</span>, <span class="string">"table_name"</span>);
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">let </span>result = table_provider.resolve_table_ref(table_ref);
<a href=#247 id=247 data-nosnippet>247</a> <span class="macro">assert!</span>(result.is_err());
<a href=#248 id=248 data-nosnippet>248</a>
<a href=#249 id=249 data-nosnippet>249</a> <span class="kw">let </span>table_ref = TableReference::partial(<span class="string">"information_schema"</span>, <span class="string">"columns"</span>);
<a href=#250 id=250 data-nosnippet>250</a> <span class="kw">let </span>result = table_provider.resolve_table_ref(table_ref);
<a href=#251 id=251 data-nosnippet>251</a> <span class="macro">assert!</span>(result.is_ok());
<a href=#252 id=252 data-nosnippet>252</a>
<a href=#253 id=253 data-nosnippet>253</a> <span class="kw">let </span>table_ref = TableReference::full(<span class="string">"greptime"</span>, <span class="string">"information_schema"</span>, <span class="string">"columns"</span>);
<a href=#254 id=254 data-nosnippet>254</a> <span class="macro">assert!</span>(table_provider.resolve_table_ref(table_ref).is_ok());
<a href=#255 id=255 data-nosnippet>255</a>
<a href=#256 id=256 data-nosnippet>256</a> <span class="kw">let </span>table_ref = TableReference::full(<span class="string">"dummy"</span>, <span class="string">"information_schema"</span>, <span class="string">"columns"</span>);
<a href=#257 id=257 data-nosnippet>257</a> <span class="macro">assert!</span>(table_provider.resolve_table_ref(table_ref).is_err());
<a href=#258 id=258 data-nosnippet>258</a>
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">let </span>table_ref = TableReference::full(<span class="string">"greptime"</span>, <span class="string">"greptime_private"</span>, <span class="string">"columns"</span>);
<a href=#260 id=260 data-nosnippet>260</a> <span class="macro">assert!</span>(table_provider.resolve_table_ref(table_ref).is_ok());
<a href=#261 id=261 data-nosnippet>261</a> }
<a href=#262 id=262 data-nosnippet>262</a>
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">use </span>std::collections::HashSet;
<a href=#264 id=264 data-nosnippet>264</a>
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">use </span>arrow::datatypes::{DataType, Field, Schema, SchemaRef};
<a href=#266 id=266 data-nosnippet>266</a> <span class="kw">use </span>cache::{build_fundamental_cache_registry, with_default_composite_cache_registry};
<a href=#267 id=267 data-nosnippet>267</a> <span class="kw">use </span>common_meta::cache::{CacheRegistryBuilder, LayeredCacheRegistryBuilder};
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw">use </span>common_meta::key::TableMetadataManager;
<a href=#269 id=269 data-nosnippet>269</a> <span class="kw">use </span>common_meta::kv_backend::memory::MemoryKvBackend;
<a href=#270 id=270 data-nosnippet>270</a> <span class="kw">use </span>common_query::error::Result <span class="kw">as </span>QueryResult;
<a href=#271 id=271 data-nosnippet>271</a> <span class="kw">use </span>common_query::logical_plan::SubstraitPlanDecoder;
<a href=#272 id=272 data-nosnippet>272</a> <span class="kw">use </span>datafusion::catalog::CatalogProviderList;
<a href=#273 id=273 data-nosnippet>273</a> <span class="kw">use </span>datafusion::logical_expr::builder::LogicalTableSource;
<a href=#274 id=274 data-nosnippet>274</a> <span class="kw">use </span>datafusion::logical_expr::{LogicalPlan, LogicalPlanBuilder, col, lit};
<a href=#275 id=275 data-nosnippet>275</a>
<a href=#276 id=276 data-nosnippet>276</a> <span class="kw">use </span><span class="kw">crate</span>::information_schema::NoopInformationExtension;
<a href=#277 id=277 data-nosnippet>277</a>
<a href=#278 id=278 data-nosnippet>278</a> <span class="kw">struct </span>MockDecoder;
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">impl </span>MockDecoder {
<a href=#280 id=280 data-nosnippet>280</a> <span class="kw">pub fn </span>arc() -&gt; Arc&lt;<span class="self">Self</span>&gt; {
<a href=#281 id=281 data-nosnippet>281</a> Arc::new(MockDecoder)
<a href=#282 id=282 data-nosnippet>282</a> }
<a href=#283 id=283 data-nosnippet>283</a> }
<a href=#284 id=284 data-nosnippet>284</a>
<a href=#285 id=285 data-nosnippet>285</a> <span class="attr">#[async_trait::async_trait]
<a href=#286 id=286 data-nosnippet>286</a> </span><span class="kw">impl </span>SubstraitPlanDecoder <span class="kw">for </span>MockDecoder {
<a href=#287 id=287 data-nosnippet>287</a> <span class="kw">async fn </span>decode(
<a href=#288 id=288 data-nosnippet>288</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#289 id=289 data-nosnippet>289</a> _message: bytes::Bytes,
<a href=#290 id=290 data-nosnippet>290</a> _catalog_list: Arc&lt;<span class="kw">dyn </span>CatalogProviderList&gt;,
<a href=#291 id=291 data-nosnippet>291</a> _optimize: bool,
<a href=#292 id=292 data-nosnippet>292</a> ) -&gt; QueryResult&lt;LogicalPlan&gt; {
<a href=#293 id=293 data-nosnippet>293</a> <span class="prelude-val">Ok</span>(mock_plan())
<a href=#294 id=294 data-nosnippet>294</a> }
<a href=#295 id=295 data-nosnippet>295</a> }
<a href=#296 id=296 data-nosnippet>296</a>
<a href=#297 id=297 data-nosnippet>297</a> <span class="kw">fn </span>mock_plan() -&gt; LogicalPlan {
<a href=#298 id=298 data-nosnippet>298</a> <span class="kw">let </span>schema = Schema::new(<span class="macro">vec!</span>[
<a href=#299 id=299 data-nosnippet>299</a> Field::new(<span class="string">"id"</span>, DataType::Int32, <span class="bool-val">true</span>),
<a href=#300 id=300 data-nosnippet>300</a> Field::new(<span class="string">"name"</span>, DataType::Utf8, <span class="bool-val">true</span>),
<a href=#301 id=301 data-nosnippet>301</a> ]);
<a href=#302 id=302 data-nosnippet>302</a> <span class="kw">let </span>table_source = LogicalTableSource::new(SchemaRef::new(schema));
<a href=#303 id=303 data-nosnippet>303</a>
<a href=#304 id=304 data-nosnippet>304</a> <span class="kw">let </span>projection = <span class="prelude-val">None</span>;
<a href=#305 id=305 data-nosnippet>305</a>
<a href=#306 id=306 data-nosnippet>306</a> <span class="kw">let </span>builder =
<a href=#307 id=307 data-nosnippet>307</a> LogicalPlanBuilder::scan(<span class="string">"person"</span>, Arc::new(table_source), projection).unwrap();
<a href=#308 id=308 data-nosnippet>308</a>
<a href=#309 id=309 data-nosnippet>309</a> builder
<a href=#310 id=310 data-nosnippet>310</a> .filter(col(<span class="string">"id"</span>).gt(lit(<span class="number">500</span>)))
<a href=#311 id=311 data-nosnippet>311</a> .unwrap()
<a href=#312 id=312 data-nosnippet>312</a> .build()
<a href=#313 id=313 data-nosnippet>313</a> .unwrap()
<a href=#314 id=314 data-nosnippet>314</a> }
<a href=#315 id=315 data-nosnippet>315</a>
<a href=#316 id=316 data-nosnippet>316</a> <span class="attr">#[tokio::test]
<a href=#317 id=317 data-nosnippet>317</a> </span><span class="kw">async fn </span>test_resolve_view() {
<a href=#318 id=318 data-nosnippet>318</a> <span class="kw">let </span>query_ctx = Arc::new(QueryContext::with(<span class="string">"greptime"</span>, <span class="string">"public"</span>));
<a href=#319 id=319 data-nosnippet>319</a> <span class="kw">let </span>backend = Arc::new(MemoryKvBackend::default());
<a href=#320 id=320 data-nosnippet>320</a> <span class="kw">let </span>layered_cache_builder = LayeredCacheRegistryBuilder::default()
<a href=#321 id=321 data-nosnippet>321</a> .add_cache_registry(CacheRegistryBuilder::default().build());
<a href=#322 id=322 data-nosnippet>322</a> <span class="kw">let </span>fundamental_cache_registry = build_fundamental_cache_registry(backend.clone());
<a href=#323 id=323 data-nosnippet>323</a> <span class="kw">let </span>layered_cache_registry = Arc::new(
<a href=#324 id=324 data-nosnippet>324</a> with_default_composite_cache_registry(
<a href=#325 id=325 data-nosnippet>325</a> layered_cache_builder.add_cache_registry(fundamental_cache_registry),
<a href=#326 id=326 data-nosnippet>326</a> )
<a href=#327 id=327 data-nosnippet>327</a> .unwrap()
<a href=#328 id=328 data-nosnippet>328</a> .build(),
<a href=#329 id=329 data-nosnippet>329</a> );
<a href=#330 id=330 data-nosnippet>330</a>
<a href=#331 id=331 data-nosnippet>331</a> <span class="kw">let </span>catalog_manager = KvBackendCatalogManagerBuilder::new(
<a href=#332 id=332 data-nosnippet>332</a> Arc::new(NoopInformationExtension),
<a href=#333 id=333 data-nosnippet>333</a> backend.clone(),
<a href=#334 id=334 data-nosnippet>334</a> layered_cache_registry,
<a href=#335 id=335 data-nosnippet>335</a> )
<a href=#336 id=336 data-nosnippet>336</a> .build();
<a href=#337 id=337 data-nosnippet>337</a>
<a href=#338 id=338 data-nosnippet>338</a> <span class="kw">let </span>table_metadata_manager = TableMetadataManager::new(backend);
<a href=#339 id=339 data-nosnippet>339</a> <span class="kw">let </span><span class="kw-2">mut </span>view_info = common_meta::key::test_utils::new_test_table_info(<span class="number">1024</span>);
<a href=#340 id=340 data-nosnippet>340</a> view_info.table_type = TableType::View;
<a href=#341 id=341 data-nosnippet>341</a> <span class="kw">let </span>logical_plan = <span class="macro">vec!</span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>];
<a href=#342 id=342 data-nosnippet>342</a> <span class="comment">// Create view metadata
<a href=#343 id=343 data-nosnippet>343</a> </span>table_metadata_manager
<a href=#344 id=344 data-nosnippet>344</a> .create_view_metadata(
<a href=#345 id=345 data-nosnippet>345</a> view_info.clone(),
<a href=#346 id=346 data-nosnippet>346</a> logical_plan,
<a href=#347 id=347 data-nosnippet>347</a> HashSet::new(),
<a href=#348 id=348 data-nosnippet>348</a> <span class="macro">vec!</span>[<span class="string">"a"</span>.to_string(), <span class="string">"b"</span>.to_string()],
<a href=#349 id=349 data-nosnippet>349</a> <span class="macro">vec!</span>[<span class="string">"id"</span>.to_string(), <span class="string">"name"</span>.to_string()],
<a href=#350 id=350 data-nosnippet>350</a> <span class="string">"definition"</span>.to_string(),
<a href=#351 id=351 data-nosnippet>351</a> )
<a href=#352 id=352 data-nosnippet>352</a> .<span class="kw">await
<a href=#353 id=353 data-nosnippet>353</a> </span>.unwrap();
<a href=#354 id=354 data-nosnippet>354</a>
<a href=#355 id=355 data-nosnippet>355</a> <span class="kw">let </span><span class="kw-2">mut </span>table_provider = DfTableSourceProvider::new(
<a href=#356 id=356 data-nosnippet>356</a> catalog_manager,
<a href=#357 id=357 data-nosnippet>357</a> <span class="bool-val">true</span>,
<a href=#358 id=358 data-nosnippet>358</a> query_ctx.clone(),
<a href=#359 id=359 data-nosnippet>359</a> MockDecoder::arc(),
<a href=#360 id=360 data-nosnippet>360</a> <span class="bool-val">true</span>,
<a href=#361 id=361 data-nosnippet>361</a> );
<a href=#362 id=362 data-nosnippet>362</a>
<a href=#363 id=363 data-nosnippet>363</a> <span class="comment">// View not found
<a href=#364 id=364 data-nosnippet>364</a> </span><span class="kw">let </span>table_ref = TableReference::bare(<span class="string">"not_exists_view"</span>);
<a href=#365 id=365 data-nosnippet>365</a> <span class="macro">assert!</span>(table_provider.resolve_table(table_ref).<span class="kw">await</span>.is_err());
<a href=#366 id=366 data-nosnippet>366</a>
<a href=#367 id=367 data-nosnippet>367</a> <span class="kw">let </span>table_ref = TableReference::bare(view_info.name);
<a href=#368 id=368 data-nosnippet>368</a> <span class="kw">let </span>source = table_provider.resolve_table(table_ref).<span class="kw">await</span>.unwrap();
<a href=#369 id=369 data-nosnippet>369</a> <span class="macro">assert_eq!</span>(
<a href=#370 id=370 data-nosnippet>370</a> <span class="string">r#"
<a href=#371 id=371 data-nosnippet>371</a>Projection: person.id AS a, person.name AS b
<a href=#372 id=372 data-nosnippet>372</a> Filter: person.id &gt; Int32(500)
<a href=#373 id=373 data-nosnippet>373</a> TableScan: person"#</span>,
<a href=#374 id=374 data-nosnippet>374</a> <span class="macro">format!</span>(<span class="string">"\n{}"</span>, source.get_logical_plan().unwrap())
<a href=#375 id=375 data-nosnippet>375</a> );
<a href=#376 id=376 data-nosnippet>376</a> }
<a href=#377 id=377 data-nosnippet>377</a>}
</code></pre></div></section></main></body></html>
@@ -0,0 +1,165 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/catalog/src/table_source/dummy_catalog.rs`."><title>dummy_catalog.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="catalog" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">catalog/table_source/</div>dummy_catalog.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! Dummy catalog for region server.
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a></span><span class="kw">use </span>std::fmt;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>std::sync::Arc;
<a href=#19 id=19 data-nosnippet>19</a>
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>async_trait::async_trait;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_catalog::format_full_table_name;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>datafusion::catalog::{CatalogProvider, CatalogProviderList, SchemaProvider};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>datafusion::datasource::TableProvider;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>session::context::QueryContextRef;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>snafu::OptionExt;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>table::table::adapter::DfTableProviderAdapter;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span><span class="kw">crate</span>::CatalogManagerRef;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span><span class="kw">crate</span>::error::TableNotExistSnafu;
<a href=#30 id=30 data-nosnippet>30</a>
<a href=#31 id=31 data-nosnippet>31</a><span class="doccomment">/// Delegate the resolving requests to the `[CatalogManager]` unconditionally.
<a href=#32 id=32 data-nosnippet>32</a></span><span class="attr">#[derive(Clone)]
<a href=#33 id=33 data-nosnippet>33</a></span><span class="kw">pub struct </span>DummyCatalogList {
<a href=#34 id=34 data-nosnippet>34</a> catalog_manager: CatalogManagerRef,
<a href=#35 id=35 data-nosnippet>35</a> query_ctx: <span class="prelude-ty">Option</span>&lt;QueryContextRef&gt;,
<a href=#36 id=36 data-nosnippet>36</a>}
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">impl </span>DummyCatalogList {
<a href=#39 id=39 data-nosnippet>39</a> <span class="doccomment">/// Creates a new catalog list with the given catalog manager (no query context).
<a href=#40 id=40 data-nosnippet>40</a> </span><span class="kw">pub fn </span>new(catalog_manager: CatalogManagerRef) -&gt; <span class="self">Self </span>{
<a href=#41 id=41 data-nosnippet>41</a> <span class="self">Self </span>{
<a href=#42 id=42 data-nosnippet>42</a> catalog_manager,
<a href=#43 id=43 data-nosnippet>43</a> query_ctx: <span class="prelude-val">None</span>,
<a href=#44 id=44 data-nosnippet>44</a> }
<a href=#45 id=45 data-nosnippet>45</a> }
<a href=#46 id=46 data-nosnippet>46</a>
<a href=#47 id=47 data-nosnippet>47</a> <span class="doccomment">/// Creates a new catalog list with the given catalog manager and query context.
<a href=#48 id=48 data-nosnippet>48</a> </span><span class="kw">pub fn </span>new_with_query_ctx(
<a href=#49 id=49 data-nosnippet>49</a> catalog_manager: CatalogManagerRef,
<a href=#50 id=50 data-nosnippet>50</a> query_ctx: QueryContextRef,
<a href=#51 id=51 data-nosnippet>51</a> ) -&gt; <span class="self">Self </span>{
<a href=#52 id=52 data-nosnippet>52</a> <span class="self">Self </span>{
<a href=#53 id=53 data-nosnippet>53</a> catalog_manager,
<a href=#54 id=54 data-nosnippet>54</a> query_ctx: <span class="prelude-val">Some</span>(query_ctx),
<a href=#55 id=55 data-nosnippet>55</a> }
<a href=#56 id=56 data-nosnippet>56</a> }
<a href=#57 id=57 data-nosnippet>57</a>}
<a href=#58 id=58 data-nosnippet>58</a>
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">impl </span>fmt::Debug <span class="kw">for </span>DummyCatalogList {
<a href=#60 id=60 data-nosnippet>60</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; fmt::Result {
<a href=#61 id=61 data-nosnippet>61</a> f.debug_struct(<span class="string">"DummyCatalogList"</span>).finish()
<a href=#62 id=62 data-nosnippet>62</a> }
<a href=#63 id=63 data-nosnippet>63</a>}
<a href=#64 id=64 data-nosnippet>64</a>
<a href=#65 id=65 data-nosnippet>65</a><span class="kw">impl </span>CatalogProviderList <span class="kw">for </span>DummyCatalogList {
<a href=#66 id=66 data-nosnippet>66</a> <span class="kw">fn </span>register_catalog(
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#68 id=68 data-nosnippet>68</a> _name: String,
<a href=#69 id=69 data-nosnippet>69</a> _catalog: Arc&lt;<span class="kw">dyn </span>CatalogProvider&gt;,
<a href=#70 id=70 data-nosnippet>70</a> ) -&gt; <span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>CatalogProvider&gt;&gt; {
<a href=#71 id=71 data-nosnippet>71</a> <span class="prelude-val">None
<a href=#72 id=72 data-nosnippet>72</a> </span>}
<a href=#73 id=73 data-nosnippet>73</a>
<a href=#74 id=74 data-nosnippet>74</a> <span class="kw">fn </span>catalog_names(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Vec&lt;String&gt; {
<a href=#75 id=75 data-nosnippet>75</a> <span class="macro">vec!</span>[]
<a href=#76 id=76 data-nosnippet>76</a> }
<a href=#77 id=77 data-nosnippet>77</a>
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">fn </span>catalog(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog_name: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>CatalogProvider&gt;&gt; {
<a href=#79 id=79 data-nosnippet>79</a> <span class="prelude-val">Some</span>(Arc::new(DummyCatalogProvider {
<a href=#80 id=80 data-nosnippet>80</a> catalog_name: catalog_name.to_string(),
<a href=#81 id=81 data-nosnippet>81</a> catalog_manager: <span class="self">self</span>.catalog_manager.clone(),
<a href=#82 id=82 data-nosnippet>82</a> query_ctx: <span class="self">self</span>.query_ctx.clone(),
<a href=#83 id=83 data-nosnippet>83</a> }))
<a href=#84 id=84 data-nosnippet>84</a> }
<a href=#85 id=85 data-nosnippet>85</a>}
<a href=#86 id=86 data-nosnippet>86</a>
<a href=#87 id=87 data-nosnippet>87</a><span class="doccomment">/// A dummy catalog provider for [DummyCatalogList].
<a href=#88 id=88 data-nosnippet>88</a></span><span class="attr">#[derive(Clone)]
<a href=#89 id=89 data-nosnippet>89</a></span><span class="kw">struct </span>DummyCatalogProvider {
<a href=#90 id=90 data-nosnippet>90</a> catalog_name: String,
<a href=#91 id=91 data-nosnippet>91</a> catalog_manager: CatalogManagerRef,
<a href=#92 id=92 data-nosnippet>92</a> query_ctx: <span class="prelude-ty">Option</span>&lt;QueryContextRef&gt;,
<a href=#93 id=93 data-nosnippet>93</a>}
<a href=#94 id=94 data-nosnippet>94</a>
<a href=#95 id=95 data-nosnippet>95</a><span class="kw">impl </span>CatalogProvider <span class="kw">for </span>DummyCatalogProvider {
<a href=#96 id=96 data-nosnippet>96</a> <span class="kw">fn </span>schema_names(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Vec&lt;String&gt; {
<a href=#97 id=97 data-nosnippet>97</a> <span class="macro">vec!</span>[]
<a href=#98 id=98 data-nosnippet>98</a> }
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">fn </span>schema(<span class="kw-2">&amp;</span><span class="self">self</span>, schema_name: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>SchemaProvider&gt;&gt; {
<a href=#101 id=101 data-nosnippet>101</a> <span class="prelude-val">Some</span>(Arc::new(DummySchemaProvider {
<a href=#102 id=102 data-nosnippet>102</a> catalog_name: <span class="self">self</span>.catalog_name.clone(),
<a href=#103 id=103 data-nosnippet>103</a> schema_name: schema_name.to_string(),
<a href=#104 id=104 data-nosnippet>104</a> catalog_manager: <span class="self">self</span>.catalog_manager.clone(),
<a href=#105 id=105 data-nosnippet>105</a> query_ctx: <span class="self">self</span>.query_ctx.clone(),
<a href=#106 id=106 data-nosnippet>106</a> }))
<a href=#107 id=107 data-nosnippet>107</a> }
<a href=#108 id=108 data-nosnippet>108</a>}
<a href=#109 id=109 data-nosnippet>109</a>
<a href=#110 id=110 data-nosnippet>110</a><span class="kw">impl </span>fmt::Debug <span class="kw">for </span>DummyCatalogProvider {
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; fmt::Result {
<a href=#112 id=112 data-nosnippet>112</a> f.debug_struct(<span class="string">"DummyCatalogProvider"</span>)
<a href=#113 id=113 data-nosnippet>113</a> .field(<span class="string">"catalog_name"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.catalog_name)
<a href=#114 id=114 data-nosnippet>114</a> .finish()
<a href=#115 id=115 data-nosnippet>115</a> }
<a href=#116 id=116 data-nosnippet>116</a>}
<a href=#117 id=117 data-nosnippet>117</a>
<a href=#118 id=118 data-nosnippet>118</a><span class="doccomment">/// A dummy schema provider for [DummyCatalogList].
<a href=#119 id=119 data-nosnippet>119</a></span><span class="attr">#[derive(Clone)]
<a href=#120 id=120 data-nosnippet>120</a></span><span class="kw">struct </span>DummySchemaProvider {
<a href=#121 id=121 data-nosnippet>121</a> catalog_name: String,
<a href=#122 id=122 data-nosnippet>122</a> schema_name: String,
<a href=#123 id=123 data-nosnippet>123</a> catalog_manager: CatalogManagerRef,
<a href=#124 id=124 data-nosnippet>124</a> query_ctx: <span class="prelude-ty">Option</span>&lt;QueryContextRef&gt;,
<a href=#125 id=125 data-nosnippet>125</a>}
<a href=#126 id=126 data-nosnippet>126</a>
<a href=#127 id=127 data-nosnippet>127</a><span class="attr">#[async_trait]
<a href=#128 id=128 data-nosnippet>128</a></span><span class="kw">impl </span>SchemaProvider <span class="kw">for </span>DummySchemaProvider {
<a href=#129 id=129 data-nosnippet>129</a> <span class="kw">fn </span>table_names(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Vec&lt;String&gt; {
<a href=#130 id=130 data-nosnippet>130</a> <span class="macro">vec!</span>[]
<a href=#131 id=131 data-nosnippet>131</a> }
<a href=#132 id=132 data-nosnippet>132</a>
<a href=#133 id=133 data-nosnippet>133</a> <span class="kw">async fn </span>table(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str) -&gt; datafusion::error::Result&lt;<span class="prelude-ty">Option</span>&lt;Arc&lt;<span class="kw">dyn </span>TableProvider&gt;&gt;&gt; {
<a href=#134 id=134 data-nosnippet>134</a> <span class="kw">let </span>table = <span class="self">self
<a href=#135 id=135 data-nosnippet>135</a> </span>.catalog_manager
<a href=#136 id=136 data-nosnippet>136</a> .table(
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw-2">&amp;</span><span class="self">self</span>.catalog_name,
<a href=#138 id=138 data-nosnippet>138</a> <span class="kw-2">&amp;</span><span class="self">self</span>.schema_name,
<a href=#139 id=139 data-nosnippet>139</a> name,
<a href=#140 id=140 data-nosnippet>140</a> <span class="self">self</span>.query_ctx.as_deref(),
<a href=#141 id=141 data-nosnippet>141</a> )
<a href=#142 id=142 data-nosnippet>142</a> .<span class="kw">await</span><span class="question-mark">?
<a href=#143 id=143 data-nosnippet>143</a> </span>.with_context(|| TableNotExistSnafu {
<a href=#144 id=144 data-nosnippet>144</a> table: format_full_table_name(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog_name, <span class="kw-2">&amp;</span><span class="self">self</span>.schema_name, name),
<a href=#145 id=145 data-nosnippet>145</a> })<span class="question-mark">?</span>;
<a href=#146 id=146 data-nosnippet>146</a>
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">let </span>table_provider: Arc&lt;<span class="kw">dyn </span>TableProvider&gt; = Arc::new(DfTableProviderAdapter::new(table));
<a href=#148 id=148 data-nosnippet>148</a>
<a href=#149 id=149 data-nosnippet>149</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(table_provider))
<a href=#150 id=150 data-nosnippet>150</a> }
<a href=#151 id=151 data-nosnippet>151</a>
<a href=#152 id=152 data-nosnippet>152</a> <span class="kw">fn </span>table_exist(<span class="kw-2">&amp;</span><span class="self">self</span>, _name: <span class="kw-2">&amp;</span>str) -&gt; bool {
<a href=#153 id=153 data-nosnippet>153</a> <span class="bool-val">true
<a href=#154 id=154 data-nosnippet>154</a> </span>}
<a href=#155 id=155 data-nosnippet>155</a>}
<a href=#156 id=156 data-nosnippet>156</a>
<a href=#157 id=157 data-nosnippet>157</a><span class="kw">impl </span>fmt::Debug <span class="kw">for </span>DummySchemaProvider {
<a href=#158 id=158 data-nosnippet>158</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; fmt::Result {
<a href=#159 id=159 data-nosnippet>159</a> f.debug_struct(<span class="string">"DummySchemaProvider"</span>)
<a href=#160 id=160 data-nosnippet>160</a> .field(<span class="string">"catalog_name"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.catalog_name)
<a href=#161 id=161 data-nosnippet>161</a> .field(<span class="string">"schema_name"</span>, <span class="kw-2">&amp;</span><span class="self">self</span>.schema_name)
<a href=#162 id=162 data-nosnippet>162</a> .finish()
<a href=#163 id=163 data-nosnippet>163</a> }
<a href=#164 id=164 data-nosnippet>164</a>}
</code></pre></div></section></main></body></html>
+214
View File
@@ -0,0 +1,214 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/bench.rs`."><title>bench.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/</div>bench.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::collections::{BTreeMap, HashMap};
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::future::Future;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>std::sync::Arc;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>std::time::Duration;
<a href=#19 id=19 data-nosnippet>19</a>
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>async_trait::async_trait;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>clap::Parser;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_meta::key::{TableMetadataManager, TableMetadataManagerRef};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_meta::kv_backend::etcd::EtcdStore;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>common_meta::kv_backend::memory::MemoryKvBackend;
<a href=#26 id=26 data-nosnippet>26</a><span class="attr">#[cfg(feature = <span class="string">"mysql_kvbackend"</span>)]
<a href=#27 id=27 data-nosnippet>27</a></span><span class="kw">use </span>common_meta::kv_backend::rds::MySqlStore;
<a href=#28 id=28 data-nosnippet>28</a><span class="attr">#[cfg(feature = <span class="string">"pg_kvbackend"</span>)]
<a href=#29 id=29 data-nosnippet>29</a></span><span class="kw">use </span>common_meta::kv_backend::rds::PgStore;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>common_meta::peer::Peer;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>common_meta::rpc::router::{Region, RegionRoute};
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span>common_telemetry::info;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span>common_wal::options::WalOptions;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span>datatypes::data_type::ConcreteDataType;
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">use </span>datatypes::schema::{ColumnSchema, Schema};
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>rand::Rng;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>store_api::storage::RegionNumber;
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">use </span>table::metadata::{TableId, TableIdent, TableInfo, TableMeta, TableType};
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span>table::table_name::TableName;
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span><span class="self">self</span>::metadata::TableMetadataBencher;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span><span class="kw">crate</span>::Tool;
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">mod </span>metadata;
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a><span class="kw">async fn </span>bench_self_recorded&lt;F, Fut&gt;(desc: <span class="kw-2">&amp;</span>str, f: F, count: u32)
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">where
<a href=#48 id=48 data-nosnippet>48</a> </span>F: Fn(u32) -&gt; Fut,
<a href=#49 id=49 data-nosnippet>49</a> Fut: Future&lt;Output = Duration&gt;,
<a href=#50 id=50 data-nosnippet>50</a>{
<a href=#51 id=51 data-nosnippet>51</a> <span class="kw">let </span><span class="kw-2">mut </span>total = Duration::default();
<a href=#52 id=52 data-nosnippet>52</a>
<a href=#53 id=53 data-nosnippet>53</a> <span class="kw">for </span>i <span class="kw">in </span><span class="number">1</span>..=count {
<a href=#54 id=54 data-nosnippet>54</a> total += f(i).<span class="kw">await</span>;
<a href=#55 id=55 data-nosnippet>55</a> }
<a href=#56 id=56 data-nosnippet>56</a>
<a href=#57 id=57 data-nosnippet>57</a> <span class="kw">let </span>cost = total.as_millis() <span class="kw">as </span>f64 / count <span class="kw">as </span>f64;
<a href=#58 id=58 data-nosnippet>58</a> <span class="macro">info!</span>(<span class="string">"{desc}, average operation cost: {cost:.2} ms"</span>);
<a href=#59 id=59 data-nosnippet>59</a>}
<a href=#60 id=60 data-nosnippet>60</a>
<a href=#61 id=61 data-nosnippet>61</a><span class="doccomment">/// Command to benchmark table metadata operations.
<a href=#62 id=62 data-nosnippet>62</a></span><span class="attr">#[derive(Debug, Default, Parser)]
<a href=#63 id=63 data-nosnippet>63</a></span><span class="kw">pub struct </span>BenchTableMetadataCommand {
<a href=#64 id=64 data-nosnippet>64</a> <span class="attr">#[clap(long)]
<a href=#65 id=65 data-nosnippet>65</a> </span>etcd_addr: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#66 id=66 data-nosnippet>66</a> <span class="attr">#[cfg(feature = <span class="string">"pg_kvbackend"</span>)]
<a href=#67 id=67 data-nosnippet>67</a> #[clap(long)]
<a href=#68 id=68 data-nosnippet>68</a> </span>postgres_addr: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#69 id=69 data-nosnippet>69</a> <span class="attr">#[cfg(feature = <span class="string">"pg_kvbackend"</span>)]
<a href=#70 id=70 data-nosnippet>70</a> #[clap(long)]
<a href=#71 id=71 data-nosnippet>71</a> </span>postgres_schema: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#72 id=72 data-nosnippet>72</a> <span class="attr">#[cfg(feature = <span class="string">"mysql_kvbackend"</span>)]
<a href=#73 id=73 data-nosnippet>73</a> #[clap(long)]
<a href=#74 id=74 data-nosnippet>74</a> </span>mysql_addr: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#75 id=75 data-nosnippet>75</a> <span class="attr">#[clap(long)]
<a href=#76 id=76 data-nosnippet>76</a> </span>count: u32,
<a href=#77 id=77 data-nosnippet>77</a>}
<a href=#78 id=78 data-nosnippet>78</a>
<a href=#79 id=79 data-nosnippet>79</a><span class="kw">impl </span>BenchTableMetadataCommand {
<a href=#80 id=80 data-nosnippet>80</a> <span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt; {
<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">let </span>kv_backend = <span class="kw">if let </span><span class="prelude-val">Some</span>(etcd_addr) = <span class="kw-2">&amp;</span><span class="self">self</span>.etcd_addr {
<a href=#82 id=82 data-nosnippet>82</a> <span class="macro">info!</span>(<span class="string">"Using etcd as kv backend"</span>);
<a href=#83 id=83 data-nosnippet>83</a> EtcdStore::with_endpoints([etcd_addr], <span class="number">128</span>).<span class="kw">await</span>.unwrap()
<a href=#84 id=84 data-nosnippet>84</a> } <span class="kw">else </span>{
<a href=#85 id=85 data-nosnippet>85</a> Arc::new(MemoryKvBackend::new())
<a href=#86 id=86 data-nosnippet>86</a> };
<a href=#87 id=87 data-nosnippet>87</a>
<a href=#88 id=88 data-nosnippet>88</a> <span class="attr">#[cfg(feature = <span class="string">"pg_kvbackend"</span>)]
<a href=#89 id=89 data-nosnippet>89</a> </span><span class="kw">let </span>kv_backend = <span class="kw">if let </span><span class="prelude-val">Some</span>(postgres_addr) = <span class="kw-2">&amp;</span><span class="self">self</span>.postgres_addr {
<a href=#90 id=90 data-nosnippet>90</a> <span class="macro">info!</span>(<span class="string">"Using postgres as kv backend"</span>);
<a href=#91 id=91 data-nosnippet>91</a> PgStore::with_url(postgres_addr, <span class="string">"greptime_metakv"</span>, <span class="number">128</span>)
<a href=#92 id=92 data-nosnippet>92</a> .<span class="kw">await
<a href=#93 id=93 data-nosnippet>93</a> </span>.unwrap()
<a href=#94 id=94 data-nosnippet>94</a> } <span class="kw">else </span>{
<a href=#95 id=95 data-nosnippet>95</a> kv_backend
<a href=#96 id=96 data-nosnippet>96</a> };
<a href=#97 id=97 data-nosnippet>97</a>
<a href=#98 id=98 data-nosnippet>98</a> <span class="attr">#[cfg(feature = <span class="string">"mysql_kvbackend"</span>)]
<a href=#99 id=99 data-nosnippet>99</a> </span><span class="kw">let </span>kv_backend = <span class="kw">if let </span><span class="prelude-val">Some</span>(mysql_addr) = <span class="kw-2">&amp;</span><span class="self">self</span>.mysql_addr {
<a href=#100 id=100 data-nosnippet>100</a> <span class="macro">info!</span>(<span class="string">"Using mysql as kv backend"</span>);
<a href=#101 id=101 data-nosnippet>101</a> MySqlStore::with_url(mysql_addr, <span class="string">"greptime_metakv"</span>, <span class="number">128</span>)
<a href=#102 id=102 data-nosnippet>102</a> .<span class="kw">await
<a href=#103 id=103 data-nosnippet>103</a> </span>.unwrap()
<a href=#104 id=104 data-nosnippet>104</a> } <span class="kw">else </span>{
<a href=#105 id=105 data-nosnippet>105</a> kv_backend
<a href=#106 id=106 data-nosnippet>106</a> };
<a href=#107 id=107 data-nosnippet>107</a>
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">let </span>table_metadata_manager = Arc::new(TableMetadataManager::new(kv_backend));
<a href=#109 id=109 data-nosnippet>109</a>
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">let </span>tool = BenchTableMetadata {
<a href=#111 id=111 data-nosnippet>111</a> table_metadata_manager,
<a href=#112 id=112 data-nosnippet>112</a> count: <span class="self">self</span>.count,
<a href=#113 id=113 data-nosnippet>113</a> };
<a href=#114 id=114 data-nosnippet>114</a> <span class="prelude-val">Ok</span>(Box::new(tool))
<a href=#115 id=115 data-nosnippet>115</a> }
<a href=#116 id=116 data-nosnippet>116</a>}
<a href=#117 id=117 data-nosnippet>117</a>
<a href=#118 id=118 data-nosnippet>118</a><span class="kw">struct </span>BenchTableMetadata {
<a href=#119 id=119 data-nosnippet>119</a> table_metadata_manager: TableMetadataManagerRef,
<a href=#120 id=120 data-nosnippet>120</a> count: u32,
<a href=#121 id=121 data-nosnippet>121</a>}
<a href=#122 id=122 data-nosnippet>122</a>
<a href=#123 id=123 data-nosnippet>123</a><span class="attr">#[async_trait]
<a href=#124 id=124 data-nosnippet>124</a></span><span class="kw">impl </span>Tool <span class="kw">for </span>BenchTableMetadata {
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw">async fn </span>do_work(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;(), BoxedError&gt; {
<a href=#126 id=126 data-nosnippet>126</a> <span class="kw">let </span>bencher = TableMetadataBencher::new(<span class="self">self</span>.table_metadata_manager.clone(), <span class="self">self</span>.count);
<a href=#127 id=127 data-nosnippet>127</a> bencher.bench_create().<span class="kw">await</span>;
<a href=#128 id=128 data-nosnippet>128</a> bencher.bench_get().<span class="kw">await</span>;
<a href=#129 id=129 data-nosnippet>129</a> bencher.bench_rename().<span class="kw">await</span>;
<a href=#130 id=130 data-nosnippet>130</a> bencher.bench_delete().<span class="kw">await</span>;
<a href=#131 id=131 data-nosnippet>131</a> <span class="prelude-val">Ok</span>(())
<a href=#132 id=132 data-nosnippet>132</a> }
<a href=#133 id=133 data-nosnippet>133</a>}
<a href=#134 id=134 data-nosnippet>134</a>
<a href=#135 id=135 data-nosnippet>135</a><span class="kw">fn </span>create_table_info(table_id: TableId, table_name: TableName) -&gt; TableInfo {
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw">let </span>columns = <span class="number">100</span>;
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">let </span><span class="kw-2">mut </span>column_schemas = Vec::with_capacity(columns);
<a href=#138 id=138 data-nosnippet>138</a> column_schemas.push(
<a href=#139 id=139 data-nosnippet>139</a> ColumnSchema::new(
<a href=#140 id=140 data-nosnippet>140</a> <span class="string">"ts"</span>,
<a href=#141 id=141 data-nosnippet>141</a> ConcreteDataType::timestamp_millisecond_datatype(),
<a href=#142 id=142 data-nosnippet>142</a> <span class="bool-val">true</span>,
<a href=#143 id=143 data-nosnippet>143</a> )
<a href=#144 id=144 data-nosnippet>144</a> .with_time_index(<span class="bool-val">true</span>),
<a href=#145 id=145 data-nosnippet>145</a> );
<a href=#146 id=146 data-nosnippet>146</a>
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">for </span>i <span class="kw">in </span><span class="number">1</span>..columns {
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">let </span>column_name = <span class="macro">format!</span>(<span class="string">"my_column_{i}"</span>);
<a href=#149 id=149 data-nosnippet>149</a> column_schemas.push(ColumnSchema::new(
<a href=#150 id=150 data-nosnippet>150</a> column_name,
<a href=#151 id=151 data-nosnippet>151</a> ConcreteDataType::string_datatype(),
<a href=#152 id=152 data-nosnippet>152</a> <span class="bool-val">true</span>,
<a href=#153 id=153 data-nosnippet>153</a> ));
<a href=#154 id=154 data-nosnippet>154</a> }
<a href=#155 id=155 data-nosnippet>155</a>
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">let </span>meta = TableMeta {
<a href=#157 id=157 data-nosnippet>157</a> schema: Arc::new(Schema::new(column_schemas)),
<a href=#158 id=158 data-nosnippet>158</a> engine: <span class="string">"mito"</span>.to_string(),
<a href=#159 id=159 data-nosnippet>159</a> created_on: chrono::DateTime::default(),
<a href=#160 id=160 data-nosnippet>160</a> updated_on: chrono::DateTime::default(),
<a href=#161 id=161 data-nosnippet>161</a> primary_key_indices: <span class="macro">vec!</span>[],
<a href=#162 id=162 data-nosnippet>162</a> next_column_id: columns <span class="kw">as </span>u32 + <span class="number">1</span>,
<a href=#163 id=163 data-nosnippet>163</a> value_indices: <span class="macro">vec!</span>[],
<a href=#164 id=164 data-nosnippet>164</a> options: Default::default(),
<a href=#165 id=165 data-nosnippet>165</a> partition_key_indices: <span class="macro">vec!</span>[],
<a href=#166 id=166 data-nosnippet>166</a> column_ids: <span class="macro">vec!</span>[],
<a href=#167 id=167 data-nosnippet>167</a> };
<a href=#168 id=168 data-nosnippet>168</a>
<a href=#169 id=169 data-nosnippet>169</a> TableInfo {
<a href=#170 id=170 data-nosnippet>170</a> ident: TableIdent {
<a href=#171 id=171 data-nosnippet>171</a> table_id,
<a href=#172 id=172 data-nosnippet>172</a> version: <span class="number">1</span>,
<a href=#173 id=173 data-nosnippet>173</a> },
<a href=#174 id=174 data-nosnippet>174</a> name: table_name.table_name,
<a href=#175 id=175 data-nosnippet>175</a> desc: <span class="prelude-val">Some</span>(<span class="string">"blah"</span>.to_string()),
<a href=#176 id=176 data-nosnippet>176</a> catalog_name: table_name.catalog_name,
<a href=#177 id=177 data-nosnippet>177</a> schema_name: table_name.schema_name,
<a href=#178 id=178 data-nosnippet>178</a> meta,
<a href=#179 id=179 data-nosnippet>179</a> table_type: TableType::Base,
<a href=#180 id=180 data-nosnippet>180</a> }
<a href=#181 id=181 data-nosnippet>181</a>}
<a href=#182 id=182 data-nosnippet>182</a>
<a href=#183 id=183 data-nosnippet>183</a><span class="kw">fn </span>create_region_routes(regions: Vec&lt;RegionNumber&gt;) -&gt; Vec&lt;RegionRoute&gt; {
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">let </span><span class="kw-2">mut </span>region_routes = Vec::with_capacity(<span class="number">100</span>);
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">let </span><span class="kw-2">mut </span>rng = rand::rng();
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">for </span>region_id <span class="kw">in </span>regions.into_iter().map(u64::from) {
<a href=#188 id=188 data-nosnippet>188</a> region_routes.push(RegionRoute {
<a href=#189 id=189 data-nosnippet>189</a> region: Region {
<a href=#190 id=190 data-nosnippet>190</a> id: region_id.into(),
<a href=#191 id=191 data-nosnippet>191</a> name: String::new(),
<a href=#192 id=192 data-nosnippet>192</a> attrs: BTreeMap::new(),
<a href=#193 id=193 data-nosnippet>193</a> partition_expr: Default::default(),
<a href=#194 id=194 data-nosnippet>194</a> },
<a href=#195 id=195 data-nosnippet>195</a> leader_peer: <span class="prelude-val">Some</span>(Peer {
<a href=#196 id=196 data-nosnippet>196</a> id: rng.random_range(<span class="number">0</span>..<span class="number">10</span>),
<a href=#197 id=197 data-nosnippet>197</a> addr: String::new(),
<a href=#198 id=198 data-nosnippet>198</a> }),
<a href=#199 id=199 data-nosnippet>199</a> follower_peers: <span class="macro">vec!</span>[],
<a href=#200 id=200 data-nosnippet>200</a> leader_state: <span class="prelude-val">None</span>,
<a href=#201 id=201 data-nosnippet>201</a> leader_down_since: <span class="prelude-val">None</span>,
<a href=#202 id=202 data-nosnippet>202</a> write_route_policy: <span class="prelude-val">None</span>,
<a href=#203 id=203 data-nosnippet>203</a> });
<a href=#204 id=204 data-nosnippet>204</a> }
<a href=#205 id=205 data-nosnippet>205</a>
<a href=#206 id=206 data-nosnippet>206</a> region_routes
<a href=#207 id=207 data-nosnippet>207</a>}
<a href=#208 id=208 data-nosnippet>208</a>
<a href=#209 id=209 data-nosnippet>209</a><span class="kw">fn </span>create_region_wal_options(regions: Vec&lt;RegionNumber&gt;) -&gt; HashMap&lt;RegionNumber, WalOptions&gt; {
<a href=#210 id=210 data-nosnippet>210</a> <span class="comment">// TODO(niebayes): construct region wal options for benchmark.
<a href=#211 id=211 data-nosnippet>211</a> </span><span class="kw">let _ </span>= regions;
<a href=#212 id=212 data-nosnippet>212</a> HashMap::default()
<a href=#213 id=213 data-nosnippet>213</a>}
</code></pre></div></section></main></body></html>
+159
View File
@@ -0,0 +1,159 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/bench/metadata.rs`."><title>metadata.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/bench/</div>metadata.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::time::Instant;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_meta::key::TableMetadataManagerRef;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_meta::key::table_route::TableRouteValue;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>table::table_name::TableName;
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span><span class="kw">crate</span>::bench::{
<a href=#22 id=22 data-nosnippet>22</a> bench_self_recorded, create_region_routes, create_region_wal_options, create_table_info,
<a href=#23 id=23 data-nosnippet>23</a>};
<a href=#24 id=24 data-nosnippet>24</a>
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">pub struct </span>TableMetadataBencher {
<a href=#26 id=26 data-nosnippet>26</a> table_metadata_manager: TableMetadataManagerRef,
<a href=#27 id=27 data-nosnippet>27</a> count: u32,
<a href=#28 id=28 data-nosnippet>28</a>}
<a href=#29 id=29 data-nosnippet>29</a>
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">impl </span>TableMetadataBencher {
<a href=#31 id=31 data-nosnippet>31</a> <span class="kw">pub fn </span>new(table_metadata_manager: TableMetadataManagerRef, count: u32) -&gt; <span class="self">Self </span>{
<a href=#32 id=32 data-nosnippet>32</a> <span class="self">Self </span>{
<a href=#33 id=33 data-nosnippet>33</a> table_metadata_manager,
<a href=#34 id=34 data-nosnippet>34</a> count,
<a href=#35 id=35 data-nosnippet>35</a> }
<a href=#36 id=36 data-nosnippet>36</a> }
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a> <span class="kw">pub async fn </span>bench_create(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<a href=#39 id=39 data-nosnippet>39</a> <span class="kw">let </span>desc = <span class="macro">format!</span>(
<a href=#40 id=40 data-nosnippet>40</a> <span class="string">"TableMetadataBencher: creating {} table metadata"</span>,
<a href=#41 id=41 data-nosnippet>41</a> <span class="self">self</span>.count
<a href=#42 id=42 data-nosnippet>42</a> );
<a href=#43 id=43 data-nosnippet>43</a> bench_self_recorded(
<a href=#44 id=44 data-nosnippet>44</a> <span class="kw-2">&amp;</span>desc,
<a href=#45 id=45 data-nosnippet>45</a> |i| <span class="kw">async move </span>{
<a href=#46 id=46 data-nosnippet>46</a> <span class="kw">let </span>table_name = <span class="macro">format!</span>(<span class="string">"bench_table_name_{}"</span>, i);
<a href=#47 id=47 data-nosnippet>47</a> <span class="kw">let </span>table_name = TableName::new(<span class="string">"bench_catalog"</span>, <span class="string">"bench_schema"</span>, table_name);
<a href=#48 id=48 data-nosnippet>48</a> <span class="kw">let </span>table_info = create_table_info(i, table_name);
<a href=#49 id=49 data-nosnippet>49</a>
<a href=#50 id=50 data-nosnippet>50</a> <span class="kw">let </span>regions: Vec&lt;<span class="kw">_</span>&gt; = (<span class="number">0</span>..<span class="number">64</span>).collect();
<a href=#51 id=51 data-nosnippet>51</a> <span class="kw">let </span>region_routes = create_region_routes(regions.clone());
<a href=#52 id=52 data-nosnippet>52</a> <span class="kw">let </span>region_wal_options = create_region_wal_options(regions);
<a href=#53 id=53 data-nosnippet>53</a>
<a href=#54 id=54 data-nosnippet>54</a> <span class="kw">let </span>start = Instant::now();
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a> <span class="self">self</span>.table_metadata_manager
<a href=#57 id=57 data-nosnippet>57</a> .create_table_metadata(
<a href=#58 id=58 data-nosnippet>58</a> table_info,
<a href=#59 id=59 data-nosnippet>59</a> TableRouteValue::physical(region_routes),
<a href=#60 id=60 data-nosnippet>60</a> region_wal_options,
<a href=#61 id=61 data-nosnippet>61</a> )
<a href=#62 id=62 data-nosnippet>62</a> .<span class="kw">await
<a href=#63 id=63 data-nosnippet>63</a> </span>.unwrap();
<a href=#64 id=64 data-nosnippet>64</a>
<a href=#65 id=65 data-nosnippet>65</a> start.elapsed()
<a href=#66 id=66 data-nosnippet>66</a> },
<a href=#67 id=67 data-nosnippet>67</a> <span class="self">self</span>.count,
<a href=#68 id=68 data-nosnippet>68</a> )
<a href=#69 id=69 data-nosnippet>69</a> .<span class="kw">await</span>;
<a href=#70 id=70 data-nosnippet>70</a> }
<a href=#71 id=71 data-nosnippet>71</a>
<a href=#72 id=72 data-nosnippet>72</a> <span class="kw">pub async fn </span>bench_get(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<a href=#73 id=73 data-nosnippet>73</a> <span class="kw">let </span>desc = <span class="macro">format!</span>(
<a href=#74 id=74 data-nosnippet>74</a> <span class="string">"TableMetadataBencher: getting {} table info and region routes"</span>,
<a href=#75 id=75 data-nosnippet>75</a> <span class="self">self</span>.count
<a href=#76 id=76 data-nosnippet>76</a> );
<a href=#77 id=77 data-nosnippet>77</a>
<a href=#78 id=78 data-nosnippet>78</a> bench_self_recorded(
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw-2">&amp;</span>desc,
<a href=#80 id=80 data-nosnippet>80</a> |i| <span class="kw">async move </span>{
<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">let </span>start = Instant::now();
<a href=#82 id=82 data-nosnippet>82</a> <span class="self">self</span>.table_metadata_manager
<a href=#83 id=83 data-nosnippet>83</a> .get_full_table_info(i)
<a href=#84 id=84 data-nosnippet>84</a> .<span class="kw">await
<a href=#85 id=85 data-nosnippet>85</a> </span>.unwrap();
<a href=#86 id=86 data-nosnippet>86</a>
<a href=#87 id=87 data-nosnippet>87</a> start.elapsed()
<a href=#88 id=88 data-nosnippet>88</a> },
<a href=#89 id=89 data-nosnippet>89</a> <span class="self">self</span>.count,
<a href=#90 id=90 data-nosnippet>90</a> )
<a href=#91 id=91 data-nosnippet>91</a> .<span class="kw">await</span>;
<a href=#92 id=92 data-nosnippet>92</a> }
<a href=#93 id=93 data-nosnippet>93</a>
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">pub async fn </span>bench_delete(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<a href=#95 id=95 data-nosnippet>95</a> <span class="kw">let </span>desc = <span class="macro">format!</span>(
<a href=#96 id=96 data-nosnippet>96</a> <span class="string">"TableMetadataBencher: deleting {} table metadata"</span>,
<a href=#97 id=97 data-nosnippet>97</a> <span class="self">self</span>.count
<a href=#98 id=98 data-nosnippet>98</a> );
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> bench_self_recorded(
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw-2">&amp;</span>desc,
<a href=#102 id=102 data-nosnippet>102</a> |i| <span class="kw">async move </span>{
<a href=#103 id=103 data-nosnippet>103</a> <span class="kw">let </span>(table_info, table_route) = <span class="self">self
<a href=#104 id=104 data-nosnippet>104</a> </span>.table_metadata_manager
<a href=#105 id=105 data-nosnippet>105</a> .get_full_table_info(i)
<a href=#106 id=106 data-nosnippet>106</a> .<span class="kw">await
<a href=#107 id=107 data-nosnippet>107</a> </span>.unwrap();
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">let </span>start = Instant::now();
<a href=#109 id=109 data-nosnippet>109</a> <span class="kw">let </span>table_info = table_info.unwrap();
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">let </span>table_route = table_route.unwrap();
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">let </span>table_id = table_info.table_info.ident.table_id;
<a href=#112 id=112 data-nosnippet>112</a>
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">let </span>regions: Vec&lt;<span class="kw">_</span>&gt; = (<span class="number">0</span>..<span class="number">64</span>).collect();
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">let </span>region_wal_options = create_region_wal_options(regions);
<a href=#115 id=115 data-nosnippet>115</a> <span class="kw">let _ </span>= <span class="self">self
<a href=#116 id=116 data-nosnippet>116</a> </span>.table_metadata_manager
<a href=#117 id=117 data-nosnippet>117</a> .delete_table_metadata(
<a href=#118 id=118 data-nosnippet>118</a> table_id,
<a href=#119 id=119 data-nosnippet>119</a> <span class="kw-2">&amp;</span>table_info.table_name(),
<a href=#120 id=120 data-nosnippet>120</a> <span class="kw-2">&amp;</span>table_route,
<a href=#121 id=121 data-nosnippet>121</a> <span class="kw-2">&amp;</span>region_wal_options,
<a href=#122 id=122 data-nosnippet>122</a> <span class="prelude-val">None</span>,
<a href=#123 id=123 data-nosnippet>123</a> )
<a href=#124 id=124 data-nosnippet>124</a> .<span class="kw">await</span>;
<a href=#125 id=125 data-nosnippet>125</a> start.elapsed()
<a href=#126 id=126 data-nosnippet>126</a> },
<a href=#127 id=127 data-nosnippet>127</a> <span class="self">self</span>.count,
<a href=#128 id=128 data-nosnippet>128</a> )
<a href=#129 id=129 data-nosnippet>129</a> .<span class="kw">await</span>;
<a href=#130 id=130 data-nosnippet>130</a> }
<a href=#131 id=131 data-nosnippet>131</a>
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">pub async fn </span>bench_rename(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<a href=#133 id=133 data-nosnippet>133</a> <span class="kw">let </span>desc = <span class="macro">format!</span>(<span class="string">"TableMetadataBencher: renaming {} table"</span>, <span class="self">self</span>.count);
<a href=#134 id=134 data-nosnippet>134</a>
<a href=#135 id=135 data-nosnippet>135</a> bench_self_recorded(
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw-2">&amp;</span>desc,
<a href=#137 id=137 data-nosnippet>137</a> |i| <span class="kw">async move </span>{
<a href=#138 id=138 data-nosnippet>138</a> <span class="kw">let </span>(table_info, <span class="kw">_</span>) = <span class="self">self
<a href=#139 id=139 data-nosnippet>139</a> </span>.table_metadata_manager
<a href=#140 id=140 data-nosnippet>140</a> .get_full_table_info(i)
<a href=#141 id=141 data-nosnippet>141</a> .<span class="kw">await
<a href=#142 id=142 data-nosnippet>142</a> </span>.unwrap();
<a href=#143 id=143 data-nosnippet>143</a>
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">let </span>new_table_name = <span class="macro">format!</span>(<span class="string">"renamed_{}"</span>, i);
<a href=#145 id=145 data-nosnippet>145</a>
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">let </span>start = Instant::now();
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">let _ </span>= <span class="self">self
<a href=#148 id=148 data-nosnippet>148</a> </span>.table_metadata_manager
<a href=#149 id=149 data-nosnippet>149</a> .rename_table(<span class="kw-2">&amp;</span>table_info.unwrap(), new_table_name)
<a href=#150 id=150 data-nosnippet>150</a> .<span class="kw">await</span>;
<a href=#151 id=151 data-nosnippet>151</a>
<a href=#152 id=152 data-nosnippet>152</a> start.elapsed()
<a href=#153 id=153 data-nosnippet>153</a> },
<a href=#154 id=154 data-nosnippet>154</a> <span class="self">self</span>.count,
<a href=#155 id=155 data-nosnippet>155</a> )
<a href=#156 id=156 data-nosnippet>156</a> .<span class="kw">await</span>;
<a href=#157 id=157 data-nosnippet>157</a> }
<a href=#158 id=158 data-nosnippet>158</a>}
</code></pre></div></section></main></body></html>
+23
View File
@@ -0,0 +1,23 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/common.rs`."><title>common.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/</div>common.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">mod </span>object_store;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">mod </span>store;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">pub use </span>object_store::{
<a href=#19 id=19 data-nosnippet>19</a> ObjectStoreConfig, PrefixedAzblobConnection, PrefixedGcsConnection, PrefixedOssConnection,
<a href=#20 id=20 data-nosnippet>20</a> PrefixedS3Connection, new_fs_object_store,
<a href=#21 id=21 data-nosnippet>21</a>};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">pub use </span>store::StoreConfig;
</code></pre></div></section></main></body></html>
+459
View File
@@ -0,0 +1,459 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/common/object_store.rs`."><title>object_store.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/common/</div>object_store.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>common_base::secrets::{ExposeSecret, SecretString};
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>object_store::services::{Azblob, Fs, Gcs, Oss, S3};
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>object_store::util::{with_instrument_layers, with_retry_layers};
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>object_store::{AzblobConnection, GcsConnection, ObjectStore, OssConnection, S3Connection};
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>paste::paste;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>snafu::ResultExt;
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span><span class="kw">crate</span>::error::{<span class="self">self</span>};
<a href=#24 id=24 data-nosnippet>24</a>
<a href=#25 id=25 data-nosnippet>25</a><span class="doccomment">/// Trait to convert CLI field types to target struct field types.
<a href=#26 id=26 data-nosnippet>26</a>/// This enables `Option&lt;SecretString&gt;` (CLI) -&gt; `SecretString` (target) conversions,
<a href=#27 id=27 data-nosnippet>27</a>/// allowing us to distinguish "not provided" from "provided but empty".
<a href=#28 id=28 data-nosnippet>28</a></span><span class="kw">trait </span>IntoField&lt;T&gt; {
<a href=#29 id=29 data-nosnippet>29</a> <span class="kw">fn </span>into_field(<span class="self">self</span>) -&gt; T;
<a href=#30 id=30 data-nosnippet>30</a>}
<a href=#31 id=31 data-nosnippet>31</a>
<a href=#32 id=32 data-nosnippet>32</a><span class="doccomment">/// Identity conversion for types that are the same.
<a href=#33 id=33 data-nosnippet>33</a></span><span class="kw">impl</span>&lt;T&gt; IntoField&lt;T&gt; <span class="kw">for </span>T {
<a href=#34 id=34 data-nosnippet>34</a> <span class="kw">fn </span>into_field(<span class="self">self</span>) -&gt; T {
<a href=#35 id=35 data-nosnippet>35</a> <span class="self">self
<a href=#36 id=36 data-nosnippet>36</a> </span>}
<a href=#37 id=37 data-nosnippet>37</a>}
<a href=#38 id=38 data-nosnippet>38</a>
<a href=#39 id=39 data-nosnippet>39</a><span class="doccomment">/// Convert `Option&lt;SecretString&gt;` to `SecretString`, using default for None.
<a href=#40 id=40 data-nosnippet>40</a></span><span class="kw">impl </span>IntoField&lt;SecretString&gt; <span class="kw">for </span><span class="prelude-ty">Option</span>&lt;SecretString&gt; {
<a href=#41 id=41 data-nosnippet>41</a> <span class="kw">fn </span>into_field(<span class="self">self</span>) -&gt; SecretString {
<a href=#42 id=42 data-nosnippet>42</a> <span class="self">self</span>.unwrap_or_default()
<a href=#43 id=43 data-nosnippet>43</a> }
<a href=#44 id=44 data-nosnippet>44</a>}
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a><span class="doccomment">/// Trait for checking if a field is effectively empty.
<a href=#47 id=47 data-nosnippet>47</a>///
<a href=#48 id=48 data-nosnippet>48</a>/// **`is_empty()`**: Checks if the field has no meaningful value
<a href=#49 id=49 data-nosnippet>49</a>/// - Used when backend is enabled to validate required fields
<a href=#50 id=50 data-nosnippet>50</a>/// - `None`, `Some("")`, `false`, or `""` are considered empty
<a href=#51 id=51 data-nosnippet>51</a></span><span class="kw">trait </span>FieldValidator {
<a href=#52 id=52 data-nosnippet>52</a> <span class="doccomment">/// Check if the field is empty (has no meaningful value).
<a href=#53 id=53 data-nosnippet>53</a> </span><span class="kw">fn </span>is_empty(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool;
<a href=#54 id=54 data-nosnippet>54</a>}
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a><span class="doccomment">/// String fields: empty if the string is empty
<a href=#57 id=57 data-nosnippet>57</a></span><span class="kw">impl </span>FieldValidator <span class="kw">for </span>String {
<a href=#58 id=58 data-nosnippet>58</a> <span class="kw">fn </span>is_empty(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#59 id=59 data-nosnippet>59</a> <span class="self">self</span>.is_empty()
<a href=#60 id=60 data-nosnippet>60</a> }
<a href=#61 id=61 data-nosnippet>61</a>}
<a href=#62 id=62 data-nosnippet>62</a>
<a href=#63 id=63 data-nosnippet>63</a><span class="doccomment">/// Bool fields: false is considered "empty", true is "provided"
<a href=#64 id=64 data-nosnippet>64</a></span><span class="kw">impl </span>FieldValidator <span class="kw">for </span>bool {
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">fn </span>is_empty(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#66 id=66 data-nosnippet>66</a> !<span class="self">self
<a href=#67 id=67 data-nosnippet>67</a> </span>}
<a href=#68 id=68 data-nosnippet>68</a>}
<a href=#69 id=69 data-nosnippet>69</a>
<a href=#70 id=70 data-nosnippet>70</a><span class="doccomment">/// Option&lt;String&gt; fields: None or empty content is empty
<a href=#71 id=71 data-nosnippet>71</a></span><span class="kw">impl </span>FieldValidator <span class="kw">for </span><span class="prelude-ty">Option</span>&lt;String&gt; {
<a href=#72 id=72 data-nosnippet>72</a> <span class="kw">fn </span>is_empty(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#73 id=73 data-nosnippet>73</a> <span class="self">self</span>.as_ref().is_none_or(|s| s.is_empty())
<a href=#74 id=74 data-nosnippet>74</a> }
<a href=#75 id=75 data-nosnippet>75</a>}
<a href=#76 id=76 data-nosnippet>76</a>
<a href=#77 id=77 data-nosnippet>77</a><span class="doccomment">/// Option&lt;SecretString&gt; fields: None or empty secret is empty
<a href=#78 id=78 data-nosnippet>78</a>/// For secrets, Some("") is treated as "not provided" for both checks
<a href=#79 id=79 data-nosnippet>79</a></span><span class="kw">impl </span>FieldValidator <span class="kw">for </span><span class="prelude-ty">Option</span>&lt;SecretString&gt; {
<a href=#80 id=80 data-nosnippet>80</a> <span class="kw">fn </span>is_empty(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#81 id=81 data-nosnippet>81</a> <span class="self">self</span>.as_ref().is_none_or(|s| s.expose_secret().is_empty())
<a href=#82 id=82 data-nosnippet>82</a> }
<a href=#83 id=83 data-nosnippet>83</a>}
<a href=#84 id=84 data-nosnippet>84</a>
<a href=#85 id=85 data-nosnippet>85</a><span class="macro">macro_rules!</span> wrap_with_clap_prefix {
<a href=#86 id=86 data-nosnippet>86</a> (
<a href=#87 id=87 data-nosnippet>87</a> <span class="macro-nonterminal">$new_name</span>:ident, <span class="macro-nonterminal">$prefix</span>:literal, <span class="macro-nonterminal">$enable_flag</span>:literal, <span class="macro-nonterminal">$base</span>:ty, {
<a href=#88 id=88 data-nosnippet>88</a> $( $( <span class="attr">#[doc = <span class="macro-nonterminal">$doc</span>:expr] </span>)<span class="question-mark">? </span>$( <span class="attr">#[alias = <span class="macro-nonterminal">$alias</span>:literal] </span>)<span class="question-mark">? </span>$( <span class="attr">#[hide = <span class="macro-nonterminal">$hide</span>:literal] </span>)<span class="question-mark">? </span><span class="macro-nonterminal">$field</span>:ident : <span class="macro-nonterminal">$type</span>:ty $( = <span class="macro-nonterminal">$default</span>:expr )<span class="question-mark">? </span>),* $(,)<span class="question-mark">?
<a href=#89 id=89 data-nosnippet>89</a> </span>}
<a href=#90 id=90 data-nosnippet>90</a> ) =&gt; {
<a href=#91 id=91 data-nosnippet>91</a> <span class="macro">paste!</span>{
<a href=#92 id=92 data-nosnippet>92</a> <span class="attr">#[derive(clap::Parser, Debug, Clone, PartialEq, Default)]
<a href=#93 id=93 data-nosnippet>93</a> </span><span class="kw">pub struct </span><span class="macro-nonterminal">$new_name </span>{
<a href=#94 id=94 data-nosnippet>94</a> $(
<a href=#95 id=95 data-nosnippet>95</a> $( <span class="attr">#[doc = <span class="macro-nonterminal">$doc</span>] </span>)<span class="question-mark">?
<a href=#96 id=96 data-nosnippet>96</a> </span>$( <span class="attr">#[clap(alias = <span class="macro-nonterminal">$alias</span>)] </span>)<span class="question-mark">?
<a href=#97 id=97 data-nosnippet>97</a> </span>$( <span class="attr">#[clap(hide = <span class="macro-nonterminal">$hide</span>)] </span>)<span class="question-mark">?
<a href=#98 id=98 data-nosnippet>98</a> </span><span class="attr">#[clap(long, requires = <span class="macro-nonterminal">$enable_flag </span>$(, default_value_t = <span class="macro-nonterminal">$default </span>)<span class="question-mark">? </span>)]
<a href=#99 id=99 data-nosnippet>99</a> </span><span class="kw">pub </span>[&lt;<span class="macro-nonterminal">$prefix $field</span>&gt;]: <span class="macro-nonterminal">$type</span>,
<a href=#100 id=100 data-nosnippet>100</a> )*
<a href=#101 id=101 data-nosnippet>101</a> }
<a href=#102 id=102 data-nosnippet>102</a>
<a href=#103 id=103 data-nosnippet>103</a> <span class="kw">impl </span>From&lt;<span class="macro-nonterminal">$new_name</span>&gt; <span class="kw">for </span><span class="macro-nonterminal">$base </span>{
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">fn </span>from(w: <span class="macro-nonterminal">$new_name</span>) -&gt; <span class="self">Self </span>{
<a href=#105 id=105 data-nosnippet>105</a> <span class="self">Self </span>{
<a href=#106 id=106 data-nosnippet>106</a> <span class="comment">// Use into_field() to handle Option&lt;SecretString&gt; -&gt; SecretString conversion
<a href=#107 id=107 data-nosnippet>107</a> </span>$( <span class="macro-nonterminal">$field</span>: w.[&lt;<span class="macro-nonterminal">$prefix $field</span>&gt;].into_field() ),*
<a href=#108 id=108 data-nosnippet>108</a> }
<a href=#109 id=109 data-nosnippet>109</a> }
<a href=#110 id=110 data-nosnippet>110</a> }
<a href=#111 id=111 data-nosnippet>111</a> }
<a href=#112 id=112 data-nosnippet>112</a> };
<a href=#113 id=113 data-nosnippet>113</a>}
<a href=#114 id=114 data-nosnippet>114</a>
<a href=#115 id=115 data-nosnippet>115</a><span class="doccomment">/// Macro for declarative backend validation.
<a href=#116 id=116 data-nosnippet>116</a>///
<a href=#117 id=117 data-nosnippet>117</a>/// # Validation Rules
<a href=#118 id=118 data-nosnippet>118</a>///
<a href=#119 id=119 data-nosnippet>119</a>/// For each storage backend (S3, OSS, GCS, Azblob), this function validates:
<a href=#120 id=120 data-nosnippet>120</a>/// **When backend is enabled** (e.g., `--s3`): All required fields must be non-empty
<a href=#121 id=121 data-nosnippet>121</a>///
<a href=#122 id=122 data-nosnippet>122</a>/// Note: When backend is disabled, clap's `requires` attribute ensures no configuration
<a href=#123 id=123 data-nosnippet>123</a>/// fields can be provided at parse time.
<a href=#124 id=124 data-nosnippet>124</a>///
<a href=#125 id=125 data-nosnippet>125</a>/// # Syntax
<a href=#126 id=126 data-nosnippet>126</a>///
<a href=#127 id=127 data-nosnippet>127</a>/// ```ignore
<a href=#128 id=128 data-nosnippet>128</a>/// validate_backend!(
<a href=#129 id=129 data-nosnippet>129</a>/// enable: self.enable_s3,
<a href=#130 id=130 data-nosnippet>130</a>/// name: "S3",
<a href=#131 id=131 data-nosnippet>131</a>/// required: [(field1, "name1"), (field2, "name2"), ...],
<a href=#132 id=132 data-nosnippet>132</a>/// custom_validator: |missing| { ... } // optional
<a href=#133 id=133 data-nosnippet>133</a>/// )
<a href=#134 id=134 data-nosnippet>134</a>/// ```
<a href=#135 id=135 data-nosnippet>135</a>///
<a href=#136 id=136 data-nosnippet>136</a>/// # Arguments
<a href=#137 id=137 data-nosnippet>137</a>///
<a href=#138 id=138 data-nosnippet>138</a>/// - `enable`: Boolean expression indicating if backend is enabled
<a href=#139 id=139 data-nosnippet>139</a>/// - `name`: Human-readable backend name for error messages
<a href=#140 id=140 data-nosnippet>140</a>/// - `required`: Array of (field_ref, field_name) tuples for required fields
<a href=#141 id=141 data-nosnippet>141</a>/// - `custom_validator`: Optional closure for complex validation logic
<a href=#142 id=142 data-nosnippet>142</a>///
<a href=#143 id=143 data-nosnippet>143</a>/// # Example
<a href=#144 id=144 data-nosnippet>144</a>///
<a href=#145 id=145 data-nosnippet>145</a>/// ```ignore
<a href=#146 id=146 data-nosnippet>146</a>/// validate_backend!(
<a href=#147 id=147 data-nosnippet>147</a>/// enable: self.enable_s3,
<a href=#148 id=148 data-nosnippet>148</a>/// name: "S3",
<a href=#149 id=149 data-nosnippet>149</a>/// required: [
<a href=#150 id=150 data-nosnippet>150</a>/// (&amp;self.s3.s3_bucket, "bucket"),
<a href=#151 id=151 data-nosnippet>151</a>/// (&amp;self.s3.s3_access_key_id, "access key ID"),
<a href=#152 id=152 data-nosnippet>152</a>/// ]
<a href=#153 id=153 data-nosnippet>153</a>/// )
<a href=#154 id=154 data-nosnippet>154</a>/// ```
<a href=#155 id=155 data-nosnippet>155</a></span><span class="macro">macro_rules!</span> validate_backend {
<a href=#156 id=156 data-nosnippet>156</a> (
<a href=#157 id=157 data-nosnippet>157</a> enable: <span class="macro-nonterminal">$enable</span>:expr,
<a href=#158 id=158 data-nosnippet>158</a> name: <span class="macro-nonterminal">$backend_name</span>:expr,
<a href=#159 id=159 data-nosnippet>159</a> required: [ $( (<span class="macro-nonterminal">$field</span>:expr, <span class="macro-nonterminal">$field_name</span>:expr) ),* $(,)<span class="question-mark">? </span>]
<a href=#160 id=160 data-nosnippet>160</a> $(, custom_validator: <span class="macro-nonterminal">$custom_validator</span>:expr)<span class="question-mark">?
<a href=#161 id=161 data-nosnippet>161</a> </span>) =&gt; {{
<a href=#162 id=162 data-nosnippet>162</a> <span class="kw">if </span><span class="macro-nonterminal">$enable </span>{
<a href=#163 id=163 data-nosnippet>163</a> <span class="comment">// Check required fields when backend is enabled
<a href=#164 id=164 data-nosnippet>164</a> </span><span class="kw">let </span><span class="kw-2">mut </span>missing = Vec::new();
<a href=#165 id=165 data-nosnippet>165</a> $(
<a href=#166 id=166 data-nosnippet>166</a> <span class="kw">if </span>FieldValidator::is_empty(<span class="macro-nonterminal">$field</span>) {
<a href=#167 id=167 data-nosnippet>167</a> missing.push(<span class="macro-nonterminal">$field_name</span>);
<a href=#168 id=168 data-nosnippet>168</a> }
<a href=#169 id=169 data-nosnippet>169</a> )*
<a href=#170 id=170 data-nosnippet>170</a>
<a href=#171 id=171 data-nosnippet>171</a> <span class="comment">// Run custom validation if provided
<a href=#172 id=172 data-nosnippet>172</a> </span>$(
<a href=#173 id=173 data-nosnippet>173</a> <span class="macro-nonterminal">$custom_validator</span>(<span class="kw-2">&amp;mut </span>missing);
<a href=#174 id=174 data-nosnippet>174</a> )<span class="question-mark">?
<a href=#175 id=175 data-nosnippet>175</a>
<a href=#176 id=176 data-nosnippet>176</a> </span><span class="kw">if </span>!missing.is_empty() {
<a href=#177 id=177 data-nosnippet>177</a> <span class="kw">return </span><span class="prelude-val">Err</span>(BoxedError::new(
<a href=#178 id=178 data-nosnippet>178</a> error::MissingConfigSnafu {
<a href=#179 id=179 data-nosnippet>179</a> msg: <span class="macro">format!</span>(
<a href=#180 id=180 data-nosnippet>180</a> <span class="string">"{} {} must be set when --{} is enabled."</span>,
<a href=#181 id=181 data-nosnippet>181</a> <span class="macro-nonterminal">$backend_name</span>,
<a href=#182 id=182 data-nosnippet>182</a> missing.join(<span class="string">", "</span>),
<a href=#183 id=183 data-nosnippet>183</a> <span class="macro-nonterminal">$backend_name</span>.to_lowercase()
<a href=#184 id=184 data-nosnippet>184</a> ),
<a href=#185 id=185 data-nosnippet>185</a> }
<a href=#186 id=186 data-nosnippet>186</a> .build(),
<a href=#187 id=187 data-nosnippet>187</a> ));
<a href=#188 id=188 data-nosnippet>188</a> }
<a href=#189 id=189 data-nosnippet>189</a> }
<a href=#190 id=190 data-nosnippet>190</a>
<a href=#191 id=191 data-nosnippet>191</a> <span class="prelude-val">Ok</span>(())
<a href=#192 id=192 data-nosnippet>192</a> }};
<a href=#193 id=193 data-nosnippet>193</a>}
<a href=#194 id=194 data-nosnippet>194</a>
<a href=#195 id=195 data-nosnippet>195</a><span class="macro">wrap_with_clap_prefix!</span> {
<a href=#196 id=196 data-nosnippet>196</a> PrefixedAzblobConnection,
<a href=#197 id=197 data-nosnippet>197</a> <span class="string">"azblob-"</span>,
<a href=#198 id=198 data-nosnippet>198</a> <span class="string">"enable_azblob"</span>,
<a href=#199 id=199 data-nosnippet>199</a> AzblobConnection,
<a href=#200 id=200 data-nosnippet>200</a> {
<a href=#201 id=201 data-nosnippet>201</a> <span class="attr">#[doc = <span class="string">"The container of the object store."</span>]
<a href=#202 id=202 data-nosnippet>202</a> </span>container: String = Default::default(),
<a href=#203 id=203 data-nosnippet>203</a> <span class="attr">#[doc = <span class="string">"The root of the object store."</span>]
<a href=#204 id=204 data-nosnippet>204</a> </span>root: String = Default::default(),
<a href=#205 id=205 data-nosnippet>205</a> <span class="attr">#[doc = <span class="string">"The account name of the object store."</span>]
<a href=#206 id=206 data-nosnippet>206</a> </span>account_name: <span class="prelude-ty">Option</span>&lt;SecretString&gt;,
<a href=#207 id=207 data-nosnippet>207</a> <span class="attr">#[doc = <span class="string">"The account key of the object store."</span>]
<a href=#208 id=208 data-nosnippet>208</a> </span>account_key: <span class="prelude-ty">Option</span>&lt;SecretString&gt;,
<a href=#209 id=209 data-nosnippet>209</a> <span class="attr">#[doc = <span class="string">"The endpoint of the object store."</span>]
<a href=#210 id=210 data-nosnippet>210</a> </span>endpoint: String = Default::default(),
<a href=#211 id=211 data-nosnippet>211</a> <span class="attr">#[doc = <span class="string">"The SAS token of the object store."</span>]
<a href=#212 id=212 data-nosnippet>212</a> </span>sas_token: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#213 id=213 data-nosnippet>213</a> }
<a href=#214 id=214 data-nosnippet>214</a>}
<a href=#215 id=215 data-nosnippet>215</a>
<a href=#216 id=216 data-nosnippet>216</a><span class="kw">impl </span>PrefixedAzblobConnection {
<a href=#217 id=217 data-nosnippet>217</a> <span class="kw">pub fn </span>validate(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#218 id=218 data-nosnippet>218</a> <span class="macro">validate_backend!</span>(
<a href=#219 id=219 data-nosnippet>219</a> enable: <span class="bool-val">true</span>,
<a href=#220 id=220 data-nosnippet>220</a> name: <span class="string">"AzBlob"</span>,
<a href=#221 id=221 data-nosnippet>221</a> required: [
<a href=#222 id=222 data-nosnippet>222</a> (<span class="kw-2">&amp;</span><span class="self">self</span>.azblob_container, <span class="string">"container"</span>),
<a href=#223 id=223 data-nosnippet>223</a> (<span class="kw-2">&amp;</span><span class="self">self</span>.azblob_endpoint, <span class="string">"endpoint"</span>),
<a href=#224 id=224 data-nosnippet>224</a> ]
<a href=#225 id=225 data-nosnippet>225</a> )
<a href=#226 id=226 data-nosnippet>226</a> }
<a href=#227 id=227 data-nosnippet>227</a>}
<a href=#228 id=228 data-nosnippet>228</a>
<a href=#229 id=229 data-nosnippet>229</a><span class="macro">wrap_with_clap_prefix!</span> {
<a href=#230 id=230 data-nosnippet>230</a> PrefixedS3Connection,
<a href=#231 id=231 data-nosnippet>231</a> <span class="string">"s3-"</span>,
<a href=#232 id=232 data-nosnippet>232</a> <span class="string">"enable_s3"</span>,
<a href=#233 id=233 data-nosnippet>233</a> S3Connection,
<a href=#234 id=234 data-nosnippet>234</a> {
<a href=#235 id=235 data-nosnippet>235</a> <span class="attr">#[doc = <span class="string">"The bucket of the object store."</span>]
<a href=#236 id=236 data-nosnippet>236</a> </span>bucket: String = Default::default(),
<a href=#237 id=237 data-nosnippet>237</a> <span class="attr">#[doc = <span class="string">"The root of the object store."</span>]
<a href=#238 id=238 data-nosnippet>238</a> </span>root: String = Default::default(),
<a href=#239 id=239 data-nosnippet>239</a> <span class="attr">#[doc = <span class="string">"The access key ID of the object store."</span>]
<a href=#240 id=240 data-nosnippet>240</a> </span>access_key_id: <span class="prelude-ty">Option</span>&lt;SecretString&gt;,
<a href=#241 id=241 data-nosnippet>241</a> <span class="attr">#[doc = <span class="string">"The secret access key of the object store."</span>]
<a href=#242 id=242 data-nosnippet>242</a> </span>secret_access_key: <span class="prelude-ty">Option</span>&lt;SecretString&gt;,
<a href=#243 id=243 data-nosnippet>243</a> <span class="attr">#[doc = <span class="string">"The endpoint of the object store."</span>]
<a href=#244 id=244 data-nosnippet>244</a> </span>endpoint: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#245 id=245 data-nosnippet>245</a> <span class="attr">#[doc = <span class="string">"The region of the object store."</span>]
<a href=#246 id=246 data-nosnippet>246</a> </span>region: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#247 id=247 data-nosnippet>247</a> <span class="attr">#[doc = <span class="string">"Enable virtual host style for the object store."</span>]
<a href=#248 id=248 data-nosnippet>248</a> </span>enable_virtual_host_style: bool = Default::default(),
<a href=#249 id=249 data-nosnippet>249</a> <span class="attr">#[doc = <span class="string">"Disable EC2 metadata service for the object store."</span>]
<a href=#250 id=250 data-nosnippet>250</a> </span>disable_ec2_metadata: bool = Default::default(),
<a href=#251 id=251 data-nosnippet>251</a> }
<a href=#252 id=252 data-nosnippet>252</a>}
<a href=#253 id=253 data-nosnippet>253</a>
<a href=#254 id=254 data-nosnippet>254</a><span class="kw">impl </span>PrefixedS3Connection {
<a href=#255 id=255 data-nosnippet>255</a> <span class="kw">pub fn </span>validate(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#256 id=256 data-nosnippet>256</a> <span class="macro">validate_backend!</span>(
<a href=#257 id=257 data-nosnippet>257</a> enable: <span class="bool-val">true</span>,
<a href=#258 id=258 data-nosnippet>258</a> name: <span class="string">"S3"</span>,
<a href=#259 id=259 data-nosnippet>259</a> required: [
<a href=#260 id=260 data-nosnippet>260</a> (<span class="kw-2">&amp;</span><span class="self">self</span>.s3_bucket, <span class="string">"bucket"</span>),
<a href=#261 id=261 data-nosnippet>261</a> (<span class="kw-2">&amp;</span><span class="self">self</span>.s3_region, <span class="string">"region"</span>),
<a href=#262 id=262 data-nosnippet>262</a> ]
<a href=#263 id=263 data-nosnippet>263</a> )
<a href=#264 id=264 data-nosnippet>264</a> }
<a href=#265 id=265 data-nosnippet>265</a>}
<a href=#266 id=266 data-nosnippet>266</a>
<a href=#267 id=267 data-nosnippet>267</a><span class="macro">wrap_with_clap_prefix!</span> {
<a href=#268 id=268 data-nosnippet>268</a> PrefixedOssConnection,
<a href=#269 id=269 data-nosnippet>269</a> <span class="string">"oss-"</span>,
<a href=#270 id=270 data-nosnippet>270</a> <span class="string">"enable_oss"</span>,
<a href=#271 id=271 data-nosnippet>271</a> OssConnection,
<a href=#272 id=272 data-nosnippet>272</a> {
<a href=#273 id=273 data-nosnippet>273</a> <span class="attr">#[doc = <span class="string">"The bucket of the object store."</span>]
<a href=#274 id=274 data-nosnippet>274</a> </span>bucket: String = Default::default(),
<a href=#275 id=275 data-nosnippet>275</a> <span class="attr">#[doc = <span class="string">"The root of the object store."</span>]
<a href=#276 id=276 data-nosnippet>276</a> </span>root: String = Default::default(),
<a href=#277 id=277 data-nosnippet>277</a> <span class="attr">#[doc = <span class="string">"The access key ID of the object store."</span>]
<a href=#278 id=278 data-nosnippet>278</a> </span>access_key_id: <span class="prelude-ty">Option</span>&lt;SecretString&gt;,
<a href=#279 id=279 data-nosnippet>279</a> <span class="attr">#[doc = <span class="string">"The access key secret of the object store."</span>]
<a href=#280 id=280 data-nosnippet>280</a> </span>access_key_secret: <span class="prelude-ty">Option</span>&lt;SecretString&gt;,
<a href=#281 id=281 data-nosnippet>281</a> <span class="attr">#[doc = <span class="string">"The endpoint of the object store."</span>]
<a href=#282 id=282 data-nosnippet>282</a> </span>endpoint: String = Default::default(),
<a href=#283 id=283 data-nosnippet>283</a> }
<a href=#284 id=284 data-nosnippet>284</a>}
<a href=#285 id=285 data-nosnippet>285</a>
<a href=#286 id=286 data-nosnippet>286</a><span class="kw">impl </span>PrefixedOssConnection {
<a href=#287 id=287 data-nosnippet>287</a> <span class="kw">pub fn </span>validate(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#288 id=288 data-nosnippet>288</a> <span class="macro">validate_backend!</span>(
<a href=#289 id=289 data-nosnippet>289</a> enable: <span class="bool-val">true</span>,
<a href=#290 id=290 data-nosnippet>290</a> name: <span class="string">"OSS"</span>,
<a href=#291 id=291 data-nosnippet>291</a> required: [
<a href=#292 id=292 data-nosnippet>292</a> (<span class="kw-2">&amp;</span><span class="self">self</span>.oss_bucket, <span class="string">"bucket"</span>),
<a href=#293 id=293 data-nosnippet>293</a> (<span class="kw-2">&amp;</span><span class="self">self</span>.oss_access_key_id, <span class="string">"access key ID"</span>),
<a href=#294 id=294 data-nosnippet>294</a> (<span class="kw-2">&amp;</span><span class="self">self</span>.oss_access_key_secret, <span class="string">"access key secret"</span>),
<a href=#295 id=295 data-nosnippet>295</a> (<span class="kw-2">&amp;</span><span class="self">self</span>.oss_endpoint, <span class="string">"endpoint"</span>),
<a href=#296 id=296 data-nosnippet>296</a> ]
<a href=#297 id=297 data-nosnippet>297</a> )
<a href=#298 id=298 data-nosnippet>298</a> }
<a href=#299 id=299 data-nosnippet>299</a>}
<a href=#300 id=300 data-nosnippet>300</a>
<a href=#301 id=301 data-nosnippet>301</a><span class="macro">wrap_with_clap_prefix!</span> {
<a href=#302 id=302 data-nosnippet>302</a> PrefixedGcsConnection,
<a href=#303 id=303 data-nosnippet>303</a> <span class="string">"gcs-"</span>,
<a href=#304 id=304 data-nosnippet>304</a> <span class="string">"enable_gcs"</span>,
<a href=#305 id=305 data-nosnippet>305</a> GcsConnection,
<a href=#306 id=306 data-nosnippet>306</a> {
<a href=#307 id=307 data-nosnippet>307</a> <span class="attr">#[doc = <span class="string">"The root of the object store."</span>]
<a href=#308 id=308 data-nosnippet>308</a> </span>root: String = Default::default(),
<a href=#309 id=309 data-nosnippet>309</a> <span class="attr">#[doc = <span class="string">"The bucket of the object store."</span>]
<a href=#310 id=310 data-nosnippet>310</a> </span>bucket: String = Default::default(),
<a href=#311 id=311 data-nosnippet>311</a> <span class="attr">#[doc = <span class="string">"The scope of the object store."</span>]
<a href=#312 id=312 data-nosnippet>312</a> </span>scope: String = Default::default(),
<a href=#313 id=313 data-nosnippet>313</a> <span class="attr">#[doc = <span class="string">"The credential path of the object store."</span>]
<a href=#314 id=314 data-nosnippet>314</a> #[hide = <span class="bool-val">true</span>]
<a href=#315 id=315 data-nosnippet>315</a> </span>credential_path: <span class="prelude-ty">Option</span>&lt;SecretString&gt;,
<a href=#316 id=316 data-nosnippet>316</a> <span class="attr">#[doc = <span class="string">"The credential of the object store."</span>]
<a href=#317 id=317 data-nosnippet>317</a> </span>credential: <span class="prelude-ty">Option</span>&lt;SecretString&gt;,
<a href=#318 id=318 data-nosnippet>318</a> <span class="attr">#[doc = <span class="string">"The endpoint of the object store."</span>]
<a href=#319 id=319 data-nosnippet>319</a> </span>endpoint: String = Default::default(),
<a href=#320 id=320 data-nosnippet>320</a> }
<a href=#321 id=321 data-nosnippet>321</a>}
<a href=#322 id=322 data-nosnippet>322</a>
<a href=#323 id=323 data-nosnippet>323</a><span class="kw">impl </span>PrefixedGcsConnection {
<a href=#324 id=324 data-nosnippet>324</a> <span class="kw">pub fn </span>validate(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#325 id=325 data-nosnippet>325</a> <span class="macro">validate_backend!</span>(
<a href=#326 id=326 data-nosnippet>326</a> enable: <span class="bool-val">true</span>,
<a href=#327 id=327 data-nosnippet>327</a> name: <span class="string">"GCS"</span>,
<a href=#328 id=328 data-nosnippet>328</a> required: [
<a href=#329 id=329 data-nosnippet>329</a> (<span class="kw-2">&amp;</span><span class="self">self</span>.gcs_bucket, <span class="string">"bucket"</span>),
<a href=#330 id=330 data-nosnippet>330</a> (<span class="kw-2">&amp;</span><span class="self">self</span>.gcs_root, <span class="string">"root"</span>),
<a href=#331 id=331 data-nosnippet>331</a> (<span class="kw-2">&amp;</span><span class="self">self</span>.gcs_scope, <span class="string">"scope"</span>),
<a href=#332 id=332 data-nosnippet>332</a> ]
<a href=#333 id=333 data-nosnippet>333</a> <span class="comment">// No custom_validator needed: GCS supports Application Default Credentials (ADC)
<a href=#334 id=334 data-nosnippet>334</a> // where neither credential_path nor credential is required.
<a href=#335 id=335 data-nosnippet>335</a> // Endpoint is also optional (defaults to https://storage.googleapis.com).
<a href=#336 id=336 data-nosnippet>336</a> </span>)
<a href=#337 id=337 data-nosnippet>337</a> }
<a href=#338 id=338 data-nosnippet>338</a>}
<a href=#339 id=339 data-nosnippet>339</a>
<a href=#340 id=340 data-nosnippet>340</a><span class="doccomment">/// Common config for object store.
<a href=#341 id=341 data-nosnippet>341</a>///
<a href=#342 id=342 data-nosnippet>342</a>/// # Dependency Enforcement
<a href=#343 id=343 data-nosnippet>343</a>///
<a href=#344 id=344 data-nosnippet>344</a>/// Each backend's configuration fields (e.g., `--s3-bucket`) requires its corresponding
<a href=#345 id=345 data-nosnippet>345</a>/// enable flag (e.g., `--s3`) to be present. This is enforced by `clap` at parse time
<a href=#346 id=346 data-nosnippet>346</a>/// using the `requires` attribute.
<a href=#347 id=347 data-nosnippet>347</a>///
<a href=#348 id=348 data-nosnippet>348</a>/// For example, attempting to use `--s3-bucket my-bucket` without `--s3` will result in:
<a href=#349 id=349 data-nosnippet>349</a>/// ```text
<a href=#350 id=350 data-nosnippet>350</a>/// error: The argument '--s3-bucket &lt;BUCKET&gt;' requires '--s3'
<a href=#351 id=351 data-nosnippet>351</a>/// ```
<a href=#352 id=352 data-nosnippet>352</a>///
<a href=#353 id=353 data-nosnippet>353</a>/// This ensures that users cannot accidentally provide backend-specific configuration
<a href=#354 id=354 data-nosnippet>354</a>/// without explicitly enabling that backend.
<a href=#355 id=355 data-nosnippet>355</a></span><span class="attr">#[derive(clap::Parser, Debug, Clone, PartialEq, Default)]
<a href=#356 id=356 data-nosnippet>356</a>#[clap(group(clap::ArgGroup::new(<span class="string">"storage_backend"</span>).required(<span class="bool-val">false</span>).multiple(<span class="bool-val">false</span>)))]
<a href=#357 id=357 data-nosnippet>357</a></span><span class="kw">pub struct </span>ObjectStoreConfig {
<a href=#358 id=358 data-nosnippet>358</a> <span class="doccomment">/// Whether to use S3 object store.
<a href=#359 id=359 data-nosnippet>359</a> </span><span class="attr">#[clap(long = <span class="string">"s3"</span>, group = <span class="string">"storage_backend"</span>)]
<a href=#360 id=360 data-nosnippet>360</a> </span><span class="kw">pub </span>enable_s3: bool,
<a href=#361 id=361 data-nosnippet>361</a>
<a href=#362 id=362 data-nosnippet>362</a> <span class="attr">#[clap(flatten)]
<a href=#363 id=363 data-nosnippet>363</a> </span><span class="kw">pub </span>s3: PrefixedS3Connection,
<a href=#364 id=364 data-nosnippet>364</a>
<a href=#365 id=365 data-nosnippet>365</a> <span class="doccomment">/// Whether to use OSS.
<a href=#366 id=366 data-nosnippet>366</a> </span><span class="attr">#[clap(long = <span class="string">"oss"</span>, group = <span class="string">"storage_backend"</span>)]
<a href=#367 id=367 data-nosnippet>367</a> </span><span class="kw">pub </span>enable_oss: bool,
<a href=#368 id=368 data-nosnippet>368</a>
<a href=#369 id=369 data-nosnippet>369</a> <span class="attr">#[clap(flatten)]
<a href=#370 id=370 data-nosnippet>370</a> </span><span class="kw">pub </span>oss: PrefixedOssConnection,
<a href=#371 id=371 data-nosnippet>371</a>
<a href=#372 id=372 data-nosnippet>372</a> <span class="doccomment">/// Whether to use GCS.
<a href=#373 id=373 data-nosnippet>373</a> </span><span class="attr">#[clap(long = <span class="string">"gcs"</span>, group = <span class="string">"storage_backend"</span>)]
<a href=#374 id=374 data-nosnippet>374</a> </span><span class="kw">pub </span>enable_gcs: bool,
<a href=#375 id=375 data-nosnippet>375</a>
<a href=#376 id=376 data-nosnippet>376</a> <span class="attr">#[clap(flatten)]
<a href=#377 id=377 data-nosnippet>377</a> </span><span class="kw">pub </span>gcs: PrefixedGcsConnection,
<a href=#378 id=378 data-nosnippet>378</a>
<a href=#379 id=379 data-nosnippet>379</a> <span class="doccomment">/// Whether to use Azure Blob.
<a href=#380 id=380 data-nosnippet>380</a> </span><span class="attr">#[clap(long = <span class="string">"azblob"</span>, group = <span class="string">"storage_backend"</span>)]
<a href=#381 id=381 data-nosnippet>381</a> </span><span class="kw">pub </span>enable_azblob: bool,
<a href=#382 id=382 data-nosnippet>382</a>
<a href=#383 id=383 data-nosnippet>383</a> <span class="attr">#[clap(flatten)]
<a href=#384 id=384 data-nosnippet>384</a> </span><span class="kw">pub </span>azblob: PrefixedAzblobConnection,
<a href=#385 id=385 data-nosnippet>385</a>}
<a href=#386 id=386 data-nosnippet>386</a>
<a href=#387 id=387 data-nosnippet>387</a><span class="doccomment">/// Creates a new file system object store.
<a href=#388 id=388 data-nosnippet>388</a></span><span class="kw">pub fn </span>new_fs_object_store(root: <span class="kw-2">&amp;</span>str) -&gt; std::result::Result&lt;ObjectStore, BoxedError&gt; {
<a href=#389 id=389 data-nosnippet>389</a> <span class="kw">let </span>builder = Fs::default().root(root);
<a href=#390 id=390 data-nosnippet>390</a> <span class="kw">let </span>object_store = ObjectStore::new(builder)
<a href=#391 id=391 data-nosnippet>391</a> .context(error::InitBackendSnafu)
<a href=#392 id=392 data-nosnippet>392</a> .map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#393 id=393 data-nosnippet>393</a>
<a href=#394 id=394 data-nosnippet>394</a> <span class="prelude-val">Ok</span>(with_instrument_layers(object_store, <span class="bool-val">false</span>))
<a href=#395 id=395 data-nosnippet>395</a>}
<a href=#396 id=396 data-nosnippet>396</a>
<a href=#397 id=397 data-nosnippet>397</a><span class="macro">macro_rules!</span> gen_object_store_builder {
<a href=#398 id=398 data-nosnippet>398</a> (<span class="macro-nonterminal">$method</span>:ident, <span class="macro-nonterminal">$field</span>:ident, <span class="macro-nonterminal">$conn_type</span>:ty, <span class="macro-nonterminal">$service_type</span>:ty) =&gt; {
<a href=#399 id=399 data-nosnippet>399</a> <span class="kw">pub fn </span><span class="macro-nonterminal">$method</span>(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;ObjectStore, BoxedError&gt; {
<a href=#400 id=400 data-nosnippet>400</a> <span class="kw">let </span>config = &lt;<span class="macro-nonterminal">$conn_type</span>&gt;::from(<span class="self">self</span>.<span class="macro-nonterminal">$field</span>.clone());
<a href=#401 id=401 data-nosnippet>401</a> <span class="macro">common_telemetry::info!</span>(
<a href=#402 id=402 data-nosnippet>402</a> <span class="string">"Building object store with {}: {:?}"</span>,
<a href=#403 id=403 data-nosnippet>403</a> <span class="macro">stringify!</span>(<span class="macro-nonterminal">$field</span>),
<a href=#404 id=404 data-nosnippet>404</a> config
<a href=#405 id=405 data-nosnippet>405</a> );
<a href=#406 id=406 data-nosnippet>406</a> <span class="kw">let </span>object_store = ObjectStore::new(&lt;<span class="macro-nonterminal">$service_type</span>&gt;::from(<span class="kw-2">&amp;</span>config))
<a href=#407 id=407 data-nosnippet>407</a> .context(error::InitBackendSnafu)
<a href=#408 id=408 data-nosnippet>408</a> .map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#409 id=409 data-nosnippet>409</a> <span class="prelude-val">Ok</span>(with_instrument_layers(
<a href=#410 id=410 data-nosnippet>410</a> with_retry_layers(object_store),
<a href=#411 id=411 data-nosnippet>411</a> <span class="bool-val">false</span>,
<a href=#412 id=412 data-nosnippet>412</a> ))
<a href=#413 id=413 data-nosnippet>413</a> }
<a href=#414 id=414 data-nosnippet>414</a> };
<a href=#415 id=415 data-nosnippet>415</a>}
<a href=#416 id=416 data-nosnippet>416</a>
<a href=#417 id=417 data-nosnippet>417</a><span class="kw">impl </span>ObjectStoreConfig {
<a href=#418 id=418 data-nosnippet>418</a> <span class="macro">gen_object_store_builder!</span>(build_s3, s3, S3Connection, S3);
<a href=#419 id=419 data-nosnippet>419</a>
<a href=#420 id=420 data-nosnippet>420</a> <span class="macro">gen_object_store_builder!</span>(build_oss, oss, OssConnection, Oss);
<a href=#421 id=421 data-nosnippet>421</a>
<a href=#422 id=422 data-nosnippet>422</a> <span class="macro">gen_object_store_builder!</span>(build_gcs, gcs, GcsConnection, Gcs);
<a href=#423 id=423 data-nosnippet>423</a>
<a href=#424 id=424 data-nosnippet>424</a> <span class="macro">gen_object_store_builder!</span>(build_azblob, azblob, AzblobConnection, Azblob);
<a href=#425 id=425 data-nosnippet>425</a>
<a href=#426 id=426 data-nosnippet>426</a> <span class="kw">pub fn </span>validate(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#427 id=427 data-nosnippet>427</a> <span class="kw">if </span><span class="self">self</span>.enable_s3 {
<a href=#428 id=428 data-nosnippet>428</a> <span class="self">self</span>.s3.validate()<span class="question-mark">?</span>;
<a href=#429 id=429 data-nosnippet>429</a> }
<a href=#430 id=430 data-nosnippet>430</a> <span class="kw">if </span><span class="self">self</span>.enable_oss {
<a href=#431 id=431 data-nosnippet>431</a> <span class="self">self</span>.oss.validate()<span class="question-mark">?</span>;
<a href=#432 id=432 data-nosnippet>432</a> }
<a href=#433 id=433 data-nosnippet>433</a> <span class="kw">if </span><span class="self">self</span>.enable_gcs {
<a href=#434 id=434 data-nosnippet>434</a> <span class="self">self</span>.gcs.validate()<span class="question-mark">?</span>;
<a href=#435 id=435 data-nosnippet>435</a> }
<a href=#436 id=436 data-nosnippet>436</a> <span class="kw">if </span><span class="self">self</span>.enable_azblob {
<a href=#437 id=437 data-nosnippet>437</a> <span class="self">self</span>.azblob.validate()<span class="question-mark">?</span>;
<a href=#438 id=438 data-nosnippet>438</a> }
<a href=#439 id=439 data-nosnippet>439</a> <span class="prelude-val">Ok</span>(())
<a href=#440 id=440 data-nosnippet>440</a> }
<a href=#441 id=441 data-nosnippet>441</a>
<a href=#442 id=442 data-nosnippet>442</a> <span class="doccomment">/// Builds the object store from the config.
<a href=#443 id=443 data-nosnippet>443</a> </span><span class="kw">pub fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;ObjectStore&gt;, BoxedError&gt; {
<a href=#444 id=444 data-nosnippet>444</a> <span class="self">self</span>.validate()<span class="question-mark">?</span>;
<a href=#445 id=445 data-nosnippet>445</a>
<a href=#446 id=446 data-nosnippet>446</a> <span class="kw">if </span><span class="self">self</span>.enable_s3 {
<a href=#447 id=447 data-nosnippet>447</a> <span class="self">self</span>.build_s3().map(<span class="prelude-val">Some</span>)
<a href=#448 id=448 data-nosnippet>448</a> } <span class="kw">else if </span><span class="self">self</span>.enable_oss {
<a href=#449 id=449 data-nosnippet>449</a> <span class="self">self</span>.build_oss().map(<span class="prelude-val">Some</span>)
<a href=#450 id=450 data-nosnippet>450</a> } <span class="kw">else if </span><span class="self">self</span>.enable_gcs {
<a href=#451 id=451 data-nosnippet>451</a> <span class="self">self</span>.build_gcs().map(<span class="prelude-val">Some</span>)
<a href=#452 id=452 data-nosnippet>452</a> } <span class="kw">else if </span><span class="self">self</span>.enable_azblob {
<a href=#453 id=453 data-nosnippet>453</a> <span class="self">self</span>.build_azblob().map(<span class="prelude-val">Some</span>)
<a href=#454 id=454 data-nosnippet>454</a> } <span class="kw">else </span>{
<a href=#455 id=455 data-nosnippet>455</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
<a href=#456 id=456 data-nosnippet>456</a> }
<a href=#457 id=457 data-nosnippet>457</a> }
<a href=#458 id=458 data-nosnippet>458</a>}
</code></pre></div></section></main></body></html>
+226
View File
@@ -0,0 +1,226 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/common/store.rs`."><title>store.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/common/</div>store.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::Arc;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>clap::{Parser, ValueEnum};
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_meta::kv_backend::KvBackendRef;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::kv_backend::chroot::ChrootKvBackend;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_meta::kv_backend::etcd::EtcdStore;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>meta_srv::metasrv::BackendClientOptions;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>meta_srv::utils::etcd::create_etcd_client_with_tls;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>serde::{Deserialize, Serialize};
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>servers::tls::{TlsMode, TlsOption};
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>snafu::OptionExt;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span><span class="kw">crate</span>::error::{EmptyStoreAddrsSnafu, InvalidArgumentsSnafu};
<a href=#29 id=29 data-nosnippet>29</a>
<a href=#30 id=30 data-nosnippet>30</a><span class="comment">// The datastores that implements metadata kvbackend.
<a href=#31 id=31 data-nosnippet>31</a></span><span class="attr">#[derive(Clone, Debug, PartialEq, Serialize, Default, Deserialize, ValueEnum)]
<a href=#32 id=32 data-nosnippet>32</a>#[serde(rename_all = <span class="string">"snake_case"</span>)]
<a href=#33 id=33 data-nosnippet>33</a>#[allow(clippy::enum_variant_names)]
<a href=#34 id=34 data-nosnippet>34</a></span><span class="kw">pub enum </span>BackendImpl {
<a href=#35 id=35 data-nosnippet>35</a> <span class="comment">// Etcd as metadata storage.
<a href=#36 id=36 data-nosnippet>36</a> </span><span class="attr">#[default]
<a href=#37 id=37 data-nosnippet>37</a> </span>EtcdStore,
<a href=#38 id=38 data-nosnippet>38</a> <span class="comment">// In memory metadata storage - mostly used for testing.
<a href=#39 id=39 data-nosnippet>39</a> </span>MemoryStore,
<a href=#40 id=40 data-nosnippet>40</a> <span class="attr">#[cfg(feature = <span class="string">"pg_kvbackend"</span>)]
<a href=#41 id=41 data-nosnippet>41</a> </span><span class="comment">// Postgres as metadata storage.
<a href=#42 id=42 data-nosnippet>42</a> </span>PostgresStore,
<a href=#43 id=43 data-nosnippet>43</a> <span class="attr">#[cfg(feature = <span class="string">"mysql_kvbackend"</span>)]
<a href=#44 id=44 data-nosnippet>44</a> </span><span class="comment">// MySql as metadata storage.
<a href=#45 id=45 data-nosnippet>45</a> </span>MysqlStore,
<a href=#46 id=46 data-nosnippet>46</a> <span class="comment">// RaftEngine as metadata storage.
<a href=#47 id=47 data-nosnippet>47</a> </span>RaftEngineStore,
<a href=#48 id=48 data-nosnippet>48</a>}
<a href=#49 id=49 data-nosnippet>49</a>
<a href=#50 id=50 data-nosnippet>50</a><span class="attr">#[derive(Debug, Default, Parser)]
<a href=#51 id=51 data-nosnippet>51</a></span><span class="kw">pub struct </span>StoreConfig {
<a href=#52 id=52 data-nosnippet>52</a> <span class="doccomment">/// The endpoint of store. one of etcd, postgres or mysql.
<a href=#53 id=53 data-nosnippet>53</a> ///
<a href=#54 id=54 data-nosnippet>54</a> /// For postgres store, the format is:
<a href=#55 id=55 data-nosnippet>55</a> /// "password=password dbname=postgres user=postgres host=localhost port=5432"
<a href=#56 id=56 data-nosnippet>56</a> ///
<a href=#57 id=57 data-nosnippet>57</a> /// For etcd store, the format is:
<a href=#58 id=58 data-nosnippet>58</a> /// "127.0.0.1:2379"
<a href=#59 id=59 data-nosnippet>59</a> ///
<a href=#60 id=60 data-nosnippet>60</a> /// For mysql store, the format is:
<a href=#61 id=61 data-nosnippet>61</a> /// "mysql://user:password@ip:port/dbname"
<a href=#62 id=62 data-nosnippet>62</a> </span><span class="attr">#[clap(long, alias = <span class="string">"store-addr"</span>, value_delimiter = <span class="string">','</span>, num_args = <span class="number">1</span>..)]
<a href=#63 id=63 data-nosnippet>63</a> </span><span class="kw">pub </span>store_addrs: Vec&lt;String&gt;,
<a href=#64 id=64 data-nosnippet>64</a>
<a href=#65 id=65 data-nosnippet>65</a> <span class="doccomment">/// The maximum number of operations in a transaction. Only used when using [etcd-store].
<a href=#66 id=66 data-nosnippet>66</a> </span><span class="attr">#[clap(long, default_value = <span class="string">"128"</span>)]
<a href=#67 id=67 data-nosnippet>67</a> </span><span class="kw">pub </span>max_txn_ops: usize,
<a href=#68 id=68 data-nosnippet>68</a>
<a href=#69 id=69 data-nosnippet>69</a> <span class="doccomment">/// The metadata store backend.
<a href=#70 id=70 data-nosnippet>70</a> </span><span class="attr">#[clap(long, value_enum, default_value = <span class="string">"etcd-store"</span>)]
<a href=#71 id=71 data-nosnippet>71</a> </span><span class="kw">pub </span>backend: BackendImpl,
<a href=#72 id=72 data-nosnippet>72</a>
<a href=#73 id=73 data-nosnippet>73</a> <span class="doccomment">/// The key prefix of the metadata store.
<a href=#74 id=74 data-nosnippet>74</a> </span><span class="attr">#[clap(long, default_value = <span class="string">""</span>)]
<a href=#75 id=75 data-nosnippet>75</a> </span><span class="kw">pub </span>store_key_prefix: String,
<a href=#76 id=76 data-nosnippet>76</a>
<a href=#77 id=77 data-nosnippet>77</a> <span class="doccomment">/// The table name in RDS to store metadata. Only used when using [postgres-store] or [mysql-store].
<a href=#78 id=78 data-nosnippet>78</a> </span><span class="attr">#[cfg(any(feature = <span class="string">"pg_kvbackend"</span>, feature = <span class="string">"mysql_kvbackend"</span>))]
<a href=#79 id=79 data-nosnippet>79</a> #[clap(long, default_value = common_meta::kv_backend::DEFAULT_META_TABLE_NAME)]
<a href=#80 id=80 data-nosnippet>80</a> </span><span class="kw">pub </span>meta_table_name: String,
<a href=#81 id=81 data-nosnippet>81</a>
<a href=#82 id=82 data-nosnippet>82</a> <span class="doccomment">/// Optional PostgreSQL schema for metadata table (defaults to current search_path if unset).
<a href=#83 id=83 data-nosnippet>83</a> </span><span class="attr">#[cfg(feature = <span class="string">"pg_kvbackend"</span>)]
<a href=#84 id=84 data-nosnippet>84</a> #[clap(long)]
<a href=#85 id=85 data-nosnippet>85</a> </span><span class="kw">pub </span>meta_schema_name: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#86 id=86 data-nosnippet>86</a>
<a href=#87 id=87 data-nosnippet>87</a> <span class="doccomment">/// Automatically create PostgreSQL schema if it doesn't exist (default: true).
<a href=#88 id=88 data-nosnippet>88</a> </span><span class="attr">#[cfg(feature = <span class="string">"pg_kvbackend"</span>)]
<a href=#89 id=89 data-nosnippet>89</a> #[clap(long, default_value_t = <span class="bool-val">true</span>)]
<a href=#90 id=90 data-nosnippet>90</a> </span><span class="kw">pub </span>auto_create_schema: bool,
<a href=#91 id=91 data-nosnippet>91</a>
<a href=#92 id=92 data-nosnippet>92</a> <span class="doccomment">/// TLS mode for backend store connections (etcd, PostgreSQL, MySQL)
<a href=#93 id=93 data-nosnippet>93</a> </span><span class="attr">#[clap(long = <span class="string">"backend-tls-mode"</span>, value_enum, default_value = <span class="string">"disable"</span>)]
<a href=#94 id=94 data-nosnippet>94</a> </span><span class="kw">pub </span>backend_tls_mode: TlsMode,
<a href=#95 id=95 data-nosnippet>95</a>
<a href=#96 id=96 data-nosnippet>96</a> <span class="doccomment">/// Path to TLS certificate file for backend store connections
<a href=#97 id=97 data-nosnippet>97</a> </span><span class="attr">#[clap(long = <span class="string">"backend-tls-cert-path"</span>, default_value = <span class="string">""</span>)]
<a href=#98 id=98 data-nosnippet>98</a> </span><span class="kw">pub </span>backend_tls_cert_path: String,
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> <span class="doccomment">/// Path to TLS private key file for backend store connections
<a href=#101 id=101 data-nosnippet>101</a> </span><span class="attr">#[clap(long = <span class="string">"backend-tls-key-path"</span>, default_value = <span class="string">""</span>)]
<a href=#102 id=102 data-nosnippet>102</a> </span><span class="kw">pub </span>backend_tls_key_path: String,
<a href=#103 id=103 data-nosnippet>103</a>
<a href=#104 id=104 data-nosnippet>104</a> <span class="doccomment">/// Path to TLS CA certificate file for backend store connections
<a href=#105 id=105 data-nosnippet>105</a> </span><span class="attr">#[clap(long = <span class="string">"backend-tls-ca-cert-path"</span>, default_value = <span class="string">""</span>)]
<a href=#106 id=106 data-nosnippet>106</a> </span><span class="kw">pub </span>backend_tls_ca_cert_path: String,
<a href=#107 id=107 data-nosnippet>107</a>
<a href=#108 id=108 data-nosnippet>108</a> <span class="doccomment">/// Enable watching TLS certificate files for changes
<a href=#109 id=109 data-nosnippet>109</a> </span><span class="attr">#[clap(long = <span class="string">"backend-tls-watch"</span>)]
<a href=#110 id=110 data-nosnippet>110</a> </span><span class="kw">pub </span>backend_tls_watch: bool,
<a href=#111 id=111 data-nosnippet>111</a>}
<a href=#112 id=112 data-nosnippet>112</a>
<a href=#113 id=113 data-nosnippet>113</a><span class="kw">impl </span>StoreConfig {
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">pub fn </span>tls_config(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Option</span>&lt;TlsOption&gt; {
<a href=#115 id=115 data-nosnippet>115</a> <span class="kw">if </span><span class="self">self</span>.backend_tls_mode != TlsMode::Disable {
<a href=#116 id=116 data-nosnippet>116</a> <span class="prelude-val">Some</span>(TlsOption {
<a href=#117 id=117 data-nosnippet>117</a> mode: <span class="self">self</span>.backend_tls_mode,
<a href=#118 id=118 data-nosnippet>118</a> cert_path: <span class="self">self</span>.backend_tls_cert_path.clone(),
<a href=#119 id=119 data-nosnippet>119</a> key_path: <span class="self">self</span>.backend_tls_key_path.clone(),
<a href=#120 id=120 data-nosnippet>120</a> ca_cert_path: <span class="self">self</span>.backend_tls_ca_cert_path.clone(),
<a href=#121 id=121 data-nosnippet>121</a> watch: <span class="self">self</span>.backend_tls_watch,
<a href=#122 id=122 data-nosnippet>122</a> })
<a href=#123 id=123 data-nosnippet>123</a> } <span class="kw">else </span>{
<a href=#124 id=124 data-nosnippet>124</a> <span class="prelude-val">None
<a href=#125 id=125 data-nosnippet>125</a> </span>}
<a href=#126 id=126 data-nosnippet>126</a> }
<a href=#127 id=127 data-nosnippet>127</a>
<a href=#128 id=128 data-nosnippet>128</a> <span class="doccomment">/// Sanitize store addrs for logging (redacts passwords in connection strings).
<a href=#129 id=129 data-nosnippet>129</a> </span><span class="kw">fn </span>sanitize_store_addrs(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Vec&lt;String&gt; {
<a href=#130 id=130 data-nosnippet>130</a> <span class="self">self</span>.store_addrs
<a href=#131 id=131 data-nosnippet>131</a> .iter()
<a href=#132 id=132 data-nosnippet>132</a> .map(|addr| common_meta::kv_backend::util::sanitize_connection_string(addr))
<a href=#133 id=133 data-nosnippet>133</a> .collect()
<a href=#134 id=134 data-nosnippet>134</a> }
<a href=#135 id=135 data-nosnippet>135</a>
<a href=#136 id=136 data-nosnippet>136</a> <span class="doccomment">/// Builds a [`KvBackendRef`] from the store configuration.
<a href=#137 id=137 data-nosnippet>137</a> </span><span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;KvBackendRef, BoxedError&gt; {
<a href=#138 id=138 data-nosnippet>138</a> <span class="kw">let </span>max_txn_ops = <span class="self">self</span>.max_txn_ops;
<a href=#139 id=139 data-nosnippet>139</a> <span class="kw">let </span>store_addrs = <span class="kw-2">&amp;</span><span class="self">self</span>.store_addrs;
<a href=#140 id=140 data-nosnippet>140</a> <span class="kw">if </span>store_addrs.is_empty() {
<a href=#141 id=141 data-nosnippet>141</a> EmptyStoreAddrsSnafu.fail().map_err(BoxedError::new)
<a href=#142 id=142 data-nosnippet>142</a> } <span class="kw">else </span>{
<a href=#143 id=143 data-nosnippet>143</a> <span class="macro">common_telemetry::info!</span>(
<a href=#144 id=144 data-nosnippet>144</a> <span class="string">"Building kvbackend with store addrs: {:?}, backend: {:?}"</span>,
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw-2">&amp;</span><span class="self">self</span>.sanitize_store_addrs(),
<a href=#146 id=146 data-nosnippet>146</a> <span class="self">self</span>.backend
<a href=#147 id=147 data-nosnippet>147</a> );
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">let </span>kvbackend = <span class="kw">match </span><span class="self">self</span>.backend {
<a href=#149 id=149 data-nosnippet>149</a> BackendImpl::EtcdStore =&gt; {
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">let </span>tls_config = <span class="self">self</span>.tls_config();
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">let </span>etcd_client = create_etcd_client_with_tls(
<a href=#152 id=152 data-nosnippet>152</a> store_addrs,
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw-2">&amp;</span>BackendClientOptions::default(),
<a href=#154 id=154 data-nosnippet>154</a> tls_config.as_ref(),
<a href=#155 id=155 data-nosnippet>155</a> )
<a href=#156 id=156 data-nosnippet>156</a> .<span class="kw">await
<a href=#157 id=157 data-nosnippet>157</a> </span>.map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#158 id=158 data-nosnippet>158</a> <span class="prelude-val">Ok</span>(EtcdStore::with_etcd_client(etcd_client, max_txn_ops))
<a href=#159 id=159 data-nosnippet>159</a> }
<a href=#160 id=160 data-nosnippet>160</a> <span class="attr">#[cfg(feature = <span class="string">"pg_kvbackend"</span>)]
<a href=#161 id=161 data-nosnippet>161</a> </span>BackendImpl::PostgresStore =&gt; {
<a href=#162 id=162 data-nosnippet>162</a> <span class="kw">let </span>table_name = <span class="kw-2">&amp;</span><span class="self">self</span>.meta_table_name;
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">let </span>tls_config = <span class="self">self</span>.tls_config();
<a href=#164 id=164 data-nosnippet>164</a> <span class="prelude-val">Ok</span>(meta_srv::utils::postgres::build_postgres_kv_backend(
<a href=#165 id=165 data-nosnippet>165</a> store_addrs,
<a href=#166 id=166 data-nosnippet>166</a> <span class="prelude-val">None</span>,
<a href=#167 id=167 data-nosnippet>167</a> tls_config,
<a href=#168 id=168 data-nosnippet>168</a> <span class="self">self</span>.meta_schema_name.as_deref(),
<a href=#169 id=169 data-nosnippet>169</a> table_name,
<a href=#170 id=170 data-nosnippet>170</a> max_txn_ops,
<a href=#171 id=171 data-nosnippet>171</a> <span class="self">self</span>.auto_create_schema,
<a href=#172 id=172 data-nosnippet>172</a> )
<a href=#173 id=173 data-nosnippet>173</a> .<span class="kw">await
<a href=#174 id=174 data-nosnippet>174</a> </span>.map_err(BoxedError::new)<span class="question-mark">?</span>)
<a href=#175 id=175 data-nosnippet>175</a> }
<a href=#176 id=176 data-nosnippet>176</a> <span class="attr">#[cfg(feature = <span class="string">"mysql_kvbackend"</span>)]
<a href=#177 id=177 data-nosnippet>177</a> </span>BackendImpl::MysqlStore =&gt; {
<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">let </span>table_name = <span class="kw-2">&amp;</span><span class="self">self</span>.meta_table_name;
<a href=#179 id=179 data-nosnippet>179</a> <span class="kw">let </span>tls_config = <span class="self">self</span>.tls_config();
<a href=#180 id=180 data-nosnippet>180</a> <span class="prelude-val">Ok</span>(meta_srv::utils::mysql::build_mysql_kv_backend(
<a href=#181 id=181 data-nosnippet>181</a> store_addrs,
<a href=#182 id=182 data-nosnippet>182</a> tls_config.as_ref(),
<a href=#183 id=183 data-nosnippet>183</a> table_name,
<a href=#184 id=184 data-nosnippet>184</a> max_txn_ops,
<a href=#185 id=185 data-nosnippet>185</a> )
<a href=#186 id=186 data-nosnippet>186</a> .<span class="kw">await
<a href=#187 id=187 data-nosnippet>187</a> </span>.map_err(BoxedError::new)<span class="question-mark">?</span>)
<a href=#188 id=188 data-nosnippet>188</a> }
<a href=#189 id=189 data-nosnippet>189</a> <span class="attr">#[cfg(not(test))]
<a href=#190 id=190 data-nosnippet>190</a> </span>BackendImpl::MemoryStore =&gt; {
<a href=#191 id=191 data-nosnippet>191</a> <span class="kw">use </span><span class="kw">crate</span>::error::UnsupportedMemoryBackendSnafu;
<a href=#192 id=192 data-nosnippet>192</a>
<a href=#193 id=193 data-nosnippet>193</a> UnsupportedMemoryBackendSnafu
<a href=#194 id=194 data-nosnippet>194</a> .fail()
<a href=#195 id=195 data-nosnippet>195</a> .map_err(BoxedError::new)
<a href=#196 id=196 data-nosnippet>196</a> }
<a href=#197 id=197 data-nosnippet>197</a> <span class="attr">#[cfg(test)]
<a href=#198 id=198 data-nosnippet>198</a> </span>BackendImpl::MemoryStore =&gt; {
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">use </span>common_meta::kv_backend::memory::MemoryKvBackend;
<a href=#200 id=200 data-nosnippet>200</a>
<a href=#201 id=201 data-nosnippet>201</a> <span class="prelude-val">Ok</span>(Arc::new(MemoryKvBackend::default()) <span class="kw">as _</span>)
<a href=#202 id=202 data-nosnippet>202</a> }
<a href=#203 id=203 data-nosnippet>203</a> BackendImpl::RaftEngineStore =&gt; {
<a href=#204 id=204 data-nosnippet>204</a> <span class="kw">let </span>url = store_addrs
<a href=#205 id=205 data-nosnippet>205</a> .first()
<a href=#206 id=206 data-nosnippet>206</a> .context(InvalidArgumentsSnafu {
<a href=#207 id=207 data-nosnippet>207</a> msg: <span class="string">"empty store addresses"</span>.to_string(),
<a href=#208 id=208 data-nosnippet>208</a> })
<a href=#209 id=209 data-nosnippet>209</a> .map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">let </span>kvbackend =
<a href=#211 id=211 data-nosnippet>211</a> standalone::build_metadata_kv_from_url(url).map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#212 id=212 data-nosnippet>212</a>
<a href=#213 id=213 data-nosnippet>213</a> <span class="prelude-val">Ok</span>(kvbackend)
<a href=#214 id=214 data-nosnippet>214</a> }
<a href=#215 id=215 data-nosnippet>215</a> };
<a href=#216 id=216 data-nosnippet>216</a> <span class="kw">if </span><span class="self">self</span>.store_key_prefix.is_empty() {
<a href=#217 id=217 data-nosnippet>217</a> kvbackend
<a href=#218 id=218 data-nosnippet>218</a> } <span class="kw">else </span>{
<a href=#219 id=219 data-nosnippet>219</a> <span class="kw">let </span>chroot_kvbackend =
<a href=#220 id=220 data-nosnippet>220</a> ChrootKvBackend::new(<span class="self">self</span>.store_key_prefix.as_bytes().to_vec(), kvbackend<span class="question-mark">?</span>);
<a href=#221 id=221 data-nosnippet>221</a> <span class="prelude-val">Ok</span>(Arc::new(chroot_kvbackend))
<a href=#222 id=222 data-nosnippet>222</a> }
<a href=#223 id=223 data-nosnippet>223</a> }
<a href=#224 id=224 data-nosnippet>224</a> }
<a href=#225 id=225 data-nosnippet>225</a>}
</code></pre></div></section></main></body></html>
+66
View File
@@ -0,0 +1,66 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data.rs`."><title>data.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/</div>data.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">mod </span>export;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">pub mod </span>export_v2;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">mod </span>import;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">pub mod </span>import_v2;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">mod </span>path;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">mod </span>progress;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">mod </span>schema_export;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">pub mod </span>snapshot_storage;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">mod </span>sql;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">mod </span>storage_export;
<a href=#25 id=25 data-nosnippet>25</a>
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>clap::Subcommand;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>client::DEFAULT_CATALOG_NAME;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#29 id=29 data-nosnippet>29</a>
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span><span class="kw">crate</span>::Tool;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span><span class="kw">crate</span>::data::export::ExportCommand;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::ExportV2Command;
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">use </span><span class="kw">crate</span>::data::import::ImportCommand;
<a href=#34 id=34 data-nosnippet>34</a><span class="kw">use </span><span class="kw">crate</span>::data::import_v2::ImportV2Command;
<a href=#35 id=35 data-nosnippet>35</a>
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>COPY_PATH_PLACEHOLDER: <span class="kw-2">&amp;</span>str = <span class="string">"&lt;PATH/TO/FILES&gt;"</span>;
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a><span class="doccomment">/// Command for data operations including exporting data from and importing data into GreptimeDB.
<a href=#39 id=39 data-nosnippet>39</a></span><span class="attr">#[derive(Subcommand)]
<a href=#40 id=40 data-nosnippet>40</a></span><span class="kw">pub enum </span>DataCommand {
<a href=#41 id=41 data-nosnippet>41</a> <span class="doccomment">/// Export data (V1 - legacy).
<a href=#42 id=42 data-nosnippet>42</a> </span>Export(ExportCommand),
<a href=#43 id=43 data-nosnippet>43</a> <span class="doccomment">/// Import data (V1 - legacy).
<a href=#44 id=44 data-nosnippet>44</a> </span>Import(ImportCommand),
<a href=#45 id=45 data-nosnippet>45</a> <span class="doccomment">/// Export V2 - JSON-based schema export with manifest support.
<a href=#46 id=46 data-nosnippet>46</a> </span><span class="attr">#[clap(subcommand)]
<a href=#47 id=47 data-nosnippet>47</a> </span>ExportV2(ExportV2Command),
<a href=#48 id=48 data-nosnippet>48</a> <span class="doccomment">/// Import V2 - Import from V2 snapshot.
<a href=#49 id=49 data-nosnippet>49</a> </span>ImportV2(ImportV2Command),
<a href=#50 id=50 data-nosnippet>50</a>}
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">impl </span>DataCommand {
<a href=#53 id=53 data-nosnippet>53</a> <span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt; {
<a href=#54 id=54 data-nosnippet>54</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#55 id=55 data-nosnippet>55</a> DataCommand::Export(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#56 id=56 data-nosnippet>56</a> DataCommand::Import(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#57 id=57 data-nosnippet>57</a> DataCommand::ExportV2(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#58 id=58 data-nosnippet>58</a> DataCommand::ImportV2(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#59 id=59 data-nosnippet>59</a> }
<a href=#60 id=60 data-nosnippet>60</a> }
<a href=#61 id=61 data-nosnippet>61</a>}
<a href=#62 id=62 data-nosnippet>62</a>
<a href=#63 id=63 data-nosnippet>63</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>default_database() -&gt; String {
<a href=#64 id=64 data-nosnippet>64</a> <span class="macro">format!</span>(<span class="string">"{DEFAULT_CATALOG_NAME}-*"</span>)
<a href=#65 id=65 data-nosnippet>65</a>}
</code></pre></div></section></main></body></html>
File diff suppressed because it is too large Load Diff
+64
View File
@@ -0,0 +1,64 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/export_v2.rs`."><title>export_v2.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/</div>export_v2.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! Export V2 module.
<a href=#16 id=16 data-nosnippet>16</a>//!
<a href=#17 id=17 data-nosnippet>17</a>//! This module provides the V2 implementation of database export functionality,
<a href=#18 id=18 data-nosnippet>18</a>//! featuring:
<a href=#19 id=19 data-nosnippet>19</a>//! - JSON-based schema export (version-agnostic)
<a href=#20 id=20 data-nosnippet>20</a>//! - Manifest-based snapshot management
<a href=#21 id=21 data-nosnippet>21</a>//! - Support for multiple storage backends (S3, OSS, GCS, Azure Blob, local FS)
<a href=#22 id=22 data-nosnippet>22</a>//! - Resume capability for interrupted exports
<a href=#23 id=23 data-nosnippet>23</a>//!
<a href=#24 id=24 data-nosnippet>24</a>//! # Example
<a href=#25 id=25 data-nosnippet>25</a>//!
<a href=#26 id=26 data-nosnippet>26</a>//! ```bash
<a href=#27 id=27 data-nosnippet>27</a>//! # Export schema only
<a href=#28 id=28 data-nosnippet>28</a>//! greptime cli data export-v2 create \
<a href=#29 id=29 data-nosnippet>29</a>//! --addr 127.0.0.1:4000 \
<a href=#30 id=30 data-nosnippet>30</a>//! --to file:///tmp/snapshot \
<a href=#31 id=31 data-nosnippet>31</a>//! --schema-only
<a href=#32 id=32 data-nosnippet>32</a>//!
<a href=#33 id=33 data-nosnippet>33</a>//! # Export with time range
<a href=#34 id=34 data-nosnippet>34</a>//! greptime cli data export-v2 create \
<a href=#35 id=35 data-nosnippet>35</a>//! --addr 127.0.0.1:4000 \
<a href=#36 id=36 data-nosnippet>36</a>//! --to s3://bucket/snapshots/prod-20250101 \
<a href=#37 id=37 data-nosnippet>37</a>//! --start-time 2025-01-01T00:00:00Z \
<a href=#38 id=38 data-nosnippet>38</a>//! --end-time 2025-01-31T23:59:59Z
<a href=#39 id=39 data-nosnippet>39</a>//! ```
<a href=#40 id=40 data-nosnippet>40</a>//!
<a href=#41 id=41 data-nosnippet>41</a>//! `--experimental-metric-export` enables shared Metric physical scans for Parquet.
<a href=#42 id=42 data-nosnippet>42</a>//! Enable `experimental_metric_export = true` on the frontend or standalone server
<a href=#43 id=43 data-nosnippet>43</a>//! and use an endpoint whose frontends all support and enable this option.
<a href=#44 id=44 data-nosnippet>44</a>//! Add `--metric-data-layout packed` to write version-2 packed snapshots.
<a href=#45 id=45 data-nosnippet>45</a>//! This requires the server packed-export capability; schema-only exports remain version 1.
<a href=#46 id=46 data-nosnippet>46</a>//! The command checks the server capability before modifying the snapshot.
<a href=#47 id=47 data-nosnippet>47</a>//! Each snapshot path belongs to one export task. Resume requires stable source
<a href=#48 id=48 data-nosnippet>48</a>//! schemas/data and confirmation that the previous export and storage writes ended;
<a href=#49 id=49 data-nosnippet>49</a>//! an HTTP timeout does not establish that. Only unfinished chunks are cleaned and
<a href=#50 id=50 data-nosnippet>50</a>//! rerun. Resume retains the snapshot version/layout and completed chunks.
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a></span><span class="kw">mod </span>chunker;
<a href=#53 id=53 data-nosnippet>53</a><span class="kw">mod </span>command;
<a href=#54 id=54 data-nosnippet>54</a><span class="kw">mod </span>coordinator;
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">mod </span>data;
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">pub mod </span>error;
<a href=#57 id=57 data-nosnippet>57</a><span class="kw">pub mod </span>extractor;
<a href=#58 id=58 data-nosnippet>58</a><span class="kw">pub mod </span>manifest;
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">pub mod </span>schema;
<a href=#60 id=60 data-nosnippet>60</a><span class="kw">pub use </span>command::ExportV2Command;
<a href=#61 id=61 data-nosnippet>61</a>
<a href=#62 id=62 data-nosnippet>62</a><span class="attr">#[cfg(test)]
<a href=#63 id=63 data-nosnippet>63</a></span><span class="kw">mod </span>tests;
</code></pre></div></section></main></body></html>
+104
View File
@@ -0,0 +1,104 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/export_v2/chunker.rs`."><title>chunker.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/export_v2/</div>chunker.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::time::Duration;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>chrono::Duration <span class="kw">as </span>ChronoDuration;
<a href=#18 id=18 data-nosnippet>18</a>
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::manifest::{ChunkMeta, TimeRange};
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">pub fn </span>generate_chunks(time_range: <span class="kw-2">&amp;</span>TimeRange, window: Duration) -&gt; Vec&lt;ChunkMeta&gt; {
<a href=#22 id=22 data-nosnippet>22</a> <span class="kw">let </span>(<span class="prelude-val">Some</span>(start), <span class="prelude-val">Some</span>(end)) = (time_range.start, time_range.end) <span class="kw">else </span>{
<a href=#23 id=23 data-nosnippet>23</a> <span class="kw">return </span><span class="macro">vec!</span>[ChunkMeta::new(<span class="number">1</span>, time_range.clone())];
<a href=#24 id=24 data-nosnippet>24</a> };
<a href=#25 id=25 data-nosnippet>25</a>
<a href=#26 id=26 data-nosnippet>26</a> <span class="kw">if </span>start == end {
<a href=#27 id=27 data-nosnippet>27</a> <span class="kw">return </span><span class="macro">vec!</span>[ChunkMeta::skipped(<span class="number">1</span>, time_range.clone())];
<a href=#28 id=28 data-nosnippet>28</a> }
<a href=#29 id=29 data-nosnippet>29</a>
<a href=#30 id=30 data-nosnippet>30</a> <span class="kw">if </span>start &gt; end {
<a href=#31 id=31 data-nosnippet>31</a> <span class="kw">return </span>Vec::new();
<a href=#32 id=32 data-nosnippet>32</a> }
<a href=#33 id=33 data-nosnippet>33</a>
<a href=#34 id=34 data-nosnippet>34</a> <span class="kw">let </span>window = <span class="kw">match </span>ChronoDuration::from_std(window) {
<a href=#35 id=35 data-nosnippet>35</a> <span class="prelude-val">Ok</span>(window) <span class="kw">if </span>window &gt; ChronoDuration::zero() =&gt; window,
<a href=#36 id=36 data-nosnippet>36</a> <span class="kw">_ </span>=&gt; <span class="kw">return </span><span class="macro">vec!</span>[ChunkMeta::new(<span class="number">1</span>, time_range.clone())],
<a href=#37 id=37 data-nosnippet>37</a> };
<a href=#38 id=38 data-nosnippet>38</a>
<a href=#39 id=39 data-nosnippet>39</a> <span class="kw">let </span><span class="kw-2">mut </span>chunks = Vec::new();
<a href=#40 id=40 data-nosnippet>40</a> <span class="kw">let </span><span class="kw-2">mut </span>cursor = start;
<a href=#41 id=41 data-nosnippet>41</a> <span class="kw">let </span><span class="kw-2">mut </span>id = <span class="number">1</span>;
<a href=#42 id=42 data-nosnippet>42</a>
<a href=#43 id=43 data-nosnippet>43</a> <span class="kw">while </span>cursor &lt; end {
<a href=#44 id=44 data-nosnippet>44</a> <span class="kw">let </span>next = cursor
<a href=#45 id=45 data-nosnippet>45</a> .checked_add_signed(window)
<a href=#46 id=46 data-nosnippet>46</a> .map_or(end, |timestamp| timestamp.min(end));
<a href=#47 id=47 data-nosnippet>47</a> chunks.push(ChunkMeta::new(id, TimeRange::new(<span class="prelude-val">Some</span>(cursor), <span class="prelude-val">Some</span>(next))));
<a href=#48 id=48 data-nosnippet>48</a> id += <span class="number">1</span>;
<a href=#49 id=49 data-nosnippet>49</a> cursor = next;
<a href=#50 id=50 data-nosnippet>50</a> }
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a> chunks
<a href=#53 id=53 data-nosnippet>53</a>}
<a href=#54 id=54 data-nosnippet>54</a>
<a href=#55 id=55 data-nosnippet>55</a><span class="attr">#[cfg(test)]
<a href=#56 id=56 data-nosnippet>56</a></span><span class="kw">mod </span>tests {
<a href=#57 id=57 data-nosnippet>57</a> <span class="kw">use </span>chrono::{TimeZone, Utc};
<a href=#58 id=58 data-nosnippet>58</a>
<a href=#59 id=59 data-nosnippet>59</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#60 id=60 data-nosnippet>60</a> <span class="kw">use </span><span class="kw">crate</span>::data::export_v2::manifest::ChunkStatus;
<a href=#61 id=61 data-nosnippet>61</a>
<a href=#62 id=62 data-nosnippet>62</a> <span class="attr">#[test]
<a href=#63 id=63 data-nosnippet>63</a> </span><span class="kw">fn </span>test_generate_chunks_unbounded() {
<a href=#64 id=64 data-nosnippet>64</a> <span class="kw">let </span>range = TimeRange::unbounded();
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">let </span>chunks = generate_chunks(<span class="kw-2">&amp;</span>range, Duration::from_secs(<span class="number">3600</span>));
<a href=#66 id=66 data-nosnippet>66</a> <span class="macro">assert_eq!</span>(chunks.len(), <span class="number">1</span>);
<a href=#67 id=67 data-nosnippet>67</a> <span class="macro">assert_eq!</span>(chunks[<span class="number">0</span>].time_range, range);
<a href=#68 id=68 data-nosnippet>68</a> }
<a href=#69 id=69 data-nosnippet>69</a>
<a href=#70 id=70 data-nosnippet>70</a> <span class="attr">#[test]
<a href=#71 id=71 data-nosnippet>71</a> </span><span class="kw">fn </span>test_generate_chunks_split() {
<a href=#72 id=72 data-nosnippet>72</a> <span class="kw">let </span>start = Utc.with_ymd_and_hms(<span class="number">2025</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>).unwrap();
<a href=#73 id=73 data-nosnippet>73</a> <span class="kw">let </span>end = Utc.with_ymd_and_hms(<span class="number">2025</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">3</span>, <span class="number">0</span>, <span class="number">0</span>).unwrap();
<a href=#74 id=74 data-nosnippet>74</a> <span class="kw">let </span>range = TimeRange::new(<span class="prelude-val">Some</span>(start), <span class="prelude-val">Some</span>(end));
<a href=#75 id=75 data-nosnippet>75</a>
<a href=#76 id=76 data-nosnippet>76</a> <span class="kw">let </span>chunks = generate_chunks(<span class="kw-2">&amp;</span>range, Duration::from_secs(<span class="number">3600</span>));
<a href=#77 id=77 data-nosnippet>77</a> <span class="macro">assert_eq!</span>(chunks.len(), <span class="number">3</span>);
<a href=#78 id=78 data-nosnippet>78</a> <span class="macro">assert_eq!</span>(chunks[<span class="number">0</span>].time_range.start, <span class="prelude-val">Some</span>(start));
<a href=#79 id=79 data-nosnippet>79</a> <span class="macro">assert_eq!</span>(
<a href=#80 id=80 data-nosnippet>80</a> chunks[<span class="number">2</span>].time_range.end,
<a href=#81 id=81 data-nosnippet>81</a> <span class="prelude-val">Some</span>(Utc.with_ymd_and_hms(<span class="number">2025</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">3</span>, <span class="number">0</span>, <span class="number">0</span>).unwrap())
<a href=#82 id=82 data-nosnippet>82</a> );
<a href=#83 id=83 data-nosnippet>83</a> }
<a href=#84 id=84 data-nosnippet>84</a>
<a href=#85 id=85 data-nosnippet>85</a> <span class="attr">#[test]
<a href=#86 id=86 data-nosnippet>86</a> </span><span class="kw">fn </span>test_generate_chunks_empty_range() {
<a href=#87 id=87 data-nosnippet>87</a> <span class="kw">let </span>start = Utc.with_ymd_and_hms(<span class="number">2025</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>).unwrap();
<a href=#88 id=88 data-nosnippet>88</a> <span class="kw">let </span>range = TimeRange::new(<span class="prelude-val">Some</span>(start), <span class="prelude-val">Some</span>(start));
<a href=#89 id=89 data-nosnippet>89</a> <span class="kw">let </span>chunks = generate_chunks(<span class="kw-2">&amp;</span>range, Duration::from_secs(<span class="number">3600</span>));
<a href=#90 id=90 data-nosnippet>90</a> <span class="macro">assert_eq!</span>(chunks.len(), <span class="number">1</span>);
<a href=#91 id=91 data-nosnippet>91</a> <span class="macro">assert_eq!</span>(chunks[<span class="number">0</span>].status, ChunkStatus::Skipped);
<a href=#92 id=92 data-nosnippet>92</a> <span class="macro">assert_eq!</span>(chunks[<span class="number">0</span>].time_range, range);
<a href=#93 id=93 data-nosnippet>93</a> }
<a href=#94 id=94 data-nosnippet>94</a>
<a href=#95 id=95 data-nosnippet>95</a> <span class="attr">#[test]
<a href=#96 id=96 data-nosnippet>96</a> </span><span class="kw">fn </span>test_generate_chunks_invalid_range_is_empty() {
<a href=#97 id=97 data-nosnippet>97</a> <span class="kw">let </span>start = Utc.with_ymd_and_hms(<span class="number">2025</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>).unwrap();
<a href=#98 id=98 data-nosnippet>98</a> <span class="kw">let </span>end = Utc.with_ymd_and_hms(<span class="number">2025</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>).unwrap();
<a href=#99 id=99 data-nosnippet>99</a> <span class="kw">let </span>range = TimeRange::new(<span class="prelude-val">Some</span>(start), <span class="prelude-val">Some</span>(end));
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">let </span>chunks = generate_chunks(<span class="kw-2">&amp;</span>range, Duration::from_secs(<span class="number">3600</span>));
<a href=#101 id=101 data-nosnippet>101</a> <span class="macro">assert!</span>(chunks.is_empty());
<a href=#102 id=102 data-nosnippet>102</a> }
<a href=#103 id=103 data-nosnippet>103</a>}
</code></pre></div></section></main></body></html>
File diff suppressed because it is too large Load Diff
+689
View File
@@ -0,0 +1,689 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/export_v2/coordinator.rs`."><title>coordinator.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/export_v2/</div>coordinator.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>common_telemetry::{error, info};
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>futures::StreamExt;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>futures::stream::FuturesUnordered;
<a href=#18 id=18 data-nosnippet>18</a>
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span><span class="kw">crate</span>::common::ObjectStoreConfig;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::data::{CopyOptions, build_copy_target, execute_copy_database};
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::error::{Error, <span class="prelude-ty">Result</span>};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::manifest::{ChunkStatus, DataFormat, Manifest, TimeRange};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span><span class="kw">crate</span>::data::path::data_dir_for_schema_chunk;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span><span class="kw">crate</span>::data::progress::{ProgressPhase, ProgressReporter};
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span><span class="kw">crate</span>::data::snapshot_storage::{SnapshotStorage, StorageScheme};
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span><span class="kw">crate</span>::database::DatabaseClient;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="doccomment">/// Owned, manifest-independent context shared by all chunk export futures.
<a href=#29 id=29 data-nosnippet>29</a>///
<a href=#30 id=30 data-nosnippet>30</a>/// `catalog`/`schemas`/`format` are cloned from the manifest up front so the
<a href=#31 id=31 data-nosnippet>31</a>/// export futures never borrow the manifest, leaving the coordinator free to
<a href=#32 id=32 data-nosnippet>32</a>/// mutate and persist it while chunks are in flight.
<a href=#33 id=33 data-nosnippet>33</a></span><span class="kw">struct </span>ExportContext&lt;<span class="lifetime">'a</span>&gt; {
<a href=#34 id=34 data-nosnippet>34</a> storage: <span class="kw-2">&amp;</span><span class="lifetime">'a </span><span class="kw">dyn </span>SnapshotStorage,
<a href=#35 id=35 data-nosnippet>35</a> database_client: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>DatabaseClient,
<a href=#36 id=36 data-nosnippet>36</a> snapshot_uri: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str,
<a href=#37 id=37 data-nosnippet>37</a> storage_config: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>ObjectStoreConfig,
<a href=#38 id=38 data-nosnippet>38</a> catalog: String,
<a href=#39 id=39 data-nosnippet>39</a> schemas: Vec&lt;String&gt;,
<a href=#40 id=40 data-nosnippet>40</a> format: DataFormat,
<a href=#41 id=41 data-nosnippet>41</a> parallelism: usize,
<a href=#42 id=42 data-nosnippet>42</a> experimental_metric_export: bool,
<a href=#43 id=43 data-nosnippet>43</a> packed: bool,
<a href=#44 id=44 data-nosnippet>44</a> resume: bool,
<a href=#45 id=45 data-nosnippet>45</a>}
<a href=#46 id=46 data-nosnippet>46</a>
<a href=#47 id=47 data-nosnippet>47</a><span class="kw">pub struct </span>ExportDataOptions&lt;<span class="lifetime">'a</span>&gt; {
<a href=#48 id=48 data-nosnippet>48</a> <span class="kw">pub </span>snapshot_uri: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str,
<a href=#49 id=49 data-nosnippet>49</a> <span class="kw">pub </span>storage_config: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>ObjectStoreConfig,
<a href=#50 id=50 data-nosnippet>50</a> <span class="kw">pub </span>parallelism: usize,
<a href=#51 id=51 data-nosnippet>51</a> <span class="kw">pub </span>chunk_parallelism: usize,
<a href=#52 id=52 data-nosnippet>52</a> <span class="kw">pub </span>experimental_metric_export: bool,
<a href=#53 id=53 data-nosnippet>53</a> <span class="kw">pub </span>resume: bool,
<a href=#54 id=54 data-nosnippet>54</a>}
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">pub async fn </span>export_data(
<a href=#57 id=57 data-nosnippet>57</a> storage: <span class="kw-2">&amp;</span><span class="kw">dyn </span>SnapshotStorage,
<a href=#58 id=58 data-nosnippet>58</a> database_client: <span class="kw-2">&amp;</span>DatabaseClient,
<a href=#59 id=59 data-nosnippet>59</a> manifest: <span class="kw-2">&amp;mut </span>Manifest,
<a href=#60 id=60 data-nosnippet>60</a> options: ExportDataOptions&lt;<span class="lifetime">'_</span>&gt;,
<a href=#61 id=61 data-nosnippet>61</a> progress: <span class="kw-2">&amp;</span><span class="kw">dyn </span>ProgressReporter,
<a href=#62 id=62 data-nosnippet>62</a>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#63 id=63 data-nosnippet>63</a> <span class="kw">if </span>manifest.chunks.is_empty() {
<a href=#64 id=64 data-nosnippet>64</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#65 id=65 data-nosnippet>65</a> }
<a href=#66 id=66 data-nosnippet>66</a>
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">let </span>context = ExportContext {
<a href=#68 id=68 data-nosnippet>68</a> storage,
<a href=#69 id=69 data-nosnippet>69</a> database_client,
<a href=#70 id=70 data-nosnippet>70</a> snapshot_uri: options.snapshot_uri,
<a href=#71 id=71 data-nosnippet>71</a> storage_config: options.storage_config,
<a href=#72 id=72 data-nosnippet>72</a> catalog: manifest.catalog.clone(),
<a href=#73 id=73 data-nosnippet>73</a> schemas: manifest.schemas.clone(),
<a href=#74 id=74 data-nosnippet>74</a> format: manifest.format,
<a href=#75 id=75 data-nosnippet>75</a> packed: manifest.is_packed(),
<a href=#76 id=76 data-nosnippet>76</a> parallelism: options.parallelism,
<a href=#77 id=77 data-nosnippet>77</a> experimental_metric_export: options.experimental_metric_export,
<a href=#78 id=78 data-nosnippet>78</a> resume: options.resume,
<a href=#79 id=79 data-nosnippet>79</a> };
<a href=#80 id=80 data-nosnippet>80</a>
<a href=#81 id=81 data-nosnippet>81</a> <span class="comment">// One progress unit per chunk. Already completed/skipped chunks from a
<a href=#82 id=82 data-nosnippet>82</a> // previous run count up front so the reported total matches the chunk plan
<a href=#83 id=83 data-nosnippet>83</a> // regardless of resume position; each chunk finalized in this run (completed,
<a href=#84 id=84 data-nosnippet>84</a> // skipped, or failed) then increments exactly once.
<a href=#85 id=85 data-nosnippet>85</a> </span><span class="kw">let </span>progress_phase = ProgressPhase::start(
<a href=#86 id=86 data-nosnippet>86</a> progress,
<a href=#87 id=87 data-nosnippet>87</a> <span class="string">"Export data chunks"</span>,
<a href=#88 id=88 data-nosnippet>88</a> <span class="prelude-val">Some</span>(manifest.chunks.len() <span class="kw">as </span>u64),
<a href=#89 id=89 data-nosnippet>89</a> );
<a href=#90 id=90 data-nosnippet>90</a> <span class="kw">let </span>already_done = (manifest.completed_count() + manifest.skipped_count()) <span class="kw">as </span>u64;
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">if </span>already_done &gt; <span class="number">0 </span>{
<a href=#92 id=92 data-nosnippet>92</a> progress.inc(already_done);
<a href=#93 id=93 data-nosnippet>93</a> }
<a href=#94 id=94 data-nosnippet>94</a>
<a href=#95 id=95 data-nosnippet>95</a> <span class="kw">let </span>result = <span class="kw">if </span>options.chunk_parallelism &lt;= <span class="number">1 </span>{
<a href=#96 id=96 data-nosnippet>96</a> export_data_serial(<span class="kw-2">&amp;</span>context, storage, manifest, progress).<span class="kw">await
<a href=#97 id=97 data-nosnippet>97</a> </span>} <span class="kw">else </span>{
<a href=#98 id=98 data-nosnippet>98</a> export_data_concurrent(
<a href=#99 id=99 data-nosnippet>99</a> storage,
<a href=#100 id=100 data-nosnippet>100</a> manifest,
<a href=#101 id=101 data-nosnippet>101</a> options.chunk_parallelism,
<a href=#102 id=102 data-nosnippet>102</a> progress,
<a href=#103 id=103 data-nosnippet>103</a> |id, range| export_chunk(<span class="kw-2">&amp;</span>context, id, range),
<a href=#104 id=104 data-nosnippet>104</a> )
<a href=#105 id=105 data-nosnippet>105</a> .<span class="kw">await
<a href=#106 id=106 data-nosnippet>106</a> </span>};
<a href=#107 id=107 data-nosnippet>107</a>
<a href=#108 id=108 data-nosnippet>108</a> progress_phase.finish();
<a href=#109 id=109 data-nosnippet>109</a> result
<a href=#110 id=110 data-nosnippet>110</a>}
<a href=#111 id=111 data-nosnippet>111</a>
<a href=#112 id=112 data-nosnippet>112</a><span class="doccomment">/// Exports chunks one at a time, preserving the original serial behavior.
<a href=#113 id=113 data-nosnippet>113</a></span><span class="kw">async fn </span>export_data_serial(
<a href=#114 id=114 data-nosnippet>114</a> context: <span class="kw-2">&amp;</span>ExportContext&lt;<span class="lifetime">'_</span>&gt;,
<a href=#115 id=115 data-nosnippet>115</a> storage: <span class="kw-2">&amp;</span><span class="kw">dyn </span>SnapshotStorage,
<a href=#116 id=116 data-nosnippet>116</a> manifest: <span class="kw-2">&amp;mut </span>Manifest,
<a href=#117 id=117 data-nosnippet>117</a> progress: <span class="kw-2">&amp;</span><span class="kw">dyn </span>ProgressReporter,
<a href=#118 id=118 data-nosnippet>118</a>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#119 id=119 data-nosnippet>119</a> <span class="kw">for </span>idx <span class="kw">in </span><span class="number">0</span>..manifest.chunks.len() {
<a href=#120 id=120 data-nosnippet>120</a> <span class="kw">if </span><span class="macro">matches!</span>(
<a href=#121 id=121 data-nosnippet>121</a> manifest.chunks[idx].status,
<a href=#122 id=122 data-nosnippet>122</a> ChunkStatus::Completed | ChunkStatus::Skipped
<a href=#123 id=123 data-nosnippet>123</a> ) {
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">continue</span>;
<a href=#125 id=125 data-nosnippet>125</a> }
<a href=#126 id=126 data-nosnippet>126</a>
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw">let </span>(chunk_id, time_range) = mark_chunk_in_progress(manifest, idx);
<a href=#128 id=128 data-nosnippet>128</a> manifest.touch();
<a href=#129 id=129 data-nosnippet>129</a> storage.write_manifest(manifest).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#130 id=130 data-nosnippet>130</a>
<a href=#131 id=131 data-nosnippet>131</a> <span class="kw">let </span>export_result = export_chunk(context, chunk_id, time_range).<span class="kw">await</span>;
<a href=#132 id=132 data-nosnippet>132</a>
<a href=#133 id=133 data-nosnippet>133</a> <span class="kw">let </span>result = <span class="kw">match </span>export_result {
<a href=#134 id=134 data-nosnippet>134</a> <span class="prelude-val">Ok</span>(files) =&gt; {
<a href=#135 id=135 data-nosnippet>135</a> mark_chunk_completed(manifest, idx, files);
<a href=#136 id=136 data-nosnippet>136</a> <span class="prelude-val">Ok</span>(())
<a href=#137 id=137 data-nosnippet>137</a> }
<a href=#138 id=138 data-nosnippet>138</a> <span class="prelude-val">Err</span>(err) =&gt; {
<a href=#139 id=139 data-nosnippet>139</a> mark_chunk_failed(manifest, idx, err.to_string());
<a href=#140 id=140 data-nosnippet>140</a> <span class="prelude-val">Err</span>(err)
<a href=#141 id=141 data-nosnippet>141</a> }
<a href=#142 id=142 data-nosnippet>142</a> };
<a href=#143 id=143 data-nosnippet>143</a>
<a href=#144 id=144 data-nosnippet>144</a> manifest.touch();
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">let </span>persistence = storage.write_manifest(manifest).<span class="kw">await</span>;
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">if </span>persistence.is_ok() {
<a href=#147 id=147 data-nosnippet>147</a> progress.inc(<span class="number">1</span>);
<a href=#148 id=148 data-nosnippet>148</a> }
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">if let </span><span class="prelude-val">Err</span>(err) = result {
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">if let </span><span class="prelude-val">Err</span>(secondary) = persistence {
<a href=#151 id=151 data-nosnippet>151</a> <span class="macro">error!</span>(secondary; <span class="string">"Failed to persist failed export chunk"</span>);
<a href=#152 id=152 data-nosnippet>152</a> }
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">return </span><span class="prelude-val">Err</span>(err);
<a href=#154 id=154 data-nosnippet>154</a> }
<a href=#155 id=155 data-nosnippet>155</a> persistence<span class="question-mark">?</span>;
<a href=#156 id=156 data-nosnippet>156</a> }
<a href=#157 id=157 data-nosnippet>157</a>
<a href=#158 id=158 data-nosnippet>158</a> <span class="prelude-val">Ok</span>(())
<a href=#159 id=159 data-nosnippet>159</a>}
<a href=#160 id=160 data-nosnippet>160</a>
<a href=#161 id=161 data-nosnippet>161</a><span class="doccomment">/// Exports up to `chunk_parallelism` chunks concurrently on the client.
<a href=#162 id=162 data-nosnippet>162</a>///
<a href=#163 id=163 data-nosnippet>163</a>/// The coordinator owns all manifest mutation/persistence: it marks chunks
<a href=#164 id=164 data-nosnippet>164</a>/// `InProgress` and persists the manifest before polling their futures, then
<a href=#165 id=165 data-nosnippet>165</a>/// applies each chunk result and persists again on completion. The export
<a href=#166 id=166 data-nosnippet>166</a>/// futures only run COPY DATABASE and collect files; they never touch the
<a href=#167 id=167 data-nosnippet>167</a>/// manifest, so manifest writes stay serialized in this task.
<a href=#168 id=168 data-nosnippet>168</a>///
<a href=#169 id=169 data-nosnippet>169</a>/// On the first chunk failure we stop scheduling new chunks but let already
<a href=#170 id=170 data-nosnippet>170</a>/// in-flight chunks finish and persist their final status, then return the
<a href=#171 id=171 data-nosnippet>171</a>/// first error.
<a href=#172 id=172 data-nosnippet>172</a></span><span class="kw">async fn </span>export_data_concurrent&lt;F, Fut&gt;(
<a href=#173 id=173 data-nosnippet>173</a> storage: <span class="kw-2">&amp;</span><span class="kw">dyn </span>SnapshotStorage,
<a href=#174 id=174 data-nosnippet>174</a> manifest: <span class="kw-2">&amp;mut </span>Manifest,
<a href=#175 id=175 data-nosnippet>175</a> chunk_parallelism: usize,
<a href=#176 id=176 data-nosnippet>176</a> progress: <span class="kw-2">&amp;</span><span class="kw">dyn </span>ProgressReporter,
<a href=#177 id=177 data-nosnippet>177</a> export: F,
<a href=#178 id=178 data-nosnippet>178</a>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt;
<a href=#179 id=179 data-nosnippet>179</a><span class="kw">where
<a href=#180 id=180 data-nosnippet>180</a> </span>F: Fn(u32, TimeRange) -&gt; Fut,
<a href=#181 id=181 data-nosnippet>181</a> Fut: std::future::Future&lt;Output = <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt;&gt;,
<a href=#182 id=182 data-nosnippet>182</a>{
<a href=#183 id=183 data-nosnippet>183</a> <span class="kw">let </span><span class="kw-2">mut </span>pending = FuturesUnordered::new();
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">let </span><span class="kw-2">mut </span>next_idx = <span class="number">0</span>;
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">let </span><span class="kw-2">mut </span>first_error: <span class="prelude-ty">Option</span>&lt;Error&gt; = <span class="prelude-val">None</span>;
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">loop </span>{
<a href=#188 id=188 data-nosnippet>188</a> <span class="kw">let </span><span class="kw-2">mut </span>admitted = Vec::new();
<a href=#189 id=189 data-nosnippet>189</a> <span class="comment">// Schedule eligible chunks in order up to the parallelism limit. Once a
<a href=#190 id=190 data-nosnippet>190</a> // failure is seen, stop scheduling but keep draining in-flight chunks.
<a href=#191 id=191 data-nosnippet>191</a> </span><span class="kw">while </span>first_error.is_none() &amp;&amp; pending.len() + admitted.len() &lt; chunk_parallelism {
<a href=#192 id=192 data-nosnippet>192</a> <span class="kw">let </span><span class="prelude-val">Some</span>(idx) = next_eligible_chunk(manifest, <span class="kw-2">&amp;mut </span>next_idx) <span class="kw">else </span>{
<a href=#193 id=193 data-nosnippet>193</a> <span class="kw">break</span>;
<a href=#194 id=194 data-nosnippet>194</a> };
<a href=#195 id=195 data-nosnippet>195</a>
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">let </span>(chunk_id, time_range) = mark_chunk_in_progress(manifest, idx);
<a href=#197 id=197 data-nosnippet>197</a> admitted.push((idx, chunk_id, time_range));
<a href=#198 id=198 data-nosnippet>198</a> }
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">if </span>!admitted.is_empty() {
<a href=#200 id=200 data-nosnippet>200</a> manifest.touch();
<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">match </span>storage.write_manifest(manifest).<span class="kw">await </span>{
<a href=#202 id=202 data-nosnippet>202</a> <span class="prelude-val">Ok</span>(()) =&gt; {
<a href=#203 id=203 data-nosnippet>203</a> <span class="kw">for </span>(idx, chunk_id, time_range) <span class="kw">in </span>admitted {
<a href=#204 id=204 data-nosnippet>204</a> <span class="kw">let </span>export = <span class="kw-2">&amp;</span>export;
<a href=#205 id=205 data-nosnippet>205</a> pending.push(<span class="kw">async move </span>{ (idx, export(chunk_id, time_range).<span class="kw">await</span>) });
<a href=#206 id=206 data-nosnippet>206</a> }
<a href=#207 id=207 data-nosnippet>207</a> }
<a href=#208 id=208 data-nosnippet>208</a> <span class="prelude-val">Err</span>(err) =&gt; first_error = <span class="prelude-val">Some</span>(err),
<a href=#209 id=209 data-nosnippet>209</a> }
<a href=#210 id=210 data-nosnippet>210</a> }
<a href=#211 id=211 data-nosnippet>211</a>
<a href=#212 id=212 data-nosnippet>212</a> <span class="kw">let </span><span class="prelude-val">Some</span>((idx, export_result)) = pending.next().<span class="kw">await else </span>{
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">break</span>;
<a href=#214 id=214 data-nosnippet>214</a> };
<a href=#215 id=215 data-nosnippet>215</a>
<a href=#216 id=216 data-nosnippet>216</a> <span class="kw">match </span>export_result {
<a href=#217 id=217 data-nosnippet>217</a> <span class="prelude-val">Ok</span>(files) =&gt; mark_chunk_completed(manifest, idx, files),
<a href=#218 id=218 data-nosnippet>218</a> <span class="prelude-val">Err</span>(err) =&gt; {
<a href=#219 id=219 data-nosnippet>219</a> mark_chunk_failed(manifest, idx, err.to_string());
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">if </span>first_error.is_none() {
<a href=#221 id=221 data-nosnippet>221</a> first_error = <span class="prelude-val">Some</span>(err);
<a href=#222 id=222 data-nosnippet>222</a> }
<a href=#223 id=223 data-nosnippet>223</a> }
<a href=#224 id=224 data-nosnippet>224</a> }
<a href=#225 id=225 data-nosnippet>225</a> manifest.touch();
<a href=#226 id=226 data-nosnippet>226</a> <span class="kw">match </span>storage.write_manifest(manifest).<span class="kw">await </span>{
<a href=#227 id=227 data-nosnippet>227</a> <span class="prelude-val">Ok</span>(()) =&gt; progress.inc(<span class="number">1</span>),
<a href=#228 id=228 data-nosnippet>228</a> <span class="prelude-val">Err</span>(err) <span class="kw">if </span>first_error.is_none() =&gt; first_error = <span class="prelude-val">Some</span>(err),
<a href=#229 id=229 data-nosnippet>229</a> <span class="prelude-val">Err</span>(err) =&gt; <span class="macro">error!</span>(err; <span class="string">"Failed to persist export chunk while draining"</span>),
<a href=#230 id=230 data-nosnippet>230</a> }
<a href=#231 id=231 data-nosnippet>231</a> }
<a href=#232 id=232 data-nosnippet>232</a>
<a href=#233 id=233 data-nosnippet>233</a> <span class="kw">match </span>first_error {
<a href=#234 id=234 data-nosnippet>234</a> <span class="prelude-val">Some</span>(err) =&gt; <span class="prelude-val">Err</span>(err),
<a href=#235 id=235 data-nosnippet>235</a> <span class="prelude-val">None </span>=&gt; <span class="prelude-val">Ok</span>(()),
<a href=#236 id=236 data-nosnippet>236</a> }
<a href=#237 id=237 data-nosnippet>237</a>}
<a href=#238 id=238 data-nosnippet>238</a>
<a href=#239 id=239 data-nosnippet>239</a><span class="doccomment">/// Returns the index of the next chunk eligible for export, scanning forward
<a href=#240 id=240 data-nosnippet>240</a>/// from `next_idx` and skipping already Completed/Skipped chunks. Advances
<a href=#241 id=241 data-nosnippet>241</a>/// `next_idx` past the returned chunk so each chunk is scheduled at most once.
<a href=#242 id=242 data-nosnippet>242</a></span><span class="kw">fn </span>next_eligible_chunk(manifest: <span class="kw-2">&amp;</span>Manifest, next_idx: <span class="kw-2">&amp;mut </span>usize) -&gt; <span class="prelude-ty">Option</span>&lt;usize&gt; {
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">while </span><span class="kw-2">*</span>next_idx &lt; manifest.chunks.len() {
<a href=#244 id=244 data-nosnippet>244</a> <span class="kw">let </span>idx = <span class="kw-2">*</span>next_idx;
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw-2">*</span>next_idx += <span class="number">1</span>;
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">if </span>!<span class="macro">matches!</span>(
<a href=#247 id=247 data-nosnippet>247</a> manifest.chunks[idx].status,
<a href=#248 id=248 data-nosnippet>248</a> ChunkStatus::Completed | ChunkStatus::Skipped
<a href=#249 id=249 data-nosnippet>249</a> ) {
<a href=#250 id=250 data-nosnippet>250</a> <span class="kw">return </span><span class="prelude-val">Some</span>(idx);
<a href=#251 id=251 data-nosnippet>251</a> }
<a href=#252 id=252 data-nosnippet>252</a> }
<a href=#253 id=253 data-nosnippet>253</a> <span class="prelude-val">None
<a href=#254 id=254 data-nosnippet>254</a></span>}
<a href=#255 id=255 data-nosnippet>255</a>
<a href=#256 id=256 data-nosnippet>256</a><span class="kw">fn </span>mark_chunk_in_progress(manifest: <span class="kw-2">&amp;mut </span>Manifest, idx: usize) -&gt; (u32, TimeRange) {
<a href=#257 id=257 data-nosnippet>257</a> <span class="kw">let </span>chunk = <span class="kw-2">&amp;mut </span>manifest.chunks[idx];
<a href=#258 id=258 data-nosnippet>258</a> chunk.mark_in_progress();
<a href=#259 id=259 data-nosnippet>259</a> (chunk.id, chunk.time_range.clone())
<a href=#260 id=260 data-nosnippet>260</a>}
<a href=#261 id=261 data-nosnippet>261</a>
<a href=#262 id=262 data-nosnippet>262</a><span class="kw">fn </span>mark_chunk_completed(manifest: <span class="kw-2">&amp;mut </span>Manifest, idx: usize, files: Vec&lt;String&gt;) {
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">let </span>chunk = <span class="kw-2">&amp;mut </span>manifest.chunks[idx];
<a href=#264 id=264 data-nosnippet>264</a> <span class="kw">if </span>files.is_empty() {
<a href=#265 id=265 data-nosnippet>265</a> chunk.mark_skipped();
<a href=#266 id=266 data-nosnippet>266</a> } <span class="kw">else </span>{
<a href=#267 id=267 data-nosnippet>267</a> chunk.mark_completed(files, <span class="prelude-val">None</span>);
<a href=#268 id=268 data-nosnippet>268</a> }
<a href=#269 id=269 data-nosnippet>269</a>}
<a href=#270 id=270 data-nosnippet>270</a>
<a href=#271 id=271 data-nosnippet>271</a><span class="kw">fn </span>mark_chunk_failed(manifest: <span class="kw-2">&amp;mut </span>Manifest, idx: usize, error: String) {
<a href=#272 id=272 data-nosnippet>272</a> <span class="kw">let </span>chunk = <span class="kw-2">&amp;mut </span>manifest.chunks[idx];
<a href=#273 id=273 data-nosnippet>273</a> chunk.mark_failed(error);
<a href=#274 id=274 data-nosnippet>274</a>}
<a href=#275 id=275 data-nosnippet>275</a>
<a href=#276 id=276 data-nosnippet>276</a><span class="kw">async fn </span>export_chunk(
<a href=#277 id=277 data-nosnippet>277</a> context: <span class="kw-2">&amp;</span>ExportContext&lt;<span class="lifetime">'_</span>&gt;,
<a href=#278 id=278 data-nosnippet>278</a> chunk_id: u32,
<a href=#279 id=279 data-nosnippet>279</a> time_range: TimeRange,
<a href=#280 id=280 data-nosnippet>280</a>) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt; {
<a href=#281 id=281 data-nosnippet>281</a> <span class="kw">if </span>context.experimental_metric_export {
<a href=#282 id=282 data-nosnippet>282</a> context
<a href=#283 id=283 data-nosnippet>283</a> .storage
<a href=#284 id=284 data-nosnippet>284</a> .prepare_export_chunk(<span class="kw-2">&amp;</span>context.schemas, chunk_id, context.resume, context.packed)
<a href=#285 id=285 data-nosnippet>285</a> .<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#286 id=286 data-nosnippet>286</a> }
<a href=#287 id=287 data-nosnippet>287</a> <span class="kw">let </span>scheme = StorageScheme::from_uri(context.snapshot_uri)<span class="question-mark">?</span>;
<a href=#288 id=288 data-nosnippet>288</a> <span class="kw">let </span>needs_dir = <span class="macro">matches!</span>(scheme, StorageScheme::File);
<a href=#289 id=289 data-nosnippet>289</a> <span class="kw">let </span>copy_options = CopyOptions {
<a href=#290 id=290 data-nosnippet>290</a> format: context.format,
<a href=#291 id=291 data-nosnippet>291</a> time_range,
<a href=#292 id=292 data-nosnippet>292</a> parallelism: context.parallelism,
<a href=#293 id=293 data-nosnippet>293</a> experimental_metric_export: context.experimental_metric_export,
<a href=#294 id=294 data-nosnippet>294</a> packed: context.packed,
<a href=#295 id=295 data-nosnippet>295</a> };
<a href=#296 id=296 data-nosnippet>296</a>
<a href=#297 id=297 data-nosnippet>297</a> <span class="kw">for </span>schema <span class="kw">in </span><span class="kw-2">&amp;</span>context.schemas {
<a href=#298 id=298 data-nosnippet>298</a> <span class="kw">let </span>prefix = data_dir_for_schema_chunk(schema, chunk_id);
<a href=#299 id=299 data-nosnippet>299</a> <span class="kw">if </span>needs_dir {
<a href=#300 id=300 data-nosnippet>300</a> context.storage.create_dir_all(<span class="kw-2">&amp;</span>prefix).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#301 id=301 data-nosnippet>301</a> }
<a href=#302 id=302 data-nosnippet>302</a>
<a href=#303 id=303 data-nosnippet>303</a> <span class="kw">let </span>target = build_copy_target(
<a href=#304 id=304 data-nosnippet>304</a> context.snapshot_uri,
<a href=#305 id=305 data-nosnippet>305</a> context.storage_config,
<a href=#306 id=306 data-nosnippet>306</a> schema,
<a href=#307 id=307 data-nosnippet>307</a> chunk_id,
<a href=#308 id=308 data-nosnippet>308</a> )<span class="question-mark">?</span>;
<a href=#309 id=309 data-nosnippet>309</a> execute_copy_database(
<a href=#310 id=310 data-nosnippet>310</a> context.database_client,
<a href=#311 id=311 data-nosnippet>311</a> <span class="kw-2">&amp;</span>context.catalog,
<a href=#312 id=312 data-nosnippet>312</a> schema,
<a href=#313 id=313 data-nosnippet>313</a> <span class="kw-2">&amp;</span>target,
<a href=#314 id=314 data-nosnippet>314</a> <span class="kw-2">&amp;</span>copy_options,
<a href=#315 id=315 data-nosnippet>315</a> )
<a href=#316 id=316 data-nosnippet>316</a> .<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#317 id=317 data-nosnippet>317</a> }
<a href=#318 id=318 data-nosnippet>318</a>
<a href=#319 id=319 data-nosnippet>319</a> <span class="kw">let </span>files = list_chunk_files(context.storage, <span class="kw-2">&amp;</span>context.schemas, chunk_id).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#320 id=320 data-nosnippet>320</a> <span class="kw">if </span>context.packed {
<a href=#321 id=321 data-nosnippet>321</a> <span class="kw">use </span>common_datasource::packed_snapshot::{PACK_INDEX_FILE, PackIndex};
<a href=#322 id=322 data-nosnippet>322</a> <span class="kw">let </span><span class="kw-2">mut </span>expected = Vec::new();
<a href=#323 id=323 data-nosnippet>323</a> <span class="kw">for </span>schema <span class="kw">in </span><span class="kw-2">&amp;</span>context.schemas {
<a href=#324 id=324 data-nosnippet>324</a> <span class="kw">let </span>prefix = data_dir_for_schema_chunk(schema, chunk_id);
<a href=#325 id=325 data-nosnippet>325</a> <span class="kw">let </span>index_path = <span class="macro">format!</span>(<span class="string">"{prefix}{PACK_INDEX_FILE}"</span>);
<a href=#326 id=326 data-nosnippet>326</a> <span class="kw">let </span>text = context.storage.read_text(<span class="kw-2">&amp;</span>index_path).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#327 id=327 data-nosnippet>327</a> <span class="kw">let </span>index: PackIndex = serde_json::from_str(<span class="kw-2">&amp;</span>text).map_err(|e| {
<a href=#328 id=328 data-nosnippet>328</a> <span class="kw">crate</span>::data::export_v2::error::InvalidUriSnafu {
<a href=#329 id=329 data-nosnippet>329</a> uri: context.snapshot_uri,
<a href=#330 id=330 data-nosnippet>330</a> reason: e.to_string(),
<a href=#331 id=331 data-nosnippet>331</a> }
<a href=#332 id=332 data-nosnippet>332</a> .build()
<a href=#333 id=333 data-nosnippet>333</a> })<span class="question-mark">?</span>;
<a href=#334 id=334 data-nosnippet>334</a> index.validate().map_err(|e| {
<a href=#335 id=335 data-nosnippet>335</a> <span class="kw">crate</span>::data::export_v2::error::InvalidUriSnafu {
<a href=#336 id=336 data-nosnippet>336</a> uri: context.snapshot_uri,
<a href=#337 id=337 data-nosnippet>337</a> reason: e.to_string(),
<a href=#338 id=338 data-nosnippet>338</a> }
<a href=#339 id=339 data-nosnippet>339</a> .build()
<a href=#340 id=340 data-nosnippet>340</a> })<span class="question-mark">?</span>;
<a href=#341 id=341 data-nosnippet>341</a> expected.push(index_path);
<a href=#342 id=342 data-nosnippet>342</a> expected.extend(index.objects.iter().map(|o| <span class="macro">format!</span>(<span class="string">"{prefix}{}"</span>, o.path)));
<a href=#343 id=343 data-nosnippet>343</a> }
<a href=#344 id=344 data-nosnippet>344</a> expected.sort();
<a href=#345 id=345 data-nosnippet>345</a> <span class="kw">if </span>files != expected {
<a href=#346 id=346 data-nosnippet>346</a> <span class="kw">return </span><span class="kw">crate</span>::data::export_v2::error::InvalidUriSnafu {
<a href=#347 id=347 data-nosnippet>347</a> uri: context.snapshot_uri,
<a href=#348 id=348 data-nosnippet>348</a> reason: <span class="string">"chunk inventory differs from packed indexes"</span>,
<a href=#349 id=349 data-nosnippet>349</a> }
<a href=#350 id=350 data-nosnippet>350</a> .fail();
<a href=#351 id=351 data-nosnippet>351</a> }
<a href=#352 id=352 data-nosnippet>352</a> }
<a href=#353 id=353 data-nosnippet>353</a> <span class="macro">info!</span>(<span class="string">"Collected {} files for chunk {}"</span>, files.len(), chunk_id);
<a href=#354 id=354 data-nosnippet>354</a> <span class="prelude-val">Ok</span>(files)
<a href=#355 id=355 data-nosnippet>355</a>}
<a href=#356 id=356 data-nosnippet>356</a>
<a href=#357 id=357 data-nosnippet>357</a><span class="kw">async fn </span>list_chunk_files(
<a href=#358 id=358 data-nosnippet>358</a> storage: <span class="kw-2">&amp;</span><span class="kw">dyn </span>SnapshotStorage,
<a href=#359 id=359 data-nosnippet>359</a> schemas: <span class="kw-2">&amp;</span>[String],
<a href=#360 id=360 data-nosnippet>360</a> chunk_id: u32,
<a href=#361 id=361 data-nosnippet>361</a>) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt; {
<a href=#362 id=362 data-nosnippet>362</a> <span class="kw">let </span><span class="kw-2">mut </span>files = Vec::new();
<a href=#363 id=363 data-nosnippet>363</a>
<a href=#364 id=364 data-nosnippet>364</a> <span class="kw">for </span>schema <span class="kw">in </span>schemas {
<a href=#365 id=365 data-nosnippet>365</a> <span class="kw">let </span>prefix = data_dir_for_schema_chunk(schema, chunk_id);
<a href=#366 id=366 data-nosnippet>366</a> files.extend(storage.list_files_recursive(<span class="kw-2">&amp;</span>prefix).<span class="kw">await</span><span class="question-mark">?</span>);
<a href=#367 id=367 data-nosnippet>367</a> }
<a href=#368 id=368 data-nosnippet>368</a>
<a href=#369 id=369 data-nosnippet>369</a> files.sort();
<a href=#370 id=370 data-nosnippet>370</a> <span class="prelude-val">Ok</span>(files)
<a href=#371 id=371 data-nosnippet>371</a>}
<a href=#372 id=372 data-nosnippet>372</a>
<a href=#373 id=373 data-nosnippet>373</a><span class="attr">#[cfg(test)]
<a href=#374 id=374 data-nosnippet>374</a></span><span class="kw">mod </span>tests {
<a href=#375 id=375 data-nosnippet>375</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#376 id=376 data-nosnippet>376</a> <span class="kw">use </span><span class="kw">crate</span>::data::export_v2::manifest::ChunkMeta;
<a href=#377 id=377 data-nosnippet>377</a>
<a href=#378 id=378 data-nosnippet>378</a> <span class="kw">fn </span>pending_manifest(n: u32) -&gt; Manifest {
<a href=#379 id=379 data-nosnippet>379</a> <span class="kw">let </span><span class="kw-2">mut </span>manifest = Manifest::new_full(
<a href=#380 id=380 data-nosnippet>380</a> <span class="string">"greptime"</span>.to_string(),
<a href=#381 id=381 data-nosnippet>381</a> <span class="macro">vec!</span>[<span class="string">"public"</span>.to_string()],
<a href=#382 id=382 data-nosnippet>382</a> TimeRange::unbounded(),
<a href=#383 id=383 data-nosnippet>383</a> DataFormat::Parquet,
<a href=#384 id=384 data-nosnippet>384</a> );
<a href=#385 id=385 data-nosnippet>385</a> manifest.chunks = (<span class="number">1</span>..=n)
<a href=#386 id=386 data-nosnippet>386</a> .map(|id| ChunkMeta::new(id, TimeRange::unbounded()))
<a href=#387 id=387 data-nosnippet>387</a> .collect();
<a href=#388 id=388 data-nosnippet>388</a> manifest
<a href=#389 id=389 data-nosnippet>389</a> }
<a href=#390 id=390 data-nosnippet>390</a>
<a href=#391 id=391 data-nosnippet>391</a> <span class="kw">struct </span>FailingManifest {
<a href=#392 id=392 data-nosnippet>392</a> fail_at: usize,
<a href=#393 id=393 data-nosnippet>393</a> writes: std::sync::atomic::AtomicUsize,
<a href=#394 id=394 data-nosnippet>394</a> release: tokio::sync::Notify,
<a href=#395 id=395 data-nosnippet>395</a> }
<a href=#396 id=396 data-nosnippet>396</a>
<a href=#397 id=397 data-nosnippet>397</a> <span class="attr">#[async_trait::async_trait]
<a href=#398 id=398 data-nosnippet>398</a> </span><span class="kw">impl </span>SnapshotStorage <span class="kw">for </span>FailingManifest {
<a href=#399 id=399 data-nosnippet>399</a> <span class="kw">async fn </span>write_manifest(<span class="kw-2">&amp;</span><span class="self">self</span>, manifest: <span class="kw-2">&amp;</span>Manifest) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#400 id=400 data-nosnippet>400</a> <span class="kw">use </span>std::sync::atomic::Ordering;
<a href=#401 id=401 data-nosnippet>401</a>
<a href=#402 id=402 data-nosnippet>402</a> <span class="kw">let </span>write = <span class="self">self</span>.writes.fetch_add(<span class="number">1</span>, Ordering::SeqCst) + <span class="number">1</span>;
<a href=#403 id=403 data-nosnippet>403</a> <span class="kw">if </span>write == <span class="number">1 </span>{
<a href=#404 id=404 data-nosnippet>404</a> <span class="macro">assert_eq!</span>(manifest.in_progress_count(), <span class="number">2</span>);
<a href=#405 id=405 data-nosnippet>405</a> }
<a href=#406 id=406 data-nosnippet>406</a> <span class="kw">if </span>write == <span class="self">self</span>.fail_at {
<a href=#407 id=407 data-nosnippet>407</a> <span class="self">self</span>.release.notify_one();
<a href=#408 id=408 data-nosnippet>408</a> <span class="kw">return </span><span class="kw">crate</span>::data::export_v2::error::IoSnafu {
<a href=#409 id=409 data-nosnippet>409</a> operation: <span class="string">"injected manifest failure"</span>,
<a href=#410 id=410 data-nosnippet>410</a> error: std::io::Error::other(<span class="string">"manifest failure"</span>),
<a href=#411 id=411 data-nosnippet>411</a> }
<a href=#412 id=412 data-nosnippet>412</a> .fail();
<a href=#413 id=413 data-nosnippet>413</a> }
<a href=#414 id=414 data-nosnippet>414</a> <span class="prelude-val">Ok</span>(())
<a href=#415 id=415 data-nosnippet>415</a> }
<a href=#416 id=416 data-nosnippet>416</a> <span class="kw">async fn </span>exists(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;bool&gt; {
<a href=#417 id=417 data-nosnippet>417</a> <span class="macro">unreachable!</span>()
<a href=#418 id=418 data-nosnippet>418</a> }
<a href=#419 id=419 data-nosnippet>419</a> <span class="kw">async fn </span>read_manifest(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Manifest&gt; {
<a href=#420 id=420 data-nosnippet>420</a> <span class="macro">unreachable!</span>()
<a href=#421 id=421 data-nosnippet>421</a> }
<a href=#422 id=422 data-nosnippet>422</a> <span class="kw">async fn </span>file_size(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;u64&gt;&gt; {
<a href=#423 id=423 data-nosnippet>423</a> <span class="macro">unreachable!</span>()
<a href=#424 id=424 data-nosnippet>424</a> }
<a href=#425 id=425 data-nosnippet>425</a> <span class="kw">async fn </span>write_schema(
<a href=#426 id=426 data-nosnippet>426</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#427 id=427 data-nosnippet>427</a> <span class="kw">_</span>: <span class="kw-2">&amp;</span><span class="kw">crate</span>::data::export_v2::schema::SchemaSnapshot,
<a href=#428 id=428 data-nosnippet>428</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#429 id=429 data-nosnippet>429</a> <span class="macro">unreachable!</span>()
<a href=#430 id=430 data-nosnippet>430</a> }
<a href=#431 id=431 data-nosnippet>431</a> <span class="kw">async fn </span>write_text(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: <span class="kw-2">&amp;</span>str, <span class="kw">_</span>: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#432 id=432 data-nosnippet>432</a> <span class="macro">unreachable!</span>()
<a href=#433 id=433 data-nosnippet>433</a> }
<a href=#434 id=434 data-nosnippet>434</a> <span class="kw">async fn </span>read_text(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;String&gt; {
<a href=#435 id=435 data-nosnippet>435</a> <span class="macro">unreachable!</span>()
<a href=#436 id=436 data-nosnippet>436</a> }
<a href=#437 id=437 data-nosnippet>437</a> <span class="kw">async fn </span>create_dir_all(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#438 id=438 data-nosnippet>438</a> <span class="macro">unreachable!</span>()
<a href=#439 id=439 data-nosnippet>439</a> }
<a href=#440 id=440 data-nosnippet>440</a> <span class="kw">async fn </span>list_files_recursive(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="kw">_</span>: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt; {
<a href=#441 id=441 data-nosnippet>441</a> <span class="macro">unreachable!</span>()
<a href=#442 id=442 data-nosnippet>442</a> }
<a href=#443 id=443 data-nosnippet>443</a> <span class="kw">async fn </span>delete_snapshot(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#444 id=444 data-nosnippet>444</a> <span class="macro">unreachable!</span>()
<a href=#445 id=445 data-nosnippet>445</a> }
<a href=#446 id=446 data-nosnippet>446</a> }
<a href=#447 id=447 data-nosnippet>447</a>
<a href=#448 id=448 data-nosnippet>448</a> <span class="attr">#[tokio::test]
<a href=#449 id=449 data-nosnippet>449</a> </span><span class="kw">async fn </span>test_manifest_failure_stops_admission_and_drains_started_chunks() {
<a href=#450 id=450 data-nosnippet>450</a> <span class="kw">use </span>std::sync::atomic::{AtomicUsize, Ordering};
<a href=#451 id=451 data-nosnippet>451</a> <span class="kw">for </span>fail_at <span class="kw">in </span>[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>] {
<a href=#452 id=452 data-nosnippet>452</a> <span class="kw">let </span>storage = FailingManifest {
<a href=#453 id=453 data-nosnippet>453</a> fail_at,
<a href=#454 id=454 data-nosnippet>454</a> writes: AtomicUsize::new(<span class="number">0</span>),
<a href=#455 id=455 data-nosnippet>455</a> release: tokio::sync::Notify::new(),
<a href=#456 id=456 data-nosnippet>456</a> };
<a href=#457 id=457 data-nosnippet>457</a> <span class="kw">let </span>started = AtomicUsize::new(<span class="number">0</span>);
<a href=#458 id=458 data-nosnippet>458</a> <span class="kw">let </span>finished = AtomicUsize::new(<span class="number">0</span>);
<a href=#459 id=459 data-nosnippet>459</a> <span class="kw">let </span>second_started = tokio::sync::Notify::new();
<a href=#460 id=460 data-nosnippet>460</a> <span class="kw">let </span><span class="kw-2">mut </span>manifest = pending_manifest(<span class="number">4</span>);
<a href=#461 id=461 data-nosnippet>461</a> <span class="kw">let </span>result = tokio::time::timeout(
<a href=#462 id=462 data-nosnippet>462</a> std::time::Duration::from_secs(<span class="number">5</span>),
<a href=#463 id=463 data-nosnippet>463</a> export_data_concurrent(
<a href=#464 id=464 data-nosnippet>464</a> <span class="kw-2">&amp;</span>storage,
<a href=#465 id=465 data-nosnippet>465</a> <span class="kw-2">&amp;mut </span>manifest,
<a href=#466 id=466 data-nosnippet>466</a> <span class="number">2</span>,
<a href=#467 id=467 data-nosnippet>467</a> <span class="kw-2">&amp;</span><span class="kw">crate</span>::data::progress::NoopProgress,
<a href=#468 id=468 data-nosnippet>468</a> |id, <span class="kw">_</span>| {
<a href=#469 id=469 data-nosnippet>469</a> <span class="kw">let </span>(started, finished, second_started, storage) =
<a href=#470 id=470 data-nosnippet>470</a> (<span class="kw-2">&amp;</span>started, <span class="kw-2">&amp;</span>finished, <span class="kw-2">&amp;</span>second_started, <span class="kw-2">&amp;</span>storage);
<a href=#471 id=471 data-nosnippet>471</a> <span class="kw">async move </span>{
<a href=#472 id=472 data-nosnippet>472</a> started.fetch_add(<span class="number">1</span>, Ordering::SeqCst);
<a href=#473 id=473 data-nosnippet>473</a> <span class="kw">match </span>id {
<a href=#474 id=474 data-nosnippet>474</a> <span class="number">1 </span>=&gt; second_started.notified().<span class="kw">await</span>,
<a href=#475 id=475 data-nosnippet>475</a> <span class="number">2 </span>=&gt; {
<a href=#476 id=476 data-nosnippet>476</a> second_started.notify_one();
<a href=#477 id=477 data-nosnippet>477</a> storage.release.notified().<span class="kw">await</span>;
<a href=#478 id=478 data-nosnippet>478</a> }
<a href=#479 id=479 data-nosnippet>479</a> <span class="kw">_ </span>=&gt; <span class="macro">panic!</span>(<span class="string">"new chunk started after manifest persistence failed"</span>),
<a href=#480 id=480 data-nosnippet>480</a> }
<a href=#481 id=481 data-nosnippet>481</a> finished.fetch_add(<span class="number">1</span>, Ordering::SeqCst);
<a href=#482 id=482 data-nosnippet>482</a> <span class="prelude-val">Ok</span>(<span class="macro">vec!</span>[<span class="macro">format!</span>(<span class="string">"data/public/{id}/a.parquet"</span>)])
<a href=#483 id=483 data-nosnippet>483</a> }
<a href=#484 id=484 data-nosnippet>484</a> },
<a href=#485 id=485 data-nosnippet>485</a> ),
<a href=#486 id=486 data-nosnippet>486</a> )
<a href=#487 id=487 data-nosnippet>487</a> .<span class="kw">await
<a href=#488 id=488 data-nosnippet>488</a> </span>.unwrap();
<a href=#489 id=489 data-nosnippet>489</a> <span class="macro">assert!</span>(
<a href=#490 id=490 data-nosnippet>490</a> result
<a href=#491 id=491 data-nosnippet>491</a> .unwrap_err()
<a href=#492 id=492 data-nosnippet>492</a> .to_string()
<a href=#493 id=493 data-nosnippet>493</a> .contains(<span class="string">"injected manifest failure"</span>)
<a href=#494 id=494 data-nosnippet>494</a> );
<a href=#495 id=495 data-nosnippet>495</a> <span class="kw">let </span>expected = <span class="kw">if </span>fail_at == <span class="number">1 </span>{ <span class="number">0 </span>} <span class="kw">else </span>{ <span class="number">2 </span>};
<a href=#496 id=496 data-nosnippet>496</a> <span class="macro">assert_eq!</span>(started.load(Ordering::SeqCst), expected);
<a href=#497 id=497 data-nosnippet>497</a> <span class="macro">assert_eq!</span>(finished.load(Ordering::SeqCst), expected);
<a href=#498 id=498 data-nosnippet>498</a> }
<a href=#499 id=499 data-nosnippet>499</a> }
<a href=#500 id=500 data-nosnippet>500</a>
<a href=#501 id=501 data-nosnippet>501</a> <span class="kw">struct </span>PausedClose {
<a href=#502 id=502 data-nosnippet>502</a> inner: <span class="prelude-ty">Option</span>&lt;object_store::layers::mock::oio::Writer&gt;,
<a href=#503 id=503 data-nosnippet>503</a> started: std::sync::Arc&lt;tokio::sync::Notify&gt;,
<a href=#504 id=504 data-nosnippet>504</a> release: std::sync::Arc&lt;tokio::sync::Notify&gt;,
<a href=#505 id=505 data-nosnippet>505</a> }
<a href=#506 id=506 data-nosnippet>506</a>
<a href=#507 id=507 data-nosnippet>507</a> <span class="kw">impl </span>object_store::layers::mock::oio::Write <span class="kw">for </span>PausedClose {
<a href=#508 id=508 data-nosnippet>508</a> <span class="kw">async fn </span>write(<span class="kw-2">&amp;mut </span><span class="self">self</span>, bytes: object_store::Buffer) -&gt; object_store::Result&lt;()&gt; {
<a href=#509 id=509 data-nosnippet>509</a> <span class="self">self</span>.inner.as_mut().unwrap().write(bytes).<span class="kw">await
<a href=#510 id=510 data-nosnippet>510</a> </span>}
<a href=#511 id=511 data-nosnippet>511</a>
<a href=#512 id=512 data-nosnippet>512</a> <span class="kw">async fn </span>close(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; object_store::Result&lt;object_store::layers::mock::Metadata&gt; {
<a href=#513 id=513 data-nosnippet>513</a> <span class="kw">let </span><span class="kw-2">mut </span>inner = <span class="self">self</span>.inner.take().unwrap();
<a href=#514 id=514 data-nosnippet>514</a> <span class="kw">let </span>(started, release) = (<span class="self">self</span>.started.clone(), <span class="self">self</span>.release.clone());
<a href=#515 id=515 data-nosnippet>515</a> <span class="comment">// Model blocking storage I/O that survives dropping its caller.
<a href=#516 id=516 data-nosnippet>516</a> </span><span class="kw">let </span>(inner, result) = tokio::spawn(<span class="kw">async move </span>{
<a href=#517 id=517 data-nosnippet>517</a> started.notify_one();
<a href=#518 id=518 data-nosnippet>518</a> release.notified().<span class="kw">await</span>;
<a href=#519 id=519 data-nosnippet>519</a> <span class="kw">let </span>result = inner.close().<span class="kw">await</span>;
<a href=#520 id=520 data-nosnippet>520</a> (inner, result)
<a href=#521 id=521 data-nosnippet>521</a> })
<a href=#522 id=522 data-nosnippet>522</a> .<span class="kw">await
<a href=#523 id=523 data-nosnippet>523</a> </span>.unwrap();
<a href=#524 id=524 data-nosnippet>524</a> <span class="self">self</span>.inner = <span class="prelude-val">Some</span>(inner);
<a href=#525 id=525 data-nosnippet>525</a> result
<a href=#526 id=526 data-nosnippet>526</a> }
<a href=#527 id=527 data-nosnippet>527</a>
<a href=#528 id=528 data-nosnippet>528</a> <span class="kw">async fn </span>abort(<span class="kw-2">&amp;mut </span><span class="self">self</span>) -&gt; object_store::Result&lt;()&gt; {
<a href=#529 id=529 data-nosnippet>529</a> <span class="self">self</span>.inner.as_mut().unwrap().abort().<span class="kw">await
<a href=#530 id=530 data-nosnippet>530</a> </span>}
<a href=#531 id=531 data-nosnippet>531</a> }
<a href=#532 id=532 data-nosnippet>532</a>
<a href=#533 id=533 data-nosnippet>533</a> <span class="attr">#[tokio::test]
<a href=#534 id=534 data-nosnippet>534</a> </span><span class="kw">async fn </span>packed_cancellation_drains_close_before_failing_chunk() {
<a href=#535 id=535 data-nosnippet>535</a> <span class="kw">use </span>std::sync::Arc;
<a href=#536 id=536 data-nosnippet>536</a>
<a href=#537 id=537 data-nosnippet>537</a> <span class="kw">use </span>common_datasource::packed_snapshot::PACK_INDEX_FILE;
<a href=#538 id=538 data-nosnippet>538</a> <span class="kw">use </span>common_datasource::packed_writer::{PackedTableWriter, PackedWriter};
<a href=#539 id=539 data-nosnippet>539</a> <span class="kw">use </span>common_datasource::parquet_writer::ParquetFileWriter;
<a href=#540 id=540 data-nosnippet>540</a> <span class="kw">use </span>datatypes::arrow::datatypes::{DataType, Field, Schema};
<a href=#541 id=541 data-nosnippet>541</a> <span class="kw">use </span>object_store::layers::mock::{MockLayerBuilder, MockWriterFactory};
<a href=#542 id=542 data-nosnippet>542</a> <span class="kw">use </span>tokio_util::sync::CancellationToken;
<a href=#543 id=543 data-nosnippet>543</a>
<a href=#544 id=544 data-nosnippet>544</a> <span class="kw">use </span><span class="kw">crate</span>::data::snapshot_storage::OpenDalStorage;
<a href=#545 id=545 data-nosnippet>545</a>
<a href=#546 id=546 data-nosnippet>546</a> <span class="kw">for </span>paused_path <span class="kw">in </span>[<span class="string">"pack-000000.bin"</span>, PACK_INDEX_FILE] {
<a href=#547 id=547 data-nosnippet>547</a> <span class="kw">let </span>directory = tempfile::tempdir().unwrap();
<a href=#548 id=548 data-nosnippet>548</a> <span class="kw">let </span>uri = url::Url::from_directory_path(directory.path()).unwrap();
<a href=#549 id=549 data-nosnippet>549</a> <span class="kw">let </span>storage =
<a href=#550 id=550 data-nosnippet>550</a> OpenDalStorage::from_uri(uri.as_str(), <span class="kw-2">&amp;</span>ObjectStoreConfig::default()).unwrap();
<a href=#551 id=551 data-nosnippet>551</a> <span class="kw">let </span>started = Arc::new(tokio::sync::Notify::new());
<a href=#552 id=552 data-nosnippet>552</a> <span class="kw">let </span>release = Arc::new(tokio::sync::Notify::new());
<a href=#553 id=553 data-nosnippet>553</a> <span class="kw">let </span>factory: MockWriterFactory = Arc::new({
<a href=#554 id=554 data-nosnippet>554</a> <span class="kw">let </span>(started, release) = (started.clone(), release.clone());
<a href=#555 id=555 data-nosnippet>555</a> <span class="kw">move </span>|path, <span class="kw">_</span>, inner| {
<a href=#556 id=556 data-nosnippet>556</a> <span class="kw">if </span>path.trim_start_matches(<span class="string">'/'</span>) == paused_path {
<a href=#557 id=557 data-nosnippet>557</a> Box::new(PausedClose {
<a href=#558 id=558 data-nosnippet>558</a> inner: <span class="prelude-val">Some</span>(inner),
<a href=#559 id=559 data-nosnippet>559</a> started: started.clone(),
<a href=#560 id=560 data-nosnippet>560</a> release: release.clone(),
<a href=#561 id=561 data-nosnippet>561</a> })
<a href=#562 id=562 data-nosnippet>562</a> } <span class="kw">else </span>{
<a href=#563 id=563 data-nosnippet>563</a> inner
<a href=#564 id=564 data-nosnippet>564</a> }
<a href=#565 id=565 data-nosnippet>565</a> }
<a href=#566 id=566 data-nosnippet>566</a> });
<a href=#567 id=567 data-nosnippet>567</a> <span class="kw">let </span>store = object_store::secure_fs::SecureFsRoot::open(directory.path())
<a href=#568 id=568 data-nosnippet>568</a> .unwrap()
<a href=#569 id=569 data-nosnippet>569</a> .build_operator()
<a href=#570 id=570 data-nosnippet>570</a> .layer(
<a href=#571 id=571 data-nosnippet>571</a> MockLayerBuilder::default()
<a href=#572 id=572 data-nosnippet>572</a> .writer_factory(factory)
<a href=#573 id=573 data-nosnippet>573</a> .build()
<a href=#574 id=574 data-nosnippet>574</a> .unwrap(),
<a href=#575 id=575 data-nosnippet>575</a> );
<a href=#576 id=576 data-nosnippet>576</a> <span class="kw">let </span>packed = PackedWriter::new(store.clone()).unwrap();
<a href=#577 id=577 data-nosnippet>577</a> <span class="kw">let </span>schema = Arc::new(Schema::new(<span class="macro">vec!</span>[Field::new(
<a href=#578 id=578 data-nosnippet>578</a> <span class="string">"value"</span>,
<a href=#579 id=579 data-nosnippet>579</a> DataType::Int64,
<a href=#580 id=580 data-nosnippet>580</a> <span class="bool-val">true</span>,
<a href=#581 id=581 data-nosnippet>581</a> )]));
<a href=#582 id=582 data-nosnippet>582</a> <span class="kw">let </span><span class="kw-2">mut </span>table = ParquetFileWriter::open_packed(
<a href=#583 id=583 data-nosnippet>583</a> schema,
<a href=#584 id=584 data-nosnippet>584</a> store.clone(),
<a href=#585 id=585 data-nosnippet>585</a> <span class="string">"unused"</span>,
<a href=#586 id=586 data-nosnippet>586</a> <span class="prelude-val">None</span>,
<a href=#587 id=587 data-nosnippet>587</a> PackedTableWriter::new(packed.clone(), <span class="string">"empty"</span>.into(), <span class="number">1</span>, <span class="bool-val">false</span>),
<a href=#588 id=588 data-nosnippet>588</a> )
<a href=#589 id=589 data-nosnippet>589</a> .unwrap();
<a href=#590 id=590 data-nosnippet>590</a> table.finish(<span class="prelude-val">None</span>).<span class="kw">await</span>.unwrap();
<a href=#591 id=591 data-nosnippet>591</a> <span class="kw">let </span>token = CancellationToken::new();
<a href=#592 id=592 data-nosnippet>592</a> <span class="kw">let </span><span class="kw-2">mut </span>manifest = pending_manifest(<span class="number">1</span>);
<a href=#593 id=593 data-nosnippet>593</a> manifest.version = <span class="number">2</span>;
<a href=#594 id=594 data-nosnippet>594</a> manifest.data_layout = <span class="prelude-val">Some</span>(common_datasource::packed_snapshot::PACKED_LAYOUT.into());
<a href=#595 id=595 data-nosnippet>595</a> <span class="kw">let </span>export = export_data_concurrent(
<a href=#596 id=596 data-nosnippet>596</a> <span class="kw-2">&amp;</span>storage,
<a href=#597 id=597 data-nosnippet>597</a> <span class="kw-2">&amp;mut </span>manifest,
<a href=#598 id=598 data-nosnippet>598</a> <span class="number">2</span>,
<a href=#599 id=599 data-nosnippet>599</a> <span class="kw-2">&amp;</span><span class="kw">crate</span>::data::progress::NoopProgress,
<a href=#600 id=600 data-nosnippet>600</a> |<span class="kw">_</span>, <span class="kw">_</span>| <span class="kw">async </span>{
<a href=#601 id=601 data-nosnippet>601</a> <span class="kw">let </span><span class="kw-2">mut </span>packed = packed.lock().<span class="kw">await</span>;
<a href=#602 id=602 data-nosnippet>602</a> <span class="kw">let </span>result = packed.finish(<span class="kw-2">&amp;</span>token).<span class="kw">await</span>;
<a href=#603 id=603 data-nosnippet>603</a> <span class="kw">if </span>result.is_err() {
<a href=#604 id=604 data-nosnippet>604</a> packed.abort().<span class="kw">await</span>.unwrap();
<a href=#605 id=605 data-nosnippet>605</a> }
<a href=#606 id=606 data-nosnippet>606</a> result.map_err(|error| {
<a href=#607 id=607 data-nosnippet>607</a> <span class="kw">crate</span>::data::export_v2::error::IoSnafu {
<a href=#608 id=608 data-nosnippet>608</a> operation: <span class="string">"exporting packed chunk"</span>,
<a href=#609 id=609 data-nosnippet>609</a> error: std::io::Error::other(error),
<a href=#610 id=610 data-nosnippet>610</a> }
<a href=#611 id=611 data-nosnippet>611</a> .build()
<a href=#612 id=612 data-nosnippet>612</a> })
<a href=#613 id=613 data-nosnippet>613</a> },
<a href=#614 id=614 data-nosnippet>614</a> );
<a href=#615 id=615 data-nosnippet>615</a> <span class="macro">tokio::pin!</span>(export);
<a href=#616 id=616 data-nosnippet>616</a> <span class="macro">tokio::select!</span> {
<a href=#617 id=617 data-nosnippet>617</a> <span class="kw">_ </span>= started.notified() =&gt; {},
<a href=#618 id=618 data-nosnippet>618</a> result = <span class="kw-2">&amp;mut </span>export =&gt; <span class="macro">panic!</span>(<span class="string">"completed while close paused: {result:?}"</span>),
<a href=#619 id=619 data-nosnippet>619</a> }
<a href=#620 id=620 data-nosnippet>620</a> token.cancel();
<a href=#621 id=621 data-nosnippet>621</a> <span class="macro">assert!</span>(<span class="macro">futures::poll!</span>(<span class="kw-2">&amp;mut </span>export).is_pending());
<a href=#622 id=622 data-nosnippet>622</a> <span class="macro">assert_eq!</span>(
<a href=#623 id=623 data-nosnippet>623</a> storage.read_manifest().<span class="kw">await</span>.unwrap().chunks[<span class="number">0</span>].status,
<a href=#624 id=624 data-nosnippet>624</a> ChunkStatus::InProgress
<a href=#625 id=625 data-nosnippet>625</a> );
<a href=#626 id=626 data-nosnippet>626</a> release.notify_one();
<a href=#627 id=627 data-nosnippet>627</a> <span class="macro">assert!</span>(export.<span class="kw">await</span>.unwrap_err().to_string().contains(<span class="string">"cancelled"</span>));
<a href=#628 id=628 data-nosnippet>628</a> <span class="kw">let </span>persisted = storage.read_manifest().<span class="kw">await</span>.unwrap();
<a href=#629 id=629 data-nosnippet>629</a> <span class="macro">assert_eq!</span>(persisted.chunks[<span class="number">0</span>].status, ChunkStatus::Failed);
<a href=#630 id=630 data-nosnippet>630</a> <span class="macro">assert!</span>(!persisted.is_complete());
<a href=#631 id=631 data-nosnippet>631</a> <span class="macro">assert!</span>(persisted.chunks[<span class="number">0</span>].files.is_empty());
<a href=#632 id=632 data-nosnippet>632</a> <span class="macro">assert!</span>(
<a href=#633 id=633 data-nosnippet>633</a> store
<a href=#634 id=634 data-nosnippet>634</a> .stat(<span class="string">"pack-000000.bin"</span>)
<a href=#635 id=635 data-nosnippet>635</a> .<span class="kw">await
<a href=#636 id=636 data-nosnippet>636</a> </span>.unwrap()
<a href=#637 id=637 data-nosnippet>637</a> .content_length()
<a href=#638 id=638 data-nosnippet>638</a> &gt; <span class="number">0
<a href=#639 id=639 data-nosnippet>639</a> </span>);
<a href=#640 id=640 data-nosnippet>640</a> <span class="macro">assert_eq!</span>(
<a href=#641 id=641 data-nosnippet>641</a> store.exists(PACK_INDEX_FILE).<span class="kw">await</span>.unwrap(),
<a href=#642 id=642 data-nosnippet>642</a> paused_path == PACK_INDEX_FILE
<a href=#643 id=643 data-nosnippet>643</a> );
<a href=#644 id=644 data-nosnippet>644</a> <span class="kw">if </span>paused_path == PACK_INDEX_FILE {
<a href=#645 id=645 data-nosnippet>645</a> <span class="kw">let </span>index: common_datasource::packed_snapshot::PackIndex =
<a href=#646 id=646 data-nosnippet>646</a> serde_json::from_slice(<span class="kw-2">&amp;</span>store.read(PACK_INDEX_FILE).<span class="kw">await</span>.unwrap().to_bytes())
<a href=#647 id=647 data-nosnippet>647</a> .unwrap();
<a href=#648 id=648 data-nosnippet>648</a> index.validate_membership([<span class="string">"empty"</span>]).unwrap();
<a href=#649 id=649 data-nosnippet>649</a> }
<a href=#650 id=650 data-nosnippet>650</a> }
<a href=#651 id=651 data-nosnippet>651</a> }
<a href=#652 id=652 data-nosnippet>652</a>
<a href=#653 id=653 data-nosnippet>653</a> <span class="attr">#[test]
<a href=#654 id=654 data-nosnippet>654</a> </span><span class="kw">fn </span>test_next_eligible_chunk_scans_in_order() {
<a href=#655 id=655 data-nosnippet>655</a> <span class="kw">let </span>manifest = pending_manifest(<span class="number">3</span>);
<a href=#656 id=656 data-nosnippet>656</a> <span class="kw">let </span><span class="kw-2">mut </span>next_idx = <span class="number">0</span>;
<a href=#657 id=657 data-nosnippet>657</a>
<a href=#658 id=658 data-nosnippet>658</a> <span class="macro">assert_eq!</span>(next_eligible_chunk(<span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;mut </span>next_idx), <span class="prelude-val">Some</span>(<span class="number">0</span>));
<a href=#659 id=659 data-nosnippet>659</a> <span class="macro">assert_eq!</span>(next_eligible_chunk(<span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;mut </span>next_idx), <span class="prelude-val">Some</span>(<span class="number">1</span>));
<a href=#660 id=660 data-nosnippet>660</a> <span class="macro">assert_eq!</span>(next_eligible_chunk(<span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;mut </span>next_idx), <span class="prelude-val">Some</span>(<span class="number">2</span>));
<a href=#661 id=661 data-nosnippet>661</a> <span class="macro">assert_eq!</span>(next_eligible_chunk(<span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;mut </span>next_idx), <span class="prelude-val">None</span>);
<a href=#662 id=662 data-nosnippet>662</a> }
<a href=#663 id=663 data-nosnippet>663</a>
<a href=#664 id=664 data-nosnippet>664</a> <span class="attr">#[test]
<a href=#665 id=665 data-nosnippet>665</a> </span><span class="kw">fn </span>test_next_eligible_chunk_skips_completed_and_skipped() {
<a href=#666 id=666 data-nosnippet>666</a> <span class="kw">let </span><span class="kw-2">mut </span>manifest = pending_manifest(<span class="number">4</span>);
<a href=#667 id=667 data-nosnippet>667</a> manifest.chunks[<span class="number">0</span>].mark_completed(<span class="macro">vec!</span>[<span class="string">"data/public/1/f.parquet"</span>.to_string()], <span class="prelude-val">None</span>);
<a href=#668 id=668 data-nosnippet>668</a> manifest.chunks[<span class="number">2</span>].mark_skipped();
<a href=#669 id=669 data-nosnippet>669</a> <span class="kw">let </span><span class="kw-2">mut </span>next_idx = <span class="number">0</span>;
<a href=#670 id=670 data-nosnippet>670</a>
<a href=#671 id=671 data-nosnippet>671</a> <span class="comment">// Chunk 0 (completed) and chunk 2 (skipped) are skipped; failed/pending eligible.
<a href=#672 id=672 data-nosnippet>672</a> </span><span class="macro">assert_eq!</span>(next_eligible_chunk(<span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;mut </span>next_idx), <span class="prelude-val">Some</span>(<span class="number">1</span>));
<a href=#673 id=673 data-nosnippet>673</a> <span class="macro">assert_eq!</span>(next_eligible_chunk(<span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;mut </span>next_idx), <span class="prelude-val">Some</span>(<span class="number">3</span>));
<a href=#674 id=674 data-nosnippet>674</a> <span class="macro">assert_eq!</span>(next_eligible_chunk(<span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;mut </span>next_idx), <span class="prelude-val">None</span>);
<a href=#675 id=675 data-nosnippet>675</a> }
<a href=#676 id=676 data-nosnippet>676</a>
<a href=#677 id=677 data-nosnippet>677</a> <span class="attr">#[test]
<a href=#678 id=678 data-nosnippet>678</a> </span><span class="kw">fn </span>test_next_eligible_chunk_treats_failed_and_in_progress_as_eligible() {
<a href=#679 id=679 data-nosnippet>679</a> <span class="kw">let </span><span class="kw-2">mut </span>manifest = pending_manifest(<span class="number">2</span>);
<a href=#680 id=680 data-nosnippet>680</a> manifest.chunks[<span class="number">0</span>].mark_failed(<span class="string">"boom"</span>.to_string());
<a href=#681 id=681 data-nosnippet>681</a> manifest.chunks[<span class="number">1</span>].mark_in_progress();
<a href=#682 id=682 data-nosnippet>682</a> <span class="kw">let </span><span class="kw-2">mut </span>next_idx = <span class="number">0</span>;
<a href=#683 id=683 data-nosnippet>683</a>
<a href=#684 id=684 data-nosnippet>684</a> <span class="macro">assert_eq!</span>(next_eligible_chunk(<span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;mut </span>next_idx), <span class="prelude-val">Some</span>(<span class="number">0</span>));
<a href=#685 id=685 data-nosnippet>685</a> <span class="macro">assert_eq!</span>(next_eligible_chunk(<span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;mut </span>next_idx), <span class="prelude-val">Some</span>(<span class="number">1</span>));
<a href=#686 id=686 data-nosnippet>686</a> <span class="macro">assert_eq!</span>(next_eligible_chunk(<span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;mut </span>next_idx), <span class="prelude-val">None</span>);
<a href=#687 id=687 data-nosnippet>687</a> }
<a href=#688 id=688 data-nosnippet>688</a>}
</code></pre></div></section></main></body></html>
+553
View File
@@ -0,0 +1,553 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/export_v2/data.rs`."><title>data.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/export_v2/</div>data.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>common_base::secrets::{ExposeSecret, SecretString};
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>common_telemetry::info;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>object_store::util::{join_path, normalize_path};
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>snafu::ResultExt;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>url::Url;
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span><span class="kw">crate</span>::common::ObjectStoreConfig;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::error::{DatabaseSnafu, InvalidUriSnafu, <span class="prelude-ty">Result</span>, UrlParseSnafu};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::manifest::{DataFormat, TimeRange};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span><span class="kw">crate</span>::data::path::data_dir_for_schema_chunk;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span><span class="kw">crate</span>::data::snapshot_storage::StorageScheme;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span><span class="kw">crate</span>::data::sql::{escape_sql_identifier, escape_sql_literal};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span><span class="kw">crate</span>::database::DatabaseClient;
<a href=#28 id=28 data-nosnippet>28</a>
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>CopyOptions {
<a href=#30 id=30 data-nosnippet>30</a> <span class="kw">pub</span>(<span class="kw">super</span>) format: DataFormat,
<a href=#31 id=31 data-nosnippet>31</a> <span class="kw">pub</span>(<span class="kw">super</span>) time_range: TimeRange,
<a href=#32 id=32 data-nosnippet>32</a> <span class="kw">pub</span>(<span class="kw">super</span>) parallelism: usize,
<a href=#33 id=33 data-nosnippet>33</a> <span class="kw">pub</span>(<span class="kw">crate</span>) experimental_metric_export: bool,
<a href=#34 id=34 data-nosnippet>34</a> <span class="kw">pub</span>(<span class="kw">super</span>) packed: bool,
<a href=#35 id=35 data-nosnippet>35</a>}
<a href=#36 id=36 data-nosnippet>36</a>
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">struct </span>CopyTarget {
<a href=#38 id=38 data-nosnippet>38</a> <span class="kw">pub</span>(<span class="kw">super</span>) location: String,
<a href=#39 id=39 data-nosnippet>39</a> <span class="kw">pub</span>(<span class="kw">super</span>) connection: String,
<a href=#40 id=40 data-nosnippet>40</a> secrets: Vec&lt;<span class="prelude-ty">Option</span>&lt;String&gt;&gt;,
<a href=#41 id=41 data-nosnippet>41</a>}
<a href=#42 id=42 data-nosnippet>42</a>
<a href=#43 id=43 data-nosnippet>43</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>CopySource {
<a href=#44 id=44 data-nosnippet>44</a> <span class="kw">pub</span>(<span class="kw">crate</span>) location: String,
<a href=#45 id=45 data-nosnippet>45</a> <span class="kw">pub</span>(<span class="kw">crate</span>) connection: String,
<a href=#46 id=46 data-nosnippet>46</a> secrets: Vec&lt;<span class="prelude-ty">Option</span>&lt;String&gt;&gt;,
<a href=#47 id=47 data-nosnippet>47</a>}
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">impl </span>CopyTarget {
<a href=#50 id=50 data-nosnippet>50</a> <span class="kw">fn </span>mask_sql(<span class="kw-2">&amp;</span><span class="self">self</span>, sql: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#51 id=51 data-nosnippet>51</a> mask_secrets(sql, <span class="kw-2">&amp;</span><span class="self">self</span>.secrets)
<a href=#52 id=52 data-nosnippet>52</a> }
<a href=#53 id=53 data-nosnippet>53</a>}
<a href=#54 id=54 data-nosnippet>54</a>
<a href=#55 id=55 data-nosnippet>55</a><span class="kw">impl </span>CopySource {
<a href=#56 id=56 data-nosnippet>56</a> <span class="kw">fn </span>mask_sql(<span class="kw-2">&amp;</span><span class="self">self</span>, sql: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#57 id=57 data-nosnippet>57</a> mask_secrets(sql, <span class="kw-2">&amp;</span><span class="self">self</span>.secrets)
<a href=#58 id=58 data-nosnippet>58</a> }
<a href=#59 id=59 data-nosnippet>59</a>}
<a href=#60 id=60 data-nosnippet>60</a>
<a href=#61 id=61 data-nosnippet>61</a><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">fn </span>build_copy_target(
<a href=#62 id=62 data-nosnippet>62</a> snapshot_uri: <span class="kw-2">&amp;</span>str,
<a href=#63 id=63 data-nosnippet>63</a> storage: <span class="kw-2">&amp;</span>ObjectStoreConfig,
<a href=#64 id=64 data-nosnippet>64</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#65 id=65 data-nosnippet>65</a> chunk_id: u32,
<a href=#66 id=66 data-nosnippet>66</a>) -&gt; <span class="prelude-ty">Result</span>&lt;CopyTarget&gt; {
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">let </span>location = build_copy_location(snapshot_uri, storage, schema, chunk_id)<span class="question-mark">?</span>;
<a href=#68 id=68 data-nosnippet>68</a> <span class="prelude-val">Ok</span>(CopyTarget {
<a href=#69 id=69 data-nosnippet>69</a> location: location.location,
<a href=#70 id=70 data-nosnippet>70</a> connection: location.connection,
<a href=#71 id=71 data-nosnippet>71</a> secrets: location.secrets,
<a href=#72 id=72 data-nosnippet>72</a> })
<a href=#73 id=73 data-nosnippet>73</a>}
<a href=#74 id=74 data-nosnippet>74</a>
<a href=#75 id=75 data-nosnippet>75</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>build_copy_source(
<a href=#76 id=76 data-nosnippet>76</a> snapshot_uri: <span class="kw-2">&amp;</span>str,
<a href=#77 id=77 data-nosnippet>77</a> storage: <span class="kw-2">&amp;</span>ObjectStoreConfig,
<a href=#78 id=78 data-nosnippet>78</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#79 id=79 data-nosnippet>79</a> chunk_id: u32,
<a href=#80 id=80 data-nosnippet>80</a>) -&gt; <span class="prelude-ty">Result</span>&lt;CopySource&gt; {
<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">let </span>location = build_copy_location(snapshot_uri, storage, schema, chunk_id)<span class="question-mark">?</span>;
<a href=#82 id=82 data-nosnippet>82</a> <span class="prelude-val">Ok</span>(CopySource {
<a href=#83 id=83 data-nosnippet>83</a> location: location.location,
<a href=#84 id=84 data-nosnippet>84</a> connection: location.connection,
<a href=#85 id=85 data-nosnippet>85</a> secrets: location.secrets,
<a href=#86 id=86 data-nosnippet>86</a> })
<a href=#87 id=87 data-nosnippet>87</a>}
<a href=#88 id=88 data-nosnippet>88</a>
<a href=#89 id=89 data-nosnippet>89</a><span class="kw">struct </span>CopyLocation {
<a href=#90 id=90 data-nosnippet>90</a> location: String,
<a href=#91 id=91 data-nosnippet>91</a> connection: String,
<a href=#92 id=92 data-nosnippet>92</a> secrets: Vec&lt;<span class="prelude-ty">Option</span>&lt;String&gt;&gt;,
<a href=#93 id=93 data-nosnippet>93</a>}
<a href=#94 id=94 data-nosnippet>94</a>
<a href=#95 id=95 data-nosnippet>95</a><span class="kw">fn </span>build_copy_location(
<a href=#96 id=96 data-nosnippet>96</a> snapshot_uri: <span class="kw-2">&amp;</span>str,
<a href=#97 id=97 data-nosnippet>97</a> storage: <span class="kw-2">&amp;</span>ObjectStoreConfig,
<a href=#98 id=98 data-nosnippet>98</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#99 id=99 data-nosnippet>99</a> chunk_id: u32,
<a href=#100 id=100 data-nosnippet>100</a>) -&gt; <span class="prelude-ty">Result</span>&lt;CopyLocation&gt; {
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">let </span>url = Url::parse(snapshot_uri).context(UrlParseSnafu)<span class="question-mark">?</span>;
<a href=#102 id=102 data-nosnippet>102</a> <span class="kw">let </span>scheme = StorageScheme::from_uri(snapshot_uri)<span class="question-mark">?</span>;
<a href=#103 id=103 data-nosnippet>103</a> <span class="kw">let </span>suffix = data_dir_for_schema_chunk(schema, chunk_id);
<a href=#104 id=104 data-nosnippet>104</a>
<a href=#105 id=105 data-nosnippet>105</a> <span class="kw">match </span>scheme {
<a href=#106 id=106 data-nosnippet>106</a> StorageScheme::File =&gt; {
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">let </span>root = url.to_file_path().map_err(|<span class="kw">_</span>| {
<a href=#108 id=108 data-nosnippet>108</a> InvalidUriSnafu {
<a href=#109 id=109 data-nosnippet>109</a> uri: snapshot_uri,
<a href=#110 id=110 data-nosnippet>110</a> reason: <span class="string">"file:// URI must use an absolute path like file:///tmp/backup"</span>,
<a href=#111 id=111 data-nosnippet>111</a> }
<a href=#112 id=112 data-nosnippet>112</a> .build()
<a href=#113 id=113 data-nosnippet>113</a> })<span class="question-mark">?</span>;
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">let </span>location = normalize_path(<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"{}/{}"</span>, root.to_string_lossy(), suffix));
<a href=#115 id=115 data-nosnippet>115</a> <span class="prelude-val">Ok</span>(CopyLocation {
<a href=#116 id=116 data-nosnippet>116</a> location,
<a href=#117 id=117 data-nosnippet>117</a> connection: String::new(),
<a href=#118 id=118 data-nosnippet>118</a> secrets: Vec::new(),
<a href=#119 id=119 data-nosnippet>119</a> })
<a href=#120 id=120 data-nosnippet>120</a> }
<a href=#121 id=121 data-nosnippet>121</a> StorageScheme::S3 =&gt; {
<a href=#122 id=122 data-nosnippet>122</a> <span class="kw">let </span>(bucket, root) = extract_bucket_root(<span class="kw-2">&amp;</span>url, snapshot_uri)<span class="question-mark">?</span>;
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">let </span>location = <span class="macro">format!</span>(<span class="string">"s3://{}/{}"</span>, bucket, join_root(<span class="kw-2">&amp;</span>root, <span class="kw-2">&amp;</span>suffix));
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">let </span>(connection, secrets) = build_s3_connection(storage);
<a href=#125 id=125 data-nosnippet>125</a> <span class="prelude-val">Ok</span>(CopyLocation {
<a href=#126 id=126 data-nosnippet>126</a> location,
<a href=#127 id=127 data-nosnippet>127</a> connection,
<a href=#128 id=128 data-nosnippet>128</a> secrets,
<a href=#129 id=129 data-nosnippet>129</a> })
<a href=#130 id=130 data-nosnippet>130</a> }
<a href=#131 id=131 data-nosnippet>131</a> StorageScheme::Oss =&gt; {
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">let </span>(bucket, root) = extract_bucket_root(<span class="kw-2">&amp;</span>url, snapshot_uri)<span class="question-mark">?</span>;
<a href=#133 id=133 data-nosnippet>133</a> <span class="kw">let </span>location = <span class="macro">format!</span>(<span class="string">"oss://{}/{}"</span>, bucket, join_root(<span class="kw-2">&amp;</span>root, <span class="kw-2">&amp;</span>suffix));
<a href=#134 id=134 data-nosnippet>134</a> <span class="kw">let </span>(connection, secrets) = build_oss_connection(storage);
<a href=#135 id=135 data-nosnippet>135</a> <span class="prelude-val">Ok</span>(CopyLocation {
<a href=#136 id=136 data-nosnippet>136</a> location,
<a href=#137 id=137 data-nosnippet>137</a> connection,
<a href=#138 id=138 data-nosnippet>138</a> secrets,
<a href=#139 id=139 data-nosnippet>139</a> })
<a href=#140 id=140 data-nosnippet>140</a> }
<a href=#141 id=141 data-nosnippet>141</a> StorageScheme::Gcs =&gt; {
<a href=#142 id=142 data-nosnippet>142</a> <span class="kw">let </span>(bucket, root) = extract_bucket_root(<span class="kw-2">&amp;</span>url, snapshot_uri)<span class="question-mark">?</span>;
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">let </span>location = <span class="macro">format!</span>(<span class="string">"gcs://{}/{}"</span>, bucket, join_root(<span class="kw-2">&amp;</span>root, <span class="kw-2">&amp;</span>suffix));
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">let </span>(connection, secrets) = build_gcs_connection(storage, snapshot_uri)<span class="question-mark">?</span>;
<a href=#145 id=145 data-nosnippet>145</a> <span class="prelude-val">Ok</span>(CopyLocation {
<a href=#146 id=146 data-nosnippet>146</a> location,
<a href=#147 id=147 data-nosnippet>147</a> connection,
<a href=#148 id=148 data-nosnippet>148</a> secrets,
<a href=#149 id=149 data-nosnippet>149</a> })
<a href=#150 id=150 data-nosnippet>150</a> }
<a href=#151 id=151 data-nosnippet>151</a> StorageScheme::Azblob =&gt; {
<a href=#152 id=152 data-nosnippet>152</a> <span class="kw">let </span>(bucket, root) = extract_bucket_root(<span class="kw-2">&amp;</span>url, snapshot_uri)<span class="question-mark">?</span>;
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">let </span>location = <span class="macro">format!</span>(<span class="string">"azblob://{}/{}"</span>, bucket, join_root(<span class="kw-2">&amp;</span>root, <span class="kw-2">&amp;</span>suffix));
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">let </span>(connection, secrets) = build_azblob_connection(storage);
<a href=#155 id=155 data-nosnippet>155</a> <span class="prelude-val">Ok</span>(CopyLocation {
<a href=#156 id=156 data-nosnippet>156</a> location,
<a href=#157 id=157 data-nosnippet>157</a> connection,
<a href=#158 id=158 data-nosnippet>158</a> secrets,
<a href=#159 id=159 data-nosnippet>159</a> })
<a href=#160 id=160 data-nosnippet>160</a> }
<a href=#161 id=161 data-nosnippet>161</a> }
<a href=#162 id=162 data-nosnippet>162</a>}
<a href=#163 id=163 data-nosnippet>163</a>
<a href=#164 id=164 data-nosnippet>164</a><span class="kw">pub</span>(<span class="kw">super</span>) <span class="kw">async fn </span>execute_copy_database(
<a href=#165 id=165 data-nosnippet>165</a> database_client: <span class="kw-2">&amp;</span>DatabaseClient,
<a href=#166 id=166 data-nosnippet>166</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#167 id=167 data-nosnippet>167</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#168 id=168 data-nosnippet>168</a> target: <span class="kw-2">&amp;</span>CopyTarget,
<a href=#169 id=169 data-nosnippet>169</a> options: <span class="kw-2">&amp;</span>CopyOptions,
<a href=#170 id=170 data-nosnippet>170</a>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">let </span>with_options = build_with_options(options);
<a href=#172 id=172 data-nosnippet>172</a> <span class="kw">let </span>sql = <span class="macro">format!</span>(
<a href=#173 id=173 data-nosnippet>173</a> <span class="string">r#"COPY DATABASE "{}"."{}" TO '{}' WITH ({}){};"#</span>,
<a href=#174 id=174 data-nosnippet>174</a> escape_sql_identifier(catalog),
<a href=#175 id=175 data-nosnippet>175</a> escape_sql_identifier(schema),
<a href=#176 id=176 data-nosnippet>176</a> escape_sql_literal(<span class="kw-2">&amp;</span>target.location),
<a href=#177 id=177 data-nosnippet>177</a> with_options,
<a href=#178 id=178 data-nosnippet>178</a> target.connection
<a href=#179 id=179 data-nosnippet>179</a> );
<a href=#180 id=180 data-nosnippet>180</a> <span class="kw">let </span>safe_sql = target.mask_sql(<span class="kw-2">&amp;</span>sql);
<a href=#181 id=181 data-nosnippet>181</a> <span class="macro">info!</span>(<span class="string">"Executing sql: {}"</span>, safe_sql);
<a href=#182 id=182 data-nosnippet>182</a> database_client
<a href=#183 id=183 data-nosnippet>183</a> .sql_in_public(<span class="kw-2">&amp;</span>sql)
<a href=#184 id=184 data-nosnippet>184</a> .<span class="kw">await
<a href=#185 id=185 data-nosnippet>185</a> </span>.context(DatabaseSnafu)<span class="question-mark">?</span>;
<a href=#186 id=186 data-nosnippet>186</a> <span class="prelude-val">Ok</span>(())
<a href=#187 id=187 data-nosnippet>187</a>}
<a href=#188 id=188 data-nosnippet>188</a>
<a href=#189 id=189 data-nosnippet>189</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">async fn </span>execute_copy_database_from(
<a href=#190 id=190 data-nosnippet>190</a> database_client: <span class="kw-2">&amp;</span>DatabaseClient,
<a href=#191 id=191 data-nosnippet>191</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#192 id=192 data-nosnippet>192</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#193 id=193 data-nosnippet>193</a> source: <span class="kw-2">&amp;</span>CopySource,
<a href=#194 id=194 data-nosnippet>194</a> format: DataFormat,
<a href=#195 id=195 data-nosnippet>195</a> packed: bool,
<a href=#196 id=196 data-nosnippet>196</a>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#197 id=197 data-nosnippet>197</a> <span class="kw">let </span>sql = <span class="macro">format!</span>(
<a href=#198 id=198 data-nosnippet>198</a> <span class="string">r#"COPY DATABASE "{}"."{}" FROM '{}' WITH (FORMAT='{}'{}){};"#</span>,
<a href=#199 id=199 data-nosnippet>199</a> escape_sql_identifier(catalog),
<a href=#200 id=200 data-nosnippet>200</a> escape_sql_identifier(schema),
<a href=#201 id=201 data-nosnippet>201</a> escape_sql_literal(<span class="kw-2">&amp;</span>source.location),
<a href=#202 id=202 data-nosnippet>202</a> format,
<a href=#203 id=203 data-nosnippet>203</a> <span class="kw">if </span>packed {
<a href=#204 id=204 data-nosnippet>204</a> <span class="string">", metric_data_layout='packed'"
<a href=#205 id=205 data-nosnippet>205</a> </span>} <span class="kw">else </span>{
<a href=#206 id=206 data-nosnippet>206</a> <span class="string">""
<a href=#207 id=207 data-nosnippet>207</a> </span>},
<a href=#208 id=208 data-nosnippet>208</a> source.connection
<a href=#209 id=209 data-nosnippet>209</a> );
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">let </span>safe_sql = source.mask_sql(<span class="kw-2">&amp;</span>sql);
<a href=#211 id=211 data-nosnippet>211</a> <span class="macro">info!</span>(<span class="string">"Executing sql: {}"</span>, safe_sql);
<a href=#212 id=212 data-nosnippet>212</a> database_client
<a href=#213 id=213 data-nosnippet>213</a> .sql_in_public(<span class="kw-2">&amp;</span>sql)
<a href=#214 id=214 data-nosnippet>214</a> .<span class="kw">await
<a href=#215 id=215 data-nosnippet>215</a> </span>.context(DatabaseSnafu)<span class="question-mark">?</span>;
<a href=#216 id=216 data-nosnippet>216</a> <span class="prelude-val">Ok</span>(())
<a href=#217 id=217 data-nosnippet>217</a>}
<a href=#218 id=218 data-nosnippet>218</a>
<a href=#219 id=219 data-nosnippet>219</a><span class="kw">fn </span>build_with_options(options: <span class="kw-2">&amp;</span>CopyOptions) -&gt; String {
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">let </span><span class="kw-2">mut </span>parts = <span class="macro">vec!</span>[<span class="macro">format!</span>(<span class="string">"FORMAT='{}'"</span>, options.format)];
<a href=#221 id=221 data-nosnippet>221</a> <span class="kw">if </span>options.experimental_metric_export {
<a href=#222 id=222 data-nosnippet>222</a> parts.push(<span class="string">"experimental_metric_export='true'"</span>.to_string());
<a href=#223 id=223 data-nosnippet>223</a> }
<a href=#224 id=224 data-nosnippet>224</a> <span class="kw">if </span>options.packed {
<a href=#225 id=225 data-nosnippet>225</a> parts.push(<span class="string">"metric_data_layout='packed'"</span>.to_string());
<a href=#226 id=226 data-nosnippet>226</a> }
<a href=#227 id=227 data-nosnippet>227</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(start) = options.time_range.start {
<a href=#228 id=228 data-nosnippet>228</a> parts.push(<span class="macro">format!</span>(
<a href=#229 id=229 data-nosnippet>229</a> <span class="string">"START_TIME='{}'"</span>,
<a href=#230 id=230 data-nosnippet>230</a> escape_sql_literal(<span class="kw-2">&amp;</span>start.to_rfc3339())
<a href=#231 id=231 data-nosnippet>231</a> ));
<a href=#232 id=232 data-nosnippet>232</a> }
<a href=#233 id=233 data-nosnippet>233</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(end) = options.time_range.end {
<a href=#234 id=234 data-nosnippet>234</a> parts.push(<span class="macro">format!</span>(
<a href=#235 id=235 data-nosnippet>235</a> <span class="string">"END_TIME='{}'"</span>,
<a href=#236 id=236 data-nosnippet>236</a> escape_sql_literal(<span class="kw-2">&amp;</span>end.to_rfc3339())
<a href=#237 id=237 data-nosnippet>237</a> ));
<a href=#238 id=238 data-nosnippet>238</a> }
<a href=#239 id=239 data-nosnippet>239</a> parts.push(<span class="macro">format!</span>(<span class="string">"PARALLELISM={}"</span>, options.parallelism));
<a href=#240 id=240 data-nosnippet>240</a> parts.join(<span class="string">", "</span>)
<a href=#241 id=241 data-nosnippet>241</a>}
<a href=#242 id=242 data-nosnippet>242</a>
<a href=#243 id=243 data-nosnippet>243</a><span class="kw">fn </span>extract_bucket_root(url: <span class="kw-2">&amp;</span>Url, snapshot_uri: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;(String, String)&gt; {
<a href=#244 id=244 data-nosnippet>244</a> <span class="kw">let </span>bucket = url.host_str().unwrap_or(<span class="string">""</span>).to_string();
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw">if </span>bucket.is_empty() {
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">return </span>InvalidUriSnafu {
<a href=#247 id=247 data-nosnippet>247</a> uri: snapshot_uri,
<a href=#248 id=248 data-nosnippet>248</a> reason: <span class="string">"URI must include bucket/container in host"</span>,
<a href=#249 id=249 data-nosnippet>249</a> }
<a href=#250 id=250 data-nosnippet>250</a> .fail();
<a href=#251 id=251 data-nosnippet>251</a> }
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw">let </span>root = url
<a href=#253 id=253 data-nosnippet>253</a> .path()
<a href=#254 id=254 data-nosnippet>254</a> .trim_start_matches(<span class="string">'/'</span>)
<a href=#255 id=255 data-nosnippet>255</a> .trim_end_matches(<span class="string">'/'</span>)
<a href=#256 id=256 data-nosnippet>256</a> .to_string();
<a href=#257 id=257 data-nosnippet>257</a> <span class="prelude-val">Ok</span>((bucket, root))
<a href=#258 id=258 data-nosnippet>258</a>}
<a href=#259 id=259 data-nosnippet>259</a>
<a href=#260 id=260 data-nosnippet>260</a><span class="kw">fn </span>join_root(root: <span class="kw-2">&amp;</span>str, suffix: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#261 id=261 data-nosnippet>261</a> join_path(root, suffix).trim_start_matches(<span class="string">'/'</span>).to_string()
<a href=#262 id=262 data-nosnippet>262</a>}
<a href=#263 id=263 data-nosnippet>263</a>
<a href=#264 id=264 data-nosnippet>264</a><span class="kw">fn </span>build_s3_connection(storage: <span class="kw-2">&amp;</span>ObjectStoreConfig) -&gt; (String, Vec&lt;<span class="prelude-ty">Option</span>&lt;String&gt;&gt;) {
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">let </span>access_key_id = expose_optional_secret(<span class="kw-2">&amp;</span>storage.s3.s3_access_key_id);
<a href=#266 id=266 data-nosnippet>266</a> <span class="kw">let </span>secret_access_key = expose_optional_secret(<span class="kw-2">&amp;</span>storage.s3.s3_secret_access_key);
<a href=#267 id=267 data-nosnippet>267</a>
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw">let </span><span class="kw-2">mut </span>options = Vec::new();
<a href=#269 id=269 data-nosnippet>269</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(access_key_id) = <span class="kw-2">&amp;</span>access_key_id {
<a href=#270 id=270 data-nosnippet>270</a> options.push(<span class="macro">format!</span>(
<a href=#271 id=271 data-nosnippet>271</a> <span class="string">"ACCESS_KEY_ID='{}'"</span>,
<a href=#272 id=272 data-nosnippet>272</a> escape_sql_literal(access_key_id)
<a href=#273 id=273 data-nosnippet>273</a> ));
<a href=#274 id=274 data-nosnippet>274</a> }
<a href=#275 id=275 data-nosnippet>275</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(secret_access_key) = <span class="kw-2">&amp;</span>secret_access_key {
<a href=#276 id=276 data-nosnippet>276</a> options.push(<span class="macro">format!</span>(
<a href=#277 id=277 data-nosnippet>277</a> <span class="string">"SECRET_ACCESS_KEY='{}'"</span>,
<a href=#278 id=278 data-nosnippet>278</a> escape_sql_literal(secret_access_key)
<a href=#279 id=279 data-nosnippet>279</a> ));
<a href=#280 id=280 data-nosnippet>280</a> }
<a href=#281 id=281 data-nosnippet>281</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(region) = <span class="kw-2">&amp;</span>storage.s3.s3_region {
<a href=#282 id=282 data-nosnippet>282</a> options.push(<span class="macro">format!</span>(<span class="string">"REGION='{}'"</span>, escape_sql_literal(region)));
<a href=#283 id=283 data-nosnippet>283</a> }
<a href=#284 id=284 data-nosnippet>284</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(endpoint) = <span class="kw-2">&amp;</span>storage.s3.s3_endpoint {
<a href=#285 id=285 data-nosnippet>285</a> options.push(<span class="macro">format!</span>(<span class="string">"ENDPOINT='{}'"</span>, escape_sql_literal(endpoint)));
<a href=#286 id=286 data-nosnippet>286</a> }
<a href=#287 id=287 data-nosnippet>287</a>
<a href=#288 id=288 data-nosnippet>288</a> <span class="kw">let </span>secrets = <span class="macro">vec!</span>[access_key_id, secret_access_key];
<a href=#289 id=289 data-nosnippet>289</a> <span class="kw">let </span>connection = <span class="kw">if </span>options.is_empty() {
<a href=#290 id=290 data-nosnippet>290</a> String::new()
<a href=#291 id=291 data-nosnippet>291</a> } <span class="kw">else </span>{
<a href=#292 id=292 data-nosnippet>292</a> <span class="macro">format!</span>(<span class="string">" CONNECTION ({})"</span>, options.join(<span class="string">", "</span>))
<a href=#293 id=293 data-nosnippet>293</a> };
<a href=#294 id=294 data-nosnippet>294</a> (connection, secrets)
<a href=#295 id=295 data-nosnippet>295</a>}
<a href=#296 id=296 data-nosnippet>296</a>
<a href=#297 id=297 data-nosnippet>297</a><span class="kw">fn </span>build_oss_connection(storage: <span class="kw-2">&amp;</span>ObjectStoreConfig) -&gt; (String, Vec&lt;<span class="prelude-ty">Option</span>&lt;String&gt;&gt;) {
<a href=#298 id=298 data-nosnippet>298</a> <span class="kw">let </span>access_key_id = expose_optional_secret(<span class="kw-2">&amp;</span>storage.oss.oss_access_key_id);
<a href=#299 id=299 data-nosnippet>299</a> <span class="kw">let </span>access_key_secret = expose_optional_secret(<span class="kw-2">&amp;</span>storage.oss.oss_access_key_secret);
<a href=#300 id=300 data-nosnippet>300</a>
<a href=#301 id=301 data-nosnippet>301</a> <span class="kw">let </span><span class="kw-2">mut </span>options = Vec::new();
<a href=#302 id=302 data-nosnippet>302</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(access_key_id) = <span class="kw-2">&amp;</span>access_key_id {
<a href=#303 id=303 data-nosnippet>303</a> options.push(<span class="macro">format!</span>(
<a href=#304 id=304 data-nosnippet>304</a> <span class="string">"ACCESS_KEY_ID='{}'"</span>,
<a href=#305 id=305 data-nosnippet>305</a> escape_sql_literal(access_key_id)
<a href=#306 id=306 data-nosnippet>306</a> ));
<a href=#307 id=307 data-nosnippet>307</a> }
<a href=#308 id=308 data-nosnippet>308</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(access_key_secret) = <span class="kw-2">&amp;</span>access_key_secret {
<a href=#309 id=309 data-nosnippet>309</a> options.push(<span class="macro">format!</span>(
<a href=#310 id=310 data-nosnippet>310</a> <span class="string">"ACCESS_KEY_SECRET='{}'"</span>,
<a href=#311 id=311 data-nosnippet>311</a> escape_sql_literal(access_key_secret)
<a href=#312 id=312 data-nosnippet>312</a> ));
<a href=#313 id=313 data-nosnippet>313</a> }
<a href=#314 id=314 data-nosnippet>314</a> <span class="kw">if </span>!storage.oss.oss_endpoint.is_empty() {
<a href=#315 id=315 data-nosnippet>315</a> options.push(<span class="macro">format!</span>(
<a href=#316 id=316 data-nosnippet>316</a> <span class="string">"ENDPOINT='{}'"</span>,
<a href=#317 id=317 data-nosnippet>317</a> escape_sql_literal(<span class="kw-2">&amp;</span>storage.oss.oss_endpoint)
<a href=#318 id=318 data-nosnippet>318</a> ));
<a href=#319 id=319 data-nosnippet>319</a> }
<a href=#320 id=320 data-nosnippet>320</a>
<a href=#321 id=321 data-nosnippet>321</a> <span class="kw">let </span>secrets = <span class="macro">vec!</span>[access_key_id, access_key_secret];
<a href=#322 id=322 data-nosnippet>322</a> <span class="kw">let </span>connection = <span class="kw">if </span>options.is_empty() {
<a href=#323 id=323 data-nosnippet>323</a> String::new()
<a href=#324 id=324 data-nosnippet>324</a> } <span class="kw">else </span>{
<a href=#325 id=325 data-nosnippet>325</a> <span class="macro">format!</span>(<span class="string">" CONNECTION ({})"</span>, options.join(<span class="string">", "</span>))
<a href=#326 id=326 data-nosnippet>326</a> };
<a href=#327 id=327 data-nosnippet>327</a> (connection, secrets)
<a href=#328 id=328 data-nosnippet>328</a>}
<a href=#329 id=329 data-nosnippet>329</a>
<a href=#330 id=330 data-nosnippet>330</a><span class="kw">fn </span>build_gcs_connection(
<a href=#331 id=331 data-nosnippet>331</a> storage: <span class="kw-2">&amp;</span>ObjectStoreConfig,
<a href=#332 id=332 data-nosnippet>332</a> snapshot_uri: <span class="kw-2">&amp;</span>str,
<a href=#333 id=333 data-nosnippet>333</a>) -&gt; <span class="prelude-ty">Result</span>&lt;(String, Vec&lt;<span class="prelude-ty">Option</span>&lt;String&gt;&gt;)&gt; {
<a href=#334 id=334 data-nosnippet>334</a> <span class="kw">let </span>credential_path = expose_optional_secret(<span class="kw-2">&amp;</span>storage.gcs.gcs_credential_path);
<a href=#335 id=335 data-nosnippet>335</a> <span class="kw">let </span>credential = expose_optional_secret(<span class="kw-2">&amp;</span>storage.gcs.gcs_credential);
<a href=#336 id=336 data-nosnippet>336</a>
<a href=#337 id=337 data-nosnippet>337</a> <span class="kw">if </span>credential.is_none() &amp;&amp; credential_path.is_some() {
<a href=#338 id=338 data-nosnippet>338</a> <span class="kw">return </span>InvalidUriSnafu {
<a href=#339 id=339 data-nosnippet>339</a> uri: snapshot_uri,
<a href=#340 id=340 data-nosnippet>340</a> reason: <span class="string">"gcs_credential_path is not supported for server-side COPY; provide gcs_credential or rely on server-side ADC"</span>,
<a href=#341 id=341 data-nosnippet>341</a> }
<a href=#342 id=342 data-nosnippet>342</a> .fail();
<a href=#343 id=343 data-nosnippet>343</a> }
<a href=#344 id=344 data-nosnippet>344</a>
<a href=#345 id=345 data-nosnippet>345</a> <span class="kw">let </span><span class="kw-2">mut </span>options = Vec::new();
<a href=#346 id=346 data-nosnippet>346</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(credential) = <span class="kw-2">&amp;</span>credential {
<a href=#347 id=347 data-nosnippet>347</a> options.push(<span class="macro">format!</span>(<span class="string">"CREDENTIAL='{}'"</span>, escape_sql_literal(credential)));
<a href=#348 id=348 data-nosnippet>348</a> }
<a href=#349 id=349 data-nosnippet>349</a> <span class="kw">if </span>!storage.gcs.gcs_scope.is_empty() {
<a href=#350 id=350 data-nosnippet>350</a> options.push(<span class="macro">format!</span>(
<a href=#351 id=351 data-nosnippet>351</a> <span class="string">"SCOPE='{}'"</span>,
<a href=#352 id=352 data-nosnippet>352</a> escape_sql_literal(<span class="kw-2">&amp;</span>storage.gcs.gcs_scope)
<a href=#353 id=353 data-nosnippet>353</a> ));
<a href=#354 id=354 data-nosnippet>354</a> }
<a href=#355 id=355 data-nosnippet>355</a> <span class="kw">if </span>!storage.gcs.gcs_endpoint.is_empty() {
<a href=#356 id=356 data-nosnippet>356</a> options.push(<span class="macro">format!</span>(
<a href=#357 id=357 data-nosnippet>357</a> <span class="string">"ENDPOINT='{}'"</span>,
<a href=#358 id=358 data-nosnippet>358</a> escape_sql_literal(<span class="kw-2">&amp;</span>storage.gcs.gcs_endpoint)
<a href=#359 id=359 data-nosnippet>359</a> ));
<a href=#360 id=360 data-nosnippet>360</a> }
<a href=#361 id=361 data-nosnippet>361</a>
<a href=#362 id=362 data-nosnippet>362</a> <span class="kw">let </span>connection = <span class="kw">if </span>options.is_empty() {
<a href=#363 id=363 data-nosnippet>363</a> String::new()
<a href=#364 id=364 data-nosnippet>364</a> } <span class="kw">else </span>{
<a href=#365 id=365 data-nosnippet>365</a> <span class="macro">format!</span>(<span class="string">" CONNECTION ({})"</span>, options.join(<span class="string">", "</span>))
<a href=#366 id=366 data-nosnippet>366</a> };
<a href=#367 id=367 data-nosnippet>367</a> <span class="kw">let </span>secrets = <span class="macro">vec!</span>[credential_path, credential];
<a href=#368 id=368 data-nosnippet>368</a> <span class="prelude-val">Ok</span>((connection, secrets))
<a href=#369 id=369 data-nosnippet>369</a>}
<a href=#370 id=370 data-nosnippet>370</a>
<a href=#371 id=371 data-nosnippet>371</a><span class="kw">fn </span>build_azblob_connection(storage: <span class="kw-2">&amp;</span>ObjectStoreConfig) -&gt; (String, Vec&lt;<span class="prelude-ty">Option</span>&lt;String&gt;&gt;) {
<a href=#372 id=372 data-nosnippet>372</a> <span class="kw">let </span>account_name = expose_optional_secret(<span class="kw-2">&amp;</span>storage.azblob.azblob_account_name);
<a href=#373 id=373 data-nosnippet>373</a> <span class="kw">let </span>account_key = expose_optional_secret(<span class="kw-2">&amp;</span>storage.azblob.azblob_account_key);
<a href=#374 id=374 data-nosnippet>374</a> <span class="kw">let </span>sas_token = storage.azblob.azblob_sas_token.clone();
<a href=#375 id=375 data-nosnippet>375</a>
<a href=#376 id=376 data-nosnippet>376</a> <span class="kw">let </span><span class="kw-2">mut </span>options = Vec::new();
<a href=#377 id=377 data-nosnippet>377</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(account_name) = <span class="kw-2">&amp;</span>account_name {
<a href=#378 id=378 data-nosnippet>378</a> options.push(<span class="macro">format!</span>(
<a href=#379 id=379 data-nosnippet>379</a> <span class="string">"ACCOUNT_NAME='{}'"</span>,
<a href=#380 id=380 data-nosnippet>380</a> escape_sql_literal(account_name)
<a href=#381 id=381 data-nosnippet>381</a> ));
<a href=#382 id=382 data-nosnippet>382</a> }
<a href=#383 id=383 data-nosnippet>383</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(account_key) = <span class="kw-2">&amp;</span>account_key {
<a href=#384 id=384 data-nosnippet>384</a> options.push(<span class="macro">format!</span>(<span class="string">"ACCOUNT_KEY='{}'"</span>, escape_sql_literal(account_key)));
<a href=#385 id=385 data-nosnippet>385</a> }
<a href=#386 id=386 data-nosnippet>386</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(sas_token) = <span class="kw-2">&amp;</span>sas_token {
<a href=#387 id=387 data-nosnippet>387</a> options.push(<span class="macro">format!</span>(<span class="string">"SAS_TOKEN='{}'"</span>, escape_sql_literal(sas_token)));
<a href=#388 id=388 data-nosnippet>388</a> }
<a href=#389 id=389 data-nosnippet>389</a> <span class="kw">if </span>!storage.azblob.azblob_endpoint.is_empty() {
<a href=#390 id=390 data-nosnippet>390</a> options.push(<span class="macro">format!</span>(
<a href=#391 id=391 data-nosnippet>391</a> <span class="string">"ENDPOINT='{}'"</span>,
<a href=#392 id=392 data-nosnippet>392</a> escape_sql_literal(<span class="kw-2">&amp;</span>storage.azblob.azblob_endpoint)
<a href=#393 id=393 data-nosnippet>393</a> ));
<a href=#394 id=394 data-nosnippet>394</a> }
<a href=#395 id=395 data-nosnippet>395</a>
<a href=#396 id=396 data-nosnippet>396</a> <span class="kw">let </span>secrets = <span class="macro">vec!</span>[account_name, account_key, sas_token];
<a href=#397 id=397 data-nosnippet>397</a> <span class="kw">let </span>connection = <span class="kw">if </span>options.is_empty() {
<a href=#398 id=398 data-nosnippet>398</a> String::new()
<a href=#399 id=399 data-nosnippet>399</a> } <span class="kw">else </span>{
<a href=#400 id=400 data-nosnippet>400</a> <span class="macro">format!</span>(<span class="string">" CONNECTION ({})"</span>, options.join(<span class="string">", "</span>))
<a href=#401 id=401 data-nosnippet>401</a> };
<a href=#402 id=402 data-nosnippet>402</a> (connection, secrets)
<a href=#403 id=403 data-nosnippet>403</a>}
<a href=#404 id=404 data-nosnippet>404</a>
<a href=#405 id=405 data-nosnippet>405</a><span class="kw">fn </span>expose_optional_secret(secret: <span class="kw-2">&amp;</span><span class="prelude-ty">Option</span>&lt;SecretString&gt;) -&gt; <span class="prelude-ty">Option</span>&lt;String&gt; {
<a href=#406 id=406 data-nosnippet>406</a> secret.as_ref().map(|s| s.expose_secret().to_owned())
<a href=#407 id=407 data-nosnippet>407</a>}
<a href=#408 id=408 data-nosnippet>408</a>
<a href=#409 id=409 data-nosnippet>409</a><span class="kw">fn </span>mask_secrets(sql: <span class="kw-2">&amp;</span>str, secrets: <span class="kw-2">&amp;</span>[<span class="prelude-ty">Option</span>&lt;String&gt;]) -&gt; String {
<a href=#410 id=410 data-nosnippet>410</a> <span class="kw">let </span><span class="kw-2">mut </span>masked = sql.to_string();
<a href=#411 id=411 data-nosnippet>411</a> <span class="kw">for </span>secret <span class="kw">in </span>secrets {
<a href=#412 id=412 data-nosnippet>412</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(secret) = secret
<a href=#413 id=413 data-nosnippet>413</a> &amp;&amp; !secret.is_empty()
<a href=#414 id=414 data-nosnippet>414</a> {
<a href=#415 id=415 data-nosnippet>415</a> <span class="kw">let </span>escaped = escape_sql_literal(secret);
<a href=#416 id=416 data-nosnippet>416</a> <span class="kw">if </span>escaped != <span class="kw-2">*</span>secret {
<a href=#417 id=417 data-nosnippet>417</a> masked = masked.replace(<span class="kw-2">&amp;</span>escaped, <span class="string">"[REDACTED]"</span>);
<a href=#418 id=418 data-nosnippet>418</a> }
<a href=#419 id=419 data-nosnippet>419</a> masked = masked.replace(secret, <span class="string">"[REDACTED]"</span>);
<a href=#420 id=420 data-nosnippet>420</a> }
<a href=#421 id=421 data-nosnippet>421</a> }
<a href=#422 id=422 data-nosnippet>422</a> masked
<a href=#423 id=423 data-nosnippet>423</a>}
<a href=#424 id=424 data-nosnippet>424</a>
<a href=#425 id=425 data-nosnippet>425</a><span class="attr">#[cfg(test)]
<a href=#426 id=426 data-nosnippet>426</a></span><span class="kw">mod </span>tests {
<a href=#427 id=427 data-nosnippet>427</a> <span class="kw">use </span>common_base::secrets::SecretString;
<a href=#428 id=428 data-nosnippet>428</a> <span class="kw">use </span>common_test_util::temp_dir::create_temp_dir;
<a href=#429 id=429 data-nosnippet>429</a>
<a href=#430 id=430 data-nosnippet>430</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#431 id=431 data-nosnippet>431</a> <span class="kw">use </span><span class="kw">crate</span>::common::{PrefixedAzblobConnection, PrefixedGcsConnection, PrefixedOssConnection};
<a href=#432 id=432 data-nosnippet>432</a>
<a href=#433 id=433 data-nosnippet>433</a> <span class="attr">#[test]
<a href=#434 id=434 data-nosnippet>434</a> </span><span class="kw">fn </span>test_build_oss_connection_includes_endpoint() {
<a href=#435 id=435 data-nosnippet>435</a> <span class="kw">let </span>storage = ObjectStoreConfig {
<a href=#436 id=436 data-nosnippet>436</a> oss: PrefixedOssConnection {
<a href=#437 id=437 data-nosnippet>437</a> oss_endpoint: <span class="string">"https://oss.example.com"</span>.to_string(),
<a href=#438 id=438 data-nosnippet>438</a> oss_access_key_id: <span class="prelude-val">Some</span>(SecretString::from(<span class="string">"key_id"</span>.to_string())),
<a href=#439 id=439 data-nosnippet>439</a> oss_access_key_secret: <span class="prelude-val">Some</span>(SecretString::from(<span class="string">"key_secret"</span>.to_string())),
<a href=#440 id=440 data-nosnippet>440</a> ..Default::default()
<a href=#441 id=441 data-nosnippet>441</a> },
<a href=#442 id=442 data-nosnippet>442</a> ..Default::default()
<a href=#443 id=443 data-nosnippet>443</a> };
<a href=#444 id=444 data-nosnippet>444</a>
<a href=#445 id=445 data-nosnippet>445</a> <span class="kw">let </span>(connection, <span class="kw">_</span>) = build_oss_connection(<span class="kw-2">&amp;</span>storage);
<a href=#446 id=446 data-nosnippet>446</a> <span class="macro">assert!</span>(connection.contains(<span class="string">"ENDPOINT='https://oss.example.com'"</span>));
<a href=#447 id=447 data-nosnippet>447</a> }
<a href=#448 id=448 data-nosnippet>448</a>
<a href=#449 id=449 data-nosnippet>449</a> <span class="attr">#[test]
<a href=#450 id=450 data-nosnippet>450</a> </span><span class="kw">fn </span>test_build_gcs_connection_uses_scope_and_inline_credential() {
<a href=#451 id=451 data-nosnippet>451</a> <span class="kw">let </span>storage = ObjectStoreConfig {
<a href=#452 id=452 data-nosnippet>452</a> gcs: PrefixedGcsConnection {
<a href=#453 id=453 data-nosnippet>453</a> gcs_scope: <span class="string">"scope-a"</span>.to_string(),
<a href=#454 id=454 data-nosnippet>454</a> gcs_endpoint: <span class="string">"https://storage.googleapis.com"</span>.to_string(),
<a href=#455 id=455 data-nosnippet>455</a> gcs_credential: <span class="prelude-val">Some</span>(SecretString::from(<span class="string">"credential-json"</span>.to_string())),
<a href=#456 id=456 data-nosnippet>456</a> ..Default::default()
<a href=#457 id=457 data-nosnippet>457</a> },
<a href=#458 id=458 data-nosnippet>458</a> ..Default::default()
<a href=#459 id=459 data-nosnippet>459</a> };
<a href=#460 id=460 data-nosnippet>460</a>
<a href=#461 id=461 data-nosnippet>461</a> <span class="kw">let </span>(connection, <span class="kw">_</span>) = build_gcs_connection(<span class="kw-2">&amp;</span>storage, <span class="string">"gcs://bucket/root"</span>).unwrap();
<a href=#462 id=462 data-nosnippet>462</a> <span class="macro">assert!</span>(connection.contains(<span class="string">"CREDENTIAL='credential-json'"</span>));
<a href=#463 id=463 data-nosnippet>463</a> <span class="macro">assert!</span>(connection.contains(<span class="string">"SCOPE='scope-a'"</span>));
<a href=#464 id=464 data-nosnippet>464</a> <span class="macro">assert!</span>(connection.contains(<span class="string">"ENDPOINT='https://storage.googleapis.com'"</span>));
<a href=#465 id=465 data-nosnippet>465</a> <span class="macro">assert!</span>(!connection.contains(<span class="string">"CREDENTIAL_PATH"</span>));
<a href=#466 id=466 data-nosnippet>466</a> }
<a href=#467 id=467 data-nosnippet>467</a>
<a href=#468 id=468 data-nosnippet>468</a> <span class="attr">#[test]
<a href=#469 id=469 data-nosnippet>469</a> </span><span class="kw">fn </span>test_build_gcs_connection_rejects_credential_path_only() {
<a href=#470 id=470 data-nosnippet>470</a> <span class="kw">let </span>storage = ObjectStoreConfig {
<a href=#471 id=471 data-nosnippet>471</a> gcs: PrefixedGcsConnection {
<a href=#472 id=472 data-nosnippet>472</a> gcs_scope: <span class="string">"scope-a"</span>.to_string(),
<a href=#473 id=473 data-nosnippet>473</a> gcs_credential_path: <span class="prelude-val">Some</span>(SecretString::from(<span class="string">"/tmp/creds.json"</span>.to_string())),
<a href=#474 id=474 data-nosnippet>474</a> ..Default::default()
<a href=#475 id=475 data-nosnippet>475</a> },
<a href=#476 id=476 data-nosnippet>476</a> ..Default::default()
<a href=#477 id=477 data-nosnippet>477</a> };
<a href=#478 id=478 data-nosnippet>478</a>
<a href=#479 id=479 data-nosnippet>479</a> <span class="kw">let </span>error = build_gcs_connection(<span class="kw-2">&amp;</span>storage, <span class="string">"gcs://bucket/root"</span>)
<a href=#480 id=480 data-nosnippet>480</a> .expect_err(<span class="string">"credential_path-only should be rejected"</span>)
<a href=#481 id=481 data-nosnippet>481</a> .to_string();
<a href=#482 id=482 data-nosnippet>482</a> <span class="macro">assert!</span>(error.contains(<span class="string">"gcs_credential_path is not supported"</span>));
<a href=#483 id=483 data-nosnippet>483</a> }
<a href=#484 id=484 data-nosnippet>484</a>
<a href=#485 id=485 data-nosnippet>485</a> <span class="attr">#[test]
<a href=#486 id=486 data-nosnippet>486</a> </span><span class="kw">fn </span>test_build_azblob_connection_includes_endpoint() {
<a href=#487 id=487 data-nosnippet>487</a> <span class="kw">let </span>storage = ObjectStoreConfig {
<a href=#488 id=488 data-nosnippet>488</a> azblob: PrefixedAzblobConnection {
<a href=#489 id=489 data-nosnippet>489</a> azblob_account_name: <span class="prelude-val">Some</span>(SecretString::from(<span class="string">"account"</span>.to_string())),
<a href=#490 id=490 data-nosnippet>490</a> azblob_account_key: <span class="prelude-val">Some</span>(SecretString::from(<span class="string">"key"</span>.to_string())),
<a href=#491 id=491 data-nosnippet>491</a> azblob_endpoint: <span class="string">"https://blob.example.com"</span>.to_string(),
<a href=#492 id=492 data-nosnippet>492</a> ..Default::default()
<a href=#493 id=493 data-nosnippet>493</a> },
<a href=#494 id=494 data-nosnippet>494</a> ..Default::default()
<a href=#495 id=495 data-nosnippet>495</a> };
<a href=#496 id=496 data-nosnippet>496</a>
<a href=#497 id=497 data-nosnippet>497</a> <span class="kw">let </span>(connection, <span class="kw">_</span>) = build_azblob_connection(<span class="kw-2">&amp;</span>storage);
<a href=#498 id=498 data-nosnippet>498</a> <span class="macro">assert!</span>(connection.contains(<span class="string">"ENDPOINT='https://blob.example.com'"</span>));
<a href=#499 id=499 data-nosnippet>499</a> }
<a href=#500 id=500 data-nosnippet>500</a>
<a href=#501 id=501 data-nosnippet>501</a> <span class="attr">#[test]
<a href=#502 id=502 data-nosnippet>502</a> </span><span class="kw">fn </span>test_build_azblob_connection_redacts_sas_token() {
<a href=#503 id=503 data-nosnippet>503</a> <span class="kw">let </span>storage = ObjectStoreConfig {
<a href=#504 id=504 data-nosnippet>504</a> azblob: PrefixedAzblobConnection {
<a href=#505 id=505 data-nosnippet>505</a> azblob_account_name: <span class="prelude-val">Some</span>(SecretString::from(<span class="string">"account"</span>.to_string())),
<a href=#506 id=506 data-nosnippet>506</a> azblob_account_key: <span class="prelude-val">Some</span>(SecretString::from(<span class="string">"key"</span>.to_string())),
<a href=#507 id=507 data-nosnippet>507</a> azblob_sas_token: <span class="prelude-val">Some</span>(<span class="string">"sig=secret-token"</span>.to_string()),
<a href=#508 id=508 data-nosnippet>508</a> ..Default::default()
<a href=#509 id=509 data-nosnippet>509</a> },
<a href=#510 id=510 data-nosnippet>510</a> ..Default::default()
<a href=#511 id=511 data-nosnippet>511</a> };
<a href=#512 id=512 data-nosnippet>512</a>
<a href=#513 id=513 data-nosnippet>513</a> <span class="kw">let </span>(connection, secrets) = build_azblob_connection(<span class="kw-2">&amp;</span>storage);
<a href=#514 id=514 data-nosnippet>514</a> <span class="kw">let </span>masked = mask_secrets(<span class="kw-2">&amp;</span>connection, <span class="kw-2">&amp;</span>secrets);
<a href=#515 id=515 data-nosnippet>515</a>
<a href=#516 id=516 data-nosnippet>516</a> <span class="macro">assert!</span>(connection.contains(<span class="string">"SAS_TOKEN='sig=secret-token'"</span>));
<a href=#517 id=517 data-nosnippet>517</a> <span class="macro">assert!</span>(masked.contains(<span class="string">"SAS_TOKEN='[REDACTED]'"</span>));
<a href=#518 id=518 data-nosnippet>518</a> <span class="macro">assert!</span>(!masked.contains(<span class="string">"sig=secret-token"</span>));
<a href=#519 id=519 data-nosnippet>519</a> }
<a href=#520 id=520 data-nosnippet>520</a>
<a href=#521 id=521 data-nosnippet>521</a> <span class="attr">#[test]
<a href=#522 id=522 data-nosnippet>522</a> </span><span class="kw">fn </span>test_mask_secrets_redacts_sql_escaped_literals() {
<a href=#523 id=523 data-nosnippet>523</a> <span class="kw">let </span>sql =
<a href=#524 id=524 data-nosnippet>524</a> <span class="string">"COPY DATABASE \"greptime\".\"public\" TO 's3://bucket' CONNECTION (SECRET='ab''cd');"</span>;
<a href=#525 id=525 data-nosnippet>525</a> <span class="kw">let </span>masked = mask_secrets(sql, <span class="kw-2">&amp;</span>[<span class="prelude-val">Some</span>(<span class="string">"ab'cd"</span>.to_string())]);
<a href=#526 id=526 data-nosnippet>526</a>
<a href=#527 id=527 data-nosnippet>527</a> <span class="macro">assert!</span>(!masked.contains(<span class="string">"ab'cd"</span>));
<a href=#528 id=528 data-nosnippet>528</a> <span class="macro">assert!</span>(!masked.contains(<span class="string">"ab''cd"</span>));
<a href=#529 id=529 data-nosnippet>529</a> <span class="macro">assert!</span>(masked.contains(<span class="string">"SECRET='[REDACTED]'"</span>));
<a href=#530 id=530 data-nosnippet>530</a> }
<a href=#531 id=531 data-nosnippet>531</a>
<a href=#532 id=532 data-nosnippet>532</a> <span class="attr">#[test]
<a href=#533 id=533 data-nosnippet>533</a> </span><span class="kw">fn </span>test_build_copy_target_decodes_file_uri_path() {
<a href=#534 id=534 data-nosnippet>534</a> <span class="kw">let </span>storage = ObjectStoreConfig::default();
<a href=#535 id=535 data-nosnippet>535</a> <span class="kw">let </span>snapshot_root = create_temp_dir(<span class="string">"my backup"</span>);
<a href=#536 id=536 data-nosnippet>536</a> <span class="kw">let </span>snapshot_uri = Url::from_file_path(snapshot_root.path())
<a href=#537 id=537 data-nosnippet>537</a> .expect(<span class="string">"absolute platform path should convert to file:// URI"</span>)
<a href=#538 id=538 data-nosnippet>538</a> .to_string();
<a href=#539 id=539 data-nosnippet>539</a> <span class="kw">let </span>expected = normalize_path(<span class="kw-2">&amp;</span><span class="macro">format!</span>(
<a href=#540 id=540 data-nosnippet>540</a> <span class="string">"{}/{}"</span>,
<a href=#541 id=541 data-nosnippet>541</a> snapshot_root.path().to_string_lossy(),
<a href=#542 id=542 data-nosnippet>542</a> data_dir_for_schema_chunk(<span class="string">"public"</span>, <span class="number">7</span>)
<a href=#543 id=543 data-nosnippet>543</a> ));
<a href=#544 id=544 data-nosnippet>544</a> <span class="kw">let </span>target = build_copy_target(<span class="kw-2">&amp;</span>snapshot_uri, <span class="kw-2">&amp;</span>storage, <span class="string">"public"</span>, <span class="number">7</span>)
<a href=#545 id=545 data-nosnippet>545</a> .expect(<span class="string">"file:// copy target should be built"</span>);
<a href=#546 id=546 data-nosnippet>546</a>
<a href=#547 id=547 data-nosnippet>547</a> <span class="macro">assert!</span>(snapshot_uri.contains(<span class="string">"%20"</span>));
<a href=#548 id=548 data-nosnippet>548</a> <span class="macro">assert!</span>(!target.location.contains(<span class="string">"%20"</span>));
<a href=#549 id=549 data-nosnippet>549</a> <span class="macro">assert!</span>(target.location.contains(<span class="string">"my backup"</span>));
<a href=#550 id=550 data-nosnippet>550</a> <span class="macro">assert_eq!</span>(target.location, expected);
<a href=#551 id=551 data-nosnippet>551</a> }
<a href=#552 id=552 data-nosnippet>552</a>}
</code></pre></div></section></main></body></html>
+267
View File
@@ -0,0 +1,267 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/export_v2/error.rs`."><title>error.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/export_v2/</div>error.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::any::Any;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_error::ext::{ErrorExt, RetryHint};
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_error::status_code::StatusCode;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_macro::stack_trace_debug;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>object_store::error::retry_hint_from_opendal_error;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>snafu::{Location, Snafu};
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a><span class="attr">#[derive(Snafu)]
<a href=#24 id=24 data-nosnippet>24</a>#[snafu(visibility(<span class="kw">pub</span>))]
<a href=#25 id=25 data-nosnippet>25</a>#[stack_trace_debug]
<a href=#26 id=26 data-nosnippet>26</a></span><span class="kw">pub enum </span>Error {
<a href=#27 id=27 data-nosnippet>27</a> <span class="attr">#[snafu(display(
<a href=#28 id=28 data-nosnippet>28</a> <span class="string">"Experimental Metric export requires Parquet and a frontend that explicitly reports experimental_metric_export=true. Use an upgraded, consistently configured frontend entry point."
<a href=#29 id=29 data-nosnippet>29</a> </span>))]
<a href=#30 id=30 data-nosnippet>30</a> </span>MetricExportUnavailable {
<a href=#31 id=31 data-nosnippet>31</a> <span class="attr">#[snafu(implicit)]
<a href=#32 id=32 data-nosnippet>32</a> </span>location: Location,
<a href=#33 id=33 data-nosnippet>33</a> },
<a href=#34 id=34 data-nosnippet>34</a>
<a href=#35 id=35 data-nosnippet>35</a> <span class="attr">#[snafu(display(<span class="string">"Invalid URI '{}': {}"</span>, uri, reason))]
<a href=#36 id=36 data-nosnippet>36</a> </span>InvalidUri {
<a href=#37 id=37 data-nosnippet>37</a> uri: String,
<a href=#38 id=38 data-nosnippet>38</a> reason: String,
<a href=#39 id=39 data-nosnippet>39</a> <span class="attr">#[snafu(implicit)]
<a href=#40 id=40 data-nosnippet>40</a> </span>location: Location,
<a href=#41 id=41 data-nosnippet>41</a> },
<a href=#42 id=42 data-nosnippet>42</a>
<a href=#43 id=43 data-nosnippet>43</a> <span class="attr">#[snafu(display(<span class="string">"Unsupported storage scheme: {}"</span>, scheme))]
<a href=#44 id=44 data-nosnippet>44</a> </span>UnsupportedScheme {
<a href=#45 id=45 data-nosnippet>45</a> scheme: String,
<a href=#46 id=46 data-nosnippet>46</a> <span class="attr">#[snafu(implicit)]
<a href=#47 id=47 data-nosnippet>47</a> </span>location: Location,
<a href=#48 id=48 data-nosnippet>48</a> },
<a href=#49 id=49 data-nosnippet>49</a>
<a href=#50 id=50 data-nosnippet>50</a> <span class="attr">#[snafu(display(<span class="string">"Storage operation '{}' failed"</span>, operation))]
<a href=#51 id=51 data-nosnippet>51</a> </span>StorageOperation {
<a href=#52 id=52 data-nosnippet>52</a> operation: String,
<a href=#53 id=53 data-nosnippet>53</a> <span class="attr">#[snafu(source)]
<a href=#54 id=54 data-nosnippet>54</a> </span>error: object_store::Error,
<a href=#55 id=55 data-nosnippet>55</a> <span class="attr">#[snafu(implicit)]
<a href=#56 id=56 data-nosnippet>56</a> </span>location: Location,
<a href=#57 id=57 data-nosnippet>57</a> },
<a href=#58 id=58 data-nosnippet>58</a>
<a href=#59 id=59 data-nosnippet>59</a> <span class="attr">#[snafu(display(<span class="string">"Failed to parse manifest"</span>))]
<a href=#60 id=60 data-nosnippet>60</a> </span>ManifestParse {
<a href=#61 id=61 data-nosnippet>61</a> <span class="attr">#[snafu(source)]
<a href=#62 id=62 data-nosnippet>62</a> </span>error: serde_json::Error,
<a href=#63 id=63 data-nosnippet>63</a> <span class="attr">#[snafu(implicit)]
<a href=#64 id=64 data-nosnippet>64</a> </span>location: Location,
<a href=#65 id=65 data-nosnippet>65</a> },
<a href=#66 id=66 data-nosnippet>66</a>
<a href=#67 id=67 data-nosnippet>67</a> <span class="attr">#[snafu(display(<span class="string">"Failed to serialize manifest"</span>))]
<a href=#68 id=68 data-nosnippet>68</a> </span>ManifestSerialize {
<a href=#69 id=69 data-nosnippet>69</a> <span class="attr">#[snafu(source)]
<a href=#70 id=70 data-nosnippet>70</a> </span>error: serde_json::Error,
<a href=#71 id=71 data-nosnippet>71</a> <span class="attr">#[snafu(implicit)]
<a href=#72 id=72 data-nosnippet>72</a> </span>location: Location,
<a href=#73 id=73 data-nosnippet>73</a> },
<a href=#74 id=74 data-nosnippet>74</a>
<a href=#75 id=75 data-nosnippet>75</a> <span class="attr">#[snafu(display(<span class="string">"Failed to decode text file as UTF-8"</span>))]
<a href=#76 id=76 data-nosnippet>76</a> </span>TextDecode {
<a href=#77 id=77 data-nosnippet>77</a> <span class="attr">#[snafu(source)]
<a href=#78 id=78 data-nosnippet>78</a> </span>error: std::string::FromUtf8Error,
<a href=#79 id=79 data-nosnippet>79</a> <span class="attr">#[snafu(implicit)]
<a href=#80 id=80 data-nosnippet>80</a> </span>location: Location,
<a href=#81 id=81 data-nosnippet>81</a> },
<a href=#82 id=82 data-nosnippet>82</a>
<a href=#83 id=83 data-nosnippet>83</a> <span class="attr">#[snafu(display(<span class="string">"I/O error while {}: {}"</span>, operation, error))]
<a href=#84 id=84 data-nosnippet>84</a> </span>Io {
<a href=#85 id=85 data-nosnippet>85</a> operation: <span class="kw-2">&amp;</span><span class="lifetime">'static </span>str,
<a href=#86 id=86 data-nosnippet>86</a> error: std::io::Error,
<a href=#87 id=87 data-nosnippet>87</a> <span class="attr">#[snafu(implicit)]
<a href=#88 id=88 data-nosnippet>88</a> </span>location: Location,
<a href=#89 id=89 data-nosnippet>89</a> },
<a href=#90 id=90 data-nosnippet>90</a>
<a href=#91 id=91 data-nosnippet>91</a> <span class="attr">#[snafu(display(
<a href=#92 id=92 data-nosnippet>92</a> <span class="string">"Cannot resume snapshot with a different schema_only mode (existing: {}, requested: {}). Use --force to recreate."</span>,
<a href=#93 id=93 data-nosnippet>93</a> existing_schema_only,
<a href=#94 id=94 data-nosnippet>94</a> requested_schema_only
<a href=#95 id=95 data-nosnippet>95</a> ))]
<a href=#96 id=96 data-nosnippet>96</a> </span>SchemaOnlyModeMismatch {
<a href=#97 id=97 data-nosnippet>97</a> existing_schema_only: bool,
<a href=#98 id=98 data-nosnippet>98</a> requested_schema_only: bool,
<a href=#99 id=99 data-nosnippet>99</a> <span class="attr">#[snafu(implicit)]
<a href=#100 id=100 data-nosnippet>100</a> </span>location: Location,
<a href=#101 id=101 data-nosnippet>101</a> },
<a href=#102 id=102 data-nosnippet>102</a>
<a href=#103 id=103 data-nosnippet>103</a> <span class="attr">#[snafu(display(
<a href=#104 id=104 data-nosnippet>104</a> <span class="string">"Cannot resume snapshot with different {} (existing: {}, requested: {}). Use --force to recreate."</span>,
<a href=#105 id=105 data-nosnippet>105</a> field,
<a href=#106 id=106 data-nosnippet>106</a> existing,
<a href=#107 id=107 data-nosnippet>107</a> requested
<a href=#108 id=108 data-nosnippet>108</a> ))]
<a href=#109 id=109 data-nosnippet>109</a> </span>ResumeConfigMismatch {
<a href=#110 id=110 data-nosnippet>110</a> field: String,
<a href=#111 id=111 data-nosnippet>111</a> existing: String,
<a href=#112 id=112 data-nosnippet>112</a> requested: String,
<a href=#113 id=113 data-nosnippet>113</a> <span class="attr">#[snafu(implicit)]
<a href=#114 id=114 data-nosnippet>114</a> </span>location: Location,
<a href=#115 id=115 data-nosnippet>115</a> },
<a href=#116 id=116 data-nosnippet>116</a>
<a href=#117 id=117 data-nosnippet>117</a> <span class="attr">#[snafu(display(<span class="string">"Failed to parse time: invalid format: {}"</span>, input))]
<a href=#118 id=118 data-nosnippet>118</a> </span>TimeParseInvalidFormat {
<a href=#119 id=119 data-nosnippet>119</a> input: String,
<a href=#120 id=120 data-nosnippet>120</a> <span class="attr">#[snafu(implicit)]
<a href=#121 id=121 data-nosnippet>121</a> </span>location: Location,
<a href=#122 id=122 data-nosnippet>122</a> },
<a href=#123 id=123 data-nosnippet>123</a>
<a href=#124 id=124 data-nosnippet>124</a> <span class="attr">#[snafu(display(<span class="string">"Failed to parse time: end_time is before start_time"</span>))]
<a href=#125 id=125 data-nosnippet>125</a> </span>TimeParseEndBeforeStart {
<a href=#126 id=126 data-nosnippet>126</a> <span class="attr">#[snafu(implicit)]
<a href=#127 id=127 data-nosnippet>127</a> </span>location: Location,
<a href=#128 id=128 data-nosnippet>128</a> },
<a href=#129 id=129 data-nosnippet>129</a>
<a href=#130 id=130 data-nosnippet>130</a> <span class="attr">#[snafu(display(
<a href=#131 id=131 data-nosnippet>131</a> <span class="string">"chunk_time_window requires both --start-time and --end-time to be specified"
<a href=#132 id=132 data-nosnippet>132</a> </span>))]
<a href=#133 id=133 data-nosnippet>133</a> </span>ChunkTimeWindowRequiresBounds {
<a href=#134 id=134 data-nosnippet>134</a> <span class="attr">#[snafu(implicit)]
<a href=#135 id=135 data-nosnippet>135</a> </span>location: Location,
<a href=#136 id=136 data-nosnippet>136</a> },
<a href=#137 id=137 data-nosnippet>137</a>
<a href=#138 id=138 data-nosnippet>138</a> <span class="attr">#[snafu(display(<span class="string">"--schema-only cannot be used with data export arguments: {}"</span>, args))]
<a href=#139 id=139 data-nosnippet>139</a> </span>SchemaOnlyArgsNotAllowed {
<a href=#140 id=140 data-nosnippet>140</a> args: String,
<a href=#141 id=141 data-nosnippet>141</a> <span class="attr">#[snafu(implicit)]
<a href=#142 id=142 data-nosnippet>142</a> </span>location: Location,
<a href=#143 id=143 data-nosnippet>143</a> },
<a href=#144 id=144 data-nosnippet>144</a>
<a href=#145 id=145 data-nosnippet>145</a> <span class="attr">#[snafu(display(<span class="string">"Empty result from query"</span>))]
<a href=#146 id=146 data-nosnippet>146</a> </span>EmptyResult {
<a href=#147 id=147 data-nosnippet>147</a> <span class="attr">#[snafu(implicit)]
<a href=#148 id=148 data-nosnippet>148</a> </span>location: Location,
<a href=#149 id=149 data-nosnippet>149</a> },
<a href=#150 id=150 data-nosnippet>150</a>
<a href=#151 id=151 data-nosnippet>151</a> <span class="attr">#[snafu(display(<span class="string">"Unexpected value type in query result"</span>))]
<a href=#152 id=152 data-nosnippet>152</a> </span>UnexpectedValueType {
<a href=#153 id=153 data-nosnippet>153</a> <span class="attr">#[snafu(implicit)]
<a href=#154 id=154 data-nosnippet>154</a> </span>location: Location,
<a href=#155 id=155 data-nosnippet>155</a> },
<a href=#156 id=156 data-nosnippet>156</a>
<a href=#157 id=157 data-nosnippet>157</a> <span class="attr">#[snafu(display(<span class="string">"Database error"</span>))]
<a href=#158 id=158 data-nosnippet>158</a> </span>Database {
<a href=#159 id=159 data-nosnippet>159</a> <span class="attr">#[snafu(source)]
<a href=#160 id=160 data-nosnippet>160</a> </span>error: <span class="kw">crate</span>::error::Error,
<a href=#161 id=161 data-nosnippet>161</a> <span class="attr">#[snafu(implicit)]
<a href=#162 id=162 data-nosnippet>162</a> </span>location: Location,
<a href=#163 id=163 data-nosnippet>163</a> },
<a href=#164 id=164 data-nosnippet>164</a>
<a href=#165 id=165 data-nosnippet>165</a> <span class="attr">#[snafu(display(<span class="string">"Snapshot not found at '{}'"</span>, uri))]
<a href=#166 id=166 data-nosnippet>166</a> </span>SnapshotNotFound {
<a href=#167 id=167 data-nosnippet>167</a> uri: String,
<a href=#168 id=168 data-nosnippet>168</a> <span class="attr">#[snafu(implicit)]
<a href=#169 id=169 data-nosnippet>169</a> </span>location: Location,
<a href=#170 id=170 data-nosnippet>170</a> },
<a href=#171 id=171 data-nosnippet>171</a>
<a href=#172 id=172 data-nosnippet>172</a> <span class="attr">#[snafu(display(<span class="string">"Schema '{}' not found in catalog '{}'"</span>, schema, catalog))]
<a href=#173 id=173 data-nosnippet>173</a> </span>SchemaNotFound {
<a href=#174 id=174 data-nosnippet>174</a> catalog: String,
<a href=#175 id=175 data-nosnippet>175</a> schema: String,
<a href=#176 id=176 data-nosnippet>176</a> <span class="attr">#[snafu(implicit)]
<a href=#177 id=177 data-nosnippet>177</a> </span>location: Location,
<a href=#178 id=178 data-nosnippet>178</a> },
<a href=#179 id=179 data-nosnippet>179</a>
<a href=#180 id=180 data-nosnippet>180</a> <span class="attr">#[snafu(display(<span class="string">"Failed to parse URL"</span>))]
<a href=#181 id=181 data-nosnippet>181</a> </span>UrlParse {
<a href=#182 id=182 data-nosnippet>182</a> <span class="attr">#[snafu(source)]
<a href=#183 id=183 data-nosnippet>183</a> </span>error: url::ParseError,
<a href=#184 id=184 data-nosnippet>184</a> <span class="attr">#[snafu(implicit)]
<a href=#185 id=185 data-nosnippet>185</a> </span>location: Location,
<a href=#186 id=186 data-nosnippet>186</a> },
<a href=#187 id=187 data-nosnippet>187</a>
<a href=#188 id=188 data-nosnippet>188</a> <span class="attr">#[snafu(display(<span class="string">"Failed to build object store"</span>))]
<a href=#189 id=189 data-nosnippet>189</a> </span>BuildObjectStore {
<a href=#190 id=190 data-nosnippet>190</a> <span class="attr">#[snafu(source)]
<a href=#191 id=191 data-nosnippet>191</a> </span>error: object_store::Error,
<a href=#192 id=192 data-nosnippet>192</a> <span class="attr">#[snafu(implicit)]
<a href=#193 id=193 data-nosnippet>193</a> </span>location: Location,
<a href=#194 id=194 data-nosnippet>194</a> },
<a href=#195 id=195 data-nosnippet>195</a>
<a href=#196 id=196 data-nosnippet>196</a> <span class="attr">#[snafu(display(<span class="string">"Manifest version mismatch: expected {}, found {}"</span>, expected, found))]
<a href=#197 id=197 data-nosnippet>197</a> </span>ManifestVersionMismatch {
<a href=#198 id=198 data-nosnippet>198</a> expected: u32,
<a href=#199 id=199 data-nosnippet>199</a> found: u32,
<a href=#200 id=200 data-nosnippet>200</a> <span class="attr">#[snafu(implicit)]
<a href=#201 id=201 data-nosnippet>201</a> </span>location: Location,
<a href=#202 id=202 data-nosnippet>202</a> },
<a href=#203 id=203 data-nosnippet>203</a>
<a href=#204 id=204 data-nosnippet>204</a> <span class="attr">#[snafu(display(
<a href=#205 id=205 data-nosnippet>205</a> <span class="string">"Snapshot verification failed: {} error(s), {} warning(s)"</span>,
<a href=#206 id=206 data-nosnippet>206</a> errors,
<a href=#207 id=207 data-nosnippet>207</a> warnings
<a href=#208 id=208 data-nosnippet>208</a> ))]
<a href=#209 id=209 data-nosnippet>209</a> </span>SnapshotVerifyFailed {
<a href=#210 id=210 data-nosnippet>210</a> errors: usize,
<a href=#211 id=211 data-nosnippet>211</a> warnings: usize,
<a href=#212 id=212 data-nosnippet>212</a> <span class="attr">#[snafu(implicit)]
<a href=#213 id=213 data-nosnippet>213</a> </span>location: Location,
<a href=#214 id=214 data-nosnippet>214</a> },
<a href=#215 id=215 data-nosnippet>215</a>}
<a href=#216 id=216 data-nosnippet>216</a>
<a href=#217 id=217 data-nosnippet>217</a><span class="kw">pub type </span><span class="prelude-ty">Result</span>&lt;T&gt; = std::result::Result&lt;T, Error&gt;;
<a href=#218 id=218 data-nosnippet>218</a>
<a href=#219 id=219 data-nosnippet>219</a><span class="kw">impl </span>ErrorExt <span class="kw">for </span>Error {
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
<a href=#221 id=221 data-nosnippet>221</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#222 id=222 data-nosnippet>222</a> Error::MetricExportUnavailable { .. }
<a href=#223 id=223 data-nosnippet>223</a> | Error::InvalidUri { .. }
<a href=#224 id=224 data-nosnippet>224</a> | Error::UnsupportedScheme { .. }
<a href=#225 id=225 data-nosnippet>225</a> | Error::SchemaOnlyModeMismatch { .. }
<a href=#226 id=226 data-nosnippet>226</a> | Error::ResumeConfigMismatch { .. }
<a href=#227 id=227 data-nosnippet>227</a> | Error::ManifestVersionMismatch { .. }
<a href=#228 id=228 data-nosnippet>228</a> | Error::SchemaOnlyArgsNotAllowed { .. }
<a href=#229 id=229 data-nosnippet>229</a> | Error::SnapshotVerifyFailed { .. } =&gt; StatusCode::InvalidArguments,
<a href=#230 id=230 data-nosnippet>230</a> Error::TimeParseInvalidFormat { .. }
<a href=#231 id=231 data-nosnippet>231</a> | Error::TimeParseEndBeforeStart { .. }
<a href=#232 id=232 data-nosnippet>232</a> | Error::ChunkTimeWindowRequiresBounds { .. } =&gt; StatusCode::InvalidArguments,
<a href=#233 id=233 data-nosnippet>233</a>
<a href=#234 id=234 data-nosnippet>234</a> Error::StorageOperation { .. }
<a href=#235 id=235 data-nosnippet>235</a> | Error::ManifestParse { .. }
<a href=#236 id=236 data-nosnippet>236</a> | Error::ManifestSerialize { .. }
<a href=#237 id=237 data-nosnippet>237</a> | Error::TextDecode { .. }
<a href=#238 id=238 data-nosnippet>238</a> | Error::BuildObjectStore { .. } =&gt; StatusCode::StorageUnavailable,
<a href=#239 id=239 data-nosnippet>239</a>
<a href=#240 id=240 data-nosnippet>240</a> Error::EmptyResult { .. }
<a href=#241 id=241 data-nosnippet>241</a> | Error::UnexpectedValueType { .. }
<a href=#242 id=242 data-nosnippet>242</a> | Error::UrlParse { .. } =&gt; StatusCode::Internal,
<a href=#243 id=243 data-nosnippet>243</a>
<a href=#244 id=244 data-nosnippet>244</a> Error::Io { .. } =&gt; StatusCode::External,
<a href=#245 id=245 data-nosnippet>245</a>
<a href=#246 id=246 data-nosnippet>246</a> Error::Database { error, .. } =&gt; error.status_code(),
<a href=#247 id=247 data-nosnippet>247</a>
<a href=#248 id=248 data-nosnippet>248</a> Error::SnapshotNotFound { .. } =&gt; StatusCode::InvalidArguments,
<a href=#249 id=249 data-nosnippet>249</a> Error::SchemaNotFound { .. } =&gt; StatusCode::DatabaseNotFound,
<a href=#250 id=250 data-nosnippet>250</a> }
<a href=#251 id=251 data-nosnippet>251</a> }
<a href=#252 id=252 data-nosnippet>252</a>
<a href=#253 id=253 data-nosnippet>253</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>Any {
<a href=#254 id=254 data-nosnippet>254</a> <span class="self">self
<a href=#255 id=255 data-nosnippet>255</a> </span>}
<a href=#256 id=256 data-nosnippet>256</a>
<a href=#257 id=257 data-nosnippet>257</a> <span class="kw">fn </span>retry_hint(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; RetryHint {
<a href=#258 id=258 data-nosnippet>258</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#259 id=259 data-nosnippet>259</a> Error::StorageOperation { error, .. } | Error::BuildObjectStore { error, .. } =&gt; {
<a href=#260 id=260 data-nosnippet>260</a> retry_hint_from_opendal_error(error)
<a href=#261 id=261 data-nosnippet>261</a> }
<a href=#262 id=262 data-nosnippet>262</a> Error::Database { error, .. } =&gt; error.retry_hint(),
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">_ </span>=&gt; RetryHint::NonRetryable,
<a href=#264 id=264 data-nosnippet>264</a> }
<a href=#265 id=265 data-nosnippet>265</a> }
<a href=#266 id=266 data-nosnippet>266</a>}
</code></pre></div></section></main></body></html>
+255
View File
@@ -0,0 +1,255 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/export_v2/extractor.rs`."><title>extractor.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/export_v2/</div>extractor.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! Schema extraction from information_schema.
<a href=#16 id=16 data-nosnippet>16</a>//!
<a href=#17 id=17 data-nosnippet>17</a>//! For V2 DDL-only snapshots, extractor only persists the schema index.
<a href=#18 id=18 data-nosnippet>18</a>
<a href=#19 id=19 data-nosnippet>19</a></span><span class="kw">use </span>std::collections::{HashMap, HashSet};
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>serde_json::Value;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>snafu::ResultExt;
<a href=#23 id=23 data-nosnippet>23</a>
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::error::{
<a href=#25 id=25 data-nosnippet>25</a> DatabaseSnafu, EmptyResultSnafu, <span class="prelude-ty">Result</span>, SchemaNotFoundSnafu, UnexpectedValueTypeSnafu,
<a href=#26 id=26 data-nosnippet>26</a>};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::schema::{SchemaDefinition, SchemaSnapshot};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span><span class="kw">crate</span>::data::sql::escape_sql_literal;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span><span class="kw">crate</span>::database::DatabaseClient;
<a href=#30 id=30 data-nosnippet>30</a>
<a href=#31 id=31 data-nosnippet>31</a><span class="doccomment">/// System schemas that should be excluded from export.
<a href=#32 id=32 data-nosnippet>32</a></span><span class="kw">const </span>SYSTEM_SCHEMAS: <span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span>str] = <span class="kw-2">&amp;</span>[<span class="string">"information_schema"</span>, <span class="string">"pg_catalog"</span>];
<a href=#33 id=33 data-nosnippet>33</a>
<a href=#34 id=34 data-nosnippet>34</a><span class="doccomment">/// Extracts schema definitions from information_schema.
<a href=#35 id=35 data-nosnippet>35</a></span><span class="kw">pub struct </span>SchemaExtractor&lt;<span class="lifetime">'a</span>&gt; {
<a href=#36 id=36 data-nosnippet>36</a> client: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>DatabaseClient,
<a href=#37 id=37 data-nosnippet>37</a> catalog: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str,
<a href=#38 id=38 data-nosnippet>38</a>}
<a href=#39 id=39 data-nosnippet>39</a>
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">impl</span>&lt;<span class="lifetime">'a</span>&gt; SchemaExtractor&lt;<span class="lifetime">'a</span>&gt; {
<a href=#41 id=41 data-nosnippet>41</a> <span class="doccomment">/// Creates a new schema extractor.
<a href=#42 id=42 data-nosnippet>42</a> </span><span class="kw">pub fn </span>new(client: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>DatabaseClient, catalog: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str) -&gt; <span class="self">Self </span>{
<a href=#43 id=43 data-nosnippet>43</a> <span class="self">Self </span>{ client, catalog }
<a href=#44 id=44 data-nosnippet>44</a> }
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a> <span class="doccomment">/// Extracts the schema index for the given schemas.
<a href=#47 id=47 data-nosnippet>47</a> ///
<a href=#48 id=48 data-nosnippet>48</a> /// If `schemas` is None, extracts all non-system schemas.
<a href=#49 id=49 data-nosnippet>49</a> </span><span class="kw">pub async fn </span>extract(<span class="kw-2">&amp;</span><span class="self">self</span>, schemas: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>[String]&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;SchemaSnapshot&gt; {
<a href=#50 id=50 data-nosnippet>50</a> <span class="kw">let </span><span class="kw-2">mut </span>snapshot = SchemaSnapshot::new();
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a> <span class="kw">let </span>schema_names = <span class="kw">match </span>schemas {
<a href=#53 id=53 data-nosnippet>53</a> <span class="prelude-val">Some</span>(names) =&gt; <span class="self">self</span>.validate_schemas(names).<span class="kw">await</span><span class="question-mark">?</span>,
<a href=#54 id=54 data-nosnippet>54</a> <span class="prelude-val">None </span>=&gt; <span class="self">self</span>.get_all_schemas().<span class="kw">await</span><span class="question-mark">?</span>,
<a href=#55 id=55 data-nosnippet>55</a> };
<a href=#56 id=56 data-nosnippet>56</a>
<a href=#57 id=57 data-nosnippet>57</a> <span class="kw">for </span>schema_name <span class="kw">in </span><span class="kw-2">&amp;</span>schema_names {
<a href=#58 id=58 data-nosnippet>58</a> <span class="kw">let </span>schema_def = <span class="self">self</span>.extract_schema_definition(schema_name).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#59 id=59 data-nosnippet>59</a> snapshot.add_schema(schema_def);
<a href=#60 id=60 data-nosnippet>60</a> }
<a href=#61 id=61 data-nosnippet>61</a>
<a href=#62 id=62 data-nosnippet>62</a> <span class="prelude-val">Ok</span>(snapshot)
<a href=#63 id=63 data-nosnippet>63</a> }
<a href=#64 id=64 data-nosnippet>64</a>
<a href=#65 id=65 data-nosnippet>65</a> <span class="doccomment">/// Gets all non-system schemas in the catalog.
<a href=#66 id=66 data-nosnippet>66</a> </span><span class="kw">async fn </span>get_all_schemas(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt; {
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">let </span>sql = <span class="macro">format!</span>(
<a href=#68 id=68 data-nosnippet>68</a> <span class="string">"SELECT schema_name FROM information_schema.schemata \
<a href=#69 id=69 data-nosnippet>69</a> WHERE catalog_name = '{}'"</span>,
<a href=#70 id=70 data-nosnippet>70</a> escape_sql_literal(<span class="self">self</span>.catalog)
<a href=#71 id=71 data-nosnippet>71</a> );
<a href=#72 id=72 data-nosnippet>72</a>
<a href=#73 id=73 data-nosnippet>73</a> <span class="kw">let </span>records = <span class="self">self</span>.query(<span class="kw-2">&amp;</span>sql).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#74 id=74 data-nosnippet>74</a> <span class="kw">let </span><span class="kw-2">mut </span>schemas = Vec::new();
<a href=#75 id=75 data-nosnippet>75</a>
<a href=#76 id=76 data-nosnippet>76</a> <span class="kw">for </span>row <span class="kw">in </span>records {
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">let </span>name = extract_string(<span class="kw-2">&amp;</span>row, <span class="number">0</span>)<span class="question-mark">?</span>;
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">if </span>!SYSTEM_SCHEMAS.contains(<span class="kw-2">&amp;</span>name.as_str()) {
<a href=#79 id=79 data-nosnippet>79</a> schemas.push(name);
<a href=#80 id=80 data-nosnippet>80</a> }
<a href=#81 id=81 data-nosnippet>81</a> }
<a href=#82 id=82 data-nosnippet>82</a>
<a href=#83 id=83 data-nosnippet>83</a> <span class="prelude-val">Ok</span>(schemas)
<a href=#84 id=84 data-nosnippet>84</a> }
<a href=#85 id=85 data-nosnippet>85</a>
<a href=#86 id=86 data-nosnippet>86</a> <span class="doccomment">/// Validates that all specified schemas exist.
<a href=#87 id=87 data-nosnippet>87</a> </span><span class="kw">async fn </span>validate_schemas(<span class="kw-2">&amp;</span><span class="self">self</span>, schemas: <span class="kw-2">&amp;</span>[String]) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt; {
<a href=#88 id=88 data-nosnippet>88</a> <span class="kw">let </span>all_schemas = <span class="self">self</span>.get_all_schemas().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#89 id=89 data-nosnippet>89</a> dedupe_canonicalized_schemas(schemas, <span class="kw-2">&amp;</span>all_schemas, <span class="self">self</span>.catalog)
<a href=#90 id=90 data-nosnippet>90</a> }
<a href=#91 id=91 data-nosnippet>91</a>
<a href=#92 id=92 data-nosnippet>92</a> <span class="doccomment">/// Extracts schema (database) definition.
<a href=#93 id=93 data-nosnippet>93</a> </span><span class="kw">async fn </span>extract_schema_definition(<span class="kw-2">&amp;</span><span class="self">self</span>, schema: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;SchemaDefinition&gt; {
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">let </span>sql = <span class="macro">format!</span>(
<a href=#95 id=95 data-nosnippet>95</a> <span class="string">"SELECT schema_name, options FROM information_schema.schemata \
<a href=#96 id=96 data-nosnippet>96</a> WHERE catalog_name = '{}' AND schema_name = '{}'"</span>,
<a href=#97 id=97 data-nosnippet>97</a> escape_sql_literal(<span class="self">self</span>.catalog),
<a href=#98 id=98 data-nosnippet>98</a> escape_sql_literal(schema)
<a href=#99 id=99 data-nosnippet>99</a> );
<a href=#100 id=100 data-nosnippet>100</a>
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">let </span>records = <span class="self">self</span>.query(<span class="kw-2">&amp;</span>sql).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#102 id=102 data-nosnippet>102</a> <span class="kw">if </span>records.is_empty() {
<a href=#103 id=103 data-nosnippet>103</a> <span class="kw">return </span>SchemaNotFoundSnafu {
<a href=#104 id=104 data-nosnippet>104</a> catalog: <span class="self">self</span>.catalog,
<a href=#105 id=105 data-nosnippet>105</a> schema,
<a href=#106 id=106 data-nosnippet>106</a> }
<a href=#107 id=107 data-nosnippet>107</a> .fail();
<a href=#108 id=108 data-nosnippet>108</a> }
<a href=#109 id=109 data-nosnippet>109</a>
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">let </span>name = extract_string(<span class="kw-2">&amp;</span>records[<span class="number">0</span>], <span class="number">0</span>)<span class="question-mark">?</span>;
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">let </span>options = extract_optional_string(<span class="kw-2">&amp;</span>records[<span class="number">0</span>], <span class="number">1</span>)
<a href=#112 id=112 data-nosnippet>112</a> .map(|opts| parse_options(<span class="kw-2">&amp;</span>opts))
<a href=#113 id=113 data-nosnippet>113</a> .unwrap_or_default();
<a href=#114 id=114 data-nosnippet>114</a>
<a href=#115 id=115 data-nosnippet>115</a> <span class="prelude-val">Ok</span>(SchemaDefinition {
<a href=#116 id=116 data-nosnippet>116</a> catalog: <span class="self">self</span>.catalog.to_string(),
<a href=#117 id=117 data-nosnippet>117</a> name,
<a href=#118 id=118 data-nosnippet>118</a> options,
<a href=#119 id=119 data-nosnippet>119</a> })
<a href=#120 id=120 data-nosnippet>120</a> }
<a href=#121 id=121 data-nosnippet>121</a>
<a href=#122 id=122 data-nosnippet>122</a> <span class="doccomment">/// Executes a SQL query and returns the results.
<a href=#123 id=123 data-nosnippet>123</a> </span><span class="kw">async fn </span>query(<span class="kw-2">&amp;</span><span class="self">self</span>, sql: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;Vec&lt;Value&gt;&gt;&gt; {
<a href=#124 id=124 data-nosnippet>124</a> <span class="self">self</span>.client
<a href=#125 id=125 data-nosnippet>125</a> .sql_in_public(sql)
<a href=#126 id=126 data-nosnippet>126</a> .<span class="kw">await
<a href=#127 id=127 data-nosnippet>127</a> </span>.context(DatabaseSnafu)<span class="question-mark">?
<a href=#128 id=128 data-nosnippet>128</a> </span>.ok_or_else(|| EmptyResultSnafu.build())
<a href=#129 id=129 data-nosnippet>129</a> }
<a href=#130 id=130 data-nosnippet>130</a>}
<a href=#131 id=131 data-nosnippet>131</a>
<a href=#132 id=132 data-nosnippet>132</a><span class="doccomment">/// Extracts a string value from a row.
<a href=#133 id=133 data-nosnippet>133</a></span><span class="kw">fn </span>extract_string(row: <span class="kw-2">&amp;</span>[Value], index: usize) -&gt; <span class="prelude-ty">Result</span>&lt;String&gt; {
<a href=#134 id=134 data-nosnippet>134</a> <span class="kw">match </span>row.get(index) {
<a href=#135 id=135 data-nosnippet>135</a> <span class="prelude-val">Some</span>(Value::String(s)) =&gt; <span class="prelude-val">Ok</span>(s.clone()),
<a href=#136 id=136 data-nosnippet>136</a> <span class="prelude-val">Some</span>(Value::Null) =&gt; UnexpectedValueTypeSnafu.fail(),
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">_ </span>=&gt; UnexpectedValueTypeSnafu.fail(),
<a href=#138 id=138 data-nosnippet>138</a> }
<a href=#139 id=139 data-nosnippet>139</a>}
<a href=#140 id=140 data-nosnippet>140</a>
<a href=#141 id=141 data-nosnippet>141</a><span class="doccomment">/// Extracts an optional string value from a row.
<a href=#142 id=142 data-nosnippet>142</a></span><span class="kw">fn </span>extract_optional_string(row: <span class="kw-2">&amp;</span>[Value], index: usize) -&gt; <span class="prelude-ty">Option</span>&lt;String&gt; {
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">match </span>row.get(index) {
<a href=#144 id=144 data-nosnippet>144</a> <span class="prelude-val">Some</span>(Value::String(s)) <span class="kw">if </span>!s.is_empty() =&gt; <span class="prelude-val">Some</span>(s.clone()),
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
<a href=#146 id=146 data-nosnippet>146</a> }
<a href=#147 id=147 data-nosnippet>147</a>}
<a href=#148 id=148 data-nosnippet>148</a>
<a href=#149 id=149 data-nosnippet>149</a><span class="doccomment">/// Parses options string into a HashMap.
<a href=#150 id=150 data-nosnippet>150</a></span><span class="kw">fn </span>parse_options(options_str: <span class="kw-2">&amp;</span>str) -&gt; HashMap&lt;String, String&gt; {
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">if let </span><span class="prelude-val">Ok</span>(map) = serde_json::from_str::&lt;HashMap&lt;String, String&gt;&gt;(options_str) {
<a href=#152 id=152 data-nosnippet>152</a> <span class="kw">return </span>map;
<a href=#153 id=153 data-nosnippet>153</a> }
<a href=#154 id=154 data-nosnippet>154</a>
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">let </span><span class="kw-2">mut </span>options = HashMap::new();
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">for </span>line <span class="kw">in </span>options_str.lines() {
<a href=#157 id=157 data-nosnippet>157</a> <span class="kw">let </span>trimmed = line.trim();
<a href=#158 id=158 data-nosnippet>158</a> <span class="kw">if </span>trimmed.is_empty() {
<a href=#159 id=159 data-nosnippet>159</a> <span class="kw">continue</span>;
<a href=#160 id=160 data-nosnippet>160</a> }
<a href=#161 id=161 data-nosnippet>161</a>
<a href=#162 id=162 data-nosnippet>162</a> <span class="kw">if let </span><span class="prelude-val">Some</span>((key, value)) = parse_quoted_option_line(trimmed) {
<a href=#163 id=163 data-nosnippet>163</a> options.insert(key, value);
<a href=#164 id=164 data-nosnippet>164</a> <span class="kw">continue</span>;
<a href=#165 id=165 data-nosnippet>165</a> }
<a href=#166 id=166 data-nosnippet>166</a>
<a href=#167 id=167 data-nosnippet>167</a> <span class="kw">for </span>part <span class="kw">in </span>trimmed.split_whitespace() {
<a href=#168 id=168 data-nosnippet>168</a> <span class="kw">if let </span><span class="prelude-val">Some</span>((key, value)) = part.split_once(<span class="string">'='</span>) {
<a href=#169 id=169 data-nosnippet>169</a> options.insert(key.to_string(), value.to_string());
<a href=#170 id=170 data-nosnippet>170</a> }
<a href=#171 id=171 data-nosnippet>171</a> }
<a href=#172 id=172 data-nosnippet>172</a> }
<a href=#173 id=173 data-nosnippet>173</a> options
<a href=#174 id=174 data-nosnippet>174</a>}
<a href=#175 id=175 data-nosnippet>175</a>
<a href=#176 id=176 data-nosnippet>176</a><span class="kw">fn </span>parse_quoted_option_line(line: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;(String, String)&gt; {
<a href=#177 id=177 data-nosnippet>177</a> <span class="kw">let </span>key = line.strip_prefix(<span class="string">'\''</span>)<span class="question-mark">?</span>;
<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">let </span>(key, rest) = key.split_once(<span class="string">"'='"</span>)<span class="question-mark">?</span>;
<a href=#179 id=179 data-nosnippet>179</a> <span class="kw">let </span>value = rest.strip_suffix(<span class="string">'\''</span>)<span class="question-mark">?</span>;
<a href=#180 id=180 data-nosnippet>180</a> <span class="prelude-val">Some</span>((key.to_string(), value.to_string()))
<a href=#181 id=181 data-nosnippet>181</a>}
<a href=#182 id=182 data-nosnippet>182</a>
<a href=#183 id=183 data-nosnippet>183</a><span class="kw">fn </span>dedupe_canonicalized_schemas(
<a href=#184 id=184 data-nosnippet>184</a> requested: <span class="kw-2">&amp;</span>[String],
<a href=#185 id=185 data-nosnippet>185</a> available: <span class="kw-2">&amp;</span>[String],
<a href=#186 id=186 data-nosnippet>186</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#187 id=187 data-nosnippet>187</a>) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt; {
<a href=#188 id=188 data-nosnippet>188</a> <span class="kw">let </span><span class="kw-2">mut </span>canonicalized = Vec::new();
<a href=#189 id=189 data-nosnippet>189</a> <span class="kw">let </span><span class="kw-2">mut </span>seen = HashSet::new();
<a href=#190 id=190 data-nosnippet>190</a>
<a href=#191 id=191 data-nosnippet>191</a> <span class="kw">for </span>schema <span class="kw">in </span>requested {
<a href=#192 id=192 data-nosnippet>192</a> <span class="kw">let </span><span class="prelude-val">Some</span>(canonical) = available.iter().find(|s| s.eq_ignore_ascii_case(schema)) <span class="kw">else </span>{
<a href=#193 id=193 data-nosnippet>193</a> <span class="kw">return </span>SchemaNotFoundSnafu { catalog, schema }.fail();
<a href=#194 id=194 data-nosnippet>194</a> };
<a href=#195 id=195 data-nosnippet>195</a>
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">if </span>seen.insert(canonical.to_ascii_lowercase()) {
<a href=#197 id=197 data-nosnippet>197</a> canonicalized.push(canonical.clone());
<a href=#198 id=198 data-nosnippet>198</a> }
<a href=#199 id=199 data-nosnippet>199</a> }
<a href=#200 id=200 data-nosnippet>200</a>
<a href=#201 id=201 data-nosnippet>201</a> <span class="prelude-val">Ok</span>(canonicalized)
<a href=#202 id=202 data-nosnippet>202</a>}
<a href=#203 id=203 data-nosnippet>203</a>
<a href=#204 id=204 data-nosnippet>204</a><span class="attr">#[cfg(test)]
<a href=#205 id=205 data-nosnippet>205</a></span><span class="kw">mod </span>tests {
<a href=#206 id=206 data-nosnippet>206</a> <span class="kw">use </span>serde_json::Value;
<a href=#207 id=207 data-nosnippet>207</a>
<a href=#208 id=208 data-nosnippet>208</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#209 id=209 data-nosnippet>209</a>
<a href=#210 id=210 data-nosnippet>210</a> <span class="attr">#[test]
<a href=#211 id=211 data-nosnippet>211</a> </span><span class="kw">fn </span>test_parse_options_json() {
<a href=#212 id=212 data-nosnippet>212</a> <span class="kw">let </span>opts = <span class="string">r#"{"ttl": "30d", "custom": "value"}"#</span>;
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">let </span>parsed = parse_options(opts);
<a href=#214 id=214 data-nosnippet>214</a> <span class="macro">assert_eq!</span>(parsed.get(<span class="string">"ttl"</span>), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="string">"30d"</span>.to_string()));
<a href=#215 id=215 data-nosnippet>215</a> <span class="macro">assert_eq!</span>(parsed.get(<span class="string">"custom"</span>), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="string">"value"</span>.to_string()));
<a href=#216 id=216 data-nosnippet>216</a> }
<a href=#217 id=217 data-nosnippet>217</a>
<a href=#218 id=218 data-nosnippet>218</a> <span class="attr">#[test]
<a href=#219 id=219 data-nosnippet>219</a> </span><span class="kw">fn </span>test_parse_options_key_value() {
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">let </span>opts = <span class="string">"ttl=30d custom=value"</span>;
<a href=#221 id=221 data-nosnippet>221</a> <span class="kw">let </span>parsed = parse_options(opts);
<a href=#222 id=222 data-nosnippet>222</a> <span class="macro">assert_eq!</span>(parsed.get(<span class="string">"ttl"</span>), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="string">"30d"</span>.to_string()));
<a href=#223 id=223 data-nosnippet>223</a> <span class="macro">assert_eq!</span>(parsed.get(<span class="string">"custom"</span>), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="string">"value"</span>.to_string()));
<a href=#224 id=224 data-nosnippet>224</a> }
<a href=#225 id=225 data-nosnippet>225</a>
<a href=#226 id=226 data-nosnippet>226</a> <span class="attr">#[test]
<a href=#227 id=227 data-nosnippet>227</a> </span><span class="kw">fn </span>test_parse_options_schema_display_format() {
<a href=#228 id=228 data-nosnippet>228</a> <span class="kw">let </span>opts = <span class="string">"'ttl'='30d'\n'custom'='value with spaces'\n"</span>;
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">let </span>parsed = parse_options(opts);
<a href=#230 id=230 data-nosnippet>230</a> <span class="macro">assert_eq!</span>(parsed.get(<span class="string">"ttl"</span>), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="string">"30d"</span>.to_string()));
<a href=#231 id=231 data-nosnippet>231</a> <span class="macro">assert_eq!</span>(parsed.get(<span class="string">"custom"</span>), <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="string">"value with spaces"</span>.to_string()));
<a href=#232 id=232 data-nosnippet>232</a> }
<a href=#233 id=233 data-nosnippet>233</a>
<a href=#234 id=234 data-nosnippet>234</a> <span class="attr">#[test]
<a href=#235 id=235 data-nosnippet>235</a> </span><span class="kw">fn </span>test_extract_string_rejects_null() {
<a href=#236 id=236 data-nosnippet>236</a> <span class="kw">let </span>row = <span class="macro">vec!</span>[Value::Null];
<a href=#237 id=237 data-nosnippet>237</a> <span class="macro">assert!</span>(extract_string(<span class="kw-2">&amp;</span>row, <span class="number">0</span>).is_err());
<a href=#238 id=238 data-nosnippet>238</a> }
<a href=#239 id=239 data-nosnippet>239</a>
<a href=#240 id=240 data-nosnippet>240</a> <span class="attr">#[test]
<a href=#241 id=241 data-nosnippet>241</a> </span><span class="kw">fn </span>test_dedupe_canonicalized_schemas() {
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">let </span>available = <span class="macro">vec!</span>[<span class="string">"public"</span>.to_string(), <span class="string">"test_db"</span>.to_string()];
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">let </span>requested = <span class="macro">vec!</span>[
<a href=#244 id=244 data-nosnippet>244</a> <span class="string">"PUBLIC"</span>.to_string(),
<a href=#245 id=245 data-nosnippet>245</a> <span class="string">"public"</span>.to_string(),
<a href=#246 id=246 data-nosnippet>246</a> <span class="string">"Test_Db"</span>.to_string(),
<a href=#247 id=247 data-nosnippet>247</a> ];
<a href=#248 id=248 data-nosnippet>248</a>
<a href=#249 id=249 data-nosnippet>249</a> <span class="kw">let </span>canonicalized = dedupe_canonicalized_schemas(<span class="kw-2">&amp;</span>requested, <span class="kw-2">&amp;</span>available, <span class="string">"greptime"</span>)
<a href=#250 id=250 data-nosnippet>250</a> .expect(<span class="string">"schemas should be canonicalized"</span>);
<a href=#251 id=251 data-nosnippet>251</a>
<a href=#252 id=252 data-nosnippet>252</a> <span class="macro">assert_eq!</span>(canonicalized, <span class="macro">vec!</span>[<span class="string">"public"</span>, <span class="string">"test_db"</span>]);
<a href=#253 id=253 data-nosnippet>253</a> }
<a href=#254 id=254 data-nosnippet>254</a>}
</code></pre></div></section></main></body></html>
+738
View File
@@ -0,0 +1,738 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/export_v2/manifest.rs`."><title>manifest.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/export_v2/</div>manifest.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! Manifest data structures for Export/Import V2.
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a></span><span class="kw">use </span>std::collections::HashSet;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>std::time::Duration;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>std::{fmt, str};
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>chrono::{DateTime, Utc};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>serde::{Deserialize, Serialize};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>uuid::Uuid;
<a href=#24 id=24 data-nosnippet>24</a>
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::chunker::generate_chunks;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::error::{
<a href=#27 id=27 data-nosnippet>27</a> ChunkTimeWindowRequiresBoundsSnafu, <span class="prelude-ty">Result </span><span class="kw">as </span>ExportResult, TimeParseEndBeforeStartSnafu,
<a href=#28 id=28 data-nosnippet>28</a> TimeParseInvalidFormatSnafu,
<a href=#29 id=29 data-nosnippet>29</a>};
<a href=#30 id=30 data-nosnippet>30</a>
<a href=#31 id=31 data-nosnippet>31</a><span class="doccomment">/// Default standalone manifest version. Packed data snapshots use version 2.
<a href=#32 id=32 data-nosnippet>32</a></span><span class="kw">pub const </span>MANIFEST_VERSION: u32 = <span class="number">1</span>;
<a href=#33 id=33 data-nosnippet>33</a>
<a href=#34 id=34 data-nosnippet>34</a><span class="doccomment">/// Manifest file name within snapshot directory.
<a href=#35 id=35 data-nosnippet>35</a></span><span class="kw">pub const </span>MANIFEST_FILE: <span class="kw-2">&amp;</span>str = <span class="string">"manifest.json"</span>;
<a href=#36 id=36 data-nosnippet>36</a>
<a href=#37 id=37 data-nosnippet>37</a><span class="doccomment">/// Time range for data export (half-open interval: [start, end)).
<a href=#38 id=38 data-nosnippet>38</a></span><span class="attr">#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
<a href=#39 id=39 data-nosnippet>39</a></span><span class="kw">pub struct </span>TimeRange {
<a href=#40 id=40 data-nosnippet>40</a> <span class="doccomment">/// Start time (inclusive). None means earliest available data.
<a href=#41 id=41 data-nosnippet>41</a> </span><span class="attr">#[serde(skip_serializing_if = <span class="string">"Option::is_none"</span>)]
<a href=#42 id=42 data-nosnippet>42</a> </span><span class="kw">pub </span>start: <span class="prelude-ty">Option</span>&lt;DateTime&lt;Utc&gt;&gt;,
<a href=#43 id=43 data-nosnippet>43</a> <span class="doccomment">/// End time (exclusive). None means current time.
<a href=#44 id=44 data-nosnippet>44</a> </span><span class="attr">#[serde(skip_serializing_if = <span class="string">"Option::is_none"</span>)]
<a href=#45 id=45 data-nosnippet>45</a> </span><span class="kw">pub </span>end: <span class="prelude-ty">Option</span>&lt;DateTime&lt;Utc&gt;&gt;,
<a href=#46 id=46 data-nosnippet>46</a>}
<a href=#47 id=47 data-nosnippet>47</a>
<a href=#48 id=48 data-nosnippet>48</a><span class="kw">impl </span>TimeRange {
<a href=#49 id=49 data-nosnippet>49</a> <span class="doccomment">/// Creates a new time range with specified bounds.
<a href=#50 id=50 data-nosnippet>50</a> </span><span class="kw">pub fn </span>new(start: <span class="prelude-ty">Option</span>&lt;DateTime&lt;Utc&gt;&gt;, end: <span class="prelude-ty">Option</span>&lt;DateTime&lt;Utc&gt;&gt;) -&gt; <span class="self">Self </span>{
<a href=#51 id=51 data-nosnippet>51</a> <span class="self">Self </span>{ start, end }
<a href=#52 id=52 data-nosnippet>52</a> }
<a href=#53 id=53 data-nosnippet>53</a>
<a href=#54 id=54 data-nosnippet>54</a> <span class="doccomment">/// Creates an unbounded time range (all data).
<a href=#55 id=55 data-nosnippet>55</a> </span><span class="kw">pub fn </span>unbounded() -&gt; <span class="self">Self </span>{
<a href=#56 id=56 data-nosnippet>56</a> <span class="self">Self </span>{
<a href=#57 id=57 data-nosnippet>57</a> start: <span class="prelude-val">None</span>,
<a href=#58 id=58 data-nosnippet>58</a> end: <span class="prelude-val">None</span>,
<a href=#59 id=59 data-nosnippet>59</a> }
<a href=#60 id=60 data-nosnippet>60</a> }
<a href=#61 id=61 data-nosnippet>61</a>
<a href=#62 id=62 data-nosnippet>62</a> <span class="doccomment">/// Returns true if this time range is unbounded.
<a href=#63 id=63 data-nosnippet>63</a> </span><span class="kw">pub fn </span>is_unbounded(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#64 id=64 data-nosnippet>64</a> <span class="self">self</span>.start.is_none() &amp;&amp; <span class="self">self</span>.end.is_none()
<a href=#65 id=65 data-nosnippet>65</a> }
<a href=#66 id=66 data-nosnippet>66</a>
<a href=#67 id=67 data-nosnippet>67</a> <span class="doccomment">/// Returns true if both bounds are specified.
<a href=#68 id=68 data-nosnippet>68</a> </span><span class="kw">pub fn </span>is_bounded(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#69 id=69 data-nosnippet>69</a> <span class="self">self</span>.start.is_some() &amp;&amp; <span class="self">self</span>.end.is_some()
<a href=#70 id=70 data-nosnippet>70</a> }
<a href=#71 id=71 data-nosnippet>71</a>
<a href=#72 id=72 data-nosnippet>72</a> <span class="doccomment">/// Parses a time range from optional RFC3339 strings.
<a href=#73 id=73 data-nosnippet>73</a> </span><span class="kw">pub fn </span>parse(start: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt;, end: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt;) -&gt; ExportResult&lt;<span class="self">Self</span>&gt; {
<a href=#74 id=74 data-nosnippet>74</a> <span class="kw">let </span>start = start.map(parse_time).transpose()<span class="question-mark">?</span>;
<a href=#75 id=75 data-nosnippet>75</a> <span class="kw">let </span>end = end.map(parse_time).transpose()<span class="question-mark">?</span>;
<a href=#76 id=76 data-nosnippet>76</a>
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">if let </span>(<span class="prelude-val">Some</span>(start), <span class="prelude-val">Some</span>(end)) = (start, end)
<a href=#78 id=78 data-nosnippet>78</a> &amp;&amp; end &lt; start
<a href=#79 id=79 data-nosnippet>79</a> {
<a href=#80 id=80 data-nosnippet>80</a> <span class="kw">return </span>TimeParseEndBeforeStartSnafu.fail();
<a href=#81 id=81 data-nosnippet>81</a> }
<a href=#82 id=82 data-nosnippet>82</a>
<a href=#83 id=83 data-nosnippet>83</a> <span class="prelude-val">Ok</span>(<span class="self">Self</span>::new(start, end))
<a href=#84 id=84 data-nosnippet>84</a> }
<a href=#85 id=85 data-nosnippet>85</a>}
<a href=#86 id=86 data-nosnippet>86</a>
<a href=#87 id=87 data-nosnippet>87</a><span class="kw">fn </span>parse_time(input: <span class="kw-2">&amp;</span>str) -&gt; ExportResult&lt;DateTime&lt;Utc&gt;&gt; {
<a href=#88 id=88 data-nosnippet>88</a> DateTime::parse_from_rfc3339(input)
<a href=#89 id=89 data-nosnippet>89</a> .map(|dt| dt.with_timezone(<span class="kw-2">&amp;</span>Utc))
<a href=#90 id=90 data-nosnippet>90</a> .map_err(|<span class="kw">_</span>| TimeParseInvalidFormatSnafu { input }.build())
<a href=#91 id=91 data-nosnippet>91</a>}
<a href=#92 id=92 data-nosnippet>92</a>
<a href=#93 id=93 data-nosnippet>93</a><span class="kw">impl </span>Default <span class="kw">for </span>TimeRange {
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">fn </span>default() -&gt; <span class="self">Self </span>{
<a href=#95 id=95 data-nosnippet>95</a> <span class="self">Self</span>::unbounded()
<a href=#96 id=96 data-nosnippet>96</a> }
<a href=#97 id=97 data-nosnippet>97</a>}
<a href=#98 id=98 data-nosnippet>98</a>
<a href=#99 id=99 data-nosnippet>99</a><span class="doccomment">/// Status of a chunk during export/import.
<a href=#100 id=100 data-nosnippet>100</a></span><span class="attr">#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
<a href=#101 id=101 data-nosnippet>101</a>#[serde(rename_all = <span class="string">"snake_case"</span>)]
<a href=#102 id=102 data-nosnippet>102</a></span><span class="kw">pub enum </span>ChunkStatus {
<a href=#103 id=103 data-nosnippet>103</a> <span class="doccomment">/// Chunk is pending export.
<a href=#104 id=104 data-nosnippet>104</a> </span><span class="attr">#[default]
<a href=#105 id=105 data-nosnippet>105</a> </span>Pending,
<a href=#106 id=106 data-nosnippet>106</a> <span class="doccomment">/// Chunk export is in progress.
<a href=#107 id=107 data-nosnippet>107</a> </span>InProgress,
<a href=#108 id=108 data-nosnippet>108</a> <span class="doccomment">/// Chunk export completed successfully.
<a href=#109 id=109 data-nosnippet>109</a> </span>Completed,
<a href=#110 id=110 data-nosnippet>110</a> <span class="doccomment">/// Chunk had no data to export.
<a href=#111 id=111 data-nosnippet>111</a> </span>Skipped,
<a href=#112 id=112 data-nosnippet>112</a> <span class="doccomment">/// Chunk export failed.
<a href=#113 id=113 data-nosnippet>113</a> </span>Failed,
<a href=#114 id=114 data-nosnippet>114</a>}
<a href=#115 id=115 data-nosnippet>115</a>
<a href=#116 id=116 data-nosnippet>116</a><span class="doccomment">/// Metadata for a single chunk of exported data.
<a href=#117 id=117 data-nosnippet>117</a></span><span class="attr">#[derive(Debug, Clone, Serialize, Deserialize)]
<a href=#118 id=118 data-nosnippet>118</a></span><span class="kw">pub struct </span>ChunkMeta {
<a href=#119 id=119 data-nosnippet>119</a> <span class="doccomment">/// Chunk identifier (sequential number starting from 1).
<a href=#120 id=120 data-nosnippet>120</a> </span><span class="kw">pub </span>id: u32,
<a href=#121 id=121 data-nosnippet>121</a> <span class="doccomment">/// Time range covered by this chunk.
<a href=#122 id=122 data-nosnippet>122</a> </span><span class="kw">pub </span>time_range: TimeRange,
<a href=#123 id=123 data-nosnippet>123</a> <span class="doccomment">/// Export status.
<a href=#124 id=124 data-nosnippet>124</a> </span><span class="kw">pub </span>status: ChunkStatus,
<a href=#125 id=125 data-nosnippet>125</a> <span class="doccomment">/// List of data files in this chunk (relative paths from snapshot root).
<a href=#126 id=126 data-nosnippet>126</a> </span><span class="attr">#[serde(default)]
<a href=#127 id=127 data-nosnippet>127</a> </span><span class="kw">pub </span>files: Vec&lt;String&gt;,
<a href=#128 id=128 data-nosnippet>128</a> <span class="doccomment">/// SHA256 checksum of all files in this chunk (aggregated).
<a href=#129 id=129 data-nosnippet>129</a> </span><span class="attr">#[serde(skip_serializing_if = <span class="string">"Option::is_none"</span>)]
<a href=#130 id=130 data-nosnippet>130</a> </span><span class="kw">pub </span>checksum: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#131 id=131 data-nosnippet>131</a> <span class="doccomment">/// Error message if status is Failed.
<a href=#132 id=132 data-nosnippet>132</a> </span><span class="attr">#[serde(skip_serializing_if = <span class="string">"Option::is_none"</span>)]
<a href=#133 id=133 data-nosnippet>133</a> </span><span class="kw">pub </span>error: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#134 id=134 data-nosnippet>134</a>}
<a href=#135 id=135 data-nosnippet>135</a>
<a href=#136 id=136 data-nosnippet>136</a><span class="kw">impl </span>ChunkMeta {
<a href=#137 id=137 data-nosnippet>137</a> <span class="doccomment">/// Creates a new pending chunk with the given id and time range.
<a href=#138 id=138 data-nosnippet>138</a> </span><span class="kw">pub fn </span>new(id: u32, time_range: TimeRange) -&gt; <span class="self">Self </span>{
<a href=#139 id=139 data-nosnippet>139</a> <span class="self">Self </span>{
<a href=#140 id=140 data-nosnippet>140</a> id,
<a href=#141 id=141 data-nosnippet>141</a> time_range,
<a href=#142 id=142 data-nosnippet>142</a> status: ChunkStatus::Pending,
<a href=#143 id=143 data-nosnippet>143</a> files: <span class="macro">vec!</span>[],
<a href=#144 id=144 data-nosnippet>144</a> checksum: <span class="prelude-val">None</span>,
<a href=#145 id=145 data-nosnippet>145</a> error: <span class="prelude-val">None</span>,
<a href=#146 id=146 data-nosnippet>146</a> }
<a href=#147 id=147 data-nosnippet>147</a> }
<a href=#148 id=148 data-nosnippet>148</a>
<a href=#149 id=149 data-nosnippet>149</a> <span class="doccomment">/// Creates a skipped chunk with the given id and time range.
<a href=#150 id=150 data-nosnippet>150</a> </span><span class="kw">pub fn </span>skipped(id: u32, time_range: TimeRange) -&gt; <span class="self">Self </span>{
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">let </span><span class="kw-2">mut </span>chunk = <span class="self">Self</span>::new(id, time_range);
<a href=#152 id=152 data-nosnippet>152</a> chunk.mark_skipped();
<a href=#153 id=153 data-nosnippet>153</a> chunk
<a href=#154 id=154 data-nosnippet>154</a> }
<a href=#155 id=155 data-nosnippet>155</a>
<a href=#156 id=156 data-nosnippet>156</a> <span class="doccomment">/// Marks this chunk as in progress.
<a href=#157 id=157 data-nosnippet>157</a> </span><span class="kw">pub fn </span>mark_in_progress(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#158 id=158 data-nosnippet>158</a> <span class="self">self</span>.status = ChunkStatus::InProgress;
<a href=#159 id=159 data-nosnippet>159</a> <span class="self">self</span>.error = <span class="prelude-val">None</span>;
<a href=#160 id=160 data-nosnippet>160</a> }
<a href=#161 id=161 data-nosnippet>161</a>
<a href=#162 id=162 data-nosnippet>162</a> <span class="doccomment">/// Marks this chunk as completed with the given files and checksum.
<a href=#163 id=163 data-nosnippet>163</a> </span><span class="kw">pub fn </span>mark_completed(<span class="kw-2">&amp;mut </span><span class="self">self</span>, files: Vec&lt;String&gt;, checksum: <span class="prelude-ty">Option</span>&lt;String&gt;) {
<a href=#164 id=164 data-nosnippet>164</a> <span class="self">self</span>.status = ChunkStatus::Completed;
<a href=#165 id=165 data-nosnippet>165</a> <span class="self">self</span>.files = files;
<a href=#166 id=166 data-nosnippet>166</a> <span class="self">self</span>.checksum = checksum;
<a href=#167 id=167 data-nosnippet>167</a> <span class="self">self</span>.error = <span class="prelude-val">None</span>;
<a href=#168 id=168 data-nosnippet>168</a> }
<a href=#169 id=169 data-nosnippet>169</a>
<a href=#170 id=170 data-nosnippet>170</a> <span class="doccomment">/// Marks this chunk as skipped because no data files were produced.
<a href=#171 id=171 data-nosnippet>171</a> </span><span class="kw">pub fn </span>mark_skipped(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#172 id=172 data-nosnippet>172</a> <span class="self">self</span>.status = ChunkStatus::Skipped;
<a href=#173 id=173 data-nosnippet>173</a> <span class="self">self</span>.files.clear();
<a href=#174 id=174 data-nosnippet>174</a> <span class="self">self</span>.checksum = <span class="prelude-val">None</span>;
<a href=#175 id=175 data-nosnippet>175</a> <span class="self">self</span>.error = <span class="prelude-val">None</span>;
<a href=#176 id=176 data-nosnippet>176</a> }
<a href=#177 id=177 data-nosnippet>177</a>
<a href=#178 id=178 data-nosnippet>178</a> <span class="doccomment">/// Marks this chunk as failed with the given error message.
<a href=#179 id=179 data-nosnippet>179</a> </span><span class="kw">pub fn </span>mark_failed(<span class="kw-2">&amp;mut </span><span class="self">self</span>, error: String) {
<a href=#180 id=180 data-nosnippet>180</a> <span class="self">self</span>.status = ChunkStatus::Failed;
<a href=#181 id=181 data-nosnippet>181</a> <span class="self">self</span>.error = <span class="prelude-val">Some</span>(error);
<a href=#182 id=182 data-nosnippet>182</a> }
<a href=#183 id=183 data-nosnippet>183</a>}
<a href=#184 id=184 data-nosnippet>184</a>
<a href=#185 id=185 data-nosnippet>185</a><span class="doccomment">/// Supported data formats for export.
<a href=#186 id=186 data-nosnippet>186</a></span><span class="attr">#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default, clap::ValueEnum)]
<a href=#187 id=187 data-nosnippet>187</a>#[serde(rename_all = <span class="string">"lowercase"</span>)]
<a href=#188 id=188 data-nosnippet>188</a>#[value(rename_all = <span class="string">"lowercase"</span>)]
<a href=#189 id=189 data-nosnippet>189</a></span><span class="kw">pub enum </span>DataFormat {
<a href=#190 id=190 data-nosnippet>190</a> <span class="doccomment">/// Apache Parquet format (default, recommended for production).
<a href=#191 id=191 data-nosnippet>191</a> </span><span class="attr">#[default]
<a href=#192 id=192 data-nosnippet>192</a> </span>Parquet,
<a href=#193 id=193 data-nosnippet>193</a> <span class="doccomment">/// CSV format (human-readable).
<a href=#194 id=194 data-nosnippet>194</a> </span>Csv,
<a href=#195 id=195 data-nosnippet>195</a> <span class="doccomment">/// JSON format (structured text).
<a href=#196 id=196 data-nosnippet>196</a> </span>Json,
<a href=#197 id=197 data-nosnippet>197</a>}
<a href=#198 id=198 data-nosnippet>198</a>
<a href=#199 id=199 data-nosnippet>199</a><span class="kw">impl </span>fmt::Display <span class="kw">for </span>DataFormat {
<a href=#200 id=200 data-nosnippet>200</a> <span class="kw">fn </span>fmt(<span class="kw-2">&amp;</span><span class="self">self</span>, f: <span class="kw-2">&amp;mut </span>fmt::Formatter&lt;<span class="lifetime">'_</span>&gt;) -&gt; fmt::Result {
<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#202 id=202 data-nosnippet>202</a> DataFormat::Parquet =&gt; <span class="macro">write!</span>(f, <span class="string">"parquet"</span>),
<a href=#203 id=203 data-nosnippet>203</a> DataFormat::Csv =&gt; <span class="macro">write!</span>(f, <span class="string">"csv"</span>),
<a href=#204 id=204 data-nosnippet>204</a> DataFormat::Json =&gt; <span class="macro">write!</span>(f, <span class="string">"json"</span>),
<a href=#205 id=205 data-nosnippet>205</a> }
<a href=#206 id=206 data-nosnippet>206</a> }
<a href=#207 id=207 data-nosnippet>207</a>}
<a href=#208 id=208 data-nosnippet>208</a>
<a href=#209 id=209 data-nosnippet>209</a><span class="kw">impl </span>str::FromStr <span class="kw">for </span>DataFormat {
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">type </span><span class="prelude-val">Err </span>= String;
<a href=#211 id=211 data-nosnippet>211</a>
<a href=#212 id=212 data-nosnippet>212</a> <span class="kw">fn </span>from_str(s: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, <span class="self">Self</span>::Err&gt; {
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">match </span>s.to_lowercase().as_str() {
<a href=#214 id=214 data-nosnippet>214</a> <span class="string">"parquet" </span>=&gt; <span class="prelude-val">Ok</span>(DataFormat::Parquet),
<a href=#215 id=215 data-nosnippet>215</a> <span class="string">"csv" </span>=&gt; <span class="prelude-val">Ok</span>(DataFormat::Csv),
<a href=#216 id=216 data-nosnippet>216</a> <span class="string">"json" </span>=&gt; <span class="prelude-val">Ok</span>(DataFormat::Json),
<a href=#217 id=217 data-nosnippet>217</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">Err</span>(<span class="macro">format!</span>(
<a href=#218 id=218 data-nosnippet>218</a> <span class="string">"invalid format '{}': expected one of parquet, csv, json"</span>,
<a href=#219 id=219 data-nosnippet>219</a> s
<a href=#220 id=220 data-nosnippet>220</a> )),
<a href=#221 id=221 data-nosnippet>221</a> }
<a href=#222 id=222 data-nosnippet>222</a> }
<a href=#223 id=223 data-nosnippet>223</a>}
<a href=#224 id=224 data-nosnippet>224</a>
<a href=#225 id=225 data-nosnippet>225</a><span class="doccomment">/// Snapshot manifest containing all metadata.
<a href=#226 id=226 data-nosnippet>226</a>///
<a href=#227 id=227 data-nosnippet>227</a>/// The manifest is stored as `manifest.json` in the snapshot root directory.
<a href=#228 id=228 data-nosnippet>228</a>/// It contains:
<a href=#229 id=229 data-nosnippet>229</a>/// - Snapshot identification (UUID, timestamps)
<a href=#230 id=230 data-nosnippet>230</a>/// - Scope (catalog, schemas, time range)
<a href=#231 id=231 data-nosnippet>231</a>/// - Export configuration (format, schema_only)
<a href=#232 id=232 data-nosnippet>232</a>/// - Chunk metadata for resume support
<a href=#233 id=233 data-nosnippet>233</a>/// - Integrity checksums
<a href=#234 id=234 data-nosnippet>234</a></span><span class="attr">#[derive(Debug, Clone, Serialize, Deserialize)]
<a href=#235 id=235 data-nosnippet>235</a></span><span class="kw">pub struct </span>Manifest {
<a href=#236 id=236 data-nosnippet>236</a> <span class="doccomment">/// Manifest format version for compatibility checking.
<a href=#237 id=237 data-nosnippet>237</a> </span><span class="kw">pub </span>version: u32,
<a href=#238 id=238 data-nosnippet>238</a> <span class="attr">#[serde(default, skip_serializing_if = <span class="string">"Option::is_none"</span>)]
<a href=#239 id=239 data-nosnippet>239</a> </span><span class="kw">pub </span>data_layout: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#240 id=240 data-nosnippet>240</a> <span class="doccomment">/// Unique snapshot identifier.
<a href=#241 id=241 data-nosnippet>241</a> </span><span class="kw">pub </span>snapshot_id: Uuid,
<a href=#242 id=242 data-nosnippet>242</a> <span class="doccomment">/// Catalog name.
<a href=#243 id=243 data-nosnippet>243</a> </span><span class="kw">pub </span>catalog: String,
<a href=#244 id=244 data-nosnippet>244</a> <span class="doccomment">/// List of schemas included in this snapshot.
<a href=#245 id=245 data-nosnippet>245</a> </span><span class="kw">pub </span>schemas: Vec&lt;String&gt;,
<a href=#246 id=246 data-nosnippet>246</a> <span class="doccomment">/// Overall time range covered by this snapshot.
<a href=#247 id=247 data-nosnippet>247</a> </span><span class="kw">pub </span>time_range: TimeRange,
<a href=#248 id=248 data-nosnippet>248</a> <span class="doccomment">/// Whether this is a schema-only snapshot (no data).
<a href=#249 id=249 data-nosnippet>249</a> </span><span class="kw">pub </span>schema_only: bool,
<a href=#250 id=250 data-nosnippet>250</a> <span class="doccomment">/// Data format used for export.
<a href=#251 id=251 data-nosnippet>251</a> </span><span class="kw">pub </span>format: DataFormat,
<a href=#252 id=252 data-nosnippet>252</a> <span class="doccomment">/// Chunk metadata (empty for schema-only snapshots).
<a href=#253 id=253 data-nosnippet>253</a> </span><span class="attr">#[serde(default)]
<a href=#254 id=254 data-nosnippet>254</a> </span><span class="kw">pub </span>chunks: Vec&lt;ChunkMeta&gt;,
<a href=#255 id=255 data-nosnippet>255</a> <span class="doccomment">/// Snapshot-level SHA256 checksum (aggregated from all chunks).
<a href=#256 id=256 data-nosnippet>256</a> </span><span class="attr">#[serde(skip_serializing_if = <span class="string">"Option::is_none"</span>)]
<a href=#257 id=257 data-nosnippet>257</a> </span><span class="kw">pub </span>checksum: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#258 id=258 data-nosnippet>258</a> <span class="doccomment">/// Creation timestamp.
<a href=#259 id=259 data-nosnippet>259</a> </span><span class="kw">pub </span>created_at: DateTime&lt;Utc&gt;,
<a href=#260 id=260 data-nosnippet>260</a> <span class="doccomment">/// Last updated timestamp.
<a href=#261 id=261 data-nosnippet>261</a> </span><span class="kw">pub </span>updated_at: DateTime&lt;Utc&gt;,
<a href=#262 id=262 data-nosnippet>262</a>}
<a href=#263 id=263 data-nosnippet>263</a>
<a href=#264 id=264 data-nosnippet>264</a><span class="kw">impl </span>Manifest {
<a href=#265 id=265 data-nosnippet>265</a> <span class="doccomment">/// Decodes version-specific required fields without changing version-1 defaults.
<a href=#266 id=266 data-nosnippet>266</a> </span><span class="kw">pub fn </span>from_json(data: <span class="kw-2">&amp;</span>[u8]) -&gt; serde_json::Result&lt;<span class="self">Self</span>&gt; {
<a href=#267 id=267 data-nosnippet>267</a> <span class="kw">use </span>serde::de::Error;
<a href=#268 id=268 data-nosnippet>268</a>
<a href=#269 id=269 data-nosnippet>269</a> <span class="kw">let </span>value: serde_json::Value = serde_json::from_slice(data)<span class="question-mark">?</span>;
<a href=#270 id=270 data-nosnippet>270</a> <span class="kw">if </span>value[<span class="string">"version"</span>] == <span class="number">2 </span>{
<a href=#271 id=271 data-nosnippet>271</a> <span class="kw">let </span>chunks = value[<span class="string">"chunks"</span>].as_array().ok_or_else(|| {
<a href=#272 id=272 data-nosnippet>272</a> serde_json::Error::custom(<span class="string">"version-2 manifest requires a chunks array"</span>)
<a href=#273 id=273 data-nosnippet>273</a> })<span class="question-mark">?</span>;
<a href=#274 id=274 data-nosnippet>274</a> <span class="kw">for </span>chunk <span class="kw">in </span>chunks {
<a href=#275 id=275 data-nosnippet>275</a> <span class="kw">if </span>!chunk[<span class="string">"files"</span>].is_array() {
<a href=#276 id=276 data-nosnippet>276</a> <span class="kw">return </span><span class="prelude-val">Err</span>(serde_json::Error::custom(
<a href=#277 id=277 data-nosnippet>277</a> <span class="string">"version-2 chunk requires a files array"</span>,
<a href=#278 id=278 data-nosnippet>278</a> ));
<a href=#279 id=279 data-nosnippet>279</a> }
<a href=#280 id=280 data-nosnippet>280</a> }
<a href=#281 id=281 data-nosnippet>281</a> }
<a href=#282 id=282 data-nosnippet>282</a> serde_json::from_slice(data)
<a href=#283 id=283 data-nosnippet>283</a> }
<a href=#284 id=284 data-nosnippet>284</a>
<a href=#285 id=285 data-nosnippet>285</a> <span class="doccomment">/// Validates the encoding contract before any snapshot operation.
<a href=#286 id=286 data-nosnippet>286</a> </span><span class="kw">pub fn </span>validate_layout(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;(), String&gt; {
<a href=#287 id=287 data-nosnippet>287</a> <span class="kw">match </span>(<span class="self">self</span>.version, <span class="self">self</span>.data_layout.as_deref(), <span class="self">self</span>.format) {
<a href=#288 id=288 data-nosnippet>288</a> (<span class="number">1</span>, <span class="prelude-val">None</span>, <span class="kw">_</span>) =&gt; <span class="prelude-val">Ok</span>(()),
<a href=#289 id=289 data-nosnippet>289</a> (<span class="number">2</span>, <span class="prelude-val">Some</span>(common_datasource::packed_snapshot::PACKED_LAYOUT), DataFormat::Parquet) =&gt; {
<a href=#290 id=290 data-nosnippet>290</a> <span class="kw">if </span><span class="self">self</span>.checksum.is_some() || <span class="self">self</span>.chunks.iter().any(|c| c.checksum.is_some()) {
<a href=#291 id=291 data-nosnippet>291</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="string">"version-2 checksums are unsupported"</span>.into());
<a href=#292 id=292 data-nosnippet>292</a> }
<a href=#293 id=293 data-nosnippet>293</a> <span class="kw">if </span><span class="self">self</span>.schema_only != <span class="self">self</span>.chunks.is_empty() {
<a href=#294 id=294 data-nosnippet>294</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="string">"version-2 schema_only requires empty chunks; data snapshots require chunks"</span>.into());
<a href=#295 id=295 data-nosnippet>295</a> }
<a href=#296 id=296 data-nosnippet>296</a> <span class="kw">let </span>schemas: HashSet&lt;<span class="kw">_</span>&gt; = <span class="self">self</span>.schemas.iter().collect();
<a href=#297 id=297 data-nosnippet>297</a> <span class="kw">if </span>schemas.len() != <span class="self">self</span>.schemas.len() {
<a href=#298 id=298 data-nosnippet>298</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="string">"duplicate version-2 schemas"</span>.into());
<a href=#299 id=299 data-nosnippet>299</a> }
<a href=#300 id=300 data-nosnippet>300</a> <span class="kw">let </span><span class="kw-2">mut </span>ids = HashSet::new();
<a href=#301 id=301 data-nosnippet>301</a> <span class="kw">for </span>chunk <span class="kw">in </span><span class="kw-2">&amp;</span><span class="self">self</span>.chunks {
<a href=#302 id=302 data-nosnippet>302</a> <span class="kw">if </span>chunk.id == <span class="number">0 </span>|| !ids.insert(chunk.id) {
<a href=#303 id=303 data-nosnippet>303</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="string">"version-2 chunk IDs must be unique and positive"</span>.into());
<a href=#304 id=304 data-nosnippet>304</a> }
<a href=#305 id=305 data-nosnippet>305</a> <span class="kw">let </span>files: HashSet&lt;<span class="kw">_</span>&gt; = chunk.files.iter().collect();
<a href=#306 id=306 data-nosnippet>306</a> <span class="kw">if </span>files.len() != chunk.files.len() {
<a href=#307 id=307 data-nosnippet>307</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="string">"duplicate version-2 chunk files"</span>.into());
<a href=#308 id=308 data-nosnippet>308</a> }
<a href=#309 id=309 data-nosnippet>309</a> <span class="kw">if </span>chunk.status == ChunkStatus::Skipped &amp;&amp; !chunk.files.is_empty() {
<a href=#310 id=310 data-nosnippet>310</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="string">"skipped version-2 chunks must have no files"</span>.into());
<a href=#311 id=311 data-nosnippet>311</a> }
<a href=#312 id=312 data-nosnippet>312</a> <span class="kw">for </span>file <span class="kw">in </span><span class="kw-2">&amp;</span>chunk.files {
<a href=#313 id=313 data-nosnippet>313</a> <span class="kw">if </span>file.contains(<span class="string">'\\'</span>)
<a href=#314 id=314 data-nosnippet>314</a> || file
<a href=#315 id=315 data-nosnippet>315</a> .split(<span class="string">'/'</span>)
<a href=#316 id=316 data-nosnippet>316</a> .any(|part| part.is_empty() || part == <span class="string">"." </span>|| part == <span class="string">".."</span>)
<a href=#317 id=317 data-nosnippet>317</a> || !<span class="self">self</span>.schemas.iter().any(|schema| {
<a href=#318 id=318 data-nosnippet>318</a> file.starts_with(<span class="kw-2">&amp;</span><span class="kw">crate</span>::data::path::data_dir_for_schema_chunk(
<a href=#319 id=319 data-nosnippet>319</a> schema, chunk.id,
<a href=#320 id=320 data-nosnippet>320</a> ))
<a href=#321 id=321 data-nosnippet>321</a> })
<a href=#322 id=322 data-nosnippet>322</a> {
<a href=#323 id=323 data-nosnippet>323</a> <span class="kw">return </span><span class="prelude-val">Err</span>(<span class="macro">format!</span>(<span class="string">"invalid version-2 chunk file: {file}"</span>));
<a href=#324 id=324 data-nosnippet>324</a> }
<a href=#325 id=325 data-nosnippet>325</a> }
<a href=#326 id=326 data-nosnippet>326</a> }
<a href=#327 id=327 data-nosnippet>327</a> <span class="prelude-val">Ok</span>(())
<a href=#328 id=328 data-nosnippet>328</a> }
<a href=#329 id=329 data-nosnippet>329</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">Err</span>(<span class="macro">format!</span>(
<a href=#330 id=330 data-nosnippet>330</a> <span class="string">"Manifest version mismatch or unsupported layout: version {}, layout {:?}, format {}"</span>,
<a href=#331 id=331 data-nosnippet>331</a> <span class="self">self</span>.version, <span class="self">self</span>.data_layout, <span class="self">self</span>.format
<a href=#332 id=332 data-nosnippet>332</a> )),
<a href=#333 id=333 data-nosnippet>333</a> }
<a href=#334 id=334 data-nosnippet>334</a> }
<a href=#335 id=335 data-nosnippet>335</a>
<a href=#336 id=336 data-nosnippet>336</a> <span class="kw">pub fn </span>is_packed(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#337 id=337 data-nosnippet>337</a> <span class="self">self</span>.version == <span class="number">2
<a href=#338 id=338 data-nosnippet>338</a> </span>}
<a href=#339 id=339 data-nosnippet>339</a>
<a href=#340 id=340 data-nosnippet>340</a> <span class="kw">pub fn </span>new_for_export(
<a href=#341 id=341 data-nosnippet>341</a> catalog: String,
<a href=#342 id=342 data-nosnippet>342</a> schemas: Vec&lt;String&gt;,
<a href=#343 id=343 data-nosnippet>343</a> schema_only: bool,
<a href=#344 id=344 data-nosnippet>344</a> time_range: TimeRange,
<a href=#345 id=345 data-nosnippet>345</a> format: DataFormat,
<a href=#346 id=346 data-nosnippet>346</a> chunk_time_window: <span class="prelude-ty">Option</span>&lt;Duration&gt;,
<a href=#347 id=347 data-nosnippet>347</a> ) -&gt; ExportResult&lt;<span class="self">Self</span>&gt; {
<a href=#348 id=348 data-nosnippet>348</a> <span class="kw">if </span>chunk_time_window.is_some() &amp;&amp; !time_range.is_bounded() {
<a href=#349 id=349 data-nosnippet>349</a> <span class="kw">return </span>ChunkTimeWindowRequiresBoundsSnafu.fail();
<a href=#350 id=350 data-nosnippet>350</a> }
<a href=#351 id=351 data-nosnippet>351</a>
<a href=#352 id=352 data-nosnippet>352</a> <span class="kw">let </span><span class="kw-2">mut </span>manifest = <span class="kw">if </span>schema_only {
<a href=#353 id=353 data-nosnippet>353</a> <span class="self">Self</span>::new_schema_only(catalog, schemas)
<a href=#354 id=354 data-nosnippet>354</a> } <span class="kw">else </span>{
<a href=#355 id=355 data-nosnippet>355</a> <span class="self">Self</span>::new_full(catalog, schemas, time_range, format)
<a href=#356 id=356 data-nosnippet>356</a> };
<a href=#357 id=357 data-nosnippet>357</a>
<a href=#358 id=358 data-nosnippet>358</a> <span class="kw">if </span>!schema_only {
<a href=#359 id=359 data-nosnippet>359</a> manifest.chunks = <span class="kw">match </span>chunk_time_window {
<a href=#360 id=360 data-nosnippet>360</a> <span class="prelude-val">Some</span>(window) =&gt; generate_chunks(<span class="kw-2">&amp;</span>manifest.time_range, window),
<a href=#361 id=361 data-nosnippet>361</a> <span class="prelude-val">None </span>=&gt; generate_single_chunk(<span class="kw-2">&amp;</span>manifest.time_range),
<a href=#362 id=362 data-nosnippet>362</a> };
<a href=#363 id=363 data-nosnippet>363</a> manifest.touch();
<a href=#364 id=364 data-nosnippet>364</a> }
<a href=#365 id=365 data-nosnippet>365</a>
<a href=#366 id=366 data-nosnippet>366</a> <span class="prelude-val">Ok</span>(manifest)
<a href=#367 id=367 data-nosnippet>367</a> }
<a href=#368 id=368 data-nosnippet>368</a>
<a href=#369 id=369 data-nosnippet>369</a> <span class="doccomment">/// Creates a new manifest for schema-only export.
<a href=#370 id=370 data-nosnippet>370</a> </span><span class="kw">pub fn </span>new_schema_only(catalog: String, schemas: Vec&lt;String&gt;) -&gt; <span class="self">Self </span>{
<a href=#371 id=371 data-nosnippet>371</a> <span class="kw">let </span>now = Utc::now();
<a href=#372 id=372 data-nosnippet>372</a> <span class="self">Self </span>{
<a href=#373 id=373 data-nosnippet>373</a> version: MANIFEST_VERSION,
<a href=#374 id=374 data-nosnippet>374</a> data_layout: <span class="prelude-val">None</span>,
<a href=#375 id=375 data-nosnippet>375</a> snapshot_id: Uuid::new_v4(),
<a href=#376 id=376 data-nosnippet>376</a> catalog,
<a href=#377 id=377 data-nosnippet>377</a> schemas,
<a href=#378 id=378 data-nosnippet>378</a> time_range: TimeRange::unbounded(),
<a href=#379 id=379 data-nosnippet>379</a> schema_only: <span class="bool-val">true</span>,
<a href=#380 id=380 data-nosnippet>380</a> format: DataFormat::Parquet,
<a href=#381 id=381 data-nosnippet>381</a> chunks: <span class="macro">vec!</span>[],
<a href=#382 id=382 data-nosnippet>382</a> checksum: <span class="prelude-val">None</span>,
<a href=#383 id=383 data-nosnippet>383</a> created_at: now,
<a href=#384 id=384 data-nosnippet>384</a> updated_at: now,
<a href=#385 id=385 data-nosnippet>385</a> }
<a href=#386 id=386 data-nosnippet>386</a> }
<a href=#387 id=387 data-nosnippet>387</a>
<a href=#388 id=388 data-nosnippet>388</a> <span class="doccomment">/// Creates a new manifest for full export with time range and format.
<a href=#389 id=389 data-nosnippet>389</a> </span><span class="kw">pub fn </span>new_full(
<a href=#390 id=390 data-nosnippet>390</a> catalog: String,
<a href=#391 id=391 data-nosnippet>391</a> schemas: Vec&lt;String&gt;,
<a href=#392 id=392 data-nosnippet>392</a> time_range: TimeRange,
<a href=#393 id=393 data-nosnippet>393</a> format: DataFormat,
<a href=#394 id=394 data-nosnippet>394</a> ) -&gt; <span class="self">Self </span>{
<a href=#395 id=395 data-nosnippet>395</a> <span class="kw">let </span>now = Utc::now();
<a href=#396 id=396 data-nosnippet>396</a> <span class="self">Self </span>{
<a href=#397 id=397 data-nosnippet>397</a> version: MANIFEST_VERSION,
<a href=#398 id=398 data-nosnippet>398</a> data_layout: <span class="prelude-val">None</span>,
<a href=#399 id=399 data-nosnippet>399</a> snapshot_id: Uuid::new_v4(),
<a href=#400 id=400 data-nosnippet>400</a> catalog,
<a href=#401 id=401 data-nosnippet>401</a> schemas,
<a href=#402 id=402 data-nosnippet>402</a> time_range,
<a href=#403 id=403 data-nosnippet>403</a> schema_only: <span class="bool-val">false</span>,
<a href=#404 id=404 data-nosnippet>404</a> format,
<a href=#405 id=405 data-nosnippet>405</a> chunks: <span class="macro">vec!</span>[],
<a href=#406 id=406 data-nosnippet>406</a> checksum: <span class="prelude-val">None</span>,
<a href=#407 id=407 data-nosnippet>407</a> created_at: now,
<a href=#408 id=408 data-nosnippet>408</a> updated_at: now,
<a href=#409 id=409 data-nosnippet>409</a> }
<a href=#410 id=410 data-nosnippet>410</a> }
<a href=#411 id=411 data-nosnippet>411</a>
<a href=#412 id=412 data-nosnippet>412</a> <span class="doccomment">/// Returns true if all chunks are completed (or if schema-only).
<a href=#413 id=413 data-nosnippet>413</a> </span><span class="kw">pub fn </span>is_complete(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#414 id=414 data-nosnippet>414</a> <span class="self">self</span>.schema_only
<a href=#415 id=415 data-nosnippet>415</a> || (!<span class="self">self</span>.chunks.is_empty()
<a href=#416 id=416 data-nosnippet>416</a> &amp;&amp; <span class="self">self
<a href=#417 id=417 data-nosnippet>417</a> </span>.chunks
<a href=#418 id=418 data-nosnippet>418</a> .iter()
<a href=#419 id=419 data-nosnippet>419</a> .all(|c| <span class="macro">matches!</span>(c.status, ChunkStatus::Completed | ChunkStatus::Skipped)))
<a href=#420 id=420 data-nosnippet>420</a> }
<a href=#421 id=421 data-nosnippet>421</a>
<a href=#422 id=422 data-nosnippet>422</a> <span class="doccomment">/// Returns the number of pending chunks.
<a href=#423 id=423 data-nosnippet>423</a> </span><span class="kw">pub fn </span>pending_count(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<a href=#424 id=424 data-nosnippet>424</a> <span class="self">self</span>.chunks
<a href=#425 id=425 data-nosnippet>425</a> .iter()
<a href=#426 id=426 data-nosnippet>426</a> .filter(|c| c.status == ChunkStatus::Pending)
<a href=#427 id=427 data-nosnippet>427</a> .count()
<a href=#428 id=428 data-nosnippet>428</a> }
<a href=#429 id=429 data-nosnippet>429</a>
<a href=#430 id=430 data-nosnippet>430</a> <span class="doccomment">/// Returns the number of in-progress chunks.
<a href=#431 id=431 data-nosnippet>431</a> </span><span class="kw">pub fn </span>in_progress_count(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<a href=#432 id=432 data-nosnippet>432</a> <span class="self">self</span>.chunks
<a href=#433 id=433 data-nosnippet>433</a> .iter()
<a href=#434 id=434 data-nosnippet>434</a> .filter(|c| c.status == ChunkStatus::InProgress)
<a href=#435 id=435 data-nosnippet>435</a> .count()
<a href=#436 id=436 data-nosnippet>436</a> }
<a href=#437 id=437 data-nosnippet>437</a>
<a href=#438 id=438 data-nosnippet>438</a> <span class="doccomment">/// Returns the number of completed chunks.
<a href=#439 id=439 data-nosnippet>439</a> </span><span class="kw">pub fn </span>completed_count(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<a href=#440 id=440 data-nosnippet>440</a> <span class="self">self</span>.chunks
<a href=#441 id=441 data-nosnippet>441</a> .iter()
<a href=#442 id=442 data-nosnippet>442</a> .filter(|c| c.status == ChunkStatus::Completed)
<a href=#443 id=443 data-nosnippet>443</a> .count()
<a href=#444 id=444 data-nosnippet>444</a> }
<a href=#445 id=445 data-nosnippet>445</a>
<a href=#446 id=446 data-nosnippet>446</a> <span class="doccomment">/// Returns the number of skipped chunks.
<a href=#447 id=447 data-nosnippet>447</a> </span><span class="kw">pub fn </span>skipped_count(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<a href=#448 id=448 data-nosnippet>448</a> <span class="self">self</span>.chunks
<a href=#449 id=449 data-nosnippet>449</a> .iter()
<a href=#450 id=450 data-nosnippet>450</a> .filter(|c| c.status == ChunkStatus::Skipped)
<a href=#451 id=451 data-nosnippet>451</a> .count()
<a href=#452 id=452 data-nosnippet>452</a> }
<a href=#453 id=453 data-nosnippet>453</a>
<a href=#454 id=454 data-nosnippet>454</a> <span class="doccomment">/// Returns the number of failed chunks.
<a href=#455 id=455 data-nosnippet>455</a> </span><span class="kw">pub fn </span>failed_count(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; usize {
<a href=#456 id=456 data-nosnippet>456</a> <span class="self">self</span>.chunks
<a href=#457 id=457 data-nosnippet>457</a> .iter()
<a href=#458 id=458 data-nosnippet>458</a> .filter(|c| c.status == ChunkStatus::Failed)
<a href=#459 id=459 data-nosnippet>459</a> .count()
<a href=#460 id=460 data-nosnippet>460</a> }
<a href=#461 id=461 data-nosnippet>461</a>
<a href=#462 id=462 data-nosnippet>462</a> <span class="doccomment">/// Updates the `updated_at` timestamp to now.
<a href=#463 id=463 data-nosnippet>463</a> </span><span class="kw">pub fn </span>touch(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#464 id=464 data-nosnippet>464</a> <span class="self">self</span>.updated_at = Utc::now();
<a href=#465 id=465 data-nosnippet>465</a> }
<a href=#466 id=466 data-nosnippet>466</a>
<a href=#467 id=467 data-nosnippet>467</a> <span class="doccomment">/// Adds a chunk to the manifest.
<a href=#468 id=468 data-nosnippet>468</a> </span><span class="kw">pub fn </span>add_chunk(<span class="kw-2">&amp;mut </span><span class="self">self</span>, chunk: ChunkMeta) {
<a href=#469 id=469 data-nosnippet>469</a> <span class="self">self</span>.chunks.push(chunk);
<a href=#470 id=470 data-nosnippet>470</a> <span class="self">self</span>.touch();
<a href=#471 id=471 data-nosnippet>471</a> }
<a href=#472 id=472 data-nosnippet>472</a>
<a href=#473 id=473 data-nosnippet>473</a> <span class="doccomment">/// Updates a chunk by id.
<a href=#474 id=474 data-nosnippet>474</a> </span><span class="kw">pub fn </span>update_chunk(<span class="kw-2">&amp;mut </span><span class="self">self</span>, id: u32, updater: <span class="kw">impl </span>FnOnce(<span class="kw-2">&amp;mut </span>ChunkMeta)) {
<a href=#475 id=475 data-nosnippet>475</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(chunk) = <span class="self">self</span>.chunks.iter_mut().find(|c| c.id == id) {
<a href=#476 id=476 data-nosnippet>476</a> updater(chunk);
<a href=#477 id=477 data-nosnippet>477</a> <span class="self">self</span>.touch();
<a href=#478 id=478 data-nosnippet>478</a> }
<a href=#479 id=479 data-nosnippet>479</a> }
<a href=#480 id=480 data-nosnippet>480</a>}
<a href=#481 id=481 data-nosnippet>481</a>
<a href=#482 id=482 data-nosnippet>482</a><span class="kw">fn </span>generate_single_chunk(time_range: <span class="kw-2">&amp;</span>TimeRange) -&gt; Vec&lt;ChunkMeta&gt; {
<a href=#483 id=483 data-nosnippet>483</a> <span class="kw">if let </span>(<span class="prelude-val">Some</span>(start), <span class="prelude-val">Some</span>(end)) = (time_range.start, time_range.end) {
<a href=#484 id=484 data-nosnippet>484</a> <span class="kw">if </span>start == end {
<a href=#485 id=485 data-nosnippet>485</a> <span class="kw">return </span><span class="macro">vec!</span>[ChunkMeta::skipped(<span class="number">1</span>, time_range.clone())];
<a href=#486 id=486 data-nosnippet>486</a> }
<a href=#487 id=487 data-nosnippet>487</a> <span class="kw">if </span>start &gt; end {
<a href=#488 id=488 data-nosnippet>488</a> <span class="kw">return </span>Vec::new();
<a href=#489 id=489 data-nosnippet>489</a> }
<a href=#490 id=490 data-nosnippet>490</a> }
<a href=#491 id=491 data-nosnippet>491</a> <span class="macro">vec!</span>[ChunkMeta::new(<span class="number">1</span>, time_range.clone())]
<a href=#492 id=492 data-nosnippet>492</a>}
<a href=#493 id=493 data-nosnippet>493</a>
<a href=#494 id=494 data-nosnippet>494</a><span class="attr">#[cfg(test)]
<a href=#495 id=495 data-nosnippet>495</a></span><span class="kw">mod </span>tests {
<a href=#496 id=496 data-nosnippet>496</a> <span class="attr">#[test]
<a href=#497 id=497 data-nosnippet>497</a> </span><span class="kw">fn </span>packed_manifest_read_contract_preserves_legacy_writer() {
<a href=#498 id=498 data-nosnippet>498</a> <span class="kw">let </span><span class="kw-2">mut </span>manifest =
<a href=#499 id=499 data-nosnippet>499</a> <span class="kw">super</span>::Manifest::new_schema_only(<span class="string">"greptime"</span>.into(), <span class="macro">vec!</span>[<span class="string">"public"</span>.into()]);
<a href=#500 id=500 data-nosnippet>500</a> <span class="macro">assert!</span>(manifest.validate_layout().is_ok());
<a href=#501 id=501 data-nosnippet>501</a> manifest.version = <span class="number">2</span>;
<a href=#502 id=502 data-nosnippet>502</a> <span class="macro">assert!</span>(manifest.validate_layout().is_err());
<a href=#503 id=503 data-nosnippet>503</a> manifest.data_layout = <span class="prelude-val">Some</span>(<span class="string">"metric-parquet-packs"</span>.into());
<a href=#504 id=504 data-nosnippet>504</a> <span class="macro">assert!</span>(manifest.validate_layout().is_ok());
<a href=#505 id=505 data-nosnippet>505</a> manifest.format = <span class="kw">super</span>::DataFormat::Csv;
<a href=#506 id=506 data-nosnippet>506</a> <span class="macro">assert!</span>(manifest.validate_layout().is_err());
<a href=#507 id=507 data-nosnippet>507</a> manifest.format = <span class="kw">super</span>::DataFormat::Parquet;
<a href=#508 id=508 data-nosnippet>508</a> manifest.version = <span class="number">3</span>;
<a href=#509 id=509 data-nosnippet>509</a> <span class="macro">assert!</span>(manifest.validate_layout().is_err());
<a href=#510 id=510 data-nosnippet>510</a> manifest.version = <span class="number">1</span>;
<a href=#511 id=511 data-nosnippet>511</a> <span class="macro">assert!</span>(manifest.validate_layout().is_err());
<a href=#512 id=512 data-nosnippet>512</a> }
<a href=#513 id=513 data-nosnippet>513</a>
<a href=#514 id=514 data-nosnippet>514</a> <span class="attr">#[test]
<a href=#515 id=515 data-nosnippet>515</a> </span><span class="kw">fn </span>packed_required_fields_and_checksums_preserve_v1_defaults() {
<a href=#516 id=516 data-nosnippet>516</a> <span class="kw">let </span><span class="kw-2">mut </span>manifest =
<a href=#517 id=517 data-nosnippet>517</a> <span class="kw">super</span>::Manifest::new_schema_only(<span class="string">"greptime"</span>.into(), <span class="macro">vec!</span>[<span class="string">"public"</span>.into()]);
<a href=#518 id=518 data-nosnippet>518</a> manifest
<a href=#519 id=519 data-nosnippet>519</a> .chunks
<a href=#520 id=520 data-nosnippet>520</a> .push(<span class="kw">super</span>::ChunkMeta::new(<span class="number">1</span>, <span class="kw">super</span>::TimeRange::unbounded()));
<a href=#521 id=521 data-nosnippet>521</a> <span class="kw">let </span>legacy = serde_json::to_value(manifest).unwrap();
<a href=#522 id=522 data-nosnippet>522</a> <span class="kw">for </span>version <span class="kw">in </span>[<span class="number">1</span>, <span class="number">2</span>] {
<a href=#523 id=523 data-nosnippet>523</a> <span class="kw">let </span><span class="kw-2">mut </span>value = legacy.clone();
<a href=#524 id=524 data-nosnippet>524</a> value[<span class="string">"version"</span>] = version.into();
<a href=#525 id=525 data-nosnippet>525</a> <span class="kw">if </span>version == <span class="number">2 </span>{
<a href=#526 id=526 data-nosnippet>526</a> value[<span class="string">"data_layout"</span>] = <span class="string">"metric-parquet-packs"</span>.into();
<a href=#527 id=527 data-nosnippet>527</a> value[<span class="string">"schema_only"</span>] = <span class="bool-val">false</span>.into();
<a href=#528 id=528 data-nosnippet>528</a> }
<a href=#529 id=529 data-nosnippet>529</a> <span class="kw">let </span>raw = serde_json::to_string(<span class="kw-2">&amp;</span>value).unwrap();
<a href=#530 id=530 data-nosnippet>530</a> <span class="kw">for </span>duplicate <span class="kw">in </span>[
<a href=#531 id=531 data-nosnippet>531</a> <span class="macro">format!</span>(
<a href=#532 id=532 data-nosnippet>532</a> <span class="string">"{{\"checksum\":\"unsupported\",\"checksum\":null,{}"</span>,
<a href=#533 id=533 data-nosnippet>533</a> <span class="kw-2">&amp;</span>raw[<span class="number">1</span>..]
<a href=#534 id=534 data-nosnippet>534</a> ),
<a href=#535 id=535 data-nosnippet>535</a> <span class="macro">format!</span>(<span class="string">"{{\"chunks\":[],{}"</span>, <span class="kw-2">&amp;</span>raw[<span class="number">1</span>..]),
<a href=#536 id=536 data-nosnippet>536</a> raw.replacen(<span class="string">"\"files\":[]"</span>, <span class="string">"\"files\":[],\"files\":[]"</span>, <span class="number">1</span>),
<a href=#537 id=537 data-nosnippet>537</a> raw.replacen(
<a href=#538 id=538 data-nosnippet>538</a> <span class="string">"\"files\":[]"</span>,
<a href=#539 id=539 data-nosnippet>539</a> <span class="string">"\"checksum\":\"unsupported\",\"checksum\":null,\"files\":[]"</span>,
<a href=#540 id=540 data-nosnippet>540</a> <span class="number">1</span>,
<a href=#541 id=541 data-nosnippet>541</a> ),
<a href=#542 id=542 data-nosnippet>542</a> ] {
<a href=#543 id=543 data-nosnippet>543</a> <span class="macro">assert!</span>(<span class="kw">super</span>::Manifest::from_json(duplicate.as_bytes()).is_err());
<a href=#544 id=544 data-nosnippet>544</a> }
<a href=#545 id=545 data-nosnippet>545</a> <span class="kw">for </span>field <span class="kw">in </span>[<span class="string">"chunks"</span>, <span class="string">"files"</span>] {
<a href=#546 id=546 data-nosnippet>546</a> <span class="kw">let </span><span class="kw-2">mut </span>missing = value.clone();
<a href=#547 id=547 data-nosnippet>547</a> <span class="kw">if </span>field == <span class="string">"chunks" </span>{
<a href=#548 id=548 data-nosnippet>548</a> missing.as_object_mut().unwrap().remove(field);
<a href=#549 id=549 data-nosnippet>549</a> } <span class="kw">else </span>{
<a href=#550 id=550 data-nosnippet>550</a> missing[<span class="string">"chunks"</span>][<span class="number">0</span>].as_object_mut().unwrap().remove(field);
<a href=#551 id=551 data-nosnippet>551</a> }
<a href=#552 id=552 data-nosnippet>552</a> <span class="macro">assert_eq!</span>(
<a href=#553 id=553 data-nosnippet>553</a> <span class="kw">super</span>::Manifest::from_json(<span class="kw-2">&amp;</span>serde_json::to_vec(<span class="kw-2">&amp;</span>missing).unwrap()).is_ok(),
<a href=#554 id=554 data-nosnippet>554</a> version == <span class="number">1
<a href=#555 id=555 data-nosnippet>555</a> </span>);
<a href=#556 id=556 data-nosnippet>556</a> }
<a href=#557 id=557 data-nosnippet>557</a> <span class="kw">for </span>checksum <span class="kw">in </span>[
<a href=#558 id=558 data-nosnippet>558</a> <span class="prelude-val">None</span>,
<a href=#559 id=559 data-nosnippet>559</a> <span class="prelude-val">Some</span>(serde_json::Value::Null),
<a href=#560 id=560 data-nosnippet>560</a> <span class="prelude-val">Some</span>(<span class="string">""</span>.into()),
<a href=#561 id=561 data-nosnippet>561</a> <span class="prelude-val">Some</span>(<span class="string">"sha256:abc"</span>.into()),
<a href=#562 id=562 data-nosnippet>562</a> ] {
<a href=#563 id=563 data-nosnippet>563</a> <span class="kw">for </span>chunk_level <span class="kw">in </span>[<span class="bool-val">false</span>, <span class="bool-val">true</span>] {
<a href=#564 id=564 data-nosnippet>564</a> <span class="kw">let </span><span class="kw-2">mut </span>candidate = value.clone();
<a href=#565 id=565 data-nosnippet>565</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(checksum) = <span class="kw-2">&amp;</span>checksum {
<a href=#566 id=566 data-nosnippet>566</a> <span class="kw">if </span>chunk_level {
<a href=#567 id=567 data-nosnippet>567</a> candidate[<span class="string">"chunks"</span>][<span class="number">0</span>][<span class="string">"checksum"</span>] = checksum.clone();
<a href=#568 id=568 data-nosnippet>568</a> } <span class="kw">else </span>{
<a href=#569 id=569 data-nosnippet>569</a> candidate[<span class="string">"checksum"</span>] = checksum.clone();
<a href=#570 id=570 data-nosnippet>570</a> }
<a href=#571 id=571 data-nosnippet>571</a> }
<a href=#572 id=572 data-nosnippet>572</a> <span class="kw">let </span>decoded =
<a href=#573 id=573 data-nosnippet>573</a> <span class="kw">super</span>::Manifest::from_json(<span class="kw-2">&amp;</span>serde_json::to_vec(<span class="kw-2">&amp;</span>candidate).unwrap())
<a href=#574 id=574 data-nosnippet>574</a> .unwrap();
<a href=#575 id=575 data-nosnippet>575</a> <span class="macro">assert_eq!</span>(
<a href=#576 id=576 data-nosnippet>576</a> decoded.validate_layout().is_ok(),
<a href=#577 id=577 data-nosnippet>577</a> version == <span class="number">1 </span>|| checksum.as_ref().is_none_or(serde_json::Value::is_null)
<a href=#578 id=578 data-nosnippet>578</a> );
<a href=#579 id=579 data-nosnippet>579</a> }
<a href=#580 id=580 data-nosnippet>580</a> }
<a href=#581 id=581 data-nosnippet>581</a> }
<a href=#582 id=582 data-nosnippet>582</a> }
<a href=#583 id=583 data-nosnippet>583</a>
<a href=#584 id=584 data-nosnippet>584</a> <span class="kw">use </span>std::time::Duration;
<a href=#585 id=585 data-nosnippet>585</a>
<a href=#586 id=586 data-nosnippet>586</a> <span class="kw">use </span>chrono::{TimeZone, Utc};
<a href=#587 id=587 data-nosnippet>587</a>
<a href=#588 id=588 data-nosnippet>588</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#589 id=589 data-nosnippet>589</a>
<a href=#590 id=590 data-nosnippet>590</a> <span class="attr">#[test]
<a href=#591 id=591 data-nosnippet>591</a> </span><span class="kw">fn </span>test_time_range_serialization() {
<a href=#592 id=592 data-nosnippet>592</a> <span class="kw">let </span>range = TimeRange::unbounded();
<a href=#593 id=593 data-nosnippet>593</a> <span class="kw">let </span>json = serde_json::to_string(<span class="kw-2">&amp;</span>range).unwrap();
<a href=#594 id=594 data-nosnippet>594</a> <span class="macro">assert_eq!</span>(json, <span class="string">"{}"</span>);
<a href=#595 id=595 data-nosnippet>595</a>
<a href=#596 id=596 data-nosnippet>596</a> <span class="kw">let </span>range: TimeRange = serde_json::from_str(<span class="string">"{}"</span>).unwrap();
<a href=#597 id=597 data-nosnippet>597</a> <span class="macro">assert!</span>(range.is_unbounded());
<a href=#598 id=598 data-nosnippet>598</a> }
<a href=#599 id=599 data-nosnippet>599</a>
<a href=#600 id=600 data-nosnippet>600</a> <span class="attr">#[test]
<a href=#601 id=601 data-nosnippet>601</a> </span><span class="kw">fn </span>test_manifest_schema_only() {
<a href=#602 id=602 data-nosnippet>602</a> <span class="kw">let </span>manifest =
<a href=#603 id=603 data-nosnippet>603</a> Manifest::new_schema_only(<span class="string">"greptime"</span>.to_string(), <span class="macro">vec!</span>[<span class="string">"public"</span>.to_string()]);
<a href=#604 id=604 data-nosnippet>604</a>
<a href=#605 id=605 data-nosnippet>605</a> <span class="macro">assert_eq!</span>(manifest.version, MANIFEST_VERSION);
<a href=#606 id=606 data-nosnippet>606</a> <span class="macro">assert!</span>(manifest.schema_only);
<a href=#607 id=607 data-nosnippet>607</a> <span class="macro">assert!</span>(manifest.chunks.is_empty());
<a href=#608 id=608 data-nosnippet>608</a> <span class="macro">assert!</span>(manifest.is_complete());
<a href=#609 id=609 data-nosnippet>609</a> }
<a href=#610 id=610 data-nosnippet>610</a>
<a href=#611 id=611 data-nosnippet>611</a> <span class="attr">#[test]
<a href=#612 id=612 data-nosnippet>612</a> </span><span class="kw">fn </span>test_generate_single_chunk_zero_width_range_is_skipped() {
<a href=#613 id=613 data-nosnippet>613</a> <span class="kw">let </span>ts = Utc.with_ymd_and_hms(<span class="number">2025</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>).unwrap();
<a href=#614 id=614 data-nosnippet>614</a> <span class="kw">let </span>chunks = generate_single_chunk(<span class="kw-2">&amp;</span>TimeRange::new(<span class="prelude-val">Some</span>(ts), <span class="prelude-val">Some</span>(ts)));
<a href=#615 id=615 data-nosnippet>615</a>
<a href=#616 id=616 data-nosnippet>616</a> <span class="macro">assert_eq!</span>(chunks.len(), <span class="number">1</span>);
<a href=#617 id=617 data-nosnippet>617</a> <span class="macro">assert_eq!</span>(chunks[<span class="number">0</span>].status, ChunkStatus::Skipped);
<a href=#618 id=618 data-nosnippet>618</a> <span class="macro">assert_eq!</span>(chunks[<span class="number">0</span>].time_range.start, <span class="prelude-val">Some</span>(ts));
<a href=#619 id=619 data-nosnippet>619</a> <span class="macro">assert_eq!</span>(chunks[<span class="number">0</span>].time_range.end, <span class="prelude-val">Some</span>(ts));
<a href=#620 id=620 data-nosnippet>620</a> }
<a href=#621 id=621 data-nosnippet>621</a>
<a href=#622 id=622 data-nosnippet>622</a> <span class="attr">#[test]
<a href=#623 id=623 data-nosnippet>623</a> </span><span class="kw">fn </span>test_generate_single_chunk_invalid_range_is_empty() {
<a href=#624 id=624 data-nosnippet>624</a> <span class="kw">let </span>start = Utc.with_ymd_and_hms(<span class="number">2025</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>).unwrap();
<a href=#625 id=625 data-nosnippet>625</a> <span class="kw">let </span>end = Utc.with_ymd_and_hms(<span class="number">2025</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>).unwrap();
<a href=#626 id=626 data-nosnippet>626</a> <span class="kw">let </span>chunks = generate_single_chunk(<span class="kw-2">&amp;</span>TimeRange::new(<span class="prelude-val">Some</span>(start), <span class="prelude-val">Some</span>(end)));
<a href=#627 id=627 data-nosnippet>627</a>
<a href=#628 id=628 data-nosnippet>628</a> <span class="macro">assert!</span>(chunks.is_empty());
<a href=#629 id=629 data-nosnippet>629</a> }
<a href=#630 id=630 data-nosnippet>630</a>
<a href=#631 id=631 data-nosnippet>631</a> <span class="attr">#[test]
<a href=#632 id=632 data-nosnippet>632</a> </span><span class="kw">fn </span>test_manifest_full() {
<a href=#633 id=633 data-nosnippet>633</a> <span class="kw">let </span>manifest = Manifest::new_full(
<a href=#634 id=634 data-nosnippet>634</a> <span class="string">"greptime"</span>.to_string(),
<a href=#635 id=635 data-nosnippet>635</a> <span class="macro">vec!</span>[<span class="string">"public"</span>.to_string()],
<a href=#636 id=636 data-nosnippet>636</a> TimeRange::unbounded(),
<a href=#637 id=637 data-nosnippet>637</a> DataFormat::Parquet,
<a href=#638 id=638 data-nosnippet>638</a> );
<a href=#639 id=639 data-nosnippet>639</a>
<a href=#640 id=640 data-nosnippet>640</a> <span class="macro">assert!</span>(!manifest.schema_only);
<a href=#641 id=641 data-nosnippet>641</a> <span class="macro">assert!</span>(manifest.chunks.is_empty());
<a href=#642 id=642 data-nosnippet>642</a> <span class="macro">assert!</span>(!manifest.is_complete());
<a href=#643 id=643 data-nosnippet>643</a> }
<a href=#644 id=644 data-nosnippet>644</a>
<a href=#645 id=645 data-nosnippet>645</a> <span class="attr">#[test]
<a href=#646 id=646 data-nosnippet>646</a> </span><span class="kw">fn </span>test_data_format_parsing() {
<a href=#647 id=647 data-nosnippet>647</a> <span class="macro">assert_eq!</span>(
<a href=#648 id=648 data-nosnippet>648</a> <span class="string">"parquet"</span>.parse::&lt;DataFormat&gt;().unwrap(),
<a href=#649 id=649 data-nosnippet>649</a> DataFormat::Parquet
<a href=#650 id=650 data-nosnippet>650</a> );
<a href=#651 id=651 data-nosnippet>651</a> <span class="macro">assert_eq!</span>(<span class="string">"CSV"</span>.parse::&lt;DataFormat&gt;().unwrap(), DataFormat::Csv);
<a href=#652 id=652 data-nosnippet>652</a> <span class="macro">assert_eq!</span>(<span class="string">"JSON"</span>.parse::&lt;DataFormat&gt;().unwrap(), DataFormat::Json);
<a href=#653 id=653 data-nosnippet>653</a> <span class="macro">assert!</span>(<span class="string">"invalid"</span>.parse::&lt;DataFormat&gt;().is_err());
<a href=#654 id=654 data-nosnippet>654</a> }
<a href=#655 id=655 data-nosnippet>655</a>
<a href=#656 id=656 data-nosnippet>656</a> <span class="attr">#[test]
<a href=#657 id=657 data-nosnippet>657</a> </span><span class="kw">fn </span>test_chunk_status_transitions() {
<a href=#658 id=658 data-nosnippet>658</a> <span class="kw">let </span><span class="kw-2">mut </span>chunk = ChunkMeta::new(<span class="number">1</span>, TimeRange::unbounded());
<a href=#659 id=659 data-nosnippet>659</a> <span class="macro">assert_eq!</span>(chunk.status, ChunkStatus::Pending);
<a href=#660 id=660 data-nosnippet>660</a>
<a href=#661 id=661 data-nosnippet>661</a> chunk.mark_in_progress();
<a href=#662 id=662 data-nosnippet>662</a> <span class="macro">assert_eq!</span>(chunk.status, ChunkStatus::InProgress);
<a href=#663 id=663 data-nosnippet>663</a>
<a href=#664 id=664 data-nosnippet>664</a> chunk.mark_completed(
<a href=#665 id=665 data-nosnippet>665</a> <span class="macro">vec!</span>[<span class="string">"file1.parquet"</span>.to_string()],
<a href=#666 id=666 data-nosnippet>666</a> <span class="prelude-val">Some</span>(<span class="string">"abc123"</span>.to_string()),
<a href=#667 id=667 data-nosnippet>667</a> );
<a href=#668 id=668 data-nosnippet>668</a> <span class="macro">assert_eq!</span>(chunk.status, ChunkStatus::Completed);
<a href=#669 id=669 data-nosnippet>669</a> <span class="macro">assert_eq!</span>(chunk.files.len(), <span class="number">1</span>);
<a href=#670 id=670 data-nosnippet>670</a>
<a href=#671 id=671 data-nosnippet>671</a> chunk.mark_skipped();
<a href=#672 id=672 data-nosnippet>672</a> <span class="macro">assert_eq!</span>(chunk.status, ChunkStatus::Skipped);
<a href=#673 id=673 data-nosnippet>673</a> <span class="macro">assert!</span>(chunk.files.is_empty());
<a href=#674 id=674 data-nosnippet>674</a> }
<a href=#675 id=675 data-nosnippet>675</a>
<a href=#676 id=676 data-nosnippet>676</a> <span class="attr">#[test]
<a href=#677 id=677 data-nosnippet>677</a> </span><span class="kw">fn </span>test_manifest_is_complete_when_chunks_are_completed_or_skipped() {
<a href=#678 id=678 data-nosnippet>678</a> <span class="kw">let </span><span class="kw-2">mut </span>manifest = Manifest::new_full(
<a href=#679 id=679 data-nosnippet>679</a> <span class="string">"greptime"</span>.to_string(),
<a href=#680 id=680 data-nosnippet>680</a> <span class="macro">vec!</span>[<span class="string">"public"</span>.to_string()],
<a href=#681 id=681 data-nosnippet>681</a> TimeRange::unbounded(),
<a href=#682 id=682 data-nosnippet>682</a> DataFormat::Parquet,
<a href=#683 id=683 data-nosnippet>683</a> );
<a href=#684 id=684 data-nosnippet>684</a> manifest.add_chunk(ChunkMeta::new(<span class="number">1</span>, TimeRange::unbounded()));
<a href=#685 id=685 data-nosnippet>685</a> manifest.add_chunk(ChunkMeta::new(<span class="number">2</span>, TimeRange::unbounded()));
<a href=#686 id=686 data-nosnippet>686</a>
<a href=#687 id=687 data-nosnippet>687</a> manifest.update_chunk(<span class="number">1</span>, |chunk| {
<a href=#688 id=688 data-nosnippet>688</a> chunk.mark_completed(<span class="macro">vec!</span>[<span class="string">"a.parquet"</span>.to_string()], <span class="prelude-val">None</span>)
<a href=#689 id=689 data-nosnippet>689</a> });
<a href=#690 id=690 data-nosnippet>690</a> manifest.update_chunk(<span class="number">2</span>, |chunk| chunk.mark_skipped());
<a href=#691 id=691 data-nosnippet>691</a>
<a href=#692 id=692 data-nosnippet>692</a> <span class="macro">assert!</span>(manifest.is_complete());
<a href=#693 id=693 data-nosnippet>693</a> <span class="macro">assert_eq!</span>(manifest.completed_count(), <span class="number">1</span>);
<a href=#694 id=694 data-nosnippet>694</a> <span class="macro">assert_eq!</span>(manifest.skipped_count(), <span class="number">1</span>);
<a href=#695 id=695 data-nosnippet>695</a> }
<a href=#696 id=696 data-nosnippet>696</a>
<a href=#697 id=697 data-nosnippet>697</a> <span class="attr">#[test]
<a href=#698 id=698 data-nosnippet>698</a> </span><span class="kw">fn </span>test_manifest_chunk_time_window_none_single_chunk() {
<a href=#699 id=699 data-nosnippet>699</a> <span class="kw">let </span>start = Utc.with_ymd_and_hms(<span class="number">2025</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>).unwrap();
<a href=#700 id=700 data-nosnippet>700</a> <span class="kw">let </span>end = Utc.with_ymd_and_hms(<span class="number">2025</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>).unwrap();
<a href=#701 id=701 data-nosnippet>701</a> <span class="kw">let </span>range = TimeRange::new(<span class="prelude-val">Some</span>(start), <span class="prelude-val">Some</span>(end));
<a href=#702 id=702 data-nosnippet>702</a> <span class="kw">let </span>manifest = Manifest::new_for_export(
<a href=#703 id=703 data-nosnippet>703</a> <span class="string">"greptime"</span>.to_string(),
<a href=#704 id=704 data-nosnippet>704</a> <span class="macro">vec!</span>[<span class="string">"public"</span>.to_string()],
<a href=#705 id=705 data-nosnippet>705</a> <span class="bool-val">false</span>,
<a href=#706 id=706 data-nosnippet>706</a> range.clone(),
<a href=#707 id=707 data-nosnippet>707</a> DataFormat::Parquet,
<a href=#708 id=708 data-nosnippet>708</a> <span class="prelude-val">None</span>,
<a href=#709 id=709 data-nosnippet>709</a> )
<a href=#710 id=710 data-nosnippet>710</a> .unwrap();
<a href=#711 id=711 data-nosnippet>711</a>
<a href=#712 id=712 data-nosnippet>712</a> <span class="macro">assert_eq!</span>(manifest.chunks.len(), <span class="number">1</span>);
<a href=#713 id=713 data-nosnippet>713</a> <span class="macro">assert_eq!</span>(manifest.chunks[<span class="number">0</span>].time_range, range);
<a href=#714 id=714 data-nosnippet>714</a> }
<a href=#715 id=715 data-nosnippet>715</a>
<a href=#716 id=716 data-nosnippet>716</a> <span class="attr">#[test]
<a href=#717 id=717 data-nosnippet>717</a> </span><span class="kw">fn </span>test_time_range_parse_requires_order() {
<a href=#718 id=718 data-nosnippet>718</a> <span class="kw">let </span>result = TimeRange::parse(<span class="prelude-val">Some</span>(<span class="string">"2025-01-02T00:00:00Z"</span>), <span class="prelude-val">Some</span>(<span class="string">"2025-01-01T00:00:00Z"</span>));
<a href=#719 id=719 data-nosnippet>719</a> <span class="macro">assert!</span>(result.is_err());
<a href=#720 id=720 data-nosnippet>720</a> }
<a href=#721 id=721 data-nosnippet>721</a>
<a href=#722 id=722 data-nosnippet>722</a> <span class="attr">#[test]
<a href=#723 id=723 data-nosnippet>723</a> </span><span class="kw">fn </span>test_new_for_export_with_chunk_window_requires_bounded_range() {
<a href=#724 id=724 data-nosnippet>724</a> <span class="kw">let </span>result = Manifest::new_for_export(
<a href=#725 id=725 data-nosnippet>725</a> <span class="string">"greptime"</span>.to_string(),
<a href=#726 id=726 data-nosnippet>726</a> <span class="macro">vec!</span>[<span class="string">"public"</span>.to_string()],
<a href=#727 id=727 data-nosnippet>727</a> <span class="bool-val">false</span>,
<a href=#728 id=728 data-nosnippet>728</a> TimeRange::new(
<a href=#729 id=729 data-nosnippet>729</a> <span class="prelude-val">None</span>,
<a href=#730 id=730 data-nosnippet>730</a> <span class="prelude-val">Some</span>(Utc.with_ymd_and_hms(<span class="number">2025</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>).unwrap()),
<a href=#731 id=731 data-nosnippet>731</a> ),
<a href=#732 id=732 data-nosnippet>732</a> DataFormat::Parquet,
<a href=#733 id=733 data-nosnippet>733</a> <span class="prelude-val">Some</span>(Duration::from_secs(<span class="number">3600</span>)),
<a href=#734 id=734 data-nosnippet>734</a> );
<a href=#735 id=735 data-nosnippet>735</a> <span class="macro">assert!</span>(result.is_err());
<a href=#736 id=736 data-nosnippet>736</a> }
<a href=#737 id=737 data-nosnippet>737</a>}
</code></pre></div></section></main></body></html>
+99
View File
@@ -0,0 +1,99 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/export_v2/schema.rs`."><title>schema.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/export_v2/</div>schema.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! Minimal schema index structures for Export/Import V2.
<a href=#16 id=16 data-nosnippet>16</a>//!
<a href=#17 id=17 data-nosnippet>17</a>//! The canonical schema representation is the per-schema DDL file under
<a href=#18 id=18 data-nosnippet>18</a>//! `schema/ddl/`. `schemas.json` only records which schemas exist in a snapshot.
<a href=#19 id=19 data-nosnippet>19</a>
<a href=#20 id=20 data-nosnippet>20</a></span><span class="kw">use </span>std::collections::HashMap;
<a href=#21 id=21 data-nosnippet>21</a>
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>serde::{Deserialize, Serialize};
<a href=#23 id=23 data-nosnippet>23</a>
<a href=#24 id=24 data-nosnippet>24</a><span class="doccomment">/// Schema directory name within snapshot.
<a href=#25 id=25 data-nosnippet>25</a></span><span class="kw">pub const </span>SCHEMA_DIR: <span class="kw-2">&amp;</span>str = <span class="string">"schema"</span>;
<a href=#26 id=26 data-nosnippet>26</a>
<a href=#27 id=27 data-nosnippet>27</a><span class="doccomment">/// DDL directory name within schema directory.
<a href=#28 id=28 data-nosnippet>28</a></span><span class="kw">pub const </span>DDL_DIR: <span class="kw-2">&amp;</span>str = <span class="string">"ddl"</span>;
<a href=#29 id=29 data-nosnippet>29</a>
<a href=#30 id=30 data-nosnippet>30</a><span class="doccomment">/// Schema definition file name.
<a href=#31 id=31 data-nosnippet>31</a></span><span class="kw">pub const </span>SCHEMAS_FILE: <span class="kw-2">&amp;</span>str = <span class="string">"schemas.json"</span>;
<a href=#32 id=32 data-nosnippet>32</a>
<a href=#33 id=33 data-nosnippet>33</a><span class="doccomment">/// Schema (database) definition.
<a href=#34 id=34 data-nosnippet>34</a></span><span class="attr">#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
<a href=#35 id=35 data-nosnippet>35</a></span><span class="kw">pub struct </span>SchemaDefinition {
<a href=#36 id=36 data-nosnippet>36</a> <span class="doccomment">/// Catalog name.
<a href=#37 id=37 data-nosnippet>37</a> </span><span class="kw">pub </span>catalog: String,
<a href=#38 id=38 data-nosnippet>38</a> <span class="doccomment">/// Schema (database) name.
<a href=#39 id=39 data-nosnippet>39</a> </span><span class="kw">pub </span>name: String,
<a href=#40 id=40 data-nosnippet>40</a> <span class="doccomment">/// Schema options (if any).
<a href=#41 id=41 data-nosnippet>41</a> </span><span class="attr">#[serde(default, skip_serializing_if = <span class="string">"HashMap::is_empty"</span>)]
<a href=#42 id=42 data-nosnippet>42</a> </span><span class="kw">pub </span>options: HashMap&lt;String, String&gt;,
<a href=#43 id=43 data-nosnippet>43</a>}
<a href=#44 id=44 data-nosnippet>44</a>
<a href=#45 id=45 data-nosnippet>45</a><span class="doccomment">/// Minimal schema index stored in a snapshot.
<a href=#46 id=46 data-nosnippet>46</a></span><span class="attr">#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
<a href=#47 id=47 data-nosnippet>47</a></span><span class="kw">pub struct </span>SchemaSnapshot {
<a href=#48 id=48 data-nosnippet>48</a> <span class="doccomment">/// Schema (database) definitions.
<a href=#49 id=49 data-nosnippet>49</a> </span><span class="kw">pub </span>schemas: Vec&lt;SchemaDefinition&gt;,
<a href=#50 id=50 data-nosnippet>50</a>}
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a><span class="kw">impl </span>SchemaSnapshot {
<a href=#53 id=53 data-nosnippet>53</a> <span class="doccomment">/// Creates an empty schema snapshot.
<a href=#54 id=54 data-nosnippet>54</a> </span><span class="kw">pub fn </span>new() -&gt; <span class="self">Self </span>{
<a href=#55 id=55 data-nosnippet>55</a> <span class="self">Self</span>::default()
<a href=#56 id=56 data-nosnippet>56</a> }
<a href=#57 id=57 data-nosnippet>57</a>
<a href=#58 id=58 data-nosnippet>58</a> <span class="doccomment">/// Adds a schema definition.
<a href=#59 id=59 data-nosnippet>59</a> </span><span class="kw">pub fn </span>add_schema(<span class="kw-2">&amp;mut </span><span class="self">self</span>, schema: SchemaDefinition) {
<a href=#60 id=60 data-nosnippet>60</a> <span class="self">self</span>.schemas.push(schema);
<a href=#61 id=61 data-nosnippet>61</a> }
<a href=#62 id=62 data-nosnippet>62</a>
<a href=#63 id=63 data-nosnippet>63</a> <span class="doccomment">/// Filters the snapshot to only include specified schemas.
<a href=#64 id=64 data-nosnippet>64</a> </span><span class="kw">pub fn </span>filter_schemas(<span class="kw-2">&amp;</span><span class="self">self</span>, schemas: <span class="kw-2">&amp;</span>[String]) -&gt; <span class="self">Self </span>{
<a href=#65 id=65 data-nosnippet>65</a> <span class="self">Self </span>{
<a href=#66 id=66 data-nosnippet>66</a> schemas: <span class="self">self
<a href=#67 id=67 data-nosnippet>67</a> </span>.schemas
<a href=#68 id=68 data-nosnippet>68</a> .iter()
<a href=#69 id=69 data-nosnippet>69</a> .filter(|s| schemas.contains(<span class="kw-2">&amp;</span>s.name))
<a href=#70 id=70 data-nosnippet>70</a> .cloned()
<a href=#71 id=71 data-nosnippet>71</a> .collect(),
<a href=#72 id=72 data-nosnippet>72</a> }
<a href=#73 id=73 data-nosnippet>73</a> }
<a href=#74 id=74 data-nosnippet>74</a>}
<a href=#75 id=75 data-nosnippet>75</a>
<a href=#76 id=76 data-nosnippet>76</a><span class="attr">#[cfg(test)]
<a href=#77 id=77 data-nosnippet>77</a></span><span class="kw">mod </span>tests {
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#79 id=79 data-nosnippet>79</a>
<a href=#80 id=80 data-nosnippet>80</a> <span class="attr">#[test]
<a href=#81 id=81 data-nosnippet>81</a> </span><span class="kw">fn </span>test_schema_snapshot_filter() {
<a href=#82 id=82 data-nosnippet>82</a> <span class="kw">let </span><span class="kw-2">mut </span>snapshot = SchemaSnapshot::new();
<a href=#83 id=83 data-nosnippet>83</a> snapshot.add_schema(SchemaDefinition {
<a href=#84 id=84 data-nosnippet>84</a> catalog: <span class="string">"greptime"</span>.to_string(),
<a href=#85 id=85 data-nosnippet>85</a> name: <span class="string">"public"</span>.to_string(),
<a href=#86 id=86 data-nosnippet>86</a> options: HashMap::new(),
<a href=#87 id=87 data-nosnippet>87</a> });
<a href=#88 id=88 data-nosnippet>88</a> snapshot.add_schema(SchemaDefinition {
<a href=#89 id=89 data-nosnippet>89</a> catalog: <span class="string">"greptime"</span>.to_string(),
<a href=#90 id=90 data-nosnippet>90</a> name: <span class="string">"private"</span>.to_string(),
<a href=#91 id=91 data-nosnippet>91</a> options: HashMap::new(),
<a href=#92 id=92 data-nosnippet>92</a> });
<a href=#93 id=93 data-nosnippet>93</a>
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">let </span>filtered = snapshot.filter_schemas(<span class="kw-2">&amp;</span>[<span class="string">"public"</span>.to_string()]);
<a href=#95 id=95 data-nosnippet>95</a> <span class="macro">assert_eq!</span>(filtered.schemas.len(), <span class="number">1</span>);
<a href=#96 id=96 data-nosnippet>96</a> <span class="macro">assert_eq!</span>(filtered.schemas[<span class="number">0</span>].name, <span class="string">"public"</span>);
<a href=#97 id=97 data-nosnippet>97</a> }
<a href=#98 id=98 data-nosnippet>98</a>}
</code></pre></div></section></main></body></html>
+354
View File
@@ -0,0 +1,354 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/import.rs`."><title>import.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/</div>import.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::path::PathBuf;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::sync::Arc;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>std::time::Duration;
<a href=#18 id=18 data-nosnippet>18</a>
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>async_trait::async_trait;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>clap::{Parser, ValueEnum};
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_catalog::consts::DEFAULT_SCHEMA_NAME;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_telemetry::{error, info, warn};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>snafu::{OptionExt, ResultExt, ensure};
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>tokio::sync::Semaphore;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>tokio::time::Instant;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span><span class="kw">crate</span>::data::{COPY_PATH_PLACEHOLDER, default_database};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span><span class="kw">crate</span>::database::{DatabaseClient, parse_proxy_opts};
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span><span class="kw">crate</span>::error::{Error, FileIoSnafu, InvalidArgumentsSnafu, <span class="prelude-ty">Result</span>, SchemaNotFoundSnafu};
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span>crate::{Tool, database};
<a href=#32 id=32 data-nosnippet>32</a>
<a href=#33 id=33 data-nosnippet>33</a><span class="attr">#[derive(Debug, Default, Clone, ValueEnum)]
<a href=#34 id=34 data-nosnippet>34</a></span><span class="kw">enum </span>ImportTarget {
<a href=#35 id=35 data-nosnippet>35</a> <span class="doccomment">/// Import all table schemas into the database.
<a href=#36 id=36 data-nosnippet>36</a> </span>Schema,
<a href=#37 id=37 data-nosnippet>37</a> <span class="doccomment">/// Import all table data into the database.
<a href=#38 id=38 data-nosnippet>38</a> </span>Data,
<a href=#39 id=39 data-nosnippet>39</a> <span class="doccomment">/// Export all table schemas and data at once.
<a href=#40 id=40 data-nosnippet>40</a> </span><span class="attr">#[default]
<a href=#41 id=41 data-nosnippet>41</a> </span>All,
<a href=#42 id=42 data-nosnippet>42</a>}
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="doccomment">/// Command to import data from a directory into a GreptimeDB instance.
<a href=#45 id=45 data-nosnippet>45</a></span><span class="attr">#[derive(Debug, Default, Parser)]
<a href=#46 id=46 data-nosnippet>46</a></span><span class="kw">pub struct </span>ImportCommand {
<a href=#47 id=47 data-nosnippet>47</a> <span class="doccomment">/// Server address to connect
<a href=#48 id=48 data-nosnippet>48</a> </span><span class="attr">#[clap(long)]
<a href=#49 id=49 data-nosnippet>49</a> </span>addr: String,
<a href=#50 id=50 data-nosnippet>50</a>
<a href=#51 id=51 data-nosnippet>51</a> <span class="doccomment">/// Directory of the data. E.g.: /tmp/greptimedb-backup
<a href=#52 id=52 data-nosnippet>52</a> </span><span class="attr">#[clap(long)]
<a href=#53 id=53 data-nosnippet>53</a> </span>input_dir: String,
<a href=#54 id=54 data-nosnippet>54</a>
<a href=#55 id=55 data-nosnippet>55</a> <span class="doccomment">/// The name of the catalog to import.
<a href=#56 id=56 data-nosnippet>56</a> </span><span class="attr">#[clap(long, default_value_t = default_database())]
<a href=#57 id=57 data-nosnippet>57</a> </span>database: String,
<a href=#58 id=58 data-nosnippet>58</a>
<a href=#59 id=59 data-nosnippet>59</a> <span class="doccomment">/// The number of databases imported in parallel.
<a href=#60 id=60 data-nosnippet>60</a> /// For example, if there are 20 databases and `db_parallelism` is 4,
<a href=#61 id=61 data-nosnippet>61</a> /// 4 databases will be imported concurrently.
<a href=#62 id=62 data-nosnippet>62</a> </span><span class="attr">#[clap(long, short = <span class="string">'j'</span>, default_value = <span class="string">"1"</span>, alias = <span class="string">"import-jobs"</span>)]
<a href=#63 id=63 data-nosnippet>63</a> </span>db_parallelism: usize,
<a href=#64 id=64 data-nosnippet>64</a>
<a href=#65 id=65 data-nosnippet>65</a> <span class="doccomment">/// Max retry times for each job.
<a href=#66 id=66 data-nosnippet>66</a> </span><span class="attr">#[clap(long, default_value = <span class="string">"3"</span>)]
<a href=#67 id=67 data-nosnippet>67</a> </span>max_retry: usize,
<a href=#68 id=68 data-nosnippet>68</a>
<a href=#69 id=69 data-nosnippet>69</a> <span class="doccomment">/// Things to export
<a href=#70 id=70 data-nosnippet>70</a> </span><span class="attr">#[clap(long, short = <span class="string">'t'</span>, value_enum, default_value = <span class="string">"all"</span>)]
<a href=#71 id=71 data-nosnippet>71</a> </span>target: ImportTarget,
<a href=#72 id=72 data-nosnippet>72</a>
<a href=#73 id=73 data-nosnippet>73</a> <span class="doccomment">/// The basic authentication for connecting to the server
<a href=#74 id=74 data-nosnippet>74</a> </span><span class="attr">#[clap(long)]
<a href=#75 id=75 data-nosnippet>75</a> </span>auth_basic: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#76 id=76 data-nosnippet>76</a>
<a href=#77 id=77 data-nosnippet>77</a> <span class="doccomment">/// The timeout of invoking the database.
<a href=#78 id=78 data-nosnippet>78</a> ///
<a href=#79 id=79 data-nosnippet>79</a> /// It is used to override the server-side timeout setting.
<a href=#80 id=80 data-nosnippet>80</a> /// The default behavior will disable server-side default timeout(i.e. `0s`).
<a href=#81 id=81 data-nosnippet>81</a> </span><span class="attr">#[clap(long, value_parser = humantime::parse_duration)]
<a href=#82 id=82 data-nosnippet>82</a> </span>timeout: <span class="prelude-ty">Option</span>&lt;Duration&gt;,
<a href=#83 id=83 data-nosnippet>83</a>
<a href=#84 id=84 data-nosnippet>84</a> <span class="doccomment">/// The proxy server address to connect.
<a href=#85 id=85 data-nosnippet>85</a> ///
<a href=#86 id=86 data-nosnippet>86</a> /// If set, it overrides the system proxy unless `--no-proxy` is specified.
<a href=#87 id=87 data-nosnippet>87</a> /// If neither `--proxy` nor `--no-proxy` is set, system proxy (env) may be used.
<a href=#88 id=88 data-nosnippet>88</a> </span><span class="attr">#[clap(long)]
<a href=#89 id=89 data-nosnippet>89</a> </span>proxy: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#90 id=90 data-nosnippet>90</a>
<a href=#91 id=91 data-nosnippet>91</a> <span class="doccomment">/// Disable all proxy usage (ignores `--proxy` and system proxy).
<a href=#92 id=92 data-nosnippet>92</a> ///
<a href=#93 id=93 data-nosnippet>93</a> /// When set and `--proxy` is not provided, this explicitly disables system proxy.
<a href=#94 id=94 data-nosnippet>94</a> </span><span class="attr">#[clap(long, default_value = <span class="string">"false"</span>)]
<a href=#95 id=95 data-nosnippet>95</a> </span>no_proxy: bool,
<a href=#96 id=96 data-nosnippet>96</a>}
<a href=#97 id=97 data-nosnippet>97</a>
<a href=#98 id=98 data-nosnippet>98</a><span class="kw">impl </span>ImportCommand {
<a href=#99 id=99 data-nosnippet>99</a> <span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt; {
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">let </span>(catalog, schema) =
<a href=#101 id=101 data-nosnippet>101</a> database::split_database(<span class="kw-2">&amp;</span><span class="self">self</span>.database).map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#102 id=102 data-nosnippet>102</a> <span class="kw">let </span>proxy = parse_proxy_opts(<span class="self">self</span>.proxy.clone(), <span class="self">self</span>.no_proxy)<span class="question-mark">?</span>;
<a href=#103 id=103 data-nosnippet>103</a> <span class="kw">let </span>database_client = DatabaseClient::new(
<a href=#104 id=104 data-nosnippet>104</a> <span class="self">self</span>.addr.clone(),
<a href=#105 id=105 data-nosnippet>105</a> catalog.clone(),
<a href=#106 id=106 data-nosnippet>106</a> <span class="self">self</span>.auth_basic.clone(),
<a href=#107 id=107 data-nosnippet>107</a> <span class="comment">// Treats `None` as `0s` to disable server-side default timeout.
<a href=#108 id=108 data-nosnippet>108</a> </span><span class="self">self</span>.timeout.unwrap_or_default(),
<a href=#109 id=109 data-nosnippet>109</a> proxy,
<a href=#110 id=110 data-nosnippet>110</a> <span class="self">self</span>.no_proxy,
<a href=#111 id=111 data-nosnippet>111</a> );
<a href=#112 id=112 data-nosnippet>112</a>
<a href=#113 id=113 data-nosnippet>113</a> <span class="prelude-val">Ok</span>(Box::new(Import {
<a href=#114 id=114 data-nosnippet>114</a> catalog,
<a href=#115 id=115 data-nosnippet>115</a> schema,
<a href=#116 id=116 data-nosnippet>116</a> database_client,
<a href=#117 id=117 data-nosnippet>117</a> input_dir: <span class="self">self</span>.input_dir.clone(),
<a href=#118 id=118 data-nosnippet>118</a> parallelism: <span class="self">self</span>.db_parallelism,
<a href=#119 id=119 data-nosnippet>119</a> target: <span class="self">self</span>.target.clone(),
<a href=#120 id=120 data-nosnippet>120</a> }))
<a href=#121 id=121 data-nosnippet>121</a> }
<a href=#122 id=122 data-nosnippet>122</a>}
<a href=#123 id=123 data-nosnippet>123</a>
<a href=#124 id=124 data-nosnippet>124</a><span class="kw">pub struct </span>Import {
<a href=#125 id=125 data-nosnippet>125</a> catalog: String,
<a href=#126 id=126 data-nosnippet>126</a> schema: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#127 id=127 data-nosnippet>127</a> database_client: DatabaseClient,
<a href=#128 id=128 data-nosnippet>128</a> input_dir: String,
<a href=#129 id=129 data-nosnippet>129</a> parallelism: usize,
<a href=#130 id=130 data-nosnippet>130</a> target: ImportTarget,
<a href=#131 id=131 data-nosnippet>131</a>}
<a href=#132 id=132 data-nosnippet>132</a>
<a href=#133 id=133 data-nosnippet>133</a><span class="kw">impl </span>Import {
<a href=#134 id=134 data-nosnippet>134</a> <span class="kw">async fn </span>import_create_table(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#135 id=135 data-nosnippet>135</a> <span class="comment">// Use default db to creates other dbs
<a href=#136 id=136 data-nosnippet>136</a> </span><span class="self">self</span>.do_sql_job(<span class="string">"create_database.sql"</span>, <span class="prelude-val">Some</span>(DEFAULT_SCHEMA_NAME))
<a href=#137 id=137 data-nosnippet>137</a> .<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#138 id=138 data-nosnippet>138</a> <span class="self">self</span>.do_sql_job(<span class="string">"create_tables.sql"</span>, <span class="prelude-val">None</span>).<span class="kw">await
<a href=#139 id=139 data-nosnippet>139</a> </span>}
<a href=#140 id=140 data-nosnippet>140</a>
<a href=#141 id=141 data-nosnippet>141</a> <span class="kw">async fn </span>import_database_data(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#142 id=142 data-nosnippet>142</a> <span class="self">self</span>.do_sql_job(<span class="string">"copy_from.sql"</span>, <span class="prelude-val">None</span>).<span class="kw">await
<a href=#143 id=143 data-nosnippet>143</a> </span>}
<a href=#144 id=144 data-nosnippet>144</a>
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">async fn </span>do_sql_job(<span class="kw-2">&amp;</span><span class="self">self</span>, filename: <span class="kw-2">&amp;</span>str, exec_db: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt;) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">let </span>timer = Instant::now();
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">let </span>semaphore = Arc::new(Semaphore::new(<span class="self">self</span>.parallelism));
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">let </span>db_names = <span class="self">self</span>.get_db_names().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">let </span>db_count = db_names.len();
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">let </span><span class="kw-2">mut </span>tasks = Vec::with_capacity(db_count);
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">for </span>schema <span class="kw">in </span>db_names {
<a href=#152 id=152 data-nosnippet>152</a> <span class="kw">let </span>semaphore_moved = semaphore.clone();
<a href=#153 id=153 data-nosnippet>153</a> tasks.push(<span class="kw">async move </span>{
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">let </span>_permit = semaphore_moved.acquire().<span class="kw">await</span>.unwrap();
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">let </span>database_input_dir = <span class="self">self</span>.catalog_path().join(<span class="kw-2">&amp;</span>schema);
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">let </span>sql_file = database_input_dir.join(filename);
<a href=#157 id=157 data-nosnippet>157</a> <span class="kw">let </span><span class="kw-2">mut </span>sql = tokio::fs::read_to_string(sql_file)
<a href=#158 id=158 data-nosnippet>158</a> .<span class="kw">await
<a href=#159 id=159 data-nosnippet>159</a> </span>.context(FileIoSnafu)<span class="question-mark">?</span>;
<a href=#160 id=160 data-nosnippet>160</a> <span class="kw">if </span>sql.trim().is_empty() {
<a href=#161 id=161 data-nosnippet>161</a> <span class="macro">info!</span>(<span class="string">"Empty `{filename}` {database_input_dir:?}"</span>);
<a href=#162 id=162 data-nosnippet>162</a> } <span class="kw">else </span>{
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">if </span>filename == <span class="string">"copy_from.sql" </span>{
<a href=#164 id=164 data-nosnippet>164</a> sql = <span class="self">self</span>.rewrite_copy_database_sql(<span class="kw-2">&amp;</span>schema, <span class="kw-2">&amp;</span>sql)<span class="question-mark">?</span>;
<a href=#165 id=165 data-nosnippet>165</a> }
<a href=#166 id=166 data-nosnippet>166</a> <span class="kw">let </span>db = exec_db.unwrap_or(<span class="kw-2">&amp;</span>schema);
<a href=#167 id=167 data-nosnippet>167</a> <span class="self">self</span>.database_client.sql(<span class="kw-2">&amp;</span>sql, db).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#168 id=168 data-nosnippet>168</a> <span class="macro">info!</span>(<span class="string">"Imported `{filename}` for database {schema}"</span>);
<a href=#169 id=169 data-nosnippet>169</a> }
<a href=#170 id=170 data-nosnippet>170</a>
<a href=#171 id=171 data-nosnippet>171</a> Ok::&lt;(), Error&gt;(())
<a href=#172 id=172 data-nosnippet>172</a> })
<a href=#173 id=173 data-nosnippet>173</a> }
<a href=#174 id=174 data-nosnippet>174</a>
<a href=#175 id=175 data-nosnippet>175</a> <span class="kw">let </span>success = futures::future::join_all(tasks)
<a href=#176 id=176 data-nosnippet>176</a> .<span class="kw">await
<a href=#177 id=177 data-nosnippet>177</a> </span>.into_iter()
<a href=#178 id=178 data-nosnippet>178</a> .filter(|r| <span class="kw">match </span>r {
<a href=#179 id=179 data-nosnippet>179</a> <span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; <span class="bool-val">true</span>,
<a href=#180 id=180 data-nosnippet>180</a> <span class="prelude-val">Err</span>(e) =&gt; {
<a href=#181 id=181 data-nosnippet>181</a> <span class="macro">error!</span>(e; <span class="string">"import {filename} job failed"</span>);
<a href=#182 id=182 data-nosnippet>182</a> <span class="bool-val">false
<a href=#183 id=183 data-nosnippet>183</a> </span>}
<a href=#184 id=184 data-nosnippet>184</a> })
<a href=#185 id=185 data-nosnippet>185</a> .count();
<a href=#186 id=186 data-nosnippet>186</a> <span class="kw">let </span>elapsed = timer.elapsed();
<a href=#187 id=187 data-nosnippet>187</a> <span class="macro">info!</span>(<span class="string">"Success {success}/{db_count} `{filename}` jobs, cost: {elapsed:?}"</span>);
<a href=#188 id=188 data-nosnippet>188</a>
<a href=#189 id=189 data-nosnippet>189</a> <span class="prelude-val">Ok</span>(())
<a href=#190 id=190 data-nosnippet>190</a> }
<a href=#191 id=191 data-nosnippet>191</a>
<a href=#192 id=192 data-nosnippet>192</a> <span class="kw">fn </span>catalog_path(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; PathBuf {
<a href=#193 id=193 data-nosnippet>193</a> PathBuf::from(<span class="kw-2">&amp;</span><span class="self">self</span>.input_dir).join(<span class="kw-2">&amp;</span><span class="self">self</span>.catalog)
<a href=#194 id=194 data-nosnippet>194</a> }
<a href=#195 id=195 data-nosnippet>195</a>
<a href=#196 id=196 data-nosnippet>196</a> <span class="kw">async fn </span>get_db_names(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt; {
<a href=#197 id=197 data-nosnippet>197</a> <span class="kw">let </span>db_names = <span class="self">self</span>.all_db_names().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">let </span><span class="prelude-val">Some</span>(schema) = <span class="kw-2">&amp;</span><span class="self">self</span>.schema <span class="kw">else </span>{
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(db_names);
<a href=#200 id=200 data-nosnippet>200</a> };
<a href=#201 id=201 data-nosnippet>201</a>
<a href=#202 id=202 data-nosnippet>202</a> <span class="comment">// Check if the schema exists
<a href=#203 id=203 data-nosnippet>203</a> </span>db_names
<a href=#204 id=204 data-nosnippet>204</a> .into_iter()
<a href=#205 id=205 data-nosnippet>205</a> .find(|db_name| db_name.to_lowercase() == schema.to_lowercase())
<a href=#206 id=206 data-nosnippet>206</a> .map(|name| <span class="macro">vec!</span>[name])
<a href=#207 id=207 data-nosnippet>207</a> .context(SchemaNotFoundSnafu {
<a href=#208 id=208 data-nosnippet>208</a> catalog: <span class="kw-2">&amp;</span><span class="self">self</span>.catalog,
<a href=#209 id=209 data-nosnippet>209</a> schema,
<a href=#210 id=210 data-nosnippet>210</a> })
<a href=#211 id=211 data-nosnippet>211</a> }
<a href=#212 id=212 data-nosnippet>212</a>
<a href=#213 id=213 data-nosnippet>213</a> <span class="comment">// Get all database names in the input directory.
<a href=#214 id=214 data-nosnippet>214</a> // The directory structure should be like:
<a href=#215 id=215 data-nosnippet>215</a> // /tmp/greptimedb-backup
<a href=#216 id=216 data-nosnippet>216</a> // ├── greptime-1
<a href=#217 id=217 data-nosnippet>217</a> // │ ├── db1
<a href=#218 id=218 data-nosnippet>218</a> // │ └── db2
<a href=#219 id=219 data-nosnippet>219</a> </span><span class="kw">async fn </span>all_db_names(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt; {
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">let </span><span class="kw-2">mut </span>db_names = <span class="macro">vec!</span>[];
<a href=#221 id=221 data-nosnippet>221</a> <span class="kw">let </span>path = <span class="self">self</span>.catalog_path();
<a href=#222 id=222 data-nosnippet>222</a> <span class="kw">let </span><span class="kw-2">mut </span>entries = tokio::fs::read_dir(path).<span class="kw">await</span>.context(FileIoSnafu)<span class="question-mark">?</span>;
<a href=#223 id=223 data-nosnippet>223</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(entry) = entries.next_entry().<span class="kw">await</span>.context(FileIoSnafu)<span class="question-mark">? </span>{
<a href=#224 id=224 data-nosnippet>224</a> <span class="kw">let </span>path = entry.path();
<a href=#225 id=225 data-nosnippet>225</a> <span class="kw">if </span>path.is_dir() {
<a href=#226 id=226 data-nosnippet>226</a> <span class="kw">let </span>db_name = <span class="kw">match </span>path.file_name() {
<a href=#227 id=227 data-nosnippet>227</a> <span class="prelude-val">Some</span>(name) =&gt; name.to_string_lossy().to_string(),
<a href=#228 id=228 data-nosnippet>228</a> <span class="prelude-val">None </span>=&gt; {
<a href=#229 id=229 data-nosnippet>229</a> <span class="macro">warn!</span>(<span class="string">"Failed to get the file name of {:?}"</span>, path);
<a href=#230 id=230 data-nosnippet>230</a> <span class="kw">continue</span>;
<a href=#231 id=231 data-nosnippet>231</a> }
<a href=#232 id=232 data-nosnippet>232</a> };
<a href=#233 id=233 data-nosnippet>233</a> db_names.push(db_name);
<a href=#234 id=234 data-nosnippet>234</a> }
<a href=#235 id=235 data-nosnippet>235</a> }
<a href=#236 id=236 data-nosnippet>236</a> <span class="prelude-val">Ok</span>(db_names)
<a href=#237 id=237 data-nosnippet>237</a> }
<a href=#238 id=238 data-nosnippet>238</a>
<a href=#239 id=239 data-nosnippet>239</a> <span class="kw">fn </span>rewrite_copy_database_sql(<span class="kw-2">&amp;</span><span class="self">self</span>, schema: <span class="kw-2">&amp;</span>str, sql: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;String&gt; {
<a href=#240 id=240 data-nosnippet>240</a> <span class="kw">let </span>target_location = <span class="self">self</span>.build_copy_database_location(schema);
<a href=#241 id=241 data-nosnippet>241</a> <span class="kw">let </span>escaped_location = target_location.replace(<span class="string">'\''</span>, <span class="string">"''"</span>);
<a href=#242 id=242 data-nosnippet>242</a>
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">let </span><span class="kw-2">mut </span>first_stmt_checked = <span class="bool-val">false</span>;
<a href=#244 id=244 data-nosnippet>244</a> <span class="kw">for </span>line <span class="kw">in </span>sql.lines() {
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw">let </span>trimmed = line.trim_start();
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">if </span>trimmed.is_empty() || trimmed.starts_with(<span class="string">"--"</span>) {
<a href=#247 id=247 data-nosnippet>247</a> <span class="kw">continue</span>;
<a href=#248 id=248 data-nosnippet>248</a> }
<a href=#249 id=249 data-nosnippet>249</a>
<a href=#250 id=250 data-nosnippet>250</a> <span class="macro">ensure!</span>(
<a href=#251 id=251 data-nosnippet>251</a> trimmed.starts_with(<span class="string">"COPY DATABASE"</span>),
<a href=#252 id=252 data-nosnippet>252</a> InvalidArgumentsSnafu {
<a href=#253 id=253 data-nosnippet>253</a> msg: <span class="string">"Expected COPY DATABASE statement at start of copy_from.sql"
<a href=#254 id=254 data-nosnippet>254</a> </span>}
<a href=#255 id=255 data-nosnippet>255</a> );
<a href=#256 id=256 data-nosnippet>256</a> first_stmt_checked = <span class="bool-val">true</span>;
<a href=#257 id=257 data-nosnippet>257</a> <span class="kw">break</span>;
<a href=#258 id=258 data-nosnippet>258</a> }
<a href=#259 id=259 data-nosnippet>259</a>
<a href=#260 id=260 data-nosnippet>260</a> <span class="macro">ensure!</span>(
<a href=#261 id=261 data-nosnippet>261</a> first_stmt_checked,
<a href=#262 id=262 data-nosnippet>262</a> InvalidArgumentsSnafu {
<a href=#263 id=263 data-nosnippet>263</a> msg: <span class="string">"COPY DATABASE statement not found in copy_from.sql"
<a href=#264 id=264 data-nosnippet>264</a> </span>}
<a href=#265 id=265 data-nosnippet>265</a> );
<a href=#266 id=266 data-nosnippet>266</a>
<a href=#267 id=267 data-nosnippet>267</a> <span class="macro">ensure!</span>(
<a href=#268 id=268 data-nosnippet>268</a> sql.contains(COPY_PATH_PLACEHOLDER),
<a href=#269 id=269 data-nosnippet>269</a> InvalidArgumentsSnafu {
<a href=#270 id=270 data-nosnippet>270</a> msg: <span class="macro">format!</span>(
<a href=#271 id=271 data-nosnippet>271</a> <span class="string">"Placeholder `{}` not found in COPY DATABASE statement"</span>,
<a href=#272 id=272 data-nosnippet>272</a> COPY_PATH_PLACEHOLDER
<a href=#273 id=273 data-nosnippet>273</a> )
<a href=#274 id=274 data-nosnippet>274</a> }
<a href=#275 id=275 data-nosnippet>275</a> );
<a href=#276 id=276 data-nosnippet>276</a>
<a href=#277 id=277 data-nosnippet>277</a> <span class="prelude-val">Ok</span>(sql.replacen(COPY_PATH_PLACEHOLDER, <span class="kw-2">&amp;</span>escaped_location, <span class="number">1</span>))
<a href=#278 id=278 data-nosnippet>278</a> }
<a href=#279 id=279 data-nosnippet>279</a>
<a href=#280 id=280 data-nosnippet>280</a> <span class="kw">fn </span>build_copy_database_location(<span class="kw-2">&amp;</span><span class="self">self</span>, schema: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#281 id=281 data-nosnippet>281</a> <span class="kw">let </span><span class="kw-2">mut </span>path = <span class="self">self</span>.catalog_path();
<a href=#282 id=282 data-nosnippet>282</a> path.push(schema);
<a href=#283 id=283 data-nosnippet>283</a> <span class="kw">let </span><span class="kw-2">mut </span>path_str = path.to_string_lossy().into_owned();
<a href=#284 id=284 data-nosnippet>284</a> <span class="kw">if </span>!path_str.ends_with(<span class="string">'/'</span>) {
<a href=#285 id=285 data-nosnippet>285</a> path_str.push(<span class="string">'/'</span>);
<a href=#286 id=286 data-nosnippet>286</a> }
<a href=#287 id=287 data-nosnippet>287</a> path_str
<a href=#288 id=288 data-nosnippet>288</a> }
<a href=#289 id=289 data-nosnippet>289</a>}
<a href=#290 id=290 data-nosnippet>290</a>
<a href=#291 id=291 data-nosnippet>291</a><span class="attr">#[async_trait]
<a href=#292 id=292 data-nosnippet>292</a></span><span class="kw">impl </span>Tool <span class="kw">for </span>Import {
<a href=#293 id=293 data-nosnippet>293</a> <span class="kw">async fn </span>do_work(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;(), BoxedError&gt; {
<a href=#294 id=294 data-nosnippet>294</a> <span class="kw">match </span><span class="self">self</span>.target {
<a href=#295 id=295 data-nosnippet>295</a> ImportTarget::Schema =&gt; <span class="self">self</span>.import_create_table().<span class="kw">await</span>.map_err(BoxedError::new),
<a href=#296 id=296 data-nosnippet>296</a> ImportTarget::Data =&gt; <span class="self">self</span>.import_database_data().<span class="kw">await</span>.map_err(BoxedError::new),
<a href=#297 id=297 data-nosnippet>297</a> ImportTarget::All =&gt; {
<a href=#298 id=298 data-nosnippet>298</a> <span class="self">self</span>.import_create_table().<span class="kw">await</span>.map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#299 id=299 data-nosnippet>299</a> <span class="self">self</span>.import_database_data().<span class="kw">await</span>.map_err(BoxedError::new)
<a href=#300 id=300 data-nosnippet>300</a> }
<a href=#301 id=301 data-nosnippet>301</a> }
<a href=#302 id=302 data-nosnippet>302</a> }
<a href=#303 id=303 data-nosnippet>303</a>}
<a href=#304 id=304 data-nosnippet>304</a>
<a href=#305 id=305 data-nosnippet>305</a><span class="attr">#[cfg(test)]
<a href=#306 id=306 data-nosnippet>306</a></span><span class="kw">mod </span>tests {
<a href=#307 id=307 data-nosnippet>307</a> <span class="kw">use </span>std::time::Duration;
<a href=#308 id=308 data-nosnippet>308</a>
<a href=#309 id=309 data-nosnippet>309</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#310 id=310 data-nosnippet>310</a>
<a href=#311 id=311 data-nosnippet>311</a> <span class="kw">fn </span>build_import(input_dir: <span class="kw-2">&amp;</span>str) -&gt; Import {
<a href=#312 id=312 data-nosnippet>312</a> Import {
<a href=#313 id=313 data-nosnippet>313</a> catalog: <span class="string">"catalog"</span>.to_string(),
<a href=#314 id=314 data-nosnippet>314</a> schema: <span class="prelude-val">None</span>,
<a href=#315 id=315 data-nosnippet>315</a> database_client: DatabaseClient::new(
<a href=#316 id=316 data-nosnippet>316</a> <span class="string">"127.0.0.1:4000"</span>.to_string(),
<a href=#317 id=317 data-nosnippet>317</a> <span class="string">"catalog"</span>.to_string(),
<a href=#318 id=318 data-nosnippet>318</a> <span class="prelude-val">None</span>,
<a href=#319 id=319 data-nosnippet>319</a> Duration::from_secs(<span class="number">0</span>),
<a href=#320 id=320 data-nosnippet>320</a> <span class="prelude-val">None</span>,
<a href=#321 id=321 data-nosnippet>321</a> <span class="bool-val">false</span>,
<a href=#322 id=322 data-nosnippet>322</a> ),
<a href=#323 id=323 data-nosnippet>323</a> input_dir: input_dir.to_string(),
<a href=#324 id=324 data-nosnippet>324</a> parallelism: <span class="number">1</span>,
<a href=#325 id=325 data-nosnippet>325</a> target: ImportTarget::Data,
<a href=#326 id=326 data-nosnippet>326</a> }
<a href=#327 id=327 data-nosnippet>327</a> }
<a href=#328 id=328 data-nosnippet>328</a>
<a href=#329 id=329 data-nosnippet>329</a> <span class="attr">#[test]
<a href=#330 id=330 data-nosnippet>330</a> </span><span class="kw">fn </span>rewrite_copy_database_sql_replaces_placeholder() {
<a href=#331 id=331 data-nosnippet>331</a> <span class="kw">let </span>import = build_import(<span class="string">"/tmp/export-path"</span>);
<a href=#332 id=332 data-nosnippet>332</a> <span class="kw">let </span>comment = <span class="string">"-- COPY DATABASE \"catalog\".\"schema\" FROM 's3://bucket/demo/' WITH (format = 'parquet') CONNECTION (region = 'us-west-2')"</span>;
<a href=#333 id=333 data-nosnippet>333</a> <span class="kw">let </span>sql = <span class="macro">format!</span>(
<a href=#334 id=334 data-nosnippet>334</a> <span class="string">"{comment}\nCOPY DATABASE \"catalog\".\"schema\" FROM '{}' WITH (format = 'parquet');"</span>,
<a href=#335 id=335 data-nosnippet>335</a> COPY_PATH_PLACEHOLDER
<a href=#336 id=336 data-nosnippet>336</a> );
<a href=#337 id=337 data-nosnippet>337</a>
<a href=#338 id=338 data-nosnippet>338</a> <span class="kw">let </span>rewritten = import.rewrite_copy_database_sql(<span class="string">"schema"</span>, <span class="kw-2">&amp;</span>sql).unwrap();
<a href=#339 id=339 data-nosnippet>339</a> <span class="kw">let </span>expected_location = import.build_copy_database_location(<span class="string">"schema"</span>);
<a href=#340 id=340 data-nosnippet>340</a> <span class="kw">let </span>escaped = expected_location.replace(<span class="string">'\''</span>, <span class="string">"''"</span>);
<a href=#341 id=341 data-nosnippet>341</a>
<a href=#342 id=342 data-nosnippet>342</a> <span class="macro">assert!</span>(rewritten.starts_with(comment));
<a href=#343 id=343 data-nosnippet>343</a> <span class="macro">assert!</span>(rewritten.contains(<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"FROM '{escaped}'"</span>)));
<a href=#344 id=344 data-nosnippet>344</a> <span class="macro">assert!</span>(!rewritten.contains(COPY_PATH_PLACEHOLDER));
<a href=#345 id=345 data-nosnippet>345</a> }
<a href=#346 id=346 data-nosnippet>346</a>
<a href=#347 id=347 data-nosnippet>347</a> <span class="attr">#[test]
<a href=#348 id=348 data-nosnippet>348</a> </span><span class="kw">fn </span>rewrite_copy_database_sql_requires_placeholder() {
<a href=#349 id=349 data-nosnippet>349</a> <span class="kw">let </span>import = build_import(<span class="string">"/tmp/export-path"</span>);
<a href=#350 id=350 data-nosnippet>350</a> <span class="kw">let </span>sql = <span class="string">"COPY DATABASE \"catalog\".\"schema\" FROM '/tmp/export-path/catalog/schema/' WITH (format = 'parquet');"</span>;
<a href=#351 id=351 data-nosnippet>351</a> <span class="macro">assert!</span>(import.rewrite_copy_database_sql(<span class="string">"schema"</span>, sql).is_err());
<a href=#352 id=352 data-nosnippet>352</a> }
<a href=#353 id=353 data-nosnippet>353</a>}
</code></pre></div></section></main></body></html>
+45
View File
@@ -0,0 +1,45 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/import_v2.rs`."><title>import_v2.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/</div>import_v2.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! Import V2 module.
<a href=#16 id=16 data-nosnippet>16</a>//!
<a href=#17 id=17 data-nosnippet>17</a>//! This module provides the V2 implementation of database import functionality,
<a href=#18 id=18 data-nosnippet>18</a>//! featuring:
<a href=#19 id=19 data-nosnippet>19</a>//! - DDL-based schema import
<a href=#20 id=20 data-nosnippet>20</a>//! - Dry-run mode for verification
<a href=#21 id=21 data-nosnippet>21</a>//!
<a href=#22 id=22 data-nosnippet>22</a>//! # Example
<a href=#23 id=23 data-nosnippet>23</a>//!
<a href=#24 id=24 data-nosnippet>24</a>//! ```bash
<a href=#25 id=25 data-nosnippet>25</a>//! # Dry-run import (verify without executing)
<a href=#26 id=26 data-nosnippet>26</a>//! greptime cli data import-v2 \
<a href=#27 id=27 data-nosnippet>27</a>//! --addr 127.0.0.1:4000 \
<a href=#28 id=28 data-nosnippet>28</a>//! --from file:///tmp/snapshot \
<a href=#29 id=29 data-nosnippet>29</a>//! --dry-run
<a href=#30 id=30 data-nosnippet>30</a>//!
<a href=#31 id=31 data-nosnippet>31</a>//! # Actual import
<a href=#32 id=32 data-nosnippet>32</a>//! greptime cli data import-v2 \
<a href=#33 id=33 data-nosnippet>33</a>//! --addr 127.0.0.1:4000 \
<a href=#34 id=34 data-nosnippet>34</a>//! --from s3://bucket/snapshots/prod-20250101
<a href=#35 id=35 data-nosnippet>35</a>//! ```
<a href=#36 id=36 data-nosnippet>36</a>
<a href=#37 id=37 data-nosnippet>37</a></span><span class="kw">mod </span>command;
<a href=#38 id=38 data-nosnippet>38</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">mod </span>coordinator;
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">pub mod </span>error;
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">pub mod </span>executor;
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">mod </span>packed;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">mod </span>state;
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">pub use </span>command::ImportV2Command;
</code></pre></div></section></main></body></html>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+237
View File
@@ -0,0 +1,237 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/import_v2/error.rs`."><title>error.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/import_v2/</div>error.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::any::Any;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_error::ext::{ErrorExt, RetryHint, retry_hint_from_io_error};
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_error::status_code::StatusCode;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_macro::stack_trace_debug;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>snafu::{Location, Snafu};
<a href=#21 id=21 data-nosnippet>21</a>
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::manifest::ChunkStatus;
<a href=#23 id=23 data-nosnippet>23</a>
<a href=#24 id=24 data-nosnippet>24</a><span class="attr">#[derive(Snafu)]
<a href=#25 id=25 data-nosnippet>25</a>#[snafu(visibility(<span class="kw">pub</span>))]
<a href=#26 id=26 data-nosnippet>26</a>#[stack_trace_debug]
<a href=#27 id=27 data-nosnippet>27</a></span><span class="kw">pub enum </span>Error {
<a href=#28 id=28 data-nosnippet>28</a> <span class="attr">#[snafu(display(<span class="string">"Invalid packed snapshot: {reason}"</span>))]
<a href=#29 id=29 data-nosnippet>29</a> </span>InvalidPackedSnapshot { reason: String },
<a href=#30 id=30 data-nosnippet>30</a>
<a href=#31 id=31 data-nosnippet>31</a> <span class="attr">#[snafu(display(<span class="string">"Snapshot not found at '{}'"</span>, uri))]
<a href=#32 id=32 data-nosnippet>32</a> </span>SnapshotNotFound {
<a href=#33 id=33 data-nosnippet>33</a> uri: String,
<a href=#34 id=34 data-nosnippet>34</a> <span class="attr">#[snafu(implicit)]
<a href=#35 id=35 data-nosnippet>35</a> </span>location: Location,
<a href=#36 id=36 data-nosnippet>36</a> },
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a> <span class="attr">#[snafu(display(<span class="string">"Schema '{}' not found in snapshot"</span>, schema))]
<a href=#39 id=39 data-nosnippet>39</a> </span>SchemaNotInSnapshot {
<a href=#40 id=40 data-nosnippet>40</a> schema: String,
<a href=#41 id=41 data-nosnippet>41</a> <span class="attr">#[snafu(implicit)]
<a href=#42 id=42 data-nosnippet>42</a> </span>location: Location,
<a href=#43 id=43 data-nosnippet>43</a> },
<a href=#44 id=44 data-nosnippet>44</a>
<a href=#45 id=45 data-nosnippet>45</a> <span class="attr">#[snafu(display(<span class="string">"Incomplete snapshot: chunk {} has status {:?}"</span>, chunk_id, status))]
<a href=#46 id=46 data-nosnippet>46</a> </span>IncompleteSnapshot {
<a href=#47 id=47 data-nosnippet>47</a> chunk_id: u32,
<a href=#48 id=48 data-nosnippet>48</a> status: ChunkStatus,
<a href=#49 id=49 data-nosnippet>49</a> <span class="attr">#[snafu(implicit)]
<a href=#50 id=50 data-nosnippet>50</a> </span>location: Location,
<a href=#51 id=51 data-nosnippet>51</a> },
<a href=#52 id=52 data-nosnippet>52</a>
<a href=#53 id=53 data-nosnippet>53</a> <span class="attr">#[snafu(display(
<a href=#54 id=54 data-nosnippet>54</a> <span class="string">"Snapshot is inconsistent: chunk {} is marked completed but its file manifest is empty"</span>,
<a href=#55 id=55 data-nosnippet>55</a> chunk_id
<a href=#56 id=56 data-nosnippet>56</a> ))]
<a href=#57 id=57 data-nosnippet>57</a> </span>EmptyChunkManifest {
<a href=#58 id=58 data-nosnippet>58</a> chunk_id: u32,
<a href=#59 id=59 data-nosnippet>59</a> <span class="attr">#[snafu(implicit)]
<a href=#60 id=60 data-nosnippet>60</a> </span>location: Location,
<a href=#61 id=61 data-nosnippet>61</a> },
<a href=#62 id=62 data-nosnippet>62</a>
<a href=#63 id=63 data-nosnippet>63</a> <span class="attr">#[snafu(display(
<a href=#64 id=64 data-nosnippet>64</a> <span class="string">"Snapshot is inconsistent: chunk {} for schema '{}' is marked completed but no files were found under '{}'"</span>,
<a href=#65 id=65 data-nosnippet>65</a> chunk_id,
<a href=#66 id=66 data-nosnippet>66</a> schema,
<a href=#67 id=67 data-nosnippet>67</a> path
<a href=#68 id=68 data-nosnippet>68</a> ))]
<a href=#69 id=69 data-nosnippet>69</a> </span>MissingChunkData {
<a href=#70 id=70 data-nosnippet>70</a> chunk_id: u32,
<a href=#71 id=71 data-nosnippet>71</a> schema: String,
<a href=#72 id=72 data-nosnippet>72</a> path: String,
<a href=#73 id=73 data-nosnippet>73</a> <span class="attr">#[snafu(implicit)]
<a href=#74 id=74 data-nosnippet>74</a> </span>location: Location,
<a href=#75 id=75 data-nosnippet>75</a> },
<a href=#76 id=76 data-nosnippet>76</a>
<a href=#77 id=77 data-nosnippet>77</a> <span class="attr">#[snafu(display(<span class="string">"Chunk {} import failed for schema '{}'"</span>, chunk_id, schema))]
<a href=#78 id=78 data-nosnippet>78</a> </span>ChunkImportFailed {
<a href=#79 id=79 data-nosnippet>79</a> chunk_id: u32,
<a href=#80 id=80 data-nosnippet>80</a> schema: String,
<a href=#81 id=81 data-nosnippet>81</a> <span class="attr">#[snafu(source)]
<a href=#82 id=82 data-nosnippet>82</a> </span>error: <span class="kw">crate</span>::data::export_v2::error::Error,
<a href=#83 id=83 data-nosnippet>83</a> <span class="attr">#[snafu(implicit)]
<a href=#84 id=84 data-nosnippet>84</a> </span>location: Location,
<a href=#85 id=85 data-nosnippet>85</a> },
<a href=#86 id=86 data-nosnippet>86</a>
<a href=#87 id=87 data-nosnippet>87</a> <span class="attr">#[snafu(display(<span class="string">"Snapshot storage error"</span>))]
<a href=#88 id=88 data-nosnippet>88</a> </span>SnapshotStorage {
<a href=#89 id=89 data-nosnippet>89</a> <span class="attr">#[snafu(source)]
<a href=#90 id=90 data-nosnippet>90</a> </span>error: <span class="kw">crate</span>::data::export_v2::error::Error,
<a href=#91 id=91 data-nosnippet>91</a> <span class="attr">#[snafu(implicit)]
<a href=#92 id=92 data-nosnippet>92</a> </span>location: Location,
<a href=#93 id=93 data-nosnippet>93</a> },
<a href=#94 id=94 data-nosnippet>94</a>
<a href=#95 id=95 data-nosnippet>95</a> <span class="attr">#[snafu(display(<span class="string">"Database error"</span>))]
<a href=#96 id=96 data-nosnippet>96</a> </span>Database {
<a href=#97 id=97 data-nosnippet>97</a> <span class="attr">#[snafu(source)]
<a href=#98 id=98 data-nosnippet>98</a> </span>error: <span class="kw">crate</span>::error::Error,
<a href=#99 id=99 data-nosnippet>99</a> <span class="attr">#[snafu(implicit)]
<a href=#100 id=100 data-nosnippet>100</a> </span>location: Location,
<a href=#101 id=101 data-nosnippet>101</a> },
<a href=#102 id=102 data-nosnippet>102</a>
<a href=#103 id=103 data-nosnippet>103</a> <span class="attr">#[snafu(display(<span class="string">"Failed to parse import state file"</span>))]
<a href=#104 id=104 data-nosnippet>104</a> </span>ImportStateParse {
<a href=#105 id=105 data-nosnippet>105</a> <span class="attr">#[snafu(source)]
<a href=#106 id=106 data-nosnippet>106</a> </span>error: serde_json::Error,
<a href=#107 id=107 data-nosnippet>107</a> <span class="attr">#[snafu(implicit)]
<a href=#108 id=108 data-nosnippet>108</a> </span>location: Location,
<a href=#109 id=109 data-nosnippet>109</a> },
<a href=#110 id=110 data-nosnippet>110</a>
<a href=#111 id=111 data-nosnippet>111</a> <span class="attr">#[snafu(display(<span class="string">"Import state I/O failed at '{}': {}"</span>, path, error))]
<a href=#112 id=112 data-nosnippet>112</a> </span>ImportStateIo {
<a href=#113 id=113 data-nosnippet>113</a> path: String,
<a href=#114 id=114 data-nosnippet>114</a> <span class="attr">#[snafu(source)]
<a href=#115 id=115 data-nosnippet>115</a> </span>error: std::io::Error,
<a href=#116 id=116 data-nosnippet>116</a> <span class="attr">#[snafu(implicit)]
<a href=#117 id=117 data-nosnippet>117</a> </span>location: Location,
<a href=#118 id=118 data-nosnippet>118</a> },
<a href=#119 id=119 data-nosnippet>119</a>
<a href=#120 id=120 data-nosnippet>120</a> <span class="attr">#[snafu(display(<span class="string">"Import state is already locked at '{}'"</span>, path))]
<a href=#121 id=121 data-nosnippet>121</a> </span>ImportStateLocked {
<a href=#122 id=122 data-nosnippet>122</a> path: String,
<a href=#123 id=123 data-nosnippet>123</a> <span class="attr">#[snafu(implicit)]
<a href=#124 id=124 data-nosnippet>124</a> </span>location: Location,
<a href=#125 id=125 data-nosnippet>125</a> },
<a href=#126 id=126 data-nosnippet>126</a>
<a href=#127 id=127 data-nosnippet>127</a> <span class="attr">#[snafu(display(
<a href=#128 id=128 data-nosnippet>128</a> <span class="string">"Failed to determine import state path for snapshot '{}'. Set HOME, USERPROFILE, or run from a valid current directory."</span>,
<a href=#129 id=129 data-nosnippet>129</a> snapshot_id
<a href=#130 id=130 data-nosnippet>130</a> ))]
<a href=#131 id=131 data-nosnippet>131</a> </span>ImportStatePathUnavailable {
<a href=#132 id=132 data-nosnippet>132</a> snapshot_id: String,
<a href=#133 id=133 data-nosnippet>133</a> <span class="attr">#[snafu(implicit)]
<a href=#134 id=134 data-nosnippet>134</a> </span>location: Location,
<a href=#135 id=135 data-nosnippet>135</a> },
<a href=#136 id=136 data-nosnippet>136</a>
<a href=#137 id=137 data-nosnippet>137</a> <span class="attr">#[snafu(display(
<a href=#138 id=138 data-nosnippet>138</a> <span class="string">"Import state at '{}' does not match current import: {}. Either rerun with matching import arguments, or delete the state file to start over (DDL will be re-executed)."</span>,
<a href=#139 id=139 data-nosnippet>139</a> path,
<a href=#140 id=140 data-nosnippet>140</a> reason
<a href=#141 id=141 data-nosnippet>141</a> ))]
<a href=#142 id=142 data-nosnippet>142</a> </span>ImportStateMismatch {
<a href=#143 id=143 data-nosnippet>143</a> path: String,
<a href=#144 id=144 data-nosnippet>144</a> reason: String,
<a href=#145 id=145 data-nosnippet>145</a> <span class="attr">#[snafu(implicit)]
<a href=#146 id=146 data-nosnippet>146</a> </span>location: Location,
<a href=#147 id=147 data-nosnippet>147</a> },
<a href=#148 id=148 data-nosnippet>148</a>
<a href=#149 id=149 data-nosnippet>149</a> <span class="attr">#[cfg(test)]
<a href=#150 id=150 data-nosnippet>150</a> #[snafu(display(<span class="string">"Test task failed: {}"</span>, message))]
<a href=#151 id=151 data-nosnippet>151</a> </span>TestTaskFailed {
<a href=#152 id=152 data-nosnippet>152</a> message: String,
<a href=#153 id=153 data-nosnippet>153</a> retryable: bool,
<a href=#154 id=154 data-nosnippet>154</a> <span class="attr">#[snafu(implicit)]
<a href=#155 id=155 data-nosnippet>155</a> </span>location: Location,
<a href=#156 id=156 data-nosnippet>156</a> },
<a href=#157 id=157 data-nosnippet>157</a>
<a href=#158 id=158 data-nosnippet>158</a> <span class="attr">#[snafu(display(
<a href=#159 id=159 data-nosnippet>159</a> <span class="string">"Import state references unknown task: chunk {}, schema '{}'"</span>,
<a href=#160 id=160 data-nosnippet>160</a> chunk_id,
<a href=#161 id=161 data-nosnippet>161</a> schema
<a href=#162 id=162 data-nosnippet>162</a> ))]
<a href=#163 id=163 data-nosnippet>163</a> </span>ImportStateUnknownTask {
<a href=#164 id=164 data-nosnippet>164</a> chunk_id: u32,
<a href=#165 id=165 data-nosnippet>165</a> schema: String,
<a href=#166 id=166 data-nosnippet>166</a> <span class="attr">#[snafu(implicit)]
<a href=#167 id=167 data-nosnippet>167</a> </span>location: Location,
<a href=#168 id=168 data-nosnippet>168</a> },
<a href=#169 id=169 data-nosnippet>169</a>
<a href=#170 id=170 data-nosnippet>170</a> <span class="attr">#[snafu(display(
<a href=#171 id=171 data-nosnippet>171</a> <span class="string">"Import state at '{}' is not ready for data import: DDL has not been marked completed"</span>,
<a href=#172 id=172 data-nosnippet>172</a> path
<a href=#173 id=173 data-nosnippet>173</a> ))]
<a href=#174 id=174 data-nosnippet>174</a> </span>ImportStateDdlIncomplete {
<a href=#175 id=175 data-nosnippet>175</a> path: String,
<a href=#176 id=176 data-nosnippet>176</a> <span class="attr">#[snafu(implicit)]
<a href=#177 id=177 data-nosnippet>177</a> </span>location: Location,
<a href=#178 id=178 data-nosnippet>178</a> },
<a href=#179 id=179 data-nosnippet>179</a>}
<a href=#180 id=180 data-nosnippet>180</a>
<a href=#181 id=181 data-nosnippet>181</a><span class="kw">pub type </span><span class="prelude-ty">Result</span>&lt;T&gt; = std::result::Result&lt;T, Error&gt;;
<a href=#182 id=182 data-nosnippet>182</a>
<a href=#183 id=183 data-nosnippet>183</a><span class="kw">impl </span>ErrorExt <span class="kw">for </span>Error {
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#186 id=186 data-nosnippet>186</a> Error::SnapshotNotFound { .. }
<a href=#187 id=187 data-nosnippet>187</a> | Error::SchemaNotInSnapshot { .. }
<a href=#188 id=188 data-nosnippet>188</a> | Error::IncompleteSnapshot { .. }
<a href=#189 id=189 data-nosnippet>189</a> | Error::EmptyChunkManifest { .. }
<a href=#190 id=190 data-nosnippet>190</a> | Error::InvalidPackedSnapshot { .. }
<a href=#191 id=191 data-nosnippet>191</a> | Error::MissingChunkData { .. } =&gt; StatusCode::InvalidArguments,
<a href=#192 id=192 data-nosnippet>192</a> Error::ImportStatePathUnavailable { .. }
<a href=#193 id=193 data-nosnippet>193</a> | Error::ImportStateUnknownTask { .. }
<a href=#194 id=194 data-nosnippet>194</a> | Error::ImportStateDdlIncomplete { .. } =&gt; StatusCode::Unexpected,
<a href=#195 id=195 data-nosnippet>195</a> Error::ImportStateMismatch { .. } =&gt; StatusCode::InvalidArguments,
<a href=#196 id=196 data-nosnippet>196</a> <span class="attr">#[cfg(test)]
<a href=#197 id=197 data-nosnippet>197</a> </span>Error::TestTaskFailed { retryable, .. } =&gt; {
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">if </span><span class="kw-2">*</span>retryable {
<a href=#199 id=199 data-nosnippet>199</a> StatusCode::StorageUnavailable
<a href=#200 id=200 data-nosnippet>200</a> } <span class="kw">else </span>{
<a href=#201 id=201 data-nosnippet>201</a> StatusCode::InvalidArguments
<a href=#202 id=202 data-nosnippet>202</a> }
<a href=#203 id=203 data-nosnippet>203</a> }
<a href=#204 id=204 data-nosnippet>204</a> Error::Database { error, .. } =&gt; error.status_code(),
<a href=#205 id=205 data-nosnippet>205</a> Error::SnapshotStorage { error, .. } | Error::ChunkImportFailed { error, .. } =&gt; {
<a href=#206 id=206 data-nosnippet>206</a> error.status_code()
<a href=#207 id=207 data-nosnippet>207</a> }
<a href=#208 id=208 data-nosnippet>208</a> Error::ImportStateParse { .. } =&gt; StatusCode::Internal,
<a href=#209 id=209 data-nosnippet>209</a> Error::ImportStateIo { .. } =&gt; StatusCode::StorageUnavailable,
<a href=#210 id=210 data-nosnippet>210</a> Error::ImportStateLocked { .. } =&gt; StatusCode::IllegalState,
<a href=#211 id=211 data-nosnippet>211</a> }
<a href=#212 id=212 data-nosnippet>212</a> }
<a href=#213 id=213 data-nosnippet>213</a>
<a href=#214 id=214 data-nosnippet>214</a> <span class="kw">fn </span>retry_hint(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; RetryHint {
<a href=#215 id=215 data-nosnippet>215</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#216 id=216 data-nosnippet>216</a> <span class="attr">#[cfg(test)]
<a href=#217 id=217 data-nosnippet>217</a> </span>Error::TestTaskFailed { retryable, .. } =&gt; {
<a href=#218 id=218 data-nosnippet>218</a> <span class="kw">if </span><span class="kw-2">*</span>retryable {
<a href=#219 id=219 data-nosnippet>219</a> RetryHint::Retryable
<a href=#220 id=220 data-nosnippet>220</a> } <span class="kw">else </span>{
<a href=#221 id=221 data-nosnippet>221</a> RetryHint::NonRetryable
<a href=#222 id=222 data-nosnippet>222</a> }
<a href=#223 id=223 data-nosnippet>223</a> }
<a href=#224 id=224 data-nosnippet>224</a> Error::Database { error, .. } =&gt; error.retry_hint(),
<a href=#225 id=225 data-nosnippet>225</a> Error::SnapshotStorage { error, .. } | Error::ChunkImportFailed { error, .. } =&gt; {
<a href=#226 id=226 data-nosnippet>226</a> error.retry_hint()
<a href=#227 id=227 data-nosnippet>227</a> }
<a href=#228 id=228 data-nosnippet>228</a> Error::ImportStateIo { error, .. } =&gt; retry_hint_from_io_error(error),
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">_ </span>=&gt; RetryHint::NonRetryable,
<a href=#230 id=230 data-nosnippet>230</a> }
<a href=#231 id=231 data-nosnippet>231</a> }
<a href=#232 id=232 data-nosnippet>232</a>
<a href=#233 id=233 data-nosnippet>233</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>Any {
<a href=#234 id=234 data-nosnippet>234</a> <span class="self">self
<a href=#235 id=235 data-nosnippet>235</a> </span>}
<a href=#236 id=236 data-nosnippet>236</a>}
</code></pre></div></section></main></body></html>
+123
View File
@@ -0,0 +1,123 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/import_v2/executor.rs`."><title>executor.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/import_v2/</div>executor.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! DDL execution for import.
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a></span><span class="kw">use </span>common_telemetry::info;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>snafu::ResultExt;
<a href=#19 id=19 data-nosnippet>19</a>
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span><span class="kw">crate</span>::data::import_v2::error::{DatabaseSnafu, <span class="prelude-ty">Result</span>};
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span><span class="kw">crate</span>::database::DatabaseClient;
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a><span class="doccomment">/// A DDL statement with an explicit execution schema context.
<a href=#24 id=24 data-nosnippet>24</a></span><span class="attr">#[derive(Debug, Clone, PartialEq, Eq)]
<a href=#25 id=25 data-nosnippet>25</a></span><span class="kw">pub struct </span>DdlStatement {
<a href=#26 id=26 data-nosnippet>26</a> <span class="kw">pub </span>sql: String,
<a href=#27 id=27 data-nosnippet>27</a> <span class="kw">pub </span>execution_schema: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#28 id=28 data-nosnippet>28</a>}
<a href=#29 id=29 data-nosnippet>29</a>
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">impl </span>DdlStatement {
<a href=#31 id=31 data-nosnippet>31</a> <span class="kw">pub fn </span>new(sql: String) -&gt; <span class="self">Self </span>{
<a href=#32 id=32 data-nosnippet>32</a> <span class="self">Self </span>{
<a href=#33 id=33 data-nosnippet>33</a> sql,
<a href=#34 id=34 data-nosnippet>34</a> execution_schema: <span class="prelude-val">None</span>,
<a href=#35 id=35 data-nosnippet>35</a> }
<a href=#36 id=36 data-nosnippet>36</a> }
<a href=#37 id=37 data-nosnippet>37</a>
<a href=#38 id=38 data-nosnippet>38</a> <span class="kw">pub fn </span>with_execution_schema(sql: String, schema: String) -&gt; <span class="self">Self </span>{
<a href=#39 id=39 data-nosnippet>39</a> <span class="self">Self </span>{
<a href=#40 id=40 data-nosnippet>40</a> sql,
<a href=#41 id=41 data-nosnippet>41</a> execution_schema: <span class="prelude-val">Some</span>(schema),
<a href=#42 id=42 data-nosnippet>42</a> }
<a href=#43 id=43 data-nosnippet>43</a> }
<a href=#44 id=44 data-nosnippet>44</a>}
<a href=#45 id=45 data-nosnippet>45</a>
<a href=#46 id=46 data-nosnippet>46</a><span class="doccomment">/// Executes DDL statements against the database.
<a href=#47 id=47 data-nosnippet>47</a></span><span class="kw">pub struct </span>DdlExecutor&lt;<span class="lifetime">'a</span>&gt; {
<a href=#48 id=48 data-nosnippet>48</a> client: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>DatabaseClient,
<a href=#49 id=49 data-nosnippet>49</a>}
<a href=#50 id=50 data-nosnippet>50</a>
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">impl</span>&lt;<span class="lifetime">'a</span>&gt; DdlExecutor&lt;<span class="lifetime">'a</span>&gt; {
<a href=#52 id=52 data-nosnippet>52</a> <span class="doccomment">/// Creates a new DDL executor.
<a href=#53 id=53 data-nosnippet>53</a> </span><span class="kw">pub fn </span>new(client: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>DatabaseClient) -&gt; <span class="self">Self </span>{
<a href=#54 id=54 data-nosnippet>54</a> <span class="self">Self </span>{ client }
<a href=#55 id=55 data-nosnippet>55</a> }
<a href=#56 id=56 data-nosnippet>56</a>
<a href=#57 id=57 data-nosnippet>57</a> <span class="doccomment">/// Executes a list of DDL statements, stopping on first error.
<a href=#58 id=58 data-nosnippet>58</a> </span><span class="kw">pub async fn </span>execute_strict(<span class="kw-2">&amp;</span><span class="self">self</span>, statements: <span class="kw-2">&amp;</span>[DdlStatement]) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#59 id=59 data-nosnippet>59</a> <span class="kw">let </span>total = statements.len();
<a href=#60 id=60 data-nosnippet>60</a>
<a href=#61 id=61 data-nosnippet>61</a> <span class="kw">for </span>(i, stmt) <span class="kw">in </span>statements.iter().enumerate() {
<a href=#62 id=62 data-nosnippet>62</a> <span class="kw">let </span>preview = preview_sql(<span class="kw-2">&amp;</span>stmt.sql);
<a href=#63 id=63 data-nosnippet>63</a>
<a href=#64 id=64 data-nosnippet>64</a> <span class="macro">info!</span>(<span class="string">"Executing DDL ({}/{}): {}"</span>, i + <span class="number">1</span>, total, preview);
<a href=#65 id=65 data-nosnippet>65</a>
<a href=#66 id=66 data-nosnippet>66</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(schema) = stmt.execution_schema.as_deref() {
<a href=#67 id=67 data-nosnippet>67</a> <span class="self">self</span>.client
<a href=#68 id=68 data-nosnippet>68</a> .sql(<span class="kw-2">&amp;</span>stmt.sql, schema)
<a href=#69 id=69 data-nosnippet>69</a> .<span class="kw">await
<a href=#70 id=70 data-nosnippet>70</a> </span>.context(DatabaseSnafu)<span class="question-mark">?</span>;
<a href=#71 id=71 data-nosnippet>71</a> } <span class="kw">else </span>{
<a href=#72 id=72 data-nosnippet>72</a> <span class="self">self</span>.client
<a href=#73 id=73 data-nosnippet>73</a> .sql_in_public(<span class="kw-2">&amp;</span>stmt.sql)
<a href=#74 id=74 data-nosnippet>74</a> .<span class="kw">await
<a href=#75 id=75 data-nosnippet>75</a> </span>.context(DatabaseSnafu)<span class="question-mark">?</span>;
<a href=#76 id=76 data-nosnippet>76</a> }
<a href=#77 id=77 data-nosnippet>77</a> }
<a href=#78 id=78 data-nosnippet>78</a>
<a href=#79 id=79 data-nosnippet>79</a> <span class="prelude-val">Ok</span>(())
<a href=#80 id=80 data-nosnippet>80</a> }
<a href=#81 id=81 data-nosnippet>81</a>}
<a href=#82 id=82 data-nosnippet>82</a>
<a href=#83 id=83 data-nosnippet>83</a><span class="kw">fn </span>preview_sql(sql: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#84 id=84 data-nosnippet>84</a> <span class="kw">let </span><span class="kw-2">mut </span>chars = sql.chars();
<a href=#85 id=85 data-nosnippet>85</a> <span class="kw">let </span>preview: String = chars.by_ref().take(<span class="number">80</span>).collect();
<a href=#86 id=86 data-nosnippet>86</a> <span class="kw">if </span>chars.next().is_some() {
<a href=#87 id=87 data-nosnippet>87</a> <span class="macro">format!</span>(<span class="string">"{preview}..."</span>)
<a href=#88 id=88 data-nosnippet>88</a> } <span class="kw">else </span>{
<a href=#89 id=89 data-nosnippet>89</a> preview
<a href=#90 id=90 data-nosnippet>90</a> }
<a href=#91 id=91 data-nosnippet>91</a>}
<a href=#92 id=92 data-nosnippet>92</a><span class="attr">#[cfg(test)]
<a href=#93 id=93 data-nosnippet>93</a></span><span class="kw">mod </span>tests {
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#95 id=95 data-nosnippet>95</a>
<a href=#96 id=96 data-nosnippet>96</a> <span class="attr">#[test]
<a href=#97 id=97 data-nosnippet>97</a> </span><span class="kw">fn </span>test_statement_without_execution_schema_uses_public() {
<a href=#98 id=98 data-nosnippet>98</a> <span class="kw">let </span>stmt = DdlStatement::new(<span class="string">"CREATE DATABASE IF NOT EXISTS test_db"</span>.to_string());
<a href=#99 id=99 data-nosnippet>99</a> <span class="macro">assert_eq!</span>(stmt.execution_schema, <span class="prelude-val">None</span>);
<a href=#100 id=100 data-nosnippet>100</a> }
<a href=#101 id=101 data-nosnippet>101</a>
<a href=#102 id=102 data-nosnippet>102</a> <span class="attr">#[test]
<a href=#103 id=103 data-nosnippet>103</a> </span><span class="kw">fn </span>test_statement_with_execution_schema_preserves_context() {
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">let </span>stmt = DdlStatement::with_execution_schema(
<a href=#105 id=105 data-nosnippet>105</a> <span class="string">r#"CREATE TABLE IF NOT EXISTS "my""schema"."metrics" (ts TIMESTAMP TIME INDEX)"#
<a href=#106 id=106 data-nosnippet>106</a> </span>.to_string(),
<a href=#107 id=107 data-nosnippet>107</a> <span class="string">r#"my"schema"#</span>.to_string(),
<a href=#108 id=108 data-nosnippet>108</a> );
<a href=#109 id=109 data-nosnippet>109</a> <span class="macro">assert_eq!</span>(stmt.execution_schema.as_deref(), <span class="prelude-val">Some</span>(<span class="string">r#"my"schema"#</span>));
<a href=#110 id=110 data-nosnippet>110</a> }
<a href=#111 id=111 data-nosnippet>111</a>
<a href=#112 id=112 data-nosnippet>112</a> <span class="attr">#[test]
<a href=#113 id=113 data-nosnippet>113</a> </span><span class="kw">fn </span>test_preview_sql_truncates_at_char_boundary() {
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">let </span>sql = <span class="macro">format!</span>(
<a href=#115 id=115 data-nosnippet>115</a> <span class="string">"CREATE TABLE {} (ts TIMESTAMP TIME INDEX)"</span>,
<a href=#116 id=116 data-nosnippet>116</a> <span class="string">"测"</span>.repeat(<span class="number">100</span>)
<a href=#117 id=117 data-nosnippet>117</a> );
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">let </span>preview = preview_sql(<span class="kw-2">&amp;</span>sql);
<a href=#119 id=119 data-nosnippet>119</a> <span class="macro">assert!</span>(preview.ends_with(<span class="string">"..."</span>));
<a href=#120 id=120 data-nosnippet>120</a> <span class="macro">assert!</span>(preview.is_char_boundary(preview.len()));
<a href=#121 id=121 data-nosnippet>121</a> }
<a href=#122 id=122 data-nosnippet>122</a>}
</code></pre></div></section></main></body></html>
+226
View File
@@ -0,0 +1,226 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/import_v2/packed.rs`."><title>packed.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/import_v2/</div>packed.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::collections::HashSet;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_datasource::packed_snapshot::{PACK_INDEX_FILE, PackIndex};
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>snafu::ResultExt;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>sql::dialect::GreptimeDbDialect;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>sql::parser::{ParseOptions, ParserContext};
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>sql::statements::statement::Statement;
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::manifest::{ChunkStatus, Manifest};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span><span class="kw">crate</span>::data::import_v2::error::{InvalidPackedSnapshotSnafu, <span class="prelude-ty">Result</span>, SnapshotStorageSnafu};
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span><span class="kw">crate</span>::data::path::{data_dir_for_schema_chunk, ddl_path_for_schema};
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span><span class="kw">crate</span>::data::snapshot_storage::SnapshotStorage;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="doccomment">/// Matches every completed schema chunk to its source DDL before target writes.
<a href=#29 id=29 data-nosnippet>29</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">async fn </span>validate_snapshot(
<a href=#30 id=30 data-nosnippet>30</a> storage: <span class="kw-2">&amp;</span><span class="kw">dyn </span>SnapshotStorage,
<a href=#31 id=31 data-nosnippet>31</a> manifest: <span class="kw-2">&amp;</span>Manifest,
<a href=#32 id=32 data-nosnippet>32</a> schemas: <span class="kw-2">&amp;</span>[String],
<a href=#33 id=33 data-nosnippet>33</a>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#34 id=34 data-nosnippet>34</a> manifest
<a href=#35 id=35 data-nosnippet>35</a> .validate_layout()
<a href=#36 id=36 data-nosnippet>36</a> .map_err(|reason| InvalidPackedSnapshotSnafu { reason }.build())<span class="question-mark">?</span>;
<a href=#37 id=37 data-nosnippet>37</a> <span class="kw">if </span>manifest.schema_only
<a href=#38 id=38 data-nosnippet>38</a> &amp;&amp; !storage
<a href=#39 id=39 data-nosnippet>39</a> .list_files_recursive(<span class="string">"data/"</span>)
<a href=#40 id=40 data-nosnippet>40</a> .<span class="kw">await
<a href=#41 id=41 data-nosnippet>41</a> </span>.context(SnapshotStorageSnafu)<span class="question-mark">?
<a href=#42 id=42 data-nosnippet>42</a> </span>.is_empty()
<a href=#43 id=43 data-nosnippet>43</a> {
<a href=#44 id=44 data-nosnippet>44</a> <span class="kw">return </span>InvalidPackedSnapshotSnafu {
<a href=#45 id=45 data-nosnippet>45</a> reason: <span class="string">"schema-only snapshot contains data objects"</span>,
<a href=#46 id=46 data-nosnippet>46</a> }
<a href=#47 id=47 data-nosnippet>47</a> .fail();
<a href=#48 id=48 data-nosnippet>48</a> }
<a href=#49 id=49 data-nosnippet>49</a> <span class="kw">for </span>schema <span class="kw">in </span>schemas {
<a href=#50 id=50 data-nosnippet>50</a> <span class="kw">let </span>ddl = storage
<a href=#51 id=51 data-nosnippet>51</a> .read_text(<span class="kw-2">&amp;</span>ddl_path_for_schema(schema))
<a href=#52 id=52 data-nosnippet>52</a> .<span class="kw">await
<a href=#53 id=53 data-nosnippet>53</a> </span>.context(SnapshotStorageSnafu)<span class="question-mark">?</span>;
<a href=#54 id=54 data-nosnippet>54</a> <span class="kw">let </span>statements = ParserContext::create_with_dialect(
<a href=#55 id=55 data-nosnippet>55</a> <span class="kw-2">&amp;</span>ddl,
<a href=#56 id=56 data-nosnippet>56</a> <span class="kw-2">&amp;</span>GreptimeDbDialect {},
<a href=#57 id=57 data-nosnippet>57</a> ParseOptions::default(),
<a href=#58 id=58 data-nosnippet>58</a> )
<a href=#59 id=59 data-nosnippet>59</a> .map_err(|e| {
<a href=#60 id=60 data-nosnippet>60</a> InvalidPackedSnapshotSnafu {
<a href=#61 id=61 data-nosnippet>61</a> reason: e.to_string(),
<a href=#62 id=62 data-nosnippet>62</a> }
<a href=#63 id=63 data-nosnippet>63</a> .build()
<a href=#64 id=64 data-nosnippet>64</a> })<span class="question-mark">?</span>;
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">let </span><span class="kw-2">mut </span>names = HashSet::new();
<a href=#66 id=66 data-nosnippet>66</a> <span class="kw">for </span>statement <span class="kw">in </span>statements {
<a href=#67 id=67 data-nosnippet>67</a> <span class="kw">if let </span>Statement::CreateTable(create) = statement {
<a href=#68 id=68 data-nosnippet>68</a> <span class="kw">if </span>create.engine.eq_ignore_ascii_case(<span class="string">"metric"</span>)
<a href=#69 id=69 data-nosnippet>69</a> &amp;&amp; create.options.get(<span class="string">"on_physical_table"</span>).is_none()
<a href=#70 id=70 data-nosnippet>70</a> {
<a href=#71 id=71 data-nosnippet>71</a> <span class="kw">continue</span>;
<a href=#72 id=72 data-nosnippet>72</a> }
<a href=#73 id=73 data-nosnippet>73</a> <span class="kw">let </span>parts: Vec&lt;<span class="kw">_</span>&gt; = create
<a href=#74 id=74 data-nosnippet>74</a> .name
<a href=#75 id=75 data-nosnippet>75</a> .<span class="number">0
<a href=#76 id=76 data-nosnippet>76</a> </span>.iter()
<a href=#77 id=77 data-nosnippet>77</a> .map(|p| p.as_ident().map(|i| i.value.as_str()))
<a href=#78 id=78 data-nosnippet>78</a> .collect();
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw">let </span>allowed = <span class="kw">match </span>parts.as_slice() {
<a href=#80 id=80 data-nosnippet>80</a> [<span class="prelude-val">Some</span>(<span class="kw">_</span>)] =&gt; <span class="bool-val">true</span>,
<a href=#81 id=81 data-nosnippet>81</a> [<span class="prelude-val">Some</span>(s), <span class="prelude-val">Some</span>(<span class="kw">_</span>)] =&gt; <span class="kw-2">*</span>s == schema,
<a href=#82 id=82 data-nosnippet>82</a> [<span class="prelude-val">Some</span>(c), <span class="prelude-val">Some</span>(s), <span class="prelude-val">Some</span>(<span class="kw">_</span>)] =&gt; <span class="kw-2">*</span>c == manifest.catalog &amp;&amp; <span class="kw-2">*</span>s == schema,
<a href=#83 id=83 data-nosnippet>83</a> <span class="kw">_ </span>=&gt; <span class="bool-val">false</span>,
<a href=#84 id=84 data-nosnippet>84</a> };
<a href=#85 id=85 data-nosnippet>85</a> <span class="kw">if </span>!allowed {
<a href=#86 id=86 data-nosnippet>86</a> <span class="kw">return </span>InvalidPackedSnapshotSnafu {
<a href=#87 id=87 data-nosnippet>87</a> reason: <span class="string">"snapshot table DDL escapes its catalog/schema"</span>,
<a href=#88 id=88 data-nosnippet>88</a> }
<a href=#89 id=89 data-nosnippet>89</a> .fail();
<a href=#90 id=90 data-nosnippet>90</a> }
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">let </span>name = parts.last().and_then(|p| <span class="kw-2">*</span>p).unwrap_or_default();
<a href=#92 id=92 data-nosnippet>92</a> <span class="kw">if </span>!names.insert(name.to_string()) {
<a href=#93 id=93 data-nosnippet>93</a> <span class="kw">return </span>InvalidPackedSnapshotSnafu {
<a href=#94 id=94 data-nosnippet>94</a> reason: <span class="string">"duplicate snapshot table DDL"</span>,
<a href=#95 id=95 data-nosnippet>95</a> }
<a href=#96 id=96 data-nosnippet>96</a> .fail();
<a href=#97 id=97 data-nosnippet>97</a> }
<a href=#98 id=98 data-nosnippet>98</a> }
<a href=#99 id=99 data-nosnippet>99</a> }
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">for </span>chunk <span class="kw">in </span><span class="kw-2">&amp;</span>manifest.chunks {
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">if </span>chunk.status == ChunkStatus::Skipped &amp;&amp; !names.is_empty() {
<a href=#102 id=102 data-nosnippet>102</a> <span class="kw">return </span>InvalidPackedSnapshotSnafu {
<a href=#103 id=103 data-nosnippet>103</a> reason: <span class="string">"packed chunks require zero-row streams for empty tables"</span>,
<a href=#104 id=104 data-nosnippet>104</a> }
<a href=#105 id=105 data-nosnippet>105</a> .fail();
<a href=#106 id=106 data-nosnippet>106</a> }
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">if </span>chunk.status != ChunkStatus::Completed {
<a href=#108 id=108 data-nosnippet>108</a> <span class="kw">continue</span>;
<a href=#109 id=109 data-nosnippet>109</a> }
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">let </span>path = <span class="macro">format!</span>(
<a href=#111 id=111 data-nosnippet>111</a> <span class="string">"{}{PACK_INDEX_FILE}"</span>,
<a href=#112 id=112 data-nosnippet>112</a> data_dir_for_schema_chunk(schema, chunk.id)
<a href=#113 id=113 data-nosnippet>113</a> );
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">let </span>text = storage
<a href=#115 id=115 data-nosnippet>115</a> .read_text(<span class="kw-2">&amp;</span>path)
<a href=#116 id=116 data-nosnippet>116</a> .<span class="kw">await
<a href=#117 id=117 data-nosnippet>117</a> </span>.context(SnapshotStorageSnafu)<span class="question-mark">?</span>;
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">let </span>index: PackIndex = serde_json::from_str(<span class="kw-2">&amp;</span>text).map_err(|e| {
<a href=#119 id=119 data-nosnippet>119</a> InvalidPackedSnapshotSnafu {
<a href=#120 id=120 data-nosnippet>120</a> reason: e.to_string(),
<a href=#121 id=121 data-nosnippet>121</a> }
<a href=#122 id=122 data-nosnippet>122</a> .build()
<a href=#123 id=123 data-nosnippet>123</a> })<span class="question-mark">?</span>;
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">let </span>prefix = data_dir_for_schema_chunk(schema, chunk.id);
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw">let </span>expected: HashSet&lt;<span class="kw">_</span>&gt; = std::iter::once(path)
<a href=#126 id=126 data-nosnippet>126</a> .chain(index.objects.iter().map(|o| <span class="macro">format!</span>(<span class="string">"{prefix}{}"</span>, o.path)))
<a href=#127 id=127 data-nosnippet>127</a> .collect();
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw">let </span>actual: HashSet&lt;<span class="kw">_</span>&gt; = chunk
<a href=#129 id=129 data-nosnippet>129</a> .files
<a href=#130 id=130 data-nosnippet>130</a> .iter()
<a href=#131 id=131 data-nosnippet>131</a> .filter(|file| file.starts_with(<span class="kw-2">&amp;</span>prefix))
<a href=#132 id=132 data-nosnippet>132</a> .cloned()
<a href=#133 id=133 data-nosnippet>133</a> .collect();
<a href=#134 id=134 data-nosnippet>134</a> <span class="kw">if </span>actual != expected {
<a href=#135 id=135 data-nosnippet>135</a> <span class="kw">return </span>InvalidPackedSnapshotSnafu {
<a href=#136 id=136 data-nosnippet>136</a> reason: <span class="string">"chunk manifest inventory differs from indexed objects"</span>,
<a href=#137 id=137 data-nosnippet>137</a> }
<a href=#138 id=138 data-nosnippet>138</a> .fail();
<a href=#139 id=139 data-nosnippet>139</a> }
<a href=#140 id=140 data-nosnippet>140</a> index
<a href=#141 id=141 data-nosnippet>141</a> .validate_membership(names.iter().map(String::as_str))
<a href=#142 id=142 data-nosnippet>142</a> .map_err(|e| {
<a href=#143 id=143 data-nosnippet>143</a> InvalidPackedSnapshotSnafu {
<a href=#144 id=144 data-nosnippet>144</a> reason: e.to_string(),
<a href=#145 id=145 data-nosnippet>145</a> }
<a href=#146 id=146 data-nosnippet>146</a> .build()
<a href=#147 id=147 data-nosnippet>147</a> })<span class="question-mark">?</span>;
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">for </span>object <span class="kw">in </span><span class="kw-2">&amp;</span>index.objects {
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">let </span>path = <span class="macro">format!</span>(<span class="string">"{prefix}{}"</span>, object.path);
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">let </span>length = storage
<a href=#151 id=151 data-nosnippet>151</a> .file_size(<span class="kw-2">&amp;</span>path)
<a href=#152 id=152 data-nosnippet>152</a> .<span class="kw">await
<a href=#153 id=153 data-nosnippet>153</a> </span>.context(SnapshotStorageSnafu)<span class="question-mark">?</span>;
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">if </span>length != <span class="prelude-val">Some</span>(object.length) {
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">return </span>InvalidPackedSnapshotSnafu {
<a href=#156 id=156 data-nosnippet>156</a> reason: <span class="macro">format!</span>(
<a href=#157 id=157 data-nosnippet>157</a> <span class="string">"object {path}: expected length {}, actual {length:?}"</span>,
<a href=#158 id=158 data-nosnippet>158</a> object.length
<a href=#159 id=159 data-nosnippet>159</a> ),
<a href=#160 id=160 data-nosnippet>160</a> }
<a href=#161 id=161 data-nosnippet>161</a> .fail();
<a href=#162 id=162 data-nosnippet>162</a> }
<a href=#163 id=163 data-nosnippet>163</a> }
<a href=#164 id=164 data-nosnippet>164</a> }
<a href=#165 id=165 data-nosnippet>165</a> }
<a href=#166 id=166 data-nosnippet>166</a> <span class="prelude-val">Ok</span>(())
<a href=#167 id=167 data-nosnippet>167</a>}
<a href=#168 id=168 data-nosnippet>168</a>
<a href=#169 id=169 data-nosnippet>169</a><span class="attr">#[cfg(test)]
<a href=#170 id=170 data-nosnippet>170</a></span><span class="kw">mod </span>tests {
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#172 id=172 data-nosnippet>172</a> <span class="kw">use </span><span class="kw">crate</span>::data::export_v2::manifest::{ChunkMeta, TimeRange};
<a href=#173 id=173 data-nosnippet>173</a> <span class="kw">use </span><span class="kw">crate</span>::data::snapshot_storage::OpenDalStorage;
<a href=#174 id=174 data-nosnippet>174</a>
<a href=#175 id=175 data-nosnippet>175</a> <span class="attr">#[tokio::test]
<a href=#176 id=176 data-nosnippet>176</a> </span><span class="kw">async fn </span>packed_membership_uses_literal_names_and_excludes_physical_and_views() {
<a href=#177 id=177 data-nosnippet>177</a> <span class="kw">let </span>dir = tempfile::Builder::new()
<a href=#178 id=178 data-nosnippet>178</a> .prefix(<span class="string">"packed snapshot # "</span>)
<a href=#179 id=179 data-nosnippet>179</a> .tempdir()
<a href=#180 id=180 data-nosnippet>180</a> .unwrap();
<a href=#181 id=181 data-nosnippet>181</a> <span class="kw">let </span>uri = url::Url::from_file_path(dir.path()).unwrap();
<a href=#182 id=182 data-nosnippet>182</a> <span class="kw">let </span>storage = OpenDalStorage::from_uri(uri.as_str(), <span class="kw-2">&amp;</span>Default::default()).unwrap();
<a href=#183 id=183 data-nosnippet>183</a> storage.write_text(<span class="string">"schema/ddl/public.sql"</span>, <span class="string">"CREATE TABLE p (ts TIMESTAMP TIME INDEX) ENGINE=metric WITH(physical_metric_table=''); CREATE TABLE \"logical.name\" (ts TIMESTAMP TIME INDEX) ENGINE=metric WITH(on_physical_table='p'); CREATE VIEW v AS SELECT * FROM \"logical.name\";"</span>).<span class="kw">await</span>.unwrap();
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">let </span>path = <span class="string">"data/public/1/pack-index.json"</span>;
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">let </span>index = <span class="macro">serde_json::json!</span>({<span class="string">"version"</span>:<span class="number">1</span>,<span class="string">"objects"</span>:[{<span class="string">"path"</span>:<span class="string">"pack-0.bin"</span>,<span class="string">"kind"</span>:<span class="string">"pack"</span>,<span class="string">"length"</span>:<span class="number">12</span>}],<span class="string">"tables"</span>:[{<span class="string">"table_name"</span>:<span class="string">"logical.name"</span>,<span class="string">"object"</span>:<span class="string">"pack-0.bin"</span>,<span class="string">"offset"</span>:<span class="number">0</span>,<span class="string">"length"</span>:<span class="number">12</span>,<span class="string">"row_count"</span>:<span class="number">0</span>}]});
<a href=#186 id=186 data-nosnippet>186</a> storage.write_text(path, <span class="kw-2">&amp;</span>index.to_string()).<span class="kw">await</span>.unwrap();
<a href=#187 id=187 data-nosnippet>187</a> <span class="macro">assert!</span>(dir.path().join(path).is_file());
<a href=#188 id=188 data-nosnippet>188</a> storage
<a href=#189 id=189 data-nosnippet>189</a> .write_text(<span class="string">"data/public/1/pack-0.bin"</span>, <span class="string">"abcdefghijkl"</span>)
<a href=#190 id=190 data-nosnippet>190</a> .<span class="kw">await
<a href=#191 id=191 data-nosnippet>191</a> </span>.unwrap();
<a href=#192 id=192 data-nosnippet>192</a> <span class="kw">let </span><span class="kw-2">mut </span>manifest = Manifest::new_schema_only(<span class="string">"greptime"</span>.into(), <span class="macro">vec!</span>[<span class="string">"public"</span>.into()]);
<a href=#193 id=193 data-nosnippet>193</a> <span class="kw">let </span><span class="kw-2">mut </span>chunk = ChunkMeta::new(<span class="number">1</span>, TimeRange::unbounded());
<a href=#194 id=194 data-nosnippet>194</a> chunk.mark_completed(<span class="macro">vec!</span>[path.into(), <span class="string">"data/public/1/pack-0.bin"</span>.into()], <span class="prelude-val">None</span>);
<a href=#195 id=195 data-nosnippet>195</a> manifest.version = <span class="number">2</span>;
<a href=#196 id=196 data-nosnippet>196</a> manifest.data_layout = <span class="prelude-val">Some</span>(<span class="string">"metric-parquet-packs"</span>.into());
<a href=#197 id=197 data-nosnippet>197</a> manifest.schema_only = <span class="bool-val">false</span>;
<a href=#198 id=198 data-nosnippet>198</a> manifest.chunks.push(chunk);
<a href=#199 id=199 data-nosnippet>199</a> validate_snapshot(<span class="kw-2">&amp;</span>storage, <span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;</span>manifest.schemas)
<a href=#200 id=200 data-nosnippet>200</a> .<span class="kw">await
<a href=#201 id=201 data-nosnippet>201</a> </span>.unwrap();
<a href=#202 id=202 data-nosnippet>202</a> <span class="kw">let </span><span class="kw-2">mut </span>missing = index.clone();
<a href=#203 id=203 data-nosnippet>203</a> missing[<span class="string">"tables"</span>] = <span class="macro">serde_json::json!</span>([]);
<a href=#204 id=204 data-nosnippet>204</a> storage
<a href=#205 id=205 data-nosnippet>205</a> .write_text(path, <span class="kw-2">&amp;</span>missing.to_string())
<a href=#206 id=206 data-nosnippet>206</a> .<span class="kw">await
<a href=#207 id=207 data-nosnippet>207</a> </span>.unwrap();
<a href=#208 id=208 data-nosnippet>208</a> <span class="macro">assert!</span>(
<a href=#209 id=209 data-nosnippet>209</a> validate_snapshot(<span class="kw-2">&amp;</span>storage, <span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;</span>manifest.schemas)
<a href=#210 id=210 data-nosnippet>210</a> .<span class="kw">await
<a href=#211 id=211 data-nosnippet>211</a> </span>.is_err()
<a href=#212 id=212 data-nosnippet>212</a> );
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">let </span><span class="kw-2">mut </span>escaped = index;
<a href=#214 id=214 data-nosnippet>214</a> escaped[<span class="string">"objects"</span>][<span class="number">0</span>][<span class="string">"path"</span>] = <span class="string">"../pack-0.bin"</span>.into();
<a href=#215 id=215 data-nosnippet>215</a> storage
<a href=#216 id=216 data-nosnippet>216</a> .write_text(path, <span class="kw-2">&amp;</span>escaped.to_string())
<a href=#217 id=217 data-nosnippet>217</a> .<span class="kw">await
<a href=#218 id=218 data-nosnippet>218</a> </span>.unwrap();
<a href=#219 id=219 data-nosnippet>219</a> <span class="macro">assert!</span>(
<a href=#220 id=220 data-nosnippet>220</a> validate_snapshot(<span class="kw-2">&amp;</span>storage, <span class="kw-2">&amp;</span>manifest, <span class="kw-2">&amp;</span>manifest.schemas)
<a href=#221 id=221 data-nosnippet>221</a> .<span class="kw">await
<a href=#222 id=222 data-nosnippet>222</a> </span>.is_err()
<a href=#223 id=223 data-nosnippet>223</a> );
<a href=#224 id=224 data-nosnippet>224</a> }
<a href=#225 id=225 data-nosnippet>225</a>}
</code></pre></div></section></main></body></html>
+805
View File
@@ -0,0 +1,805 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/import_v2/state.rs`."><title>state.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/import_v2/</div>state.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::path::{Path, PathBuf};
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::sync::atomic::{AtomicU64, Ordering};
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>chrono::{DateTime, Utc};
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>fs2::FileExt;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>serde::{Deserialize, Serialize};
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>snafu::{IntoError, OptionExt, ResultExt};
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>tokio::io::AsyncWriteExt;
<a href=#23 id=23 data-nosnippet>23</a>
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span><span class="kw">crate</span>::data::import_v2::error::{
<a href=#25 id=25 data-nosnippet>25</a> ImportStateIoSnafu, ImportStateLockedSnafu, ImportStateParseSnafu, ImportStateUnknownTaskSnafu,
<a href=#26 id=26 data-nosnippet>26</a> <span class="prelude-ty">Result</span>,
<a href=#27 id=27 data-nosnippet>27</a>};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span><span class="kw">crate</span>::data::path::encode_path_segment;
<a href=#29 id=29 data-nosnippet>29</a>
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">const </span>IMPORT_STATE_ROOT: <span class="kw-2">&amp;</span>str = <span class="string">".greptime"</span>;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">const </span>IMPORT_STATE_DIR: <span class="kw-2">&amp;</span>str = <span class="string">"import_state"</span>;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">static </span>IMPORT_STATE_TMP_ID: AtomicU64 = AtomicU64::new(<span class="number">0</span>);
<a href=#33 id=33 data-nosnippet>33</a>
<a href=#34 id=34 data-nosnippet>34</a><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
<a href=#35 id=35 data-nosnippet>35</a>#[serde(rename_all = <span class="string">"snake_case"</span>)]
<a href=#36 id=36 data-nosnippet>36</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">enum </span>ImportTaskStatus {
<a href=#37 id=37 data-nosnippet>37</a> Pending,
<a href=#38 id=38 data-nosnippet>38</a> InProgress,
<a href=#39 id=39 data-nosnippet>39</a> Completed,
<a href=#40 id=40 data-nosnippet>40</a> Failed,
<a href=#41 id=41 data-nosnippet>41</a>}
<a href=#42 id=42 data-nosnippet>42</a>
<a href=#43 id=43 data-nosnippet>43</a><span class="attr">#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
<a href=#44 id=44 data-nosnippet>44</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>ImportTaskKey {
<a href=#45 id=45 data-nosnippet>45</a> <span class="kw">pub</span>(<span class="kw">crate</span>) chunk_id: u32,
<a href=#46 id=46 data-nosnippet>46</a> <span class="kw">pub</span>(<span class="kw">crate</span>) schema: String,
<a href=#47 id=47 data-nosnippet>47</a>}
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">impl </span>ImportTaskKey {
<a href=#50 id=50 data-nosnippet>50</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new(chunk_id: u32, schema: <span class="kw">impl </span>Into&lt;String&gt;) -&gt; <span class="self">Self </span>{
<a href=#51 id=51 data-nosnippet>51</a> <span class="self">Self </span>{
<a href=#52 id=52 data-nosnippet>52</a> chunk_id,
<a href=#53 id=53 data-nosnippet>53</a> schema: schema.into(),
<a href=#54 id=54 data-nosnippet>54</a> }
<a href=#55 id=55 data-nosnippet>55</a> }
<a href=#56 id=56 data-nosnippet>56</a>}
<a href=#57 id=57 data-nosnippet>57</a>
<a href=#58 id=58 data-nosnippet>58</a><span class="attr">#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
<a href=#59 id=59 data-nosnippet>59</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>ImportTaskState {
<a href=#60 id=60 data-nosnippet>60</a> <span class="kw">pub</span>(<span class="kw">crate</span>) chunk_id: u32,
<a href=#61 id=61 data-nosnippet>61</a> <span class="kw">pub</span>(<span class="kw">crate</span>) schema: String,
<a href=#62 id=62 data-nosnippet>62</a> <span class="kw">pub</span>(<span class="kw">crate</span>) status: ImportTaskStatus,
<a href=#63 id=63 data-nosnippet>63</a> <span class="attr">#[serde(skip_serializing_if = <span class="string">"Option::is_none"</span>)]
<a href=#64 id=64 data-nosnippet>64</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) error: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#65 id=65 data-nosnippet>65</a>}
<a href=#66 id=66 data-nosnippet>66</a>
<a href=#67 id=67 data-nosnippet>67</a><span class="attr">#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
<a href=#68 id=68 data-nosnippet>68</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>ImportState {
<a href=#69 id=69 data-nosnippet>69</a> <span class="kw">pub</span>(<span class="kw">crate</span>) snapshot_id: String,
<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">pub</span>(<span class="kw">crate</span>) target_addr: String,
<a href=#71 id=71 data-nosnippet>71</a> <span class="kw">pub</span>(<span class="kw">crate</span>) catalog: String,
<a href=#72 id=72 data-nosnippet>72</a> <span class="kw">pub</span>(<span class="kw">crate</span>) schemas: Vec&lt;String&gt;,
<a href=#73 id=73 data-nosnippet>73</a> <span class="attr">#[serde(default)]
<a href=#74 id=74 data-nosnippet>74</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) ddl_completed: bool,
<a href=#75 id=75 data-nosnippet>75</a> <span class="kw">pub</span>(<span class="kw">crate</span>) updated_at: DateTime&lt;Utc&gt;,
<a href=#76 id=76 data-nosnippet>76</a> <span class="comment">// Tasks are (chunk-schema) tuples and can reach the tens of thousands;
<a href=#77 id=77 data-nosnippet>77</a> // linear scans here are accepted because per-task work is dominated by
<a href=#78 id=78 data-nosnippet>78</a> // network I/O and an fsync, but if the bound grows further this should be
<a href=#79 id=79 data-nosnippet>79</a> // backed by a HashMap&lt;(chunk_id, schema), index&gt; rebuilt after load.
<a href=#80 id=80 data-nosnippet>80</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) tasks: Vec&lt;ImportTaskState&gt;,
<a href=#81 id=81 data-nosnippet>81</a>}
<a href=#82 id=82 data-nosnippet>82</a>
<a href=#83 id=83 data-nosnippet>83</a><span class="kw">impl </span>ImportState {
<a href=#84 id=84 data-nosnippet>84</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new&lt;I&gt;(
<a href=#85 id=85 data-nosnippet>85</a> snapshot_id: <span class="kw">impl </span>Into&lt;String&gt;,
<a href=#86 id=86 data-nosnippet>86</a> target_addr: <span class="kw">impl </span>Into&lt;String&gt;,
<a href=#87 id=87 data-nosnippet>87</a> catalog: <span class="kw">impl </span>Into&lt;String&gt;,
<a href=#88 id=88 data-nosnippet>88</a> schemas: <span class="kw-2">&amp;</span>[String],
<a href=#89 id=89 data-nosnippet>89</a> tasks: I,
<a href=#90 id=90 data-nosnippet>90</a> ) -&gt; <span class="self">Self
<a href=#91 id=91 data-nosnippet>91</a> </span><span class="kw">where
<a href=#92 id=92 data-nosnippet>92</a> </span>I: IntoIterator&lt;Item = ImportTaskKey&gt;,
<a href=#93 id=93 data-nosnippet>93</a> {
<a href=#94 id=94 data-nosnippet>94</a> <span class="self">Self </span>{
<a href=#95 id=95 data-nosnippet>95</a> snapshot_id: snapshot_id.into(),
<a href=#96 id=96 data-nosnippet>96</a> target_addr: target_addr.into(),
<a href=#97 id=97 data-nosnippet>97</a> catalog: catalog.into(),
<a href=#98 id=98 data-nosnippet>98</a> schemas: canonical_schema_selection(schemas),
<a href=#99 id=99 data-nosnippet>99</a> ddl_completed: <span class="bool-val">false</span>,
<a href=#100 id=100 data-nosnippet>100</a> updated_at: Utc::now(),
<a href=#101 id=101 data-nosnippet>101</a> tasks: tasks
<a href=#102 id=102 data-nosnippet>102</a> .into_iter()
<a href=#103 id=103 data-nosnippet>103</a> .map(|task| ImportTaskState {
<a href=#104 id=104 data-nosnippet>104</a> chunk_id: task.chunk_id,
<a href=#105 id=105 data-nosnippet>105</a> schema: task.schema,
<a href=#106 id=106 data-nosnippet>106</a> status: ImportTaskStatus::Pending,
<a href=#107 id=107 data-nosnippet>107</a> error: <span class="prelude-val">None</span>,
<a href=#108 id=108 data-nosnippet>108</a> })
<a href=#109 id=109 data-nosnippet>109</a> .collect(),
<a href=#110 id=110 data-nosnippet>110</a> }
<a href=#111 id=111 data-nosnippet>111</a> }
<a href=#112 id=112 data-nosnippet>112</a>
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>mark_ddl_completed(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#114 id=114 data-nosnippet>114</a> <span class="self">self</span>.ddl_completed = <span class="bool-val">true</span>;
<a href=#115 id=115 data-nosnippet>115</a> <span class="self">self</span>.updated_at = Utc::now();
<a href=#116 id=116 data-nosnippet>116</a> }
<a href=#117 id=117 data-nosnippet>117</a>
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>task_status(<span class="kw-2">&amp;</span><span class="self">self</span>, chunk_id: u32, schema: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;ImportTaskStatus&gt; {
<a href=#119 id=119 data-nosnippet>119</a> <span class="self">self</span>.tasks
<a href=#120 id=120 data-nosnippet>120</a> .iter()
<a href=#121 id=121 data-nosnippet>121</a> .find(|task| task.chunk_id == chunk_id &amp;&amp; task.schema == schema)
<a href=#122 id=122 data-nosnippet>122</a> .map(|task| task.status)
<a href=#123 id=123 data-nosnippet>123</a> }
<a href=#124 id=124 data-nosnippet>124</a>
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>set_task_status(
<a href=#126 id=126 data-nosnippet>126</a> <span class="kw-2">&amp;mut </span><span class="self">self</span>,
<a href=#127 id=127 data-nosnippet>127</a> chunk_id: u32,
<a href=#128 id=128 data-nosnippet>128</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#129 id=129 data-nosnippet>129</a> status: ImportTaskStatus,
<a href=#130 id=130 data-nosnippet>130</a> error: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#131 id=131 data-nosnippet>131</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">let </span>task = <span class="self">self
<a href=#133 id=133 data-nosnippet>133</a> </span>.tasks
<a href=#134 id=134 data-nosnippet>134</a> .iter_mut()
<a href=#135 id=135 data-nosnippet>135</a> .find(|task| task.chunk_id == chunk_id &amp;&amp; task.schema == schema)
<a href=#136 id=136 data-nosnippet>136</a> .context(ImportStateUnknownTaskSnafu {
<a href=#137 id=137 data-nosnippet>137</a> chunk_id,
<a href=#138 id=138 data-nosnippet>138</a> schema: schema.to_string(),
<a href=#139 id=139 data-nosnippet>139</a> })<span class="question-mark">?</span>;
<a href=#140 id=140 data-nosnippet>140</a> task.status = status;
<a href=#141 id=141 data-nosnippet>141</a> task.error = error;
<a href=#142 id=142 data-nosnippet>142</a> <span class="self">self</span>.updated_at = Utc::now();
<a href=#143 id=143 data-nosnippet>143</a> <span class="prelude-val">Ok</span>(())
<a href=#144 id=144 data-nosnippet>144</a> }
<a href=#145 id=145 data-nosnippet>145</a>}
<a href=#146 id=146 data-nosnippet>146</a>
<a href=#147 id=147 data-nosnippet>147</a><span class="attr">#[derive(Debug)]
<a href=#148 id=148 data-nosnippet>148</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>ImportStateLockGuard {
<a href=#149 id=149 data-nosnippet>149</a> file: std::fs::File,
<a href=#150 id=150 data-nosnippet>150</a>}
<a href=#151 id=151 data-nosnippet>151</a>
<a href=#152 id=152 data-nosnippet>152</a><span class="kw">impl </span>Drop <span class="kw">for </span>ImportStateLockGuard {
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">let _ </span>= <span class="self">self</span>.file.unlock();
<a href=#155 id=155 data-nosnippet>155</a> }
<a href=#156 id=156 data-nosnippet>156</a>}
<a href=#157 id=157 data-nosnippet>157</a>
<a href=#158 id=158 data-nosnippet>158</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>default_state_path(
<a href=#159 id=159 data-nosnippet>159</a> snapshot_id: <span class="kw-2">&amp;</span>str,
<a href=#160 id=160 data-nosnippet>160</a> target_addr: <span class="kw-2">&amp;</span>str,
<a href=#161 id=161 data-nosnippet>161</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#162 id=162 data-nosnippet>162</a> schemas: <span class="kw-2">&amp;</span>[String],
<a href=#163 id=163 data-nosnippet>163</a>) -&gt; <span class="prelude-ty">Option</span>&lt;PathBuf&gt; {
<a href=#164 id=164 data-nosnippet>164</a> <span class="kw">let </span>home = default_home_dir_with(|key| std::env::var_os(key));
<a href=#165 id=165 data-nosnippet>165</a> <span class="kw">let </span>cwd = std::env::current_dir().ok();
<a href=#166 id=166 data-nosnippet>166</a> default_state_path_with(
<a href=#167 id=167 data-nosnippet>167</a> home.as_deref(),
<a href=#168 id=168 data-nosnippet>168</a> cwd.as_deref(),
<a href=#169 id=169 data-nosnippet>169</a> snapshot_id,
<a href=#170 id=170 data-nosnippet>170</a> target_addr,
<a href=#171 id=171 data-nosnippet>171</a> catalog,
<a href=#172 id=172 data-nosnippet>172</a> schemas,
<a href=#173 id=173 data-nosnippet>173</a> )
<a href=#174 id=174 data-nosnippet>174</a>}
<a href=#175 id=175 data-nosnippet>175</a>
<a href=#176 id=176 data-nosnippet>176</a><span class="kw">fn </span>default_home_dir_with&lt;F&gt;(get: F) -&gt; <span class="prelude-ty">Option</span>&lt;PathBuf&gt;
<a href=#177 id=177 data-nosnippet>177</a><span class="kw">where
<a href=#178 id=178 data-nosnippet>178</a> </span>F: Fn(<span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;std::ffi::OsString&gt;,
<a href=#179 id=179 data-nosnippet>179</a>{
<a href=#180 id=180 data-nosnippet>180</a> get(<span class="string">"HOME"</span>)
<a href=#181 id=181 data-nosnippet>181</a> .or_else(|| get(<span class="string">"USERPROFILE"</span>))
<a href=#182 id=182 data-nosnippet>182</a> .map(PathBuf::from)
<a href=#183 id=183 data-nosnippet>183</a> .or_else(|| {
<a href=#184 id=184 data-nosnippet>184</a> <span class="kw">let </span>drive = get(<span class="string">"HOMEDRIVE"</span>)<span class="question-mark">?</span>;
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">let </span>path = get(<span class="string">"HOMEPATH"</span>)<span class="question-mark">?</span>;
<a href=#186 id=186 data-nosnippet>186</a> <span class="prelude-val">Some</span>(PathBuf::from(drive).join(path))
<a href=#187 id=187 data-nosnippet>187</a> })
<a href=#188 id=188 data-nosnippet>188</a>}
<a href=#189 id=189 data-nosnippet>189</a>
<a href=#190 id=190 data-nosnippet>190</a><span class="kw">fn </span>default_state_path_with(
<a href=#191 id=191 data-nosnippet>191</a> home: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>Path&gt;,
<a href=#192 id=192 data-nosnippet>192</a> cwd: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>Path&gt;,
<a href=#193 id=193 data-nosnippet>193</a> snapshot_id: <span class="kw-2">&amp;</span>str,
<a href=#194 id=194 data-nosnippet>194</a> target_addr: <span class="kw-2">&amp;</span>str,
<a href=#195 id=195 data-nosnippet>195</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#196 id=196 data-nosnippet>196</a> schemas: <span class="kw-2">&amp;</span>[String],
<a href=#197 id=197 data-nosnippet>197</a>) -&gt; <span class="prelude-ty">Option</span>&lt;PathBuf&gt; {
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">let </span>file_name = import_state_file_name(snapshot_id, target_addr, catalog, schemas);
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">match </span>(home, cwd) {
<a href=#200 id=200 data-nosnippet>200</a> (<span class="prelude-val">Some</span>(home), <span class="kw">_</span>) =&gt; <span class="prelude-val">Some</span>(
<a href=#201 id=201 data-nosnippet>201</a> home.join(IMPORT_STATE_ROOT)
<a href=#202 id=202 data-nosnippet>202</a> .join(IMPORT_STATE_DIR)
<a href=#203 id=203 data-nosnippet>203</a> .join(file_name),
<a href=#204 id=204 data-nosnippet>204</a> ),
<a href=#205 id=205 data-nosnippet>205</a> (<span class="prelude-val">None</span>, <span class="prelude-val">Some</span>(cwd)) =&gt; <span class="prelude-val">Some</span>(cwd.join(file_name)),
<a href=#206 id=206 data-nosnippet>206</a> (<span class="prelude-val">None</span>, <span class="prelude-val">None</span>) =&gt; <span class="prelude-val">None</span>,
<a href=#207 id=207 data-nosnippet>207</a> }
<a href=#208 id=208 data-nosnippet>208</a>}
<a href=#209 id=209 data-nosnippet>209</a>
<a href=#210 id=210 data-nosnippet>210</a><span class="kw">fn </span>import_state_file_name(
<a href=#211 id=211 data-nosnippet>211</a> snapshot_id: <span class="kw-2">&amp;</span>str,
<a href=#212 id=212 data-nosnippet>212</a> target_addr: <span class="kw-2">&amp;</span>str,
<a href=#213 id=213 data-nosnippet>213</a> catalog: <span class="kw-2">&amp;</span>str,
<a href=#214 id=214 data-nosnippet>214</a> schemas: <span class="kw-2">&amp;</span>[String],
<a href=#215 id=215 data-nosnippet>215</a>) -&gt; String {
<a href=#216 id=216 data-nosnippet>216</a> <span class="macro">format!</span>(
<a href=#217 id=217 data-nosnippet>217</a> <span class="string">".import_state_{}_{}_{}.json"</span>,
<a href=#218 id=218 data-nosnippet>218</a> encode_path_segment(snapshot_id),
<a href=#219 id=219 data-nosnippet>219</a> encode_path_segment(target_addr),
<a href=#220 id=220 data-nosnippet>220</a> import_identity_hash(catalog, schemas)
<a href=#221 id=221 data-nosnippet>221</a> )
<a href=#222 id=222 data-nosnippet>222</a>}
<a href=#223 id=223 data-nosnippet>223</a>
<a href=#224 id=224 data-nosnippet>224</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>canonical_schema_selection(schemas: <span class="kw-2">&amp;</span>[String]) -&gt; Vec&lt;String&gt; {
<a href=#225 id=225 data-nosnippet>225</a> <span class="kw">let </span><span class="kw-2">mut </span>canonicalized = schemas
<a href=#226 id=226 data-nosnippet>226</a> .iter()
<a href=#227 id=227 data-nosnippet>227</a> .map(|schema| schema.to_ascii_lowercase())
<a href=#228 id=228 data-nosnippet>228</a> .collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;();
<a href=#229 id=229 data-nosnippet>229</a> canonicalized.sort();
<a href=#230 id=230 data-nosnippet>230</a> canonicalized.dedup();
<a href=#231 id=231 data-nosnippet>231</a> canonicalized
<a href=#232 id=232 data-nosnippet>232</a>}
<a href=#233 id=233 data-nosnippet>233</a>
<a href=#234 id=234 data-nosnippet>234</a><span class="doccomment">/// FNV-1a over `(catalog, schemas)`. The output is part of the persisted state
<a href=#235 id=235 data-nosnippet>235</a>/// filename, so we cannot use `std::collections::hash_map::DefaultHasher` -
<a href=#236 id=236 data-nosnippet>236</a>/// Rust does not guarantee its algorithm across releases, which would make a
<a href=#237 id=237 data-nosnippet>237</a>/// state file written by one toolchain undiscoverable by another.
<a href=#238 id=238 data-nosnippet>238</a></span><span class="kw">fn </span>import_identity_hash(catalog: <span class="kw-2">&amp;</span>str, schemas: <span class="kw-2">&amp;</span>[String]) -&gt; String {
<a href=#239 id=239 data-nosnippet>239</a> <span class="kw">const </span>FNV_OFFSET: u64 = <span class="number">0xcbf29ce484222325</span>;
<a href=#240 id=240 data-nosnippet>240</a> <span class="kw">const </span>FNV_PRIME: u64 = <span class="number">0x100000001b3</span>;
<a href=#241 id=241 data-nosnippet>241</a>
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">fn </span>hash_bytes(<span class="kw-2">mut </span>hash: u64, bytes: <span class="kw-2">&amp;</span>[u8]) -&gt; u64 {
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">for </span>byte <span class="kw">in </span>bytes {
<a href=#244 id=244 data-nosnippet>244</a> hash ^= u64::from(<span class="kw-2">*</span>byte);
<a href=#245 id=245 data-nosnippet>245</a> hash = hash.wrapping_mul(FNV_PRIME);
<a href=#246 id=246 data-nosnippet>246</a> }
<a href=#247 id=247 data-nosnippet>247</a> hash
<a href=#248 id=248 data-nosnippet>248</a> }
<a href=#249 id=249 data-nosnippet>249</a>
<a href=#250 id=250 data-nosnippet>250</a> <span class="kw">let </span><span class="kw-2">mut </span>hash = FNV_OFFSET;
<a href=#251 id=251 data-nosnippet>251</a> hash = hash_bytes(hash, catalog.as_bytes());
<a href=#252 id=252 data-nosnippet>252</a> <span class="comment">// 0xff cannot appear in valid UTF-8, so it works as an unambiguous
<a href=#253 id=253 data-nosnippet>253</a> // field separator between adjacent identifiers.
<a href=#254 id=254 data-nosnippet>254</a> </span>hash = hash_bytes(hash, <span class="kw-2">&amp;</span>[<span class="number">0xff</span>]);
<a href=#255 id=255 data-nosnippet>255</a> <span class="kw">for </span>schema <span class="kw">in </span>canonical_schema_selection(schemas) {
<a href=#256 id=256 data-nosnippet>256</a> hash = hash_bytes(hash, schema.as_bytes());
<a href=#257 id=257 data-nosnippet>257</a> hash = hash_bytes(hash, <span class="kw-2">&amp;</span>[<span class="number">0xff</span>]);
<a href=#258 id=258 data-nosnippet>258</a> }
<a href=#259 id=259 data-nosnippet>259</a> <span class="macro">format!</span>(<span class="string">"{hash:016x}"</span>)
<a href=#260 id=260 data-nosnippet>260</a>}
<a href=#261 id=261 data-nosnippet>261</a>
<a href=#262 id=262 data-nosnippet>262</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">async fn </span>load_import_state(path: <span class="kw-2">&amp;</span>Path) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;ImportState&gt;&gt; {
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">match </span>tokio::fs::read(path).<span class="kw">await </span>{
<a href=#264 id=264 data-nosnippet>264</a> <span class="prelude-val">Ok</span>(bytes) =&gt; {
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">let </span><span class="kw-2">mut </span>state: ImportState =
<a href=#266 id=266 data-nosnippet>266</a> serde_json::from_slice(<span class="kw-2">&amp;</span>bytes).context(ImportStateParseSnafu)<span class="question-mark">?</span>;
<a href=#267 id=267 data-nosnippet>267</a> normalize_import_state_for_resume(<span class="kw-2">&amp;mut </span>state);
<a href=#268 id=268 data-nosnippet>268</a> <span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(state))
<a href=#269 id=269 data-nosnippet>269</a> }
<a href=#270 id=270 data-nosnippet>270</a> <span class="prelude-val">Err</span>(error) <span class="kw">if </span>error.kind() == std::io::ErrorKind::NotFound =&gt; <span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>),
<a href=#271 id=271 data-nosnippet>271</a> <span class="prelude-val">Err</span>(source) =&gt; <span class="prelude-val">Err</span>(source).context(ImportStateIoSnafu {
<a href=#272 id=272 data-nosnippet>272</a> path: path.display().to_string(),
<a href=#273 id=273 data-nosnippet>273</a> }),
<a href=#274 id=274 data-nosnippet>274</a> }
<a href=#275 id=275 data-nosnippet>275</a>}
<a href=#276 id=276 data-nosnippet>276</a>
<a href=#277 id=277 data-nosnippet>277</a><span class="doccomment">/// Caller must hold the lock acquired via `try_acquire_import_state_lock`.
<a href=#278 id=278 data-nosnippet>278</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">async fn </span>save_import_state(path: <span class="kw-2">&amp;</span>Path, state: <span class="kw-2">&amp;</span>ImportState) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(parent) = path.parent() {
<a href=#280 id=280 data-nosnippet>280</a> tokio::fs::create_dir_all(parent)
<a href=#281 id=281 data-nosnippet>281</a> .<span class="kw">await
<a href=#282 id=282 data-nosnippet>282</a> </span>.context(ImportStateIoSnafu {
<a href=#283 id=283 data-nosnippet>283</a> path: parent.display().to_string(),
<a href=#284 id=284 data-nosnippet>284</a> })<span class="question-mark">?</span>;
<a href=#285 id=285 data-nosnippet>285</a> }
<a href=#286 id=286 data-nosnippet>286</a>
<a href=#287 id=287 data-nosnippet>287</a> <span class="kw">let </span>bytes =
<a href=#288 id=288 data-nosnippet>288</a> serde_json::to_vec_pretty(state).expect(<span class="string">"ImportState should always be serializable"</span>);
<a href=#289 id=289 data-nosnippet>289</a> <span class="kw">let </span>tmp_path = unique_tmp_path(path);
<a href=#290 id=290 data-nosnippet>290</a> <span class="kw">let </span><span class="kw-2">mut </span>file = tokio::fs::File::create(<span class="kw-2">&amp;</span>tmp_path)
<a href=#291 id=291 data-nosnippet>291</a> .<span class="kw">await
<a href=#292 id=292 data-nosnippet>292</a> </span>.context(ImportStateIoSnafu {
<a href=#293 id=293 data-nosnippet>293</a> path: tmp_path.display().to_string(),
<a href=#294 id=294 data-nosnippet>294</a> })<span class="question-mark">?</span>;
<a href=#295 id=295 data-nosnippet>295</a> file.write_all(<span class="kw-2">&amp;</span>bytes).<span class="kw">await</span>.context(ImportStateIoSnafu {
<a href=#296 id=296 data-nosnippet>296</a> path: tmp_path.display().to_string(),
<a href=#297 id=297 data-nosnippet>297</a> })<span class="question-mark">?</span>;
<a href=#298 id=298 data-nosnippet>298</a> file.sync_all().<span class="kw">await</span>.context(ImportStateIoSnafu {
<a href=#299 id=299 data-nosnippet>299</a> path: tmp_path.display().to_string(),
<a href=#300 id=300 data-nosnippet>300</a> })<span class="question-mark">?</span>;
<a href=#301 id=301 data-nosnippet>301</a> <span class="comment">// Close before rename; Windows forbids renaming an open file.
<a href=#302 id=302 data-nosnippet>302</a> </span>drop(file);
<a href=#303 id=303 data-nosnippet>303</a>
<a href=#304 id=304 data-nosnippet>304</a> tokio::fs::rename(<span class="kw-2">&amp;</span>tmp_path, path)
<a href=#305 id=305 data-nosnippet>305</a> .<span class="kw">await
<a href=#306 id=306 data-nosnippet>306</a> </span>.context(ImportStateIoSnafu {
<a href=#307 id=307 data-nosnippet>307</a> path: path.display().to_string(),
<a href=#308 id=308 data-nosnippet>308</a> })<span class="question-mark">?</span>;
<a href=#309 id=309 data-nosnippet>309</a> sync_parent_dir(path).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#310 id=310 data-nosnippet>310</a> <span class="prelude-val">Ok</span>(())
<a href=#311 id=311 data-nosnippet>311</a>}
<a href=#312 id=312 data-nosnippet>312</a>
<a href=#313 id=313 data-nosnippet>313</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>try_acquire_import_state_lock(path: <span class="kw-2">&amp;</span>Path) -&gt; <span class="prelude-ty">Result</span>&lt;ImportStateLockGuard&gt; {
<a href=#314 id=314 data-nosnippet>314</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(parent) = path.parent() {
<a href=#315 id=315 data-nosnippet>315</a> std::fs::create_dir_all(parent).context(ImportStateIoSnafu {
<a href=#316 id=316 data-nosnippet>316</a> path: parent.display().to_string(),
<a href=#317 id=317 data-nosnippet>317</a> })<span class="question-mark">?</span>;
<a href=#318 id=318 data-nosnippet>318</a> }
<a href=#319 id=319 data-nosnippet>319</a>
<a href=#320 id=320 data-nosnippet>320</a> <span class="kw">let </span>lock_path = import_state_lock_path(path);
<a href=#321 id=321 data-nosnippet>321</a> <span class="kw">let </span>file = std::fs::OpenOptions::new()
<a href=#322 id=322 data-nosnippet>322</a> .create(<span class="bool-val">true</span>)
<a href=#323 id=323 data-nosnippet>323</a> .read(<span class="bool-val">true</span>)
<a href=#324 id=324 data-nosnippet>324</a> .write(<span class="bool-val">true</span>)
<a href=#325 id=325 data-nosnippet>325</a> .truncate(<span class="bool-val">false</span>)
<a href=#326 id=326 data-nosnippet>326</a> .open(<span class="kw-2">&amp;</span>lock_path)
<a href=#327 id=327 data-nosnippet>327</a> .context(ImportStateIoSnafu {
<a href=#328 id=328 data-nosnippet>328</a> path: lock_path.display().to_string(),
<a href=#329 id=329 data-nosnippet>329</a> })<span class="question-mark">?</span>;
<a href=#330 id=330 data-nosnippet>330</a> file.try_lock_exclusive().map_err(|error| {
<a href=#331 id=331 data-nosnippet>331</a> <span class="kw">if </span>is_lock_contention(<span class="kw-2">&amp;</span>error) {
<a href=#332 id=332 data-nosnippet>332</a> ImportStateLockedSnafu {
<a href=#333 id=333 data-nosnippet>333</a> path: lock_path.display().to_string(),
<a href=#334 id=334 data-nosnippet>334</a> }
<a href=#335 id=335 data-nosnippet>335</a> .build()
<a href=#336 id=336 data-nosnippet>336</a> } <span class="kw">else </span>{
<a href=#337 id=337 data-nosnippet>337</a> ImportStateIoSnafu {
<a href=#338 id=338 data-nosnippet>338</a> path: lock_path.display().to_string(),
<a href=#339 id=339 data-nosnippet>339</a> }
<a href=#340 id=340 data-nosnippet>340</a> .into_error(error)
<a href=#341 id=341 data-nosnippet>341</a> }
<a href=#342 id=342 data-nosnippet>342</a> })<span class="question-mark">?</span>;
<a href=#343 id=343 data-nosnippet>343</a>
<a href=#344 id=344 data-nosnippet>344</a> <span class="prelude-val">Ok</span>(ImportStateLockGuard { file })
<a href=#345 id=345 data-nosnippet>345</a>}
<a href=#346 id=346 data-nosnippet>346</a>
<a href=#347 id=347 data-nosnippet>347</a><span class="kw">fn </span>is_lock_contention(error: <span class="kw-2">&amp;</span>std::io::Error) -&gt; bool {
<a href=#348 id=348 data-nosnippet>348</a> error.kind() == std::io::ErrorKind::WouldBlock
<a href=#349 id=349 data-nosnippet>349</a> || error.raw_os_error() == fs2::lock_contended_error().raw_os_error()
<a href=#350 id=350 data-nosnippet>350</a>}
<a href=#351 id=351 data-nosnippet>351</a>
<a href=#352 id=352 data-nosnippet>352</a><span class="kw">fn </span>unique_tmp_path(path: <span class="kw-2">&amp;</span>Path) -&gt; PathBuf {
<a href=#353 id=353 data-nosnippet>353</a> <span class="kw">let </span>pid = std::process::id();
<a href=#354 id=354 data-nosnippet>354</a> <span class="kw">let </span>seq = IMPORT_STATE_TMP_ID.fetch_add(<span class="number">1</span>, Ordering::Relaxed);
<a href=#355 id=355 data-nosnippet>355</a> <span class="kw">let </span>file_name = path.file_name().unwrap_or_default().to_string_lossy();
<a href=#356 id=356 data-nosnippet>356</a> path.with_file_name(<span class="macro">format!</span>(<span class="string">"{file_name}.{pid}.{seq}.tmp"</span>))
<a href=#357 id=357 data-nosnippet>357</a>}
<a href=#358 id=358 data-nosnippet>358</a>
<a href=#359 id=359 data-nosnippet>359</a><span class="kw">fn </span>import_state_lock_path(path: <span class="kw-2">&amp;</span>Path) -&gt; PathBuf {
<a href=#360 id=360 data-nosnippet>360</a> <span class="kw">let </span>file_name = path.file_name().unwrap_or_default().to_string_lossy();
<a href=#361 id=361 data-nosnippet>361</a> path.with_file_name(<span class="macro">format!</span>(<span class="string">"{file_name}.lock"</span>))
<a href=#362 id=362 data-nosnippet>362</a>}
<a href=#363 id=363 data-nosnippet>363</a>
<a href=#364 id=364 data-nosnippet>364</a><span class="kw">fn </span>normalize_import_state_for_resume(state: <span class="kw-2">&amp;mut </span>ImportState) {
<a href=#365 id=365 data-nosnippet>365</a> <span class="kw">for </span>task <span class="kw">in </span><span class="kw-2">&amp;mut </span>state.tasks {
<a href=#366 id=366 data-nosnippet>366</a> <span class="kw">if </span>task.status == ImportTaskStatus::InProgress {
<a href=#367 id=367 data-nosnippet>367</a> task.status = ImportTaskStatus::Pending;
<a href=#368 id=368 data-nosnippet>368</a> task.error = <span class="prelude-val">None</span>;
<a href=#369 id=369 data-nosnippet>369</a> }
<a href=#370 id=370 data-nosnippet>370</a> }
<a href=#371 id=371 data-nosnippet>371</a>}
<a href=#372 id=372 data-nosnippet>372</a>
<a href=#373 id=373 data-nosnippet>373</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">async fn </span>delete_import_state(path: <span class="kw-2">&amp;</span>Path) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#374 id=374 data-nosnippet>374</a> <span class="kw">match </span>tokio::fs::remove_file(path).<span class="kw">await </span>{
<a href=#375 id=375 data-nosnippet>375</a> <span class="prelude-val">Ok</span>(()) =&gt; {
<a href=#376 id=376 data-nosnippet>376</a> sync_parent_dir(path).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#377 id=377 data-nosnippet>377</a> <span class="prelude-val">Ok</span>(())
<a href=#378 id=378 data-nosnippet>378</a> }
<a href=#379 id=379 data-nosnippet>379</a> <span class="prelude-val">Err</span>(error) <span class="kw">if </span>error.kind() == std::io::ErrorKind::NotFound =&gt; <span class="prelude-val">Ok</span>(()),
<a href=#380 id=380 data-nosnippet>380</a> <span class="prelude-val">Err</span>(source) =&gt; <span class="prelude-val">Err</span>(source).context(ImportStateIoSnafu {
<a href=#381 id=381 data-nosnippet>381</a> path: path.display().to_string(),
<a href=#382 id=382 data-nosnippet>382</a> }),
<a href=#383 id=383 data-nosnippet>383</a> }
<a href=#384 id=384 data-nosnippet>384</a>}
<a href=#385 id=385 data-nosnippet>385</a>
<a href=#386 id=386 data-nosnippet>386</a><span class="attr">#[cfg(unix)]
<a href=#387 id=387 data-nosnippet>387</a></span><span class="kw">async fn </span>sync_parent_dir(path: <span class="kw-2">&amp;</span>Path) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#388 id=388 data-nosnippet>388</a> <span class="kw">let </span><span class="prelude-val">Some</span>(parent) = path.parent() <span class="kw">else </span>{
<a href=#389 id=389 data-nosnippet>389</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#390 id=390 data-nosnippet>390</a> };
<a href=#391 id=391 data-nosnippet>391</a>
<a href=#392 id=392 data-nosnippet>392</a> <span class="kw">let </span>dir = tokio::fs::File::open(parent)
<a href=#393 id=393 data-nosnippet>393</a> .<span class="kw">await
<a href=#394 id=394 data-nosnippet>394</a> </span>.context(ImportStateIoSnafu {
<a href=#395 id=395 data-nosnippet>395</a> path: parent.display().to_string(),
<a href=#396 id=396 data-nosnippet>396</a> })<span class="question-mark">?</span>;
<a href=#397 id=397 data-nosnippet>397</a> dir.sync_all().<span class="kw">await</span>.context(ImportStateIoSnafu {
<a href=#398 id=398 data-nosnippet>398</a> path: parent.display().to_string(),
<a href=#399 id=399 data-nosnippet>399</a> })<span class="question-mark">?</span>;
<a href=#400 id=400 data-nosnippet>400</a> <span class="prelude-val">Ok</span>(())
<a href=#401 id=401 data-nosnippet>401</a>}
<a href=#402 id=402 data-nosnippet>402</a>
<a href=#403 id=403 data-nosnippet>403</a><span class="attr">#[cfg(not(unix))]
<a href=#404 id=404 data-nosnippet>404</a></span><span class="kw">async fn </span>sync_parent_dir(_path: <span class="kw-2">&amp;</span>Path) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#405 id=405 data-nosnippet>405</a> <span class="prelude-val">Ok</span>(())
<a href=#406 id=406 data-nosnippet>406</a>}
<a href=#407 id=407 data-nosnippet>407</a>
<a href=#408 id=408 data-nosnippet>408</a><span class="attr">#[cfg(test)]
<a href=#409 id=409 data-nosnippet>409</a></span><span class="kw">mod </span>tests {
<a href=#410 id=410 data-nosnippet>410</a> <span class="kw">use </span>std::process::Command;
<a href=#411 id=411 data-nosnippet>411</a>
<a href=#412 id=412 data-nosnippet>412</a> <span class="kw">use </span>chrono::Utc;
<a href=#413 id=413 data-nosnippet>413</a> <span class="kw">use </span>tempfile::tempdir;
<a href=#414 id=414 data-nosnippet>414</a>
<a href=#415 id=415 data-nosnippet>415</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#416 id=416 data-nosnippet>416</a>
<a href=#417 id=417 data-nosnippet>417</a> <span class="kw">const </span>CHILD_LOCK_PATH_ENV: <span class="kw-2">&amp;</span>str = <span class="string">"GREPTIME_IMPORT_STATE_LOCK_PATH"</span>;
<a href=#418 id=418 data-nosnippet>418</a> <span class="kw">const </span>CHILD_LOCK_TEST: <span class="kw-2">&amp;</span>str =
<a href=#419 id=419 data-nosnippet>419</a> <span class="string">"data::import_v2::state::tests::test_try_acquire_import_state_lock_child_process"</span>;
<a href=#420 id=420 data-nosnippet>420</a>
<a href=#421 id=421 data-nosnippet>421</a> <span class="kw">fn </span>schemas() -&gt; Vec&lt;String&gt; {
<a href=#422 id=422 data-nosnippet>422</a> <span class="macro">vec!</span>[<span class="string">"public"</span>.to_string(), <span class="string">"analytics"</span>.to_string()]
<a href=#423 id=423 data-nosnippet>423</a> }
<a href=#424 id=424 data-nosnippet>424</a>
<a href=#425 id=425 data-nosnippet>425</a> <span class="kw">fn </span>tasks() -&gt; Vec&lt;ImportTaskKey&gt; {
<a href=#426 id=426 data-nosnippet>426</a> <span class="macro">vec!</span>[
<a href=#427 id=427 data-nosnippet>427</a> ImportTaskKey::new(<span class="number">1</span>, <span class="string">"public"</span>),
<a href=#428 id=428 data-nosnippet>428</a> ImportTaskKey::new(<span class="number">2</span>, <span class="string">"analytics"</span>),
<a href=#429 id=429 data-nosnippet>429</a> ]
<a href=#430 id=430 data-nosnippet>430</a> }
<a href=#431 id=431 data-nosnippet>431</a>
<a href=#432 id=432 data-nosnippet>432</a> <span class="attr">#[test]
<a href=#433 id=433 data-nosnippet>433</a> </span><span class="kw">fn </span>test_import_state_new_initializes_pending_tasks() {
<a href=#434 id=434 data-nosnippet>434</a> <span class="kw">let </span>state = ImportState::new(
<a href=#435 id=435 data-nosnippet>435</a> <span class="string">"snapshot-1"</span>,
<a href=#436 id=436 data-nosnippet>436</a> <span class="string">"127.0.0.1:4000"</span>,
<a href=#437 id=437 data-nosnippet>437</a> <span class="string">"greptime"</span>,
<a href=#438 id=438 data-nosnippet>438</a> <span class="kw-2">&amp;</span>schemas(),
<a href=#439 id=439 data-nosnippet>439</a> tasks(),
<a href=#440 id=440 data-nosnippet>440</a> );
<a href=#441 id=441 data-nosnippet>441</a>
<a href=#442 id=442 data-nosnippet>442</a> <span class="macro">assert_eq!</span>(state.snapshot_id, <span class="string">"snapshot-1"</span>);
<a href=#443 id=443 data-nosnippet>443</a> <span class="macro">assert_eq!</span>(state.target_addr, <span class="string">"127.0.0.1:4000"</span>);
<a href=#444 id=444 data-nosnippet>444</a> <span class="macro">assert_eq!</span>(state.catalog, <span class="string">"greptime"</span>);
<a href=#445 id=445 data-nosnippet>445</a> <span class="macro">assert_eq!</span>(state.schemas, <span class="macro">vec!</span>[<span class="string">"analytics"</span>, <span class="string">"public"</span>]);
<a href=#446 id=446 data-nosnippet>446</a> <span class="macro">assert_eq!</span>(state.tasks.len(), <span class="number">2</span>);
<a href=#447 id=447 data-nosnippet>447</a> <span class="macro">assert_eq!</span>(state.tasks[<span class="number">0</span>].status, ImportTaskStatus::Pending);
<a href=#448 id=448 data-nosnippet>448</a> <span class="macro">assert_eq!</span>(state.tasks[<span class="number">1</span>].status, ImportTaskStatus::Pending);
<a href=#449 id=449 data-nosnippet>449</a> }
<a href=#450 id=450 data-nosnippet>450</a>
<a href=#451 id=451 data-nosnippet>451</a> <span class="attr">#[test]
<a href=#452 id=452 data-nosnippet>452</a> </span><span class="kw">fn </span>test_set_task_status_updates_timestamp_and_error() {
<a href=#453 id=453 data-nosnippet>453</a> <span class="kw">let </span><span class="kw-2">mut </span>state = ImportState::new(
<a href=#454 id=454 data-nosnippet>454</a> <span class="string">"snapshot-1"</span>,
<a href=#455 id=455 data-nosnippet>455</a> <span class="string">"127.0.0.1:4000"</span>,
<a href=#456 id=456 data-nosnippet>456</a> <span class="string">"greptime"</span>,
<a href=#457 id=457 data-nosnippet>457</a> <span class="kw-2">&amp;</span>schemas(),
<a href=#458 id=458 data-nosnippet>458</a> tasks(),
<a href=#459 id=459 data-nosnippet>459</a> );
<a href=#460 id=460 data-nosnippet>460</a> <span class="kw">let </span>before = state.updated_at;
<a href=#461 id=461 data-nosnippet>461</a> state.updated_at = Utc::now() - chrono::Duration::seconds(<span class="number">10</span>);
<a href=#462 id=462 data-nosnippet>462</a>
<a href=#463 id=463 data-nosnippet>463</a> state
<a href=#464 id=464 data-nosnippet>464</a> .set_task_status(
<a href=#465 id=465 data-nosnippet>465</a> <span class="number">1</span>,
<a href=#466 id=466 data-nosnippet>466</a> <span class="string">"public"</span>,
<a href=#467 id=467 data-nosnippet>467</a> ImportTaskStatus::Failed,
<a href=#468 id=468 data-nosnippet>468</a> <span class="prelude-val">Some</span>(<span class="string">"timeout"</span>.to_string()),
<a href=#469 id=469 data-nosnippet>469</a> )
<a href=#470 id=470 data-nosnippet>470</a> .unwrap();
<a href=#471 id=471 data-nosnippet>471</a> <span class="macro">assert_eq!</span>(
<a href=#472 id=472 data-nosnippet>472</a> state.task_status(<span class="number">1</span>, <span class="string">"public"</span>),
<a href=#473 id=473 data-nosnippet>473</a> <span class="prelude-val">Some</span>(ImportTaskStatus::Failed)
<a href=#474 id=474 data-nosnippet>474</a> );
<a href=#475 id=475 data-nosnippet>475</a> <span class="macro">assert_eq!</span>(state.tasks[<span class="number">0</span>].error.as_deref(), <span class="prelude-val">Some</span>(<span class="string">"timeout"</span>));
<a href=#476 id=476 data-nosnippet>476</a> <span class="macro">assert!</span>(state.updated_at &gt; before);
<a href=#477 id=477 data-nosnippet>477</a> }
<a href=#478 id=478 data-nosnippet>478</a>
<a href=#479 id=479 data-nosnippet>479</a> <span class="attr">#[test]
<a href=#480 id=480 data-nosnippet>480</a> </span><span class="kw">fn </span>test_set_task_status_rejects_unknown_task() {
<a href=#481 id=481 data-nosnippet>481</a> <span class="kw">let </span><span class="kw-2">mut </span>state = ImportState::new(
<a href=#482 id=482 data-nosnippet>482</a> <span class="string">"snapshot-1"</span>,
<a href=#483 id=483 data-nosnippet>483</a> <span class="string">"127.0.0.1:4000"</span>,
<a href=#484 id=484 data-nosnippet>484</a> <span class="string">"greptime"</span>,
<a href=#485 id=485 data-nosnippet>485</a> <span class="kw-2">&amp;</span>schemas(),
<a href=#486 id=486 data-nosnippet>486</a> tasks(),
<a href=#487 id=487 data-nosnippet>487</a> );
<a href=#488 id=488 data-nosnippet>488</a>
<a href=#489 id=489 data-nosnippet>489</a> <span class="kw">let </span>error = state
<a href=#490 id=490 data-nosnippet>490</a> .set_task_status(<span class="number">99</span>, <span class="string">"public"</span>, ImportTaskStatus::Completed, <span class="prelude-val">None</span>)
<a href=#491 id=491 data-nosnippet>491</a> .unwrap_err();
<a href=#492 id=492 data-nosnippet>492</a>
<a href=#493 id=493 data-nosnippet>493</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(
<a href=#494 id=494 data-nosnippet>494</a> error,
<a href=#495 id=495 data-nosnippet>495</a> <span class="kw">crate</span>::data::import_v2::error::Error::ImportStateUnknownTask { chunk_id, schema, .. }
<a href=#496 id=496 data-nosnippet>496</a> <span class="kw">if </span>chunk_id == <span class="number">99 </span>&amp;&amp; schema == <span class="string">"public"
<a href=#497 id=497 data-nosnippet>497</a> </span>));
<a href=#498 id=498 data-nosnippet>498</a> }
<a href=#499 id=499 data-nosnippet>499</a>
<a href=#500 id=500 data-nosnippet>500</a> <span class="attr">#[tokio::test]
<a href=#501 id=501 data-nosnippet>501</a> </span><span class="kw">async fn </span>test_save_and_load_import_state_round_trip() {
<a href=#502 id=502 data-nosnippet>502</a> <span class="kw">let </span>dir = tempdir().unwrap();
<a href=#503 id=503 data-nosnippet>503</a> <span class="kw">let </span>path = dir.path().join(<span class="string">"import_state.json"</span>);
<a href=#504 id=504 data-nosnippet>504</a> <span class="kw">let </span><span class="kw-2">mut </span>state = ImportState::new(
<a href=#505 id=505 data-nosnippet>505</a> <span class="string">"snapshot-1"</span>,
<a href=#506 id=506 data-nosnippet>506</a> <span class="string">"127.0.0.1:4000"</span>,
<a href=#507 id=507 data-nosnippet>507</a> <span class="string">"greptime"</span>,
<a href=#508 id=508 data-nosnippet>508</a> <span class="kw-2">&amp;</span>schemas(),
<a href=#509 id=509 data-nosnippet>509</a> tasks(),
<a href=#510 id=510 data-nosnippet>510</a> );
<a href=#511 id=511 data-nosnippet>511</a> state
<a href=#512 id=512 data-nosnippet>512</a> .set_task_status(<span class="number">2</span>, <span class="string">"analytics"</span>, ImportTaskStatus::Completed, <span class="prelude-val">None</span>)
<a href=#513 id=513 data-nosnippet>513</a> .unwrap();
<a href=#514 id=514 data-nosnippet>514</a>
<a href=#515 id=515 data-nosnippet>515</a> save_import_state(<span class="kw-2">&amp;</span>path, <span class="kw-2">&amp;</span>state).<span class="kw">await</span>.unwrap();
<a href=#516 id=516 data-nosnippet>516</a> <span class="kw">let </span>loaded = load_import_state(<span class="kw-2">&amp;</span>path).<span class="kw">await</span>.unwrap().unwrap();
<a href=#517 id=517 data-nosnippet>517</a>
<a href=#518 id=518 data-nosnippet>518</a> <span class="macro">assert_eq!</span>(loaded.snapshot_id, state.snapshot_id);
<a href=#519 id=519 data-nosnippet>519</a> <span class="macro">assert_eq!</span>(loaded.target_addr, state.target_addr);
<a href=#520 id=520 data-nosnippet>520</a> <span class="macro">assert_eq!</span>(loaded.catalog, state.catalog);
<a href=#521 id=521 data-nosnippet>521</a> <span class="macro">assert_eq!</span>(loaded.schemas, state.schemas);
<a href=#522 id=522 data-nosnippet>522</a> <span class="macro">assert_eq!</span>(loaded.tasks, state.tasks);
<a href=#523 id=523 data-nosnippet>523</a> }
<a href=#524 id=524 data-nosnippet>524</a>
<a href=#525 id=525 data-nosnippet>525</a> <span class="attr">#[tokio::test]
<a href=#526 id=526 data-nosnippet>526</a> </span><span class="kw">async fn </span>test_save_import_state_overwrites_existing_file() {
<a href=#527 id=527 data-nosnippet>527</a> <span class="kw">let </span>dir = tempdir().unwrap();
<a href=#528 id=528 data-nosnippet>528</a> <span class="kw">let </span>path = dir.path().join(<span class="string">"import_state.json"</span>);
<a href=#529 id=529 data-nosnippet>529</a> <span class="kw">let </span><span class="kw-2">mut </span>state = ImportState::new(
<a href=#530 id=530 data-nosnippet>530</a> <span class="string">"snapshot-1"</span>,
<a href=#531 id=531 data-nosnippet>531</a> <span class="string">"127.0.0.1:4000"</span>,
<a href=#532 id=532 data-nosnippet>532</a> <span class="string">"greptime"</span>,
<a href=#533 id=533 data-nosnippet>533</a> <span class="kw-2">&amp;</span>schemas(),
<a href=#534 id=534 data-nosnippet>534</a> tasks(),
<a href=#535 id=535 data-nosnippet>535</a> );
<a href=#536 id=536 data-nosnippet>536</a> save_import_state(<span class="kw-2">&amp;</span>path, <span class="kw-2">&amp;</span>state).<span class="kw">await</span>.unwrap();
<a href=#537 id=537 data-nosnippet>537</a>
<a href=#538 id=538 data-nosnippet>538</a> state
<a href=#539 id=539 data-nosnippet>539</a> .set_task_status(<span class="number">1</span>, <span class="string">"public"</span>, ImportTaskStatus::Completed, <span class="prelude-val">None</span>)
<a href=#540 id=540 data-nosnippet>540</a> .unwrap();
<a href=#541 id=541 data-nosnippet>541</a> save_import_state(<span class="kw-2">&amp;</span>path, <span class="kw-2">&amp;</span>state).<span class="kw">await</span>.unwrap();
<a href=#542 id=542 data-nosnippet>542</a>
<a href=#543 id=543 data-nosnippet>543</a> <span class="kw">let </span>loaded = load_import_state(<span class="kw-2">&amp;</span>path).<span class="kw">await</span>.unwrap().unwrap();
<a href=#544 id=544 data-nosnippet>544</a> <span class="macro">assert_eq!</span>(
<a href=#545 id=545 data-nosnippet>545</a> loaded.task_status(<span class="number">1</span>, <span class="string">"public"</span>),
<a href=#546 id=546 data-nosnippet>546</a> <span class="prelude-val">Some</span>(ImportTaskStatus::Completed)
<a href=#547 id=547 data-nosnippet>547</a> );
<a href=#548 id=548 data-nosnippet>548</a> }
<a href=#549 id=549 data-nosnippet>549</a>
<a href=#550 id=550 data-nosnippet>550</a> <span class="attr">#[test]
<a href=#551 id=551 data-nosnippet>551</a> </span><span class="kw">fn </span>test_load_import_state_resets_in_progress_to_pending() {
<a href=#552 id=552 data-nosnippet>552</a> <span class="kw">let </span><span class="kw-2">mut </span>state = ImportState::new(
<a href=#553 id=553 data-nosnippet>553</a> <span class="string">"snapshot-1"</span>,
<a href=#554 id=554 data-nosnippet>554</a> <span class="string">"127.0.0.1:4000"</span>,
<a href=#555 id=555 data-nosnippet>555</a> <span class="string">"greptime"</span>,
<a href=#556 id=556 data-nosnippet>556</a> <span class="kw-2">&amp;</span>schemas(),
<a href=#557 id=557 data-nosnippet>557</a> tasks(),
<a href=#558 id=558 data-nosnippet>558</a> );
<a href=#559 id=559 data-nosnippet>559</a> state
<a href=#560 id=560 data-nosnippet>560</a> .set_task_status(
<a href=#561 id=561 data-nosnippet>561</a> <span class="number">2</span>,
<a href=#562 id=562 data-nosnippet>562</a> <span class="string">"analytics"</span>,
<a href=#563 id=563 data-nosnippet>563</a> ImportTaskStatus::InProgress,
<a href=#564 id=564 data-nosnippet>564</a> <span class="prelude-val">Some</span>(<span class="string">"running"</span>.to_string()),
<a href=#565 id=565 data-nosnippet>565</a> )
<a href=#566 id=566 data-nosnippet>566</a> .unwrap();
<a href=#567 id=567 data-nosnippet>567</a>
<a href=#568 id=568 data-nosnippet>568</a> normalize_import_state_for_resume(<span class="kw-2">&amp;mut </span>state);
<a href=#569 id=569 data-nosnippet>569</a>
<a href=#570 id=570 data-nosnippet>570</a> <span class="macro">assert_eq!</span>(
<a href=#571 id=571 data-nosnippet>571</a> state.task_status(<span class="number">1</span>, <span class="string">"public"</span>),
<a href=#572 id=572 data-nosnippet>572</a> <span class="prelude-val">Some</span>(ImportTaskStatus::Pending)
<a href=#573 id=573 data-nosnippet>573</a> );
<a href=#574 id=574 data-nosnippet>574</a> <span class="macro">assert_eq!</span>(
<a href=#575 id=575 data-nosnippet>575</a> state.task_status(<span class="number">2</span>, <span class="string">"analytics"</span>),
<a href=#576 id=576 data-nosnippet>576</a> <span class="prelude-val">Some</span>(ImportTaskStatus::Pending)
<a href=#577 id=577 data-nosnippet>577</a> );
<a href=#578 id=578 data-nosnippet>578</a> <span class="macro">assert_eq!</span>(state.tasks[<span class="number">1</span>].error, <span class="prelude-val">None</span>);
<a href=#579 id=579 data-nosnippet>579</a> }
<a href=#580 id=580 data-nosnippet>580</a>
<a href=#581 id=581 data-nosnippet>581</a> <span class="attr">#[test]
<a href=#582 id=582 data-nosnippet>582</a> </span><span class="kw">fn </span>test_unique_tmp_path_generates_distinct_paths() {
<a href=#583 id=583 data-nosnippet>583</a> <span class="kw">let </span>dir = tempdir().unwrap();
<a href=#584 id=584 data-nosnippet>584</a> <span class="kw">let </span>path = dir.path().join(<span class="string">"import_state.json"</span>);
<a href=#585 id=585 data-nosnippet>585</a>
<a href=#586 id=586 data-nosnippet>586</a> <span class="kw">let </span>first = unique_tmp_path(<span class="kw-2">&amp;</span>path);
<a href=#587 id=587 data-nosnippet>587</a> <span class="kw">let </span>second = unique_tmp_path(<span class="kw-2">&amp;</span>path);
<a href=#588 id=588 data-nosnippet>588</a>
<a href=#589 id=589 data-nosnippet>589</a> <span class="macro">assert_ne!</span>(first, second);
<a href=#590 id=590 data-nosnippet>590</a> <span class="macro">assert!</span>(first.starts_with(dir.path()));
<a href=#591 id=591 data-nosnippet>591</a> <span class="macro">assert!</span>(second.starts_with(dir.path()));
<a href=#592 id=592 data-nosnippet>592</a> <span class="macro">assert!</span>(
<a href=#593 id=593 data-nosnippet>593</a> first
<a href=#594 id=594 data-nosnippet>594</a> .file_name()
<a href=#595 id=595 data-nosnippet>595</a> .unwrap()
<a href=#596 id=596 data-nosnippet>596</a> .to_string_lossy()
<a href=#597 id=597 data-nosnippet>597</a> .ends_with(<span class="string">".tmp"</span>)
<a href=#598 id=598 data-nosnippet>598</a> );
<a href=#599 id=599 data-nosnippet>599</a> <span class="macro">assert!</span>(
<a href=#600 id=600 data-nosnippet>600</a> second
<a href=#601 id=601 data-nosnippet>601</a> .file_name()
<a href=#602 id=602 data-nosnippet>602</a> .unwrap()
<a href=#603 id=603 data-nosnippet>603</a> .to_string_lossy()
<a href=#604 id=604 data-nosnippet>604</a> .ends_with(<span class="string">".tmp"</span>)
<a href=#605 id=605 data-nosnippet>605</a> );
<a href=#606 id=606 data-nosnippet>606</a> }
<a href=#607 id=607 data-nosnippet>607</a>
<a href=#608 id=608 data-nosnippet>608</a> <span class="attr">#[test]
<a href=#609 id=609 data-nosnippet>609</a> </span><span class="kw">fn </span>test_lock_contention_detection_accepts_platform_error() {
<a href=#610 id=610 data-nosnippet>610</a> <span class="kw">let </span>error = fs2::lock_contended_error();
<a href=#611 id=611 data-nosnippet>611</a>
<a href=#612 id=612 data-nosnippet>612</a> <span class="macro">assert!</span>(is_lock_contention(<span class="kw-2">&amp;</span>error));
<a href=#613 id=613 data-nosnippet>613</a> }
<a href=#614 id=614 data-nosnippet>614</a>
<a href=#615 id=615 data-nosnippet>615</a> <span class="attr">#[test]
<a href=#616 id=616 data-nosnippet>616</a> </span><span class="kw">fn </span>test_try_acquire_import_state_lock_rejects_second_holder() {
<a href=#617 id=617 data-nosnippet>617</a> <span class="kw">let </span>dir = tempdir().unwrap();
<a href=#618 id=618 data-nosnippet>618</a> <span class="kw">let </span>path = dir.path().join(<span class="string">"import_state.json"</span>);
<a href=#619 id=619 data-nosnippet>619</a>
<a href=#620 id=620 data-nosnippet>620</a> <span class="kw">let </span>_first = try_acquire_import_state_lock(<span class="kw-2">&amp;</span>path).unwrap();
<a href=#621 id=621 data-nosnippet>621</a> <span class="comment">// Import state locking guards concurrent CLI processes, so validate cross-process exclusion.
<a href=#622 id=622 data-nosnippet>622</a> </span><span class="kw">let </span>output = Command::new(std::env::current_exe().unwrap())
<a href=#623 id=623 data-nosnippet>623</a> .arg(CHILD_LOCK_TEST)
<a href=#624 id=624 data-nosnippet>624</a> .arg(<span class="string">"--ignored"</span>)
<a href=#625 id=625 data-nosnippet>625</a> .arg(<span class="string">"--exact"</span>)
<a href=#626 id=626 data-nosnippet>626</a> .env(CHILD_LOCK_PATH_ENV, <span class="kw-2">&amp;</span>path)
<a href=#627 id=627 data-nosnippet>627</a> .output()
<a href=#628 id=628 data-nosnippet>628</a> .unwrap();
<a href=#629 id=629 data-nosnippet>629</a>
<a href=#630 id=630 data-nosnippet>630</a> <span class="macro">assert!</span>(
<a href=#631 id=631 data-nosnippet>631</a> output.status.success(),
<a href=#632 id=632 data-nosnippet>632</a> <span class="string">"child lock test failed\nstdout:\n{}\nstderr:\n{}"</span>,
<a href=#633 id=633 data-nosnippet>633</a> String::from_utf8_lossy(<span class="kw-2">&amp;</span>output.stdout),
<a href=#634 id=634 data-nosnippet>634</a> String::from_utf8_lossy(<span class="kw-2">&amp;</span>output.stderr)
<a href=#635 id=635 data-nosnippet>635</a> );
<a href=#636 id=636 data-nosnippet>636</a> <span class="kw">let </span>stdout = String::from_utf8_lossy(<span class="kw-2">&amp;</span>output.stdout);
<a href=#637 id=637 data-nosnippet>637</a> <span class="macro">assert!</span>(
<a href=#638 id=638 data-nosnippet>638</a> stdout.contains(<span class="string">"1 passed"</span>),
<a href=#639 id=639 data-nosnippet>639</a> <span class="string">"child lock test did not run the expected ignored test\nstdout:\n{stdout}"
<a href=#640 id=640 data-nosnippet>640</a> </span>);
<a href=#641 id=641 data-nosnippet>641</a> }
<a href=#642 id=642 data-nosnippet>642</a>
<a href=#643 id=643 data-nosnippet>643</a> <span class="attr">#[test]
<a href=#644 id=644 data-nosnippet>644</a> #[ignore = <span class="string">"spawned by test_try_acquire_import_state_lock_rejects_second_holder"</span>]
<a href=#645 id=645 data-nosnippet>645</a> </span><span class="kw">fn </span>test_try_acquire_import_state_lock_child_process() {
<a href=#646 id=646 data-nosnippet>646</a> <span class="kw">let </span>path = std::env::var_os(CHILD_LOCK_PATH_ENV)
<a href=#647 id=647 data-nosnippet>647</a> .expect(<span class="string">"child lock path must be set by the parent test"</span>);
<a href=#648 id=648 data-nosnippet>648</a> <span class="kw">let </span>path = PathBuf::from(path);
<a href=#649 id=649 data-nosnippet>649</a> <span class="kw">let </span>error = try_acquire_import_state_lock(<span class="kw-2">&amp;</span>path).unwrap_err();
<a href=#650 id=650 data-nosnippet>650</a>
<a href=#651 id=651 data-nosnippet>651</a> <span class="macro">assert!</span>(<span class="macro">matches!</span>(
<a href=#652 id=652 data-nosnippet>652</a> error,
<a href=#653 id=653 data-nosnippet>653</a> <span class="kw">crate</span>::data::import_v2::error::Error::ImportStateLocked { .. }
<a href=#654 id=654 data-nosnippet>654</a> ));
<a href=#655 id=655 data-nosnippet>655</a> }
<a href=#656 id=656 data-nosnippet>656</a>
<a href=#657 id=657 data-nosnippet>657</a> <span class="attr">#[tokio::test]
<a href=#658 id=658 data-nosnippet>658</a> </span><span class="kw">async fn </span>test_delete_import_state_ignores_missing_file() {
<a href=#659 id=659 data-nosnippet>659</a> <span class="kw">let </span>dir = tempdir().unwrap();
<a href=#660 id=660 data-nosnippet>660</a> <span class="kw">let </span>path = dir.path().join(<span class="string">"missing.json"</span>);
<a href=#661 id=661 data-nosnippet>661</a>
<a href=#662 id=662 data-nosnippet>662</a> delete_import_state(<span class="kw-2">&amp;</span>path).<span class="kw">await</span>.unwrap();
<a href=#663 id=663 data-nosnippet>663</a> }
<a href=#664 id=664 data-nosnippet>664</a>
<a href=#665 id=665 data-nosnippet>665</a> <span class="attr">#[test]
<a href=#666 id=666 data-nosnippet>666</a> </span><span class="kw">fn </span>test_default_state_path_prefers_home_and_encodes_snapshot_id() {
<a href=#667 id=667 data-nosnippet>667</a> <span class="kw">let </span>home = tempdir().unwrap();
<a href=#668 id=668 data-nosnippet>668</a> <span class="kw">let </span>cwd = tempdir().unwrap();
<a href=#669 id=669 data-nosnippet>669</a>
<a href=#670 id=670 data-nosnippet>670</a> <span class="kw">let </span>path = default_state_path_with(
<a href=#671 id=671 data-nosnippet>671</a> <span class="prelude-val">Some</span>(home.path()),
<a href=#672 id=672 data-nosnippet>672</a> <span class="prelude-val">Some</span>(cwd.path()),
<a href=#673 id=673 data-nosnippet>673</a> <span class="string">"../snapshot"</span>,
<a href=#674 id=674 data-nosnippet>674</a> <span class="string">"127.0.0.1:4000"</span>,
<a href=#675 id=675 data-nosnippet>675</a> <span class="string">"greptime"</span>,
<a href=#676 id=676 data-nosnippet>676</a> <span class="kw-2">&amp;</span>schemas(),
<a href=#677 id=677 data-nosnippet>677</a> )
<a href=#678 id=678 data-nosnippet>678</a> .unwrap();
<a href=#679 id=679 data-nosnippet>679</a>
<a href=#680 id=680 data-nosnippet>680</a> <span class="macro">assert_eq!</span>(
<a href=#681 id=681 data-nosnippet>681</a> path.parent().unwrap(),
<a href=#682 id=682 data-nosnippet>682</a> home.path().join(IMPORT_STATE_ROOT).join(IMPORT_STATE_DIR)
<a href=#683 id=683 data-nosnippet>683</a> );
<a href=#684 id=684 data-nosnippet>684</a> <span class="kw">let </span>file_name = path.file_name().unwrap().to_string_lossy();
<a href=#685 id=685 data-nosnippet>685</a> <span class="macro">assert!</span>(file_name.starts_with(<span class="string">".import_state_%2E%2E%2Fsnapshot_127%2E0%2E0%2E1%3A4000_"</span>));
<a href=#686 id=686 data-nosnippet>686</a> <span class="macro">assert!</span>(file_name.ends_with(<span class="string">".json"</span>));
<a href=#687 id=687 data-nosnippet>687</a> }
<a href=#688 id=688 data-nosnippet>688</a>
<a href=#689 id=689 data-nosnippet>689</a> <span class="attr">#[test]
<a href=#690 id=690 data-nosnippet>690</a> </span><span class="kw">fn </span>test_default_state_path_falls_back_to_cwd_when_home_missing() {
<a href=#691 id=691 data-nosnippet>691</a> <span class="kw">let </span>cwd = tempdir().unwrap();
<a href=#692 id=692 data-nosnippet>692</a>
<a href=#693 id=693 data-nosnippet>693</a> <span class="kw">let </span>path = default_state_path_with(
<a href=#694 id=694 data-nosnippet>694</a> <span class="prelude-val">None</span>,
<a href=#695 id=695 data-nosnippet>695</a> <span class="prelude-val">Some</span>(cwd.path()),
<a href=#696 id=696 data-nosnippet>696</a> <span class="string">"snapshot-1"</span>,
<a href=#697 id=697 data-nosnippet>697</a> <span class="string">"target-a"</span>,
<a href=#698 id=698 data-nosnippet>698</a> <span class="string">"greptime"</span>,
<a href=#699 id=699 data-nosnippet>699</a> <span class="kw-2">&amp;</span>schemas(),
<a href=#700 id=700 data-nosnippet>700</a> )
<a href=#701 id=701 data-nosnippet>701</a> .unwrap();
<a href=#702 id=702 data-nosnippet>702</a>
<a href=#703 id=703 data-nosnippet>703</a> <span class="macro">assert_eq!</span>(path.parent().unwrap(), cwd.path());
<a href=#704 id=704 data-nosnippet>704</a> <span class="kw">let </span>file_name = path.file_name().unwrap().to_string_lossy();
<a href=#705 id=705 data-nosnippet>705</a> <span class="macro">assert!</span>(file_name.starts_with(<span class="string">".import_state_snapshot-1_target-a_"</span>));
<a href=#706 id=706 data-nosnippet>706</a> <span class="macro">assert!</span>(file_name.ends_with(<span class="string">".json"</span>));
<a href=#707 id=707 data-nosnippet>707</a> }
<a href=#708 id=708 data-nosnippet>708</a>
<a href=#709 id=709 data-nosnippet>709</a> <span class="attr">#[test]
<a href=#710 id=710 data-nosnippet>710</a> </span><span class="kw">fn </span>test_default_state_path_isolated_by_target_addr() {
<a href=#711 id=711 data-nosnippet>711</a> <span class="kw">let </span>cwd = tempdir().unwrap();
<a href=#712 id=712 data-nosnippet>712</a>
<a href=#713 id=713 data-nosnippet>713</a> <span class="kw">let </span>first = default_state_path_with(
<a href=#714 id=714 data-nosnippet>714</a> <span class="prelude-val">None</span>,
<a href=#715 id=715 data-nosnippet>715</a> <span class="prelude-val">Some</span>(cwd.path()),
<a href=#716 id=716 data-nosnippet>716</a> <span class="string">"snapshot-1"</span>,
<a href=#717 id=717 data-nosnippet>717</a> <span class="string">"127.0.0.1:4000"</span>,
<a href=#718 id=718 data-nosnippet>718</a> <span class="string">"greptime"</span>,
<a href=#719 id=719 data-nosnippet>719</a> <span class="kw-2">&amp;</span>schemas(),
<a href=#720 id=720 data-nosnippet>720</a> )
<a href=#721 id=721 data-nosnippet>721</a> .unwrap();
<a href=#722 id=722 data-nosnippet>722</a> <span class="kw">let </span>second = default_state_path_with(
<a href=#723 id=723 data-nosnippet>723</a> <span class="prelude-val">None</span>,
<a href=#724 id=724 data-nosnippet>724</a> <span class="prelude-val">Some</span>(cwd.path()),
<a href=#725 id=725 data-nosnippet>725</a> <span class="string">"snapshot-1"</span>,
<a href=#726 id=726 data-nosnippet>726</a> <span class="string">"127.0.0.1:4001"</span>,
<a href=#727 id=727 data-nosnippet>727</a> <span class="string">"greptime"</span>,
<a href=#728 id=728 data-nosnippet>728</a> <span class="kw-2">&amp;</span>schemas(),
<a href=#729 id=729 data-nosnippet>729</a> )
<a href=#730 id=730 data-nosnippet>730</a> .unwrap();
<a href=#731 id=731 data-nosnippet>731</a>
<a href=#732 id=732 data-nosnippet>732</a> <span class="macro">assert_ne!</span>(first, second);
<a href=#733 id=733 data-nosnippet>733</a> }
<a href=#734 id=734 data-nosnippet>734</a>
<a href=#735 id=735 data-nosnippet>735</a> <span class="attr">#[test]
<a href=#736 id=736 data-nosnippet>736</a> </span><span class="kw">fn </span>test_default_state_path_isolated_by_catalog_and_schemas() {
<a href=#737 id=737 data-nosnippet>737</a> <span class="kw">let </span>cwd = tempdir().unwrap();
<a href=#738 id=738 data-nosnippet>738</a> <span class="kw">let </span>public_only = <span class="macro">vec!</span>[<span class="string">"public"</span>.to_string()];
<a href=#739 id=739 data-nosnippet>739</a> <span class="kw">let </span>analytics_only = <span class="macro">vec!</span>[<span class="string">"analytics"</span>.to_string()];
<a href=#740 id=740 data-nosnippet>740</a>
<a href=#741 id=741 data-nosnippet>741</a> <span class="kw">let </span>first = default_state_path_with(
<a href=#742 id=742 data-nosnippet>742</a> <span class="prelude-val">None</span>,
<a href=#743 id=743 data-nosnippet>743</a> <span class="prelude-val">Some</span>(cwd.path()),
<a href=#744 id=744 data-nosnippet>744</a> <span class="string">"snapshot-1"</span>,
<a href=#745 id=745 data-nosnippet>745</a> <span class="string">"127.0.0.1:4000"</span>,
<a href=#746 id=746 data-nosnippet>746</a> <span class="string">"greptime"</span>,
<a href=#747 id=747 data-nosnippet>747</a> <span class="kw-2">&amp;</span>public_only,
<a href=#748 id=748 data-nosnippet>748</a> )
<a href=#749 id=749 data-nosnippet>749</a> .unwrap();
<a href=#750 id=750 data-nosnippet>750</a> <span class="kw">let </span>second = default_state_path_with(
<a href=#751 id=751 data-nosnippet>751</a> <span class="prelude-val">None</span>,
<a href=#752 id=752 data-nosnippet>752</a> <span class="prelude-val">Some</span>(cwd.path()),
<a href=#753 id=753 data-nosnippet>753</a> <span class="string">"snapshot-1"</span>,
<a href=#754 id=754 data-nosnippet>754</a> <span class="string">"127.0.0.1:4000"</span>,
<a href=#755 id=755 data-nosnippet>755</a> <span class="string">"other"</span>,
<a href=#756 id=756 data-nosnippet>756</a> <span class="kw-2">&amp;</span>public_only,
<a href=#757 id=757 data-nosnippet>757</a> )
<a href=#758 id=758 data-nosnippet>758</a> .unwrap();
<a href=#759 id=759 data-nosnippet>759</a> <span class="kw">let </span>third = default_state_path_with(
<a href=#760 id=760 data-nosnippet>760</a> <span class="prelude-val">None</span>,
<a href=#761 id=761 data-nosnippet>761</a> <span class="prelude-val">Some</span>(cwd.path()),
<a href=#762 id=762 data-nosnippet>762</a> <span class="string">"snapshot-1"</span>,
<a href=#763 id=763 data-nosnippet>763</a> <span class="string">"127.0.0.1:4000"</span>,
<a href=#764 id=764 data-nosnippet>764</a> <span class="string">"greptime"</span>,
<a href=#765 id=765 data-nosnippet>765</a> <span class="kw-2">&amp;</span>analytics_only,
<a href=#766 id=766 data-nosnippet>766</a> )
<a href=#767 id=767 data-nosnippet>767</a> .unwrap();
<a href=#768 id=768 data-nosnippet>768</a>
<a href=#769 id=769 data-nosnippet>769</a> <span class="macro">assert_ne!</span>(first, second);
<a href=#770 id=770 data-nosnippet>770</a> <span class="macro">assert_ne!</span>(first, third);
<a href=#771 id=771 data-nosnippet>771</a> }
<a href=#772 id=772 data-nosnippet>772</a>
<a href=#773 id=773 data-nosnippet>773</a> <span class="attr">#[test]
<a href=#774 id=774 data-nosnippet>774</a> </span><span class="kw">fn </span>test_default_home_dir_prefers_home() {
<a href=#775 id=775 data-nosnippet>775</a> <span class="kw">let </span>detected = default_home_dir_with(|key| <span class="kw">match </span>key {
<a href=#776 id=776 data-nosnippet>776</a> <span class="string">"HOME" </span>=&gt; <span class="prelude-val">Some</span>(std::ffi::OsString::from(<span class="string">"/tmp/home"</span>)),
<a href=#777 id=777 data-nosnippet>777</a> <span class="string">"USERPROFILE" </span>=&gt; <span class="prelude-val">Some</span>(std::ffi::OsString::from(<span class="string">"/tmp/userprofile"</span>)),
<a href=#778 id=778 data-nosnippet>778</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
<a href=#779 id=779 data-nosnippet>779</a> });
<a href=#780 id=780 data-nosnippet>780</a>
<a href=#781 id=781 data-nosnippet>781</a> <span class="macro">assert_eq!</span>(detected, <span class="prelude-val">Some</span>(PathBuf::from(<span class="string">"/tmp/home"</span>)));
<a href=#782 id=782 data-nosnippet>782</a> }
<a href=#783 id=783 data-nosnippet>783</a>
<a href=#784 id=784 data-nosnippet>784</a> <span class="attr">#[test]
<a href=#785 id=785 data-nosnippet>785</a> </span><span class="kw">fn </span>test_default_home_dir_falls_back_to_userprofile() {
<a href=#786 id=786 data-nosnippet>786</a> <span class="kw">let </span>detected = default_home_dir_with(|key| <span class="kw">match </span>key {
<a href=#787 id=787 data-nosnippet>787</a> <span class="string">"USERPROFILE" </span>=&gt; <span class="prelude-val">Some</span>(std::ffi::OsString::from(<span class="string">"/tmp/userprofile"</span>)),
<a href=#788 id=788 data-nosnippet>788</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
<a href=#789 id=789 data-nosnippet>789</a> });
<a href=#790 id=790 data-nosnippet>790</a>
<a href=#791 id=791 data-nosnippet>791</a> <span class="macro">assert_eq!</span>(detected, <span class="prelude-val">Some</span>(PathBuf::from(<span class="string">"/tmp/userprofile"</span>)));
<a href=#792 id=792 data-nosnippet>792</a> }
<a href=#793 id=793 data-nosnippet>793</a>
<a href=#794 id=794 data-nosnippet>794</a> <span class="attr">#[test]
<a href=#795 id=795 data-nosnippet>795</a> </span><span class="kw">fn </span>test_default_home_dir_falls_back_to_home_drive_and_path() {
<a href=#796 id=796 data-nosnippet>796</a> <span class="kw">let </span>detected = default_home_dir_with(|key| <span class="kw">match </span>key {
<a href=#797 id=797 data-nosnippet>797</a> <span class="string">"HOMEDRIVE" </span>=&gt; <span class="prelude-val">Some</span>(std::ffi::OsString::from(<span class="string">"/tmp"</span>)),
<a href=#798 id=798 data-nosnippet>798</a> <span class="string">"HOMEPATH" </span>=&gt; <span class="prelude-val">Some</span>(std::ffi::OsString::from(<span class="string">"windows-home"</span>)),
<a href=#799 id=799 data-nosnippet>799</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
<a href=#800 id=800 data-nosnippet>800</a> });
<a href=#801 id=801 data-nosnippet>801</a>
<a href=#802 id=802 data-nosnippet>802</a> <span class="macro">assert_eq!</span>(detected, <span class="prelude-val">Some</span>(PathBuf::from(<span class="string">"/tmp"</span>).join(<span class="string">"windows-home"</span>)));
<a href=#803 id=803 data-nosnippet>803</a> }
<a href=#804 id=804 data-nosnippet>804</a>}
</code></pre></div></section></main></body></html>
+90
View File
@@ -0,0 +1,90 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/path.rs`."><title>path.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/</div>path.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! Shared path helpers for export/import data files.
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a></span><span class="kw">use </span><span class="kw">crate</span>::data::export_v2::schema::{DDL_DIR, SCHEMA_DIR};
<a href=#18 id=18 data-nosnippet>18</a>
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>ddl_path_for_schema(schema: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#20 id=20 data-nosnippet>20</a> <span class="macro">format!</span>(
<a href=#21 id=21 data-nosnippet>21</a> <span class="string">"{}/{}/{}.sql"</span>,
<a href=#22 id=22 data-nosnippet>22</a> SCHEMA_DIR,
<a href=#23 id=23 data-nosnippet>23</a> DDL_DIR,
<a href=#24 id=24 data-nosnippet>24</a> encode_path_segment(schema)
<a href=#25 id=25 data-nosnippet>25</a> )
<a href=#26 id=26 data-nosnippet>26</a>}
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>data_dir_for_schema_chunk(schema: <span class="kw-2">&amp;</span>str, chunk_id: u32) -&gt; String {
<a href=#29 id=29 data-nosnippet>29</a> <span class="macro">format!</span>(<span class="string">"data/{}/{}/"</span>, encode_path_segment(schema), chunk_id)
<a href=#30 id=30 data-nosnippet>30</a>}
<a href=#31 id=31 data-nosnippet>31</a>
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>encode_path_segment(value: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#33 id=33 data-nosnippet>33</a> <span class="kw">let </span><span class="kw-2">mut </span>encoded = String::with_capacity(value.len());
<a href=#34 id=34 data-nosnippet>34</a> <span class="kw">for </span>byte <span class="kw">in </span>value.bytes() {
<a href=#35 id=35 data-nosnippet>35</a> <span class="kw">match </span>byte {
<a href=#36 id=36 data-nosnippet>36</a> <span class="string">b'A'</span>..=<span class="string">b'Z' </span>| <span class="string">b'a'</span>..=<span class="string">b'z' </span>| <span class="string">b'0'</span>..=<span class="string">b'9' </span>| <span class="string">b'-' </span>| <span class="string">b'_' </span>=&gt; {
<a href=#37 id=37 data-nosnippet>37</a> encoded.push(byte <span class="kw">as </span>char);
<a href=#38 id=38 data-nosnippet>38</a> }
<a href=#39 id=39 data-nosnippet>39</a> <span class="kw">_ </span>=&gt; {
<a href=#40 id=40 data-nosnippet>40</a> encoded.push(<span class="string">'%'</span>);
<a href=#41 id=41 data-nosnippet>41</a> encoded.push(hex_char(byte &gt;&gt; <span class="number">4</span>));
<a href=#42 id=42 data-nosnippet>42</a> encoded.push(hex_char(byte &amp; <span class="number">0x0F</span>));
<a href=#43 id=43 data-nosnippet>43</a> }
<a href=#44 id=44 data-nosnippet>44</a> }
<a href=#45 id=45 data-nosnippet>45</a> }
<a href=#46 id=46 data-nosnippet>46</a> encoded
<a href=#47 id=47 data-nosnippet>47</a>}
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">fn </span>hex_char(nibble: u8) -&gt; char {
<a href=#50 id=50 data-nosnippet>50</a> <span class="kw">match </span>nibble {
<a href=#51 id=51 data-nosnippet>51</a> <span class="number">0</span>..=<span class="number">9 </span>=&gt; (<span class="string">b'0' </span>+ nibble) <span class="kw">as </span>char,
<a href=#52 id=52 data-nosnippet>52</a> <span class="number">10</span>..=<span class="number">15 </span>=&gt; (<span class="string">b'A' </span>+ (nibble - <span class="number">10</span>)) <span class="kw">as </span>char,
<a href=#53 id=53 data-nosnippet>53</a> <span class="kw">_ </span>=&gt; <span class="macro">unreachable!</span>(<span class="string">"nibble must be in 0..=15"</span>),
<a href=#54 id=54 data-nosnippet>54</a> }
<a href=#55 id=55 data-nosnippet>55</a>}
<a href=#56 id=56 data-nosnippet>56</a>
<a href=#57 id=57 data-nosnippet>57</a><span class="attr">#[cfg(test)]
<a href=#58 id=58 data-nosnippet>58</a></span><span class="kw">mod </span>tests {
<a href=#59 id=59 data-nosnippet>59</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#60 id=60 data-nosnippet>60</a>
<a href=#61 id=61 data-nosnippet>61</a> <span class="attr">#[test]
<a href=#62 id=62 data-nosnippet>62</a> </span><span class="kw">fn </span>test_encode_path_segment_preserves_safe_ascii() {
<a href=#63 id=63 data-nosnippet>63</a> <span class="macro">assert_eq!</span>(encode_path_segment(<span class="string">"test_db"</span>), <span class="string">"test_db"</span>);
<a href=#64 id=64 data-nosnippet>64</a> }
<a href=#65 id=65 data-nosnippet>65</a>
<a href=#66 id=66 data-nosnippet>66</a> <span class="attr">#[test]
<a href=#67 id=67 data-nosnippet>67</a> </span><span class="kw">fn </span>test_encode_path_segment_escapes_path_traversal_chars() {
<a href=#68 id=68 data-nosnippet>68</a> <span class="macro">assert_eq!</span>(encode_path_segment(<span class="string">"../evil"</span>), <span class="string">"%2E%2E%2Fevil"</span>);
<a href=#69 id=69 data-nosnippet>69</a> <span class="macro">assert_eq!</span>(encode_path_segment(<span class="string">r"..\\evil"</span>), <span class="string">"%2E%2E%5C%5Cevil"</span>);
<a href=#70 id=70 data-nosnippet>70</a> }
<a href=#71 id=71 data-nosnippet>71</a>
<a href=#72 id=72 data-nosnippet>72</a> <span class="attr">#[test]
<a href=#73 id=73 data-nosnippet>73</a> </span><span class="kw">fn </span>test_ddl_path_for_schema_encodes_schema_segment() {
<a href=#74 id=74 data-nosnippet>74</a> <span class="macro">assert_eq!</span>(ddl_path_for_schema(<span class="string">"public"</span>), <span class="string">"schema/ddl/public.sql"</span>);
<a href=#75 id=75 data-nosnippet>75</a> <span class="macro">assert_eq!</span>(
<a href=#76 id=76 data-nosnippet>76</a> ddl_path_for_schema(<span class="string">"../evil"</span>),
<a href=#77 id=77 data-nosnippet>77</a> <span class="string">"schema/ddl/%2E%2E%2Fevil.sql"
<a href=#78 id=78 data-nosnippet>78</a> </span>);
<a href=#79 id=79 data-nosnippet>79</a> }
<a href=#80 id=80 data-nosnippet>80</a>
<a href=#81 id=81 data-nosnippet>81</a> <span class="attr">#[test]
<a href=#82 id=82 data-nosnippet>82</a> </span><span class="kw">fn </span>test_data_dir_for_schema_chunk_encodes_schema_segment() {
<a href=#83 id=83 data-nosnippet>83</a> <span class="macro">assert_eq!</span>(data_dir_for_schema_chunk(<span class="string">"public"</span>, <span class="number">1</span>), <span class="string">"data/public/1/"</span>);
<a href=#84 id=84 data-nosnippet>84</a> <span class="macro">assert_eq!</span>(
<a href=#85 id=85 data-nosnippet>85</a> data_dir_for_schema_chunk(<span class="string">"../evil"</span>, <span class="number">7</span>),
<a href=#86 id=86 data-nosnippet>86</a> <span class="string">"data/%2E%2E%2Fevil/7/"
<a href=#87 id=87 data-nosnippet>87</a> </span>);
<a href=#88 id=88 data-nosnippet>88</a> }
<a href=#89 id=89 data-nosnippet>89</a>}
</code></pre></div></section></main></body></html>
+457
View File
@@ -0,0 +1,457 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/progress.rs`."><title>progress.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/</div>progress.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! Minimal internal progress abstraction for Export/Import V2.
<a href=#16 id=16 data-nosnippet>16</a>//!
<a href=#17 id=17 data-nosnippet>17</a>//! This is intentionally small and log/internal oriented. It does not touch
<a href=#18 id=18 data-nosnippet>18</a>//! stdout and is safe for non-interactive runs. [`LogProgress`] backs the
<a href=#19 id=19 data-nosnippet>19</a>//! import-v2 `--progress` flag for non-interactive runs by routing events to
<a href=#20 id=20 data-nosnippet>20</a>//! stderr, while [`IndicatifProgress`] renders an interactive bar on a TTY.
<a href=#21 id=21 data-nosnippet>21</a>//! Both implement [`ProgressReporter`], so call sites stay agnostic.
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a></span><span class="kw">use </span>std::io::{<span class="self">self</span>, IsTerminal, Write};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>std::sync::Mutex;
<a href=#25 id=25 data-nosnippet>25</a>
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="doccomment">/// Controls progress reporting for Export/Import V2.
<a href=#29 id=29 data-nosnippet>29</a>///
<a href=#30 id=30 data-nosnippet>30</a>/// `auto` shows an interactive bar only on a TTY and falls back to lightweight
<a href=#31 id=31 data-nosnippet>31</a>/// log progress otherwise; `always` always emits progress, using the bar on a
<a href=#32 id=32 data-nosnippet>32</a>/// TTY and lightweight logs otherwise; `never` is silent.
<a href=#33 id=33 data-nosnippet>33</a></span><span class="attr">#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, clap::ValueEnum)]
<a href=#34 id=34 data-nosnippet>34</a>#[value(rename_all = <span class="string">"lowercase"</span>)]
<a href=#35 id=35 data-nosnippet>35</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">enum </span>ProgressMode {
<a href=#36 id=36 data-nosnippet>36</a> <span class="doccomment">/// Show an interactive bar on a TTY, otherwise log progress.
<a href=#37 id=37 data-nosnippet>37</a> </span><span class="attr">#[default]
<a href=#38 id=38 data-nosnippet>38</a> </span>Auto,
<a href=#39 id=39 data-nosnippet>39</a> <span class="doccomment">/// Always emit progress: a bar on TTY, lightweight logs otherwise.
<a href=#40 id=40 data-nosnippet>40</a> </span>Always,
<a href=#41 id=41 data-nosnippet>41</a> <span class="doccomment">/// Never emit progress.
<a href=#42 id=42 data-nosnippet>42</a> </span>Never,
<a href=#43 id=43 data-nosnippet>43</a>}
<a href=#44 id=44 data-nosnippet>44</a>
<a href=#45 id=45 data-nosnippet>45</a><span class="attr">#[derive(Debug, Clone, Copy, PartialEq, Eq)]
<a href=#46 id=46 data-nosnippet>46</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">enum </span>ProgressOutputKind {
<a href=#47 id=47 data-nosnippet>47</a> Bar,
<a href=#48 id=48 data-nosnippet>48</a> Log,
<a href=#49 id=49 data-nosnippet>49</a> Silent,
<a href=#50 id=50 data-nosnippet>50</a>}
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a><span class="doccomment">/// Selects the progress output style for `mode` given whether stderr is a TTY
<a href=#53 id=53 data-nosnippet>53</a>/// and whether the terminal environment is suitable for progress-bar control
<a href=#54 id=54 data-nosnippet>54</a>/// sequences.
<a href=#55 id=55 data-nosnippet>55</a>///
<a href=#56 id=56 data-nosnippet>56</a>/// The interactive `indicatif` stderr target hides itself when redirected or
<a href=#57 id=57 data-nosnippet>57</a>/// when the terminal is not user-attended, so forced progress falls back to
<a href=#58 id=58 data-nosnippet>58</a>/// [`LogProgress`] instead of a hidden bar in those cases.
<a href=#59 id=59 data-nosnippet>59</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>progress_output_kind(
<a href=#60 id=60 data-nosnippet>60</a> mode: ProgressMode,
<a href=#61 id=61 data-nosnippet>61</a> stderr_is_tty: bool,
<a href=#62 id=62 data-nosnippet>62</a> term_supports_progress_bar: bool,
<a href=#63 id=63 data-nosnippet>63</a>) -&gt; ProgressOutputKind {
<a href=#64 id=64 data-nosnippet>64</a> <span class="kw">let </span>can_show_bar = stderr_is_tty &amp;&amp; term_supports_progress_bar;
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">match </span>mode {
<a href=#66 id=66 data-nosnippet>66</a> ProgressMode::Never =&gt; ProgressOutputKind::Silent,
<a href=#67 id=67 data-nosnippet>67</a> ProgressMode::Always <span class="kw">if </span>can_show_bar =&gt; ProgressOutputKind::Bar,
<a href=#68 id=68 data-nosnippet>68</a> ProgressMode::Always =&gt; ProgressOutputKind::Log,
<a href=#69 id=69 data-nosnippet>69</a> ProgressMode::Auto <span class="kw">if </span>can_show_bar =&gt; ProgressOutputKind::Bar,
<a href=#70 id=70 data-nosnippet>70</a> ProgressMode::Auto =&gt; ProgressOutputKind::Log,
<a href=#71 id=71 data-nosnippet>71</a> }
<a href=#72 id=72 data-nosnippet>72</a>}
<a href=#73 id=73 data-nosnippet>73</a>
<a href=#74 id=74 data-nosnippet>74</a><span class="kw">fn </span>progress_bar_supported(term: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>std::ffi::OsStr&gt;, no_color: bool) -&gt; bool {
<a href=#75 id=75 data-nosnippet>75</a> <span class="kw">if </span>no_color {
<a href=#76 id=76 data-nosnippet>76</a> <span class="kw">return </span><span class="bool-val">false</span>;
<a href=#77 id=77 data-nosnippet>77</a> }
<a href=#78 id=78 data-nosnippet>78</a>
<a href=#79 id=79 data-nosnippet>79</a> term.map(|term| !term.is_empty() &amp;&amp; term != <span class="string">"dumb"</span>)
<a href=#80 id=80 data-nosnippet>80</a> .unwrap_or(<span class="bool-val">false</span>)
<a href=#81 id=81 data-nosnippet>81</a>}
<a href=#82 id=82 data-nosnippet>82</a>
<a href=#83 id=83 data-nosnippet>83</a><span class="kw">fn </span>term_supports_progress_bar() -&gt; bool {
<a href=#84 id=84 data-nosnippet>84</a> progress_bar_supported(
<a href=#85 id=85 data-nosnippet>85</a> std::env::var_os(<span class="string">"TERM"</span>).as_deref(),
<a href=#86 id=86 data-nosnippet>86</a> std::env::var_os(<span class="string">"NO_COLOR"</span>).is_some(),
<a href=#87 id=87 data-nosnippet>87</a> )
<a href=#88 id=88 data-nosnippet>88</a>}
<a href=#89 id=89 data-nosnippet>89</a>
<a href=#90 id=90 data-nosnippet>90</a><span class="doccomment">/// Builds the progress reporter for `mode`. `never` is silent; otherwise an
<a href=#91 id=91 data-nosnippet>91</a>/// interactive bar is used on TTY stderr, falling back to lightweight log
<a href=#92 id=92 data-nosnippet>92</a>/// progress when stderr is redirected.
<a href=#93 id=93 data-nosnippet>93</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>build_progress_reporter(mode: ProgressMode) -&gt; Box&lt;<span class="kw">dyn </span>ProgressReporter&gt; {
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">match </span>progress_output_kind(
<a href=#95 id=95 data-nosnippet>95</a> mode,
<a href=#96 id=96 data-nosnippet>96</a> std::io::stderr().is_terminal(),
<a href=#97 id=97 data-nosnippet>97</a> term_supports_progress_bar(),
<a href=#98 id=98 data-nosnippet>98</a> ) {
<a href=#99 id=99 data-nosnippet>99</a> ProgressOutputKind::Bar =&gt; Box::new(IndicatifProgress::new()),
<a href=#100 id=100 data-nosnippet>100</a> ProgressOutputKind::Log =&gt; Box::new(LogProgress::new()),
<a href=#101 id=101 data-nosnippet>101</a> ProgressOutputKind::Silent =&gt; Box::new(NoopProgress),
<a href=#102 id=102 data-nosnippet>102</a> }
<a href=#103 id=103 data-nosnippet>103</a>}
<a href=#104 id=104 data-nosnippet>104</a>
<a href=#105 id=105 data-nosnippet>105</a><span class="doccomment">/// Receives progress events from long-running Export/Import V2 work.
<a href=#106 id=106 data-nosnippet>106</a>///
<a href=#107 id=107 data-nosnippet>107</a>/// The trait is object-safe so callers can take `&amp;dyn ProgressReporter` and stay
<a href=#108 id=108 data-nosnippet>108</a>/// agnostic about the concrete implementation (no-op in production today, a
<a href=#109 id=109 data-nosnippet>109</a>/// recording fake in tests).
<a href=#110 id=110 data-nosnippet>110</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">trait </span>ProgressReporter: Send + Sync {
<a href=#111 id=111 data-nosnippet>111</a> <span class="doccomment">/// Begins a phase with an optional known total number of units.
<a href=#112 id=112 data-nosnippet>112</a> </span><span class="kw">fn </span>start_phase(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str, total: <span class="prelude-ty">Option</span>&lt;u64&gt;);
<a href=#113 id=113 data-nosnippet>113</a>
<a href=#114 id=114 data-nosnippet>114</a> <span class="doccomment">/// Advances the current phase by `delta` units.
<a href=#115 id=115 data-nosnippet>115</a> </span><span class="kw">fn </span>inc(<span class="kw-2">&amp;</span><span class="self">self</span>, delta: u64);
<a href=#116 id=116 data-nosnippet>116</a>
<a href=#117 id=117 data-nosnippet>117</a> <span class="doccomment">/// Marks the current phase as finished.
<a href=#118 id=118 data-nosnippet>118</a> </span><span class="kw">fn </span>finish_phase(<span class="kw-2">&amp;</span><span class="self">self</span>);
<a href=#119 id=119 data-nosnippet>119</a>}
<a href=#120 id=120 data-nosnippet>120</a>
<a href=#121 id=121 data-nosnippet>121</a><span class="doccomment">/// A reporter that discards every event. Used as the production default and in
<a href=#122 id=122 data-nosnippet>122</a>/// tests that do not care about progress.
<a href=#123 id=123 data-nosnippet>123</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>NoopProgress;
<a href=#124 id=124 data-nosnippet>124</a>
<a href=#125 id=125 data-nosnippet>125</a><span class="kw">impl </span>ProgressReporter <span class="kw">for </span>NoopProgress {
<a href=#126 id=126 data-nosnippet>126</a> <span class="kw">fn </span>start_phase(<span class="kw-2">&amp;</span><span class="self">self</span>, _name: <span class="kw-2">&amp;</span>str, _total: <span class="prelude-ty">Option</span>&lt;u64&gt;) {}
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw">fn </span>inc(<span class="kw-2">&amp;</span><span class="self">self</span>, _delta: u64) {}
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw">fn </span>finish_phase(<span class="kw-2">&amp;</span><span class="self">self</span>) {}
<a href=#129 id=129 data-nosnippet>129</a>}
<a href=#130 id=130 data-nosnippet>130</a>
<a href=#131 id=131 data-nosnippet>131</a><span class="doccomment">/// A lightweight reporter that logs phase lifecycle and progress through the
<a href=#132 id=132 data-nosnippet>132</a>/// stderr. It never touches stdout, so it is safe for non-interactive runs and
<a href=#133 id=133 data-nosnippet>133</a>/// keeps dry-run output clean.
<a href=#134 id=134 data-nosnippet>134</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>LogProgress {
<a href=#135 id=135 data-nosnippet>135</a> phase: Mutex&lt;<span class="prelude-ty">Option</span>&lt;PhaseState&gt;&gt;,
<a href=#136 id=136 data-nosnippet>136</a>}
<a href=#137 id=137 data-nosnippet>137</a>
<a href=#138 id=138 data-nosnippet>138</a><span class="kw">struct </span>PhaseState {
<a href=#139 id=139 data-nosnippet>139</a> name: String,
<a href=#140 id=140 data-nosnippet>140</a> total: <span class="prelude-ty">Option</span>&lt;u64&gt;,
<a href=#141 id=141 data-nosnippet>141</a> done: u64,
<a href=#142 id=142 data-nosnippet>142</a>}
<a href=#143 id=143 data-nosnippet>143</a>
<a href=#144 id=144 data-nosnippet>144</a><span class="kw">impl </span>LogProgress {
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new() -&gt; <span class="self">Self </span>{
<a href=#146 id=146 data-nosnippet>146</a> <span class="self">Self </span>{
<a href=#147 id=147 data-nosnippet>147</a> phase: Mutex::new(<span class="prelude-val">None</span>),
<a href=#148 id=148 data-nosnippet>148</a> }
<a href=#149 id=149 data-nosnippet>149</a> }
<a href=#150 id=150 data-nosnippet>150</a>}
<a href=#151 id=151 data-nosnippet>151</a>
<a href=#152 id=152 data-nosnippet>152</a><span class="kw">fn </span>write_progress_line(line: String) {
<a href=#153 id=153 data-nosnippet>153</a> <span class="kw">let _ </span>= <span class="macro">writeln!</span>(io::stderr().lock(), <span class="string">"{line}"</span>);
<a href=#154 id=154 data-nosnippet>154</a>}
<a href=#155 id=155 data-nosnippet>155</a>
<a href=#156 id=156 data-nosnippet>156</a><span class="kw">impl </span>ProgressReporter <span class="kw">for </span>LogProgress {
<a href=#157 id=157 data-nosnippet>157</a> <span class="kw">fn </span>start_phase(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str, total: <span class="prelude-ty">Option</span>&lt;u64&gt;) {
<a href=#158 id=158 data-nosnippet>158</a> <span class="kw">let </span><span class="prelude-val">Ok</span>(<span class="kw-2">mut </span>phase) = <span class="self">self</span>.phase.lock() <span class="kw">else </span>{
<a href=#159 id=159 data-nosnippet>159</a> <span class="kw">return</span>;
<a href=#160 id=160 data-nosnippet>160</a> };
<a href=#161 id=161 data-nosnippet>161</a> <span class="kw-2">*</span>phase = <span class="prelude-val">Some</span>(PhaseState {
<a href=#162 id=162 data-nosnippet>162</a> name: name.to_string(),
<a href=#163 id=163 data-nosnippet>163</a> total,
<a href=#164 id=164 data-nosnippet>164</a> done: <span class="number">0</span>,
<a href=#165 id=165 data-nosnippet>165</a> });
<a href=#166 id=166 data-nosnippet>166</a> <span class="kw">match </span>total {
<a href=#167 id=167 data-nosnippet>167</a> <span class="prelude-val">Some</span>(total) =&gt; write_progress_line(<span class="macro">format!</span>(<span class="string">"Starting phase '{name}' ({total} units)"</span>)),
<a href=#168 id=168 data-nosnippet>168</a> <span class="prelude-val">None </span>=&gt; write_progress_line(<span class="macro">format!</span>(<span class="string">"Starting phase '{name}'"</span>)),
<a href=#169 id=169 data-nosnippet>169</a> }
<a href=#170 id=170 data-nosnippet>170</a> }
<a href=#171 id=171 data-nosnippet>171</a>
<a href=#172 id=172 data-nosnippet>172</a> <span class="kw">fn </span>inc(<span class="kw-2">&amp;</span><span class="self">self</span>, delta: u64) {
<a href=#173 id=173 data-nosnippet>173</a> <span class="kw">let </span><span class="prelude-val">Ok</span>(<span class="kw-2">mut </span>guard) = <span class="self">self</span>.phase.lock() <span class="kw">else </span>{
<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">return</span>;
<a href=#175 id=175 data-nosnippet>175</a> };
<a href=#176 id=176 data-nosnippet>176</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(phase) = guard.as_mut() {
<a href=#177 id=177 data-nosnippet>177</a> phase.done += delta;
<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">match </span>phase.total {
<a href=#179 id=179 data-nosnippet>179</a> <span class="prelude-val">Some</span>(total) =&gt; {
<a href=#180 id=180 data-nosnippet>180</a> write_progress_line(<span class="macro">format!</span>(<span class="string">"Phase '{}': {}/{}"</span>, phase.name, phase.done, total))
<a href=#181 id=181 data-nosnippet>181</a> }
<a href=#182 id=182 data-nosnippet>182</a> <span class="prelude-val">None </span>=&gt; write_progress_line(<span class="macro">format!</span>(<span class="string">"Phase '{}': {}"</span>, phase.name, phase.done)),
<a href=#183 id=183 data-nosnippet>183</a> }
<a href=#184 id=184 data-nosnippet>184</a> }
<a href=#185 id=185 data-nosnippet>185</a> }
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">fn </span>finish_phase(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<a href=#188 id=188 data-nosnippet>188</a> <span class="kw">let </span><span class="prelude-val">Ok</span>(<span class="kw-2">mut </span>guard) = <span class="self">self</span>.phase.lock() <span class="kw">else </span>{
<a href=#189 id=189 data-nosnippet>189</a> <span class="kw">return</span>;
<a href=#190 id=190 data-nosnippet>190</a> };
<a href=#191 id=191 data-nosnippet>191</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(phase) = guard.take() {
<a href=#192 id=192 data-nosnippet>192</a> write_progress_line(<span class="macro">format!</span>(
<a href=#193 id=193 data-nosnippet>193</a> <span class="string">"Finished phase '{}' ({} units)"</span>,
<a href=#194 id=194 data-nosnippet>194</a> phase.name, phase.done
<a href=#195 id=195 data-nosnippet>195</a> ));
<a href=#196 id=196 data-nosnippet>196</a> }
<a href=#197 id=197 data-nosnippet>197</a> }
<a href=#198 id=198 data-nosnippet>198</a>}
<a href=#199 id=199 data-nosnippet>199</a>
<a href=#200 id=200 data-nosnippet>200</a><span class="doccomment">/// A reporter that renders an interactive progress bar via `indicatif`.
<a href=#201 id=201 data-nosnippet>201</a>///
<a href=#202 id=202 data-nosnippet>202</a>/// It draws to stderr through an explicit [`ProgressDrawTarget::stderr`] so it
<a href=#203 id=203 data-nosnippet>203</a>/// never collides with stdout (e.g. dry-run SQL). Phases with a known total get
<a href=#204 id=204 data-nosnippet>204</a>/// a determinate bar; unknown totals fall back to an animated spinner. Each
<a href=#205 id=205 data-nosnippet>205</a>/// phase clears itself on finish via [`ProgressBar::finish_and_clear`].
<a href=#206 id=206 data-nosnippet>206</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>IndicatifProgress {
<a href=#207 id=207 data-nosnippet>207</a> bar: Mutex&lt;<span class="prelude-ty">Option</span>&lt;ProgressBar&gt;&gt;,
<a href=#208 id=208 data-nosnippet>208</a>}
<a href=#209 id=209 data-nosnippet>209</a>
<a href=#210 id=210 data-nosnippet>210</a><span class="kw">impl </span>IndicatifProgress {
<a href=#211 id=211 data-nosnippet>211</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>new() -&gt; <span class="self">Self </span>{
<a href=#212 id=212 data-nosnippet>212</a> <span class="self">Self </span>{
<a href=#213 id=213 data-nosnippet>213</a> bar: Mutex::new(<span class="prelude-val">None</span>),
<a href=#214 id=214 data-nosnippet>214</a> }
<a href=#215 id=215 data-nosnippet>215</a> }
<a href=#216 id=216 data-nosnippet>216</a>}
<a href=#217 id=217 data-nosnippet>217</a>
<a href=#218 id=218 data-nosnippet>218</a><span class="kw">impl </span>ProgressReporter <span class="kw">for </span>IndicatifProgress {
<a href=#219 id=219 data-nosnippet>219</a> <span class="kw">fn </span>start_phase(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str, total: <span class="prelude-ty">Option</span>&lt;u64&gt;) {
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">let </span><span class="prelude-val">Ok</span>(<span class="kw-2">mut </span>guard) = <span class="self">self</span>.bar.lock() <span class="kw">else </span>{
<a href=#221 id=221 data-nosnippet>221</a> <span class="kw">return</span>;
<a href=#222 id=222 data-nosnippet>222</a> };
<a href=#223 id=223 data-nosnippet>223</a>
<a href=#224 id=224 data-nosnippet>224</a> <span class="comment">// Replacing any prior phase: clear it before starting the next.
<a href=#225 id=225 data-nosnippet>225</a> </span><span class="kw">if let </span><span class="prelude-val">Some</span>(prev) = guard.take() {
<a href=#226 id=226 data-nosnippet>226</a> prev.finish_and_clear();
<a href=#227 id=227 data-nosnippet>227</a> }
<a href=#228 id=228 data-nosnippet>228</a>
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">let </span>bar = ProgressBar::with_draw_target(total, ProgressDrawTarget::stderr());
<a href=#230 id=230 data-nosnippet>230</a> <span class="kw">match </span>total {
<a href=#231 id=231 data-nosnippet>231</a> <span class="prelude-val">Some</span>(<span class="kw">_</span>) =&gt; {
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">let </span>style =
<a href=#233 id=233 data-nosnippet>233</a> ProgressStyle::with_template(<span class="string">"{msg} [{bar:40}] {pos}/{len} ({percent}%)"</span>)
<a href=#234 id=234 data-nosnippet>234</a> .unwrap_or_else(|<span class="kw">_</span>| ProgressStyle::default_bar())
<a href=#235 id=235 data-nosnippet>235</a> .progress_chars(<span class="string">"=&gt;-"</span>);
<a href=#236 id=236 data-nosnippet>236</a> bar.set_style(style);
<a href=#237 id=237 data-nosnippet>237</a> }
<a href=#238 id=238 data-nosnippet>238</a> <span class="prelude-val">None </span>=&gt; {
<a href=#239 id=239 data-nosnippet>239</a> <span class="kw">let </span>style = ProgressStyle::with_template(<span class="string">"{spinner} {msg} {pos}"</span>)
<a href=#240 id=240 data-nosnippet>240</a> .unwrap_or_else(|<span class="kw">_</span>| ProgressStyle::default_spinner());
<a href=#241 id=241 data-nosnippet>241</a> bar.set_style(style);
<a href=#242 id=242 data-nosnippet>242</a> }
<a href=#243 id=243 data-nosnippet>243</a> }
<a href=#244 id=244 data-nosnippet>244</a> bar.set_message(name.to_string());
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw-2">*</span>guard = <span class="prelude-val">Some</span>(bar);
<a href=#246 id=246 data-nosnippet>246</a> }
<a href=#247 id=247 data-nosnippet>247</a>
<a href=#248 id=248 data-nosnippet>248</a> <span class="kw">fn </span>inc(<span class="kw-2">&amp;</span><span class="self">self</span>, delta: u64) {
<a href=#249 id=249 data-nosnippet>249</a> <span class="kw">let </span><span class="prelude-val">Ok</span>(guard) = <span class="self">self</span>.bar.lock() <span class="kw">else </span>{
<a href=#250 id=250 data-nosnippet>250</a> <span class="kw">return</span>;
<a href=#251 id=251 data-nosnippet>251</a> };
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(bar) = guard.as_ref() {
<a href=#253 id=253 data-nosnippet>253</a> bar.inc(delta);
<a href=#254 id=254 data-nosnippet>254</a> }
<a href=#255 id=255 data-nosnippet>255</a> }
<a href=#256 id=256 data-nosnippet>256</a>
<a href=#257 id=257 data-nosnippet>257</a> <span class="kw">fn </span>finish_phase(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<a href=#258 id=258 data-nosnippet>258</a> <span class="kw">let </span><span class="prelude-val">Ok</span>(<span class="kw-2">mut </span>guard) = <span class="self">self</span>.bar.lock() <span class="kw">else </span>{
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">return</span>;
<a href=#260 id=260 data-nosnippet>260</a> };
<a href=#261 id=261 data-nosnippet>261</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(bar) = guard.take() {
<a href=#262 id=262 data-nosnippet>262</a> bar.finish_and_clear();
<a href=#263 id=263 data-nosnippet>263</a> }
<a href=#264 id=264 data-nosnippet>264</a> }
<a href=#265 id=265 data-nosnippet>265</a>}
<a href=#266 id=266 data-nosnippet>266</a>
<a href=#267 id=267 data-nosnippet>267</a><span class="doccomment">/// RAII guard for a started progress phase.
<a href=#268 id=268 data-nosnippet>268</a>///
<a href=#269 id=269 data-nosnippet>269</a>/// This keeps future stateful reporters safe on every early-return path after a
<a href=#270 id=270 data-nosnippet>270</a>/// phase starts. Call [`Self::finish`] to end the phase at a deliberate point;
<a href=#271 id=271 data-nosnippet>271</a>/// otherwise the guard finishes it when dropped.
<a href=#272 id=272 data-nosnippet>272</a></span><span class="attr">#[must_use = <span class="string">"dropping the guard immediately finishes the phase"</span>]
<a href=#273 id=273 data-nosnippet>273</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>ProgressPhase&lt;<span class="lifetime">'a</span>&gt; {
<a href=#274 id=274 data-nosnippet>274</a> reporter: <span class="kw-2">&amp;</span><span class="lifetime">'a </span><span class="kw">dyn </span>ProgressReporter,
<a href=#275 id=275 data-nosnippet>275</a> finished: bool,
<a href=#276 id=276 data-nosnippet>276</a>}
<a href=#277 id=277 data-nosnippet>277</a>
<a href=#278 id=278 data-nosnippet>278</a><span class="kw">impl</span>&lt;<span class="lifetime">'a</span>&gt; ProgressPhase&lt;<span class="lifetime">'a</span>&gt; {
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>start(
<a href=#280 id=280 data-nosnippet>280</a> reporter: <span class="kw-2">&amp;</span><span class="lifetime">'a </span><span class="kw">dyn </span>ProgressReporter,
<a href=#281 id=281 data-nosnippet>281</a> name: <span class="kw-2">&amp;</span>str,
<a href=#282 id=282 data-nosnippet>282</a> total: <span class="prelude-ty">Option</span>&lt;u64&gt;,
<a href=#283 id=283 data-nosnippet>283</a> ) -&gt; <span class="self">Self </span>{
<a href=#284 id=284 data-nosnippet>284</a> reporter.start_phase(name, total);
<a href=#285 id=285 data-nosnippet>285</a> <span class="self">Self </span>{
<a href=#286 id=286 data-nosnippet>286</a> reporter,
<a href=#287 id=287 data-nosnippet>287</a> finished: <span class="bool-val">false</span>,
<a href=#288 id=288 data-nosnippet>288</a> }
<a href=#289 id=289 data-nosnippet>289</a> }
<a href=#290 id=290 data-nosnippet>290</a>
<a href=#291 id=291 data-nosnippet>291</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>finish(<span class="kw-2">mut </span><span class="self">self</span>) {
<a href=#292 id=292 data-nosnippet>292</a> <span class="self">self</span>.finish_once();
<a href=#293 id=293 data-nosnippet>293</a> }
<a href=#294 id=294 data-nosnippet>294</a>
<a href=#295 id=295 data-nosnippet>295</a> <span class="kw">fn </span>finish_once(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#296 id=296 data-nosnippet>296</a> <span class="kw">if </span>!<span class="self">self</span>.finished {
<a href=#297 id=297 data-nosnippet>297</a> <span class="self">self</span>.reporter.finish_phase();
<a href=#298 id=298 data-nosnippet>298</a> <span class="self">self</span>.finished = <span class="bool-val">true</span>;
<a href=#299 id=299 data-nosnippet>299</a> }
<a href=#300 id=300 data-nosnippet>300</a> }
<a href=#301 id=301 data-nosnippet>301</a>}
<a href=#302 id=302 data-nosnippet>302</a>
<a href=#303 id=303 data-nosnippet>303</a><span class="kw">impl </span>Drop <span class="kw">for </span>ProgressPhase&lt;<span class="lifetime">'_</span>&gt; {
<a href=#304 id=304 data-nosnippet>304</a> <span class="kw">fn </span>drop(<span class="kw-2">&amp;mut </span><span class="self">self</span>) {
<a href=#305 id=305 data-nosnippet>305</a> <span class="self">self</span>.finish_once();
<a href=#306 id=306 data-nosnippet>306</a> }
<a href=#307 id=307 data-nosnippet>307</a>}
<a href=#308 id=308 data-nosnippet>308</a>
<a href=#309 id=309 data-nosnippet>309</a><span class="attr">#[cfg(test)]
<a href=#310 id=310 data-nosnippet>310</a></span><span class="kw">mod </span>tests {
<a href=#311 id=311 data-nosnippet>311</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#312 id=312 data-nosnippet>312</a>
<a href=#313 id=313 data-nosnippet>313</a> <span class="attr">#[test]
<a href=#314 id=314 data-nosnippet>314</a> </span><span class="kw">fn </span>test_log_progress_is_safe_across_phase_lifecycle() {
<a href=#315 id=315 data-nosnippet>315</a> <span class="comment">// LogProgress takes only `&amp;self`, so it must drive a full phase
<a href=#316 id=316 data-nosnippet>316</a> // lifecycle (including an out-of-phase `inc`) without panicking.
<a href=#317 id=317 data-nosnippet>317</a> </span><span class="kw">let </span>progress = LogProgress::new();
<a href=#318 id=318 data-nosnippet>318</a> <span class="kw">let </span>reporter: <span class="kw-2">&amp;</span><span class="kw">dyn </span>ProgressReporter = <span class="kw-2">&amp;</span>progress;
<a href=#319 id=319 data-nosnippet>319</a>
<a href=#320 id=320 data-nosnippet>320</a> reporter.inc(<span class="number">1</span>); <span class="comment">// No active phase yet: must be a no-op, not a panic.
<a href=#321 id=321 data-nosnippet>321</a> </span>reporter.start_phase(<span class="string">"Import data tasks"</span>, <span class="prelude-val">Some</span>(<span class="number">2</span>));
<a href=#322 id=322 data-nosnippet>322</a> reporter.inc(<span class="number">1</span>);
<a href=#323 id=323 data-nosnippet>323</a> reporter.inc(<span class="number">1</span>);
<a href=#324 id=324 data-nosnippet>324</a> reporter.finish_phase();
<a href=#325 id=325 data-nosnippet>325</a> reporter.finish_phase(); <span class="comment">// Idempotent: finishing twice is harmless.
<a href=#326 id=326 data-nosnippet>326</a> </span>}
<a href=#327 id=327 data-nosnippet>327</a>
<a href=#328 id=328 data-nosnippet>328</a> <span class="attr">#[test]
<a href=#329 id=329 data-nosnippet>329</a> </span><span class="kw">fn </span>test_progress_output_kind_visibility_matrix() {
<a href=#330 id=330 data-nosnippet>330</a> <span class="comment">// auto follows the TTY for the bar and falls back to log progress;
<a href=#331 id=331 data-nosnippet>331</a> // always emits progress even when stderr is redirected; never is silent.
<a href=#332 id=332 data-nosnippet>332</a> </span><span class="macro">assert_eq!</span>(
<a href=#333 id=333 data-nosnippet>333</a> ProgressOutputKind::Bar,
<a href=#334 id=334 data-nosnippet>334</a> progress_output_kind(ProgressMode::Auto, <span class="bool-val">true</span>, <span class="bool-val">true</span>)
<a href=#335 id=335 data-nosnippet>335</a> );
<a href=#336 id=336 data-nosnippet>336</a> <span class="macro">assert_eq!</span>(
<a href=#337 id=337 data-nosnippet>337</a> ProgressOutputKind::Log,
<a href=#338 id=338 data-nosnippet>338</a> progress_output_kind(ProgressMode::Auto, <span class="bool-val">true</span>, <span class="bool-val">false</span>)
<a href=#339 id=339 data-nosnippet>339</a> );
<a href=#340 id=340 data-nosnippet>340</a> <span class="macro">assert_eq!</span>(
<a href=#341 id=341 data-nosnippet>341</a> ProgressOutputKind::Log,
<a href=#342 id=342 data-nosnippet>342</a> progress_output_kind(ProgressMode::Auto, <span class="bool-val">false</span>, <span class="bool-val">true</span>)
<a href=#343 id=343 data-nosnippet>343</a> );
<a href=#344 id=344 data-nosnippet>344</a> <span class="macro">assert_eq!</span>(
<a href=#345 id=345 data-nosnippet>345</a> ProgressOutputKind::Log,
<a href=#346 id=346 data-nosnippet>346</a> progress_output_kind(ProgressMode::Always, <span class="bool-val">false</span>, <span class="bool-val">true</span>)
<a href=#347 id=347 data-nosnippet>347</a> );
<a href=#348 id=348 data-nosnippet>348</a> <span class="macro">assert_eq!</span>(
<a href=#349 id=349 data-nosnippet>349</a> ProgressOutputKind::Log,
<a href=#350 id=350 data-nosnippet>350</a> progress_output_kind(ProgressMode::Always, <span class="bool-val">true</span>, <span class="bool-val">false</span>)
<a href=#351 id=351 data-nosnippet>351</a> );
<a href=#352 id=352 data-nosnippet>352</a> <span class="macro">assert_eq!</span>(
<a href=#353 id=353 data-nosnippet>353</a> ProgressOutputKind::Bar,
<a href=#354 id=354 data-nosnippet>354</a> progress_output_kind(ProgressMode::Always, <span class="bool-val">true</span>, <span class="bool-val">true</span>)
<a href=#355 id=355 data-nosnippet>355</a> );
<a href=#356 id=356 data-nosnippet>356</a> <span class="macro">assert_eq!</span>(
<a href=#357 id=357 data-nosnippet>357</a> ProgressOutputKind::Silent,
<a href=#358 id=358 data-nosnippet>358</a> progress_output_kind(ProgressMode::Never, <span class="bool-val">true</span>, <span class="bool-val">true</span>)
<a href=#359 id=359 data-nosnippet>359</a> );
<a href=#360 id=360 data-nosnippet>360</a> <span class="macro">assert_eq!</span>(
<a href=#361 id=361 data-nosnippet>361</a> ProgressOutputKind::Silent,
<a href=#362 id=362 data-nosnippet>362</a> progress_output_kind(ProgressMode::Never, <span class="bool-val">false</span>, <span class="bool-val">true</span>)
<a href=#363 id=363 data-nosnippet>363</a> );
<a href=#364 id=364 data-nosnippet>364</a> }
<a href=#365 id=365 data-nosnippet>365</a>
<a href=#366 id=366 data-nosnippet>366</a> <span class="attr">#[test]
<a href=#367 id=367 data-nosnippet>367</a> </span><span class="kw">fn </span>test_progress_bar_supported_respects_terminal_environment() {
<a href=#368 id=368 data-nosnippet>368</a> <span class="macro">assert!</span>(progress_bar_supported(<span class="prelude-val">Some</span>(<span class="string">"xterm"</span>.as_ref()), <span class="bool-val">false</span>));
<a href=#369 id=369 data-nosnippet>369</a> <span class="macro">assert!</span>(!progress_bar_supported(<span class="prelude-val">Some</span>(<span class="string">"dumb"</span>.as_ref()), <span class="bool-val">false</span>));
<a href=#370 id=370 data-nosnippet>370</a> <span class="macro">assert!</span>(!progress_bar_supported(<span class="prelude-val">Some</span>(<span class="string">""</span>.as_ref()), <span class="bool-val">false</span>));
<a href=#371 id=371 data-nosnippet>371</a> <span class="macro">assert!</span>(!progress_bar_supported(<span class="prelude-val">None</span>, <span class="bool-val">false</span>));
<a href=#372 id=372 data-nosnippet>372</a> <span class="macro">assert!</span>(!progress_bar_supported(<span class="prelude-val">Some</span>(<span class="string">"xterm"</span>.as_ref()), <span class="bool-val">true</span>));
<a href=#373 id=373 data-nosnippet>373</a> }
<a href=#374 id=374 data-nosnippet>374</a>
<a href=#375 id=375 data-nosnippet>375</a> <span class="attr">#[test]
<a href=#376 id=376 data-nosnippet>376</a> </span><span class="kw">fn </span>test_indicatif_progress_is_safe_across_phase_lifecycle() {
<a href=#377 id=377 data-nosnippet>377</a> <span class="comment">// IndicatifProgress takes only `&amp;self`, so it must survive a full
<a href=#378 id=378 data-nosnippet>378</a> // lifecycle (including determinate and spinner phases, an out-of-phase
<a href=#379 id=379 data-nosnippet>379</a> // `inc`, and double finish) without panicking. The draw target is
<a href=#380 id=380 data-nosnippet>380</a> // stderr, which is non-interactive under the test harness, so nothing
<a href=#381 id=381 data-nosnippet>381</a> // actually renders.
<a href=#382 id=382 data-nosnippet>382</a> </span><span class="kw">let </span>progress = IndicatifProgress::new();
<a href=#383 id=383 data-nosnippet>383</a> <span class="kw">let </span>reporter: <span class="kw-2">&amp;</span><span class="kw">dyn </span>ProgressReporter = <span class="kw-2">&amp;</span>progress;
<a href=#384 id=384 data-nosnippet>384</a>
<a href=#385 id=385 data-nosnippet>385</a> reporter.inc(<span class="number">1</span>); <span class="comment">// No active phase yet: must be a no-op, not a panic.
<a href=#386 id=386 data-nosnippet>386</a> </span>reporter.start_phase(<span class="string">"Import data tasks"</span>, <span class="prelude-val">Some</span>(<span class="number">2</span>));
<a href=#387 id=387 data-nosnippet>387</a> reporter.inc(<span class="number">1</span>);
<a href=#388 id=388 data-nosnippet>388</a> reporter.inc(<span class="number">1</span>);
<a href=#389 id=389 data-nosnippet>389</a> reporter.start_phase(<span class="string">"Streaming"</span>, <span class="prelude-val">None</span>); <span class="comment">// Spinner phase replaces the bar.
<a href=#390 id=390 data-nosnippet>390</a> </span>reporter.inc(<span class="number">5</span>);
<a href=#391 id=391 data-nosnippet>391</a> reporter.finish_phase();
<a href=#392 id=392 data-nosnippet>392</a> reporter.finish_phase(); <span class="comment">// Idempotent: finishing twice is harmless.
<a href=#393 id=393 data-nosnippet>393</a> </span>}
<a href=#394 id=394 data-nosnippet>394</a>}
<a href=#395 id=395 data-nosnippet>395</a>
<a href=#396 id=396 data-nosnippet>396</a><span class="attr">#[cfg(test)]
<a href=#397 id=397 data-nosnippet>397</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">mod </span>test_util {
<a href=#398 id=398 data-nosnippet>398</a> <span class="kw">use </span>std::sync::Mutex;
<a href=#399 id=399 data-nosnippet>399</a>
<a href=#400 id=400 data-nosnippet>400</a> <span class="kw">use </span><span class="kw">super</span>::ProgressReporter;
<a href=#401 id=401 data-nosnippet>401</a>
<a href=#402 id=402 data-nosnippet>402</a> <span class="doccomment">/// A single recorded progress event, used to assert progress behavior in
<a href=#403 id=403 data-nosnippet>403</a> /// unit tests.
<a href=#404 id=404 data-nosnippet>404</a> </span><span class="attr">#[derive(Debug, Clone, PartialEq, Eq)]
<a href=#405 id=405 data-nosnippet>405</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">enum </span>ProgressEvent {
<a href=#406 id=406 data-nosnippet>406</a> StartPhase { name: String, total: <span class="prelude-ty">Option</span>&lt;u64&gt; },
<a href=#407 id=407 data-nosnippet>407</a> Inc { delta: u64 },
<a href=#408 id=408 data-nosnippet>408</a> FinishPhase,
<a href=#409 id=409 data-nosnippet>409</a> }
<a href=#410 id=410 data-nosnippet>410</a>
<a href=#411 id=411 data-nosnippet>411</a> <span class="doccomment">/// A reporter that records every event in order for later assertions.
<a href=#412 id=412 data-nosnippet>412</a> </span><span class="attr">#[derive(Default)]
<a href=#413 id=413 data-nosnippet>413</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>RecordingProgress {
<a href=#414 id=414 data-nosnippet>414</a> events: Mutex&lt;Vec&lt;ProgressEvent&gt;&gt;,
<a href=#415 id=415 data-nosnippet>415</a> }
<a href=#416 id=416 data-nosnippet>416</a>
<a href=#417 id=417 data-nosnippet>417</a> <span class="kw">impl </span>RecordingProgress {
<a href=#418 id=418 data-nosnippet>418</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>events(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; Vec&lt;ProgressEvent&gt; {
<a href=#419 id=419 data-nosnippet>419</a> <span class="self">self</span>.events.lock().unwrap().clone()
<a href=#420 id=420 data-nosnippet>420</a> }
<a href=#421 id=421 data-nosnippet>421</a>
<a href=#422 id=422 data-nosnippet>422</a> <span class="doccomment">/// Sum of all `inc` deltas recorded so far.
<a href=#423 id=423 data-nosnippet>423</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>total_inc(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; u64 {
<a href=#424 id=424 data-nosnippet>424</a> <span class="self">self</span>.events
<a href=#425 id=425 data-nosnippet>425</a> .lock()
<a href=#426 id=426 data-nosnippet>426</a> .unwrap()
<a href=#427 id=427 data-nosnippet>427</a> .iter()
<a href=#428 id=428 data-nosnippet>428</a> .filter_map(|event| <span class="kw">match </span>event {
<a href=#429 id=429 data-nosnippet>429</a> ProgressEvent::Inc { delta } =&gt; <span class="prelude-val">Some</span>(<span class="kw-2">*</span>delta),
<a href=#430 id=430 data-nosnippet>430</a> <span class="kw">_ </span>=&gt; <span class="prelude-val">None</span>,
<a href=#431 id=431 data-nosnippet>431</a> })
<a href=#432 id=432 data-nosnippet>432</a> .sum()
<a href=#433 id=433 data-nosnippet>433</a> }
<a href=#434 id=434 data-nosnippet>434</a>
<a href=#435 id=435 data-nosnippet>435</a> <span class="kw">fn </span>push(<span class="kw-2">&amp;</span><span class="self">self</span>, event: ProgressEvent) {
<a href=#436 id=436 data-nosnippet>436</a> <span class="self">self</span>.events.lock().unwrap().push(event);
<a href=#437 id=437 data-nosnippet>437</a> }
<a href=#438 id=438 data-nosnippet>438</a> }
<a href=#439 id=439 data-nosnippet>439</a>
<a href=#440 id=440 data-nosnippet>440</a> <span class="kw">impl </span>ProgressReporter <span class="kw">for </span>RecordingProgress {
<a href=#441 id=441 data-nosnippet>441</a> <span class="kw">fn </span>start_phase(<span class="kw-2">&amp;</span><span class="self">self</span>, name: <span class="kw-2">&amp;</span>str, total: <span class="prelude-ty">Option</span>&lt;u64&gt;) {
<a href=#442 id=442 data-nosnippet>442</a> <span class="self">self</span>.push(ProgressEvent::StartPhase {
<a href=#443 id=443 data-nosnippet>443</a> name: name.to_string(),
<a href=#444 id=444 data-nosnippet>444</a> total,
<a href=#445 id=445 data-nosnippet>445</a> });
<a href=#446 id=446 data-nosnippet>446</a> }
<a href=#447 id=447 data-nosnippet>447</a>
<a href=#448 id=448 data-nosnippet>448</a> <span class="kw">fn </span>inc(<span class="kw-2">&amp;</span><span class="self">self</span>, delta: u64) {
<a href=#449 id=449 data-nosnippet>449</a> <span class="self">self</span>.push(ProgressEvent::Inc { delta });
<a href=#450 id=450 data-nosnippet>450</a> }
<a href=#451 id=451 data-nosnippet>451</a>
<a href=#452 id=452 data-nosnippet>452</a> <span class="kw">fn </span>finish_phase(<span class="kw-2">&amp;</span><span class="self">self</span>) {
<a href=#453 id=453 data-nosnippet>453</a> <span class="self">self</span>.push(ProgressEvent::FinishPhase);
<a href=#454 id=454 data-nosnippet>454</a> }
<a href=#455 id=455 data-nosnippet>455</a> }
<a href=#456 id=456 data-nosnippet>456</a>}
</code></pre></div></section></main></body></html>
+509
View File
@@ -0,0 +1,509 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/schema_export.rs`."><title>schema_export.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/</div>schema_export.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! Bounded SHOW CREATE requests shared by both export commands.
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a></span><span class="kw">use </span>common_catalog::consts::DEFAULT_SCHEMA_NAME;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>servers::http::GreptimeQueryOutput;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>servers::http::result::greptime_result_v1::GreptimedbV1Response;
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span><span class="kw">crate</span>::data::sql::escape_sql_identifier;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span><span class="kw">crate</span>::database::DatabaseClient;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span><span class="kw">crate</span>::error::{InvalidArgumentsSnafu, <span class="prelude-ty">Result</span>, UnexpectedSnafu};
<a href=#24 id=24 data-nosnippet>24</a>
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">const </span>MAX_STATEMENTS: usize = <span class="number">128</span>;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">const </span>MAX_SQL_BYTES: usize = <span class="number">128 </span>* <span class="number">1024</span>;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="doccomment">/// Appends DDL in dependency order supplied by the caller using bounded requests.
<a href=#29 id=29 data-nosnippet>29</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>append_schema_ddl&lt;<span class="lifetime">'a</span>&gt;(
<a href=#30 id=30 data-nosnippet>30</a> client: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>DatabaseClient,
<a href=#31 id=31 data-nosnippet>31</a> catalog: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str,
<a href=#32 id=32 data-nosnippet>32</a> schema: <span class="kw-2">&amp;</span><span class="lifetime">'a </span>str,
<a href=#33 id=33 data-nosnippet>33</a> objects: <span class="kw">impl </span>Iterator&lt;Item = (<span class="kw-2">&amp;</span><span class="lifetime">'static </span>str, <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span><span class="lifetime">'a </span>str&gt;)&gt; + Send + <span class="lifetime">'a</span>,
<a href=#34 id=34 data-nosnippet>34</a> ddl: <span class="kw-2">&amp;</span><span class="lifetime">'a </span><span class="kw-2">mut </span>String,
<a href=#35 id=35 data-nosnippet>35</a>) -&gt; <span class="kw">impl </span>std::future::Future&lt;Output = <span class="prelude-ty">Result</span>&lt;()&gt;&gt; + Send + <span class="lifetime">'a </span>{
<a href=#36 id=36 data-nosnippet>36</a> <span class="kw">let </span><span class="kw-2">mut </span>statements = objects
<a href=#37 id=37 data-nosnippet>37</a> .map(<span class="kw">move </span>|(kind, table)| show_create_sql(kind, catalog, schema, table))
<a href=#38 id=38 data-nosnippet>38</a> .peekable();
<a href=#39 id=39 data-nosnippet>39</a> <span class="kw">async move </span>{
<a href=#40 id=40 data-nosnippet>40</a> <span class="kw">loop </span>{
<a href=#41 id=41 data-nosnippet>41</a> <span class="kw">let </span>batch = next_batch(<span class="kw-2">&amp;mut </span>statements)<span class="question-mark">?</span>;
<a href=#42 id=42 data-nosnippet>42</a> <span class="kw">if </span>batch.is_empty() {
<a href=#43 id=43 data-nosnippet>43</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#44 id=44 data-nosnippet>44</a> }
<a href=#45 id=45 data-nosnippet>45</a> <span class="kw">let </span>response = client
<a href=#46 id=46 data-nosnippet>46</a> .sql_response(<span class="kw-2">&amp;</span>batch.concat(), DEFAULT_SCHEMA_NAME)
<a href=#47 id=47 data-nosnippet>47</a> .<span class="kw">await
<a href=#48 id=48 data-nosnippet>48</a> </span>.map_err(|error| {
<a href=#49 id=49 data-nosnippet>49</a> UnexpectedSnafu {
<a href=#50 id=50 data-nosnippet>50</a> msg: <span class="macro">format!</span>(<span class="string">"SHOW CREATE batch failed for {}: {error}"</span>, batch.concat()),
<a href=#51 id=51 data-nosnippet>51</a> }
<a href=#52 id=52 data-nosnippet>52</a> .build()
<a href=#53 id=53 data-nosnippet>53</a> })<span class="question-mark">?</span>;
<a href=#54 id=54 data-nosnippet>54</a> append_results(<span class="kw-2">&amp;</span>batch, <span class="kw-2">&amp;</span>response, ddl)<span class="question-mark">?</span>;
<a href=#55 id=55 data-nosnippet>55</a> }
<a href=#56 id=56 data-nosnippet>56</a> }
<a href=#57 id=57 data-nosnippet>57</a>}
<a href=#58 id=58 data-nosnippet>58</a>
<a href=#59 id=59 data-nosnippet>59</a><span class="kw">fn </span>show_create_sql(kind: <span class="kw-2">&amp;</span>str, catalog: <span class="kw-2">&amp;</span>str, schema: <span class="kw-2">&amp;</span>str, table: <span class="prelude-ty">Option</span>&lt;<span class="kw-2">&amp;</span>str&gt;) -&gt; String {
<a href=#60 id=60 data-nosnippet>60</a> <span class="kw">let </span><span class="kw-2">mut </span>sql = <span class="macro">format!</span>(
<a href=#61 id=61 data-nosnippet>61</a> <span class="string">"SHOW CREATE {kind} \"{}\".\"{}\""</span>,
<a href=#62 id=62 data-nosnippet>62</a> escape_sql_identifier(catalog),
<a href=#63 id=63 data-nosnippet>63</a> escape_sql_identifier(schema),
<a href=#64 id=64 data-nosnippet>64</a> );
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table) = table {
<a href=#66 id=66 data-nosnippet>66</a> sql.push_str(<span class="string">".\""</span>);
<a href=#67 id=67 data-nosnippet>67</a> sql.push_str(<span class="kw-2">&amp;</span>escape_sql_identifier(table));
<a href=#68 id=68 data-nosnippet>68</a> sql.push(<span class="string">'"'</span>);
<a href=#69 id=69 data-nosnippet>69</a> }
<a href=#70 id=70 data-nosnippet>70</a> sql.push_str(<span class="string">";\n"</span>);
<a href=#71 id=71 data-nosnippet>71</a> sql
<a href=#72 id=72 data-nosnippet>72</a>}
<a href=#73 id=73 data-nosnippet>73</a>
<a href=#74 id=74 data-nosnippet>74</a><span class="kw">fn </span>next_batch(
<a href=#75 id=75 data-nosnippet>75</a> statements: <span class="kw-2">&amp;mut </span>std::iter::Peekable&lt;<span class="kw">impl </span>Iterator&lt;Item = String&gt;&gt;,
<a href=#76 id=76 data-nosnippet>76</a>) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;String&gt;&gt; {
<a href=#77 id=77 data-nosnippet>77</a> <span class="kw">let </span><span class="kw-2">mut </span>batch = Vec::new();
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">let </span><span class="kw-2">mut </span>bytes = <span class="number">0</span>;
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw">while let </span><span class="prelude-val">Some</span>(sql) = statements.peek() {
<a href=#80 id=80 data-nosnippet>80</a> <span class="kw">if </span>sql.len() &gt; MAX_SQL_BYTES {
<a href=#81 id=81 data-nosnippet>81</a> <span class="kw">return </span>InvalidArgumentsSnafu {
<a href=#82 id=82 data-nosnippet>82</a> msg: <span class="macro">format!</span>(
<a href=#83 id=83 data-nosnippet>83</a> <span class="string">"SHOW CREATE exceeds {MAX_SQL_BYTES} SQL bytes ({}): {sql}"</span>,
<a href=#84 id=84 data-nosnippet>84</a> sql.len()
<a href=#85 id=85 data-nosnippet>85</a> ),
<a href=#86 id=86 data-nosnippet>86</a> }
<a href=#87 id=87 data-nosnippet>87</a> .fail();
<a href=#88 id=88 data-nosnippet>88</a> }
<a href=#89 id=89 data-nosnippet>89</a> <span class="kw">if </span>batch.len() == MAX_STATEMENTS || bytes + sql.len() &gt; MAX_SQL_BYTES {
<a href=#90 id=90 data-nosnippet>90</a> <span class="kw">break</span>;
<a href=#91 id=91 data-nosnippet>91</a> }
<a href=#92 id=92 data-nosnippet>92</a> bytes += sql.len();
<a href=#93 id=93 data-nosnippet>93</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(sql) = statements.next() {
<a href=#94 id=94 data-nosnippet>94</a> batch.push(sql);
<a href=#95 id=95 data-nosnippet>95</a> }
<a href=#96 id=96 data-nosnippet>96</a> }
<a href=#97 id=97 data-nosnippet>97</a> <span class="prelude-val">Ok</span>(batch)
<a href=#98 id=98 data-nosnippet>98</a>}
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a><span class="kw">fn </span>append_results(
<a href=#101 id=101 data-nosnippet>101</a> batch: <span class="kw-2">&amp;</span>[String],
<a href=#102 id=102 data-nosnippet>102</a> response: <span class="kw-2">&amp;</span>GreptimedbV1Response,
<a href=#103 id=103 data-nosnippet>103</a> ddl: <span class="kw-2">&amp;mut </span>String,
<a href=#104 id=104 data-nosnippet>104</a>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#105 id=105 data-nosnippet>105</a> <span class="kw">let </span>outputs = response.output();
<a href=#106 id=106 data-nosnippet>106</a> <span class="kw">if </span>outputs.len() != batch.len() {
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">return </span>UnexpectedSnafu {
<a href=#108 id=108 data-nosnippet>108</a> msg: <span class="macro">format!</span>(
<a href=#109 id=109 data-nosnippet>109</a> <span class="string">"SHOW CREATE expected {} results, received {} for {}"</span>,
<a href=#110 id=110 data-nosnippet>110</a> batch.len(),
<a href=#111 id=111 data-nosnippet>111</a> outputs.len(),
<a href=#112 id=112 data-nosnippet>112</a> batch.concat()
<a href=#113 id=113 data-nosnippet>113</a> ),
<a href=#114 id=114 data-nosnippet>114</a> }
<a href=#115 id=115 data-nosnippet>115</a> .fail();
<a href=#116 id=116 data-nosnippet>116</a> }
<a href=#117 id=117 data-nosnippet>117</a> <span class="kw">for </span>(sql, output) <span class="kw">in </span>batch.iter().zip(outputs) {
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">let </span>GreptimeQueryOutput::Records(records) = output <span class="kw">else </span>{
<a href=#119 id=119 data-nosnippet>119</a> <span class="kw">return </span>UnexpectedSnafu {
<a href=#120 id=120 data-nosnippet>120</a> msg: <span class="macro">format!</span>(<span class="string">"expected SHOW CREATE records for {sql}"</span>),
<a href=#121 id=121 data-nosnippet>121</a> }
<a href=#122 id=122 data-nosnippet>122</a> .fail();
<a href=#123 id=123 data-nosnippet>123</a> };
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">if </span>records.num_cols() != <span class="number">2 </span>|| records.rows().len() != <span class="number">1 </span>|| records.rows()[<span class="number">0</span>].len() != <span class="number">2 </span>{
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw">return </span>UnexpectedSnafu {
<a href=#126 id=126 data-nosnippet>126</a> msg: <span class="macro">format!</span>(<span class="string">"expected one two-column SHOW CREATE row for {sql}"</span>),
<a href=#127 id=127 data-nosnippet>127</a> }
<a href=#128 id=128 data-nosnippet>128</a> .fail();
<a href=#129 id=129 data-nosnippet>129</a> }
<a href=#130 id=130 data-nosnippet>130</a> <span class="kw">let </span>row = <span class="kw-2">&amp;</span>records.rows()[<span class="number">0</span>];
<a href=#131 id=131 data-nosnippet>131</a> <span class="kw">let </span><span class="prelude-val">Some</span>(create) = row[<span class="number">1</span>].as_str().filter(|value| !value.is_empty()) <span class="kw">else </span>{
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">return </span>UnexpectedSnafu {
<a href=#133 id=133 data-nosnippet>133</a> msg: <span class="macro">format!</span>(<span class="string">"expected SHOW CREATE DDL string for {sql}"</span>),
<a href=#134 id=134 data-nosnippet>134</a> }
<a href=#135 id=135 data-nosnippet>135</a> .fail();
<a href=#136 id=136 data-nosnippet>136</a> };
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">if </span>!row[<span class="number">0</span>].is_string() {
<a href=#138 id=138 data-nosnippet>138</a> <span class="kw">return </span>UnexpectedSnafu {
<a href=#139 id=139 data-nosnippet>139</a> msg: <span class="macro">format!</span>(<span class="string">"expected SHOW CREATE object name for {sql}"</span>),
<a href=#140 id=140 data-nosnippet>140</a> }
<a href=#141 id=141 data-nosnippet>141</a> .fail();
<a href=#142 id=142 data-nosnippet>142</a> }
<a href=#143 id=143 data-nosnippet>143</a> ddl.push_str(create);
<a href=#144 id=144 data-nosnippet>144</a> ddl.push_str(<span class="string">";\n"</span>);
<a href=#145 id=145 data-nosnippet>145</a> }
<a href=#146 id=146 data-nosnippet>146</a> <span class="prelude-val">Ok</span>(())
<a href=#147 id=147 data-nosnippet>147</a>}
<a href=#148 id=148 data-nosnippet>148</a>
<a href=#149 id=149 data-nosnippet>149</a><span class="attr">#[cfg(test)]
<a href=#150 id=150 data-nosnippet>150</a></span><span class="kw">mod </span>tests {
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">use </span>serde_json::{Value, json};
<a href=#152 id=152 data-nosnippet>152</a> <span class="kw">use </span>tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader};
<a href=#153 id=153 data-nosnippet>153</a>
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#155 id=155 data-nosnippet>155</a>
<a href=#156 id=156 data-nosnippet>156</a> <span class="kw">fn </span>records(name: <span class="kw-2">&amp;</span>str, ddl: <span class="kw-2">&amp;</span>str) -&gt; Value {
<a href=#157 id=157 data-nosnippet>157</a> <span class="macro">json!</span>({<span class="string">"records"</span>: {<span class="string">"schema"</span>: {<span class="string">"column_schemas"</span>: [
<a href=#158 id=158 data-nosnippet>158</a> {<span class="string">"name"</span>: <span class="string">"Table"</span>, <span class="string">"data_type"</span>: <span class="string">"String"</span>},
<a href=#159 id=159 data-nosnippet>159</a> {<span class="string">"name"</span>: <span class="string">"Create Table"</span>, <span class="string">"data_type"</span>: <span class="string">"String"</span>}
<a href=#160 id=160 data-nosnippet>160</a> ]}, <span class="string">"rows"</span>: [[name, ddl]], <span class="string">"total_rows"</span>: <span class="number">1</span>}})
<a href=#161 id=161 data-nosnippet>161</a> }
<a href=#162 id=162 data-nosnippet>162</a>
<a href=#163 id=163 data-nosnippet>163</a> <span class="attr">#[test]
<a href=#164 id=164 data-nosnippet>164</a> </span><span class="kw">fn </span>batch_limits_include_quoted_utf8_and_separators() {
<a href=#165 id=165 data-nosnippet>165</a> <span class="kw">let </span>special = show_create_sql(<span class="string">"TABLE"</span>, <span class="string">"cat.name"</span>, <span class="string">"s\";库"</span>, <span class="prelude-val">Some</span>(<span class="string">"ta.\";表"</span>));
<a href=#166 id=166 data-nosnippet>166</a> <span class="macro">assert_eq!</span>(
<a href=#167 id=167 data-nosnippet>167</a> special,
<a href=#168 id=168 data-nosnippet>168</a> <span class="string">"SHOW CREATE TABLE \"cat.name\".\"s\"\";库\".\"ta.\"\";表\";\n"
<a href=#169 id=169 data-nosnippet>169</a> </span>);
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw">let </span><span class="kw-2">mut </span>statements = std::iter::repeat_n(special.clone(), <span class="number">129</span>).peekable();
<a href=#171 id=171 data-nosnippet>171</a> <span class="macro">assert_eq!</span>(
<a href=#172 id=172 data-nosnippet>172</a> next_batch(<span class="kw-2">&amp;mut </span>statements).unwrap(),
<a href=#173 id=173 data-nosnippet>173</a> <span class="macro">vec!</span>[special.clone(); <span class="number">128</span>]
<a href=#174 id=174 data-nosnippet>174</a> );
<a href=#175 id=175 data-nosnippet>175</a> <span class="macro">assert_eq!</span>(next_batch(<span class="kw-2">&amp;mut </span>statements).unwrap(), <span class="macro">vec!</span>[special]);
<a href=#176 id=176 data-nosnippet>176</a> <span class="macro">assert!</span>(next_batch(<span class="kw-2">&amp;mut </span>statements).unwrap().is_empty());
<a href=#177 id=177 data-nosnippet>177</a>
<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">let </span>prefix = show_create_sql(<span class="string">"TABLE"</span>, <span class="string">"c"</span>, <span class="string">"s"</span>, <span class="prelude-val">Some</span>(<span class="string">""</span>));
<a href=#179 id=179 data-nosnippet>179</a> <span class="comment">// Every quote expands to two bytes; this also exercises a multibyte name.
<a href=#180 id=180 data-nosnippet>180</a> </span><span class="kw">let </span>name = <span class="macro">format!</span>(<span class="string">"表{}"</span>, <span class="string">"\""</span>.repeat((MAX_SQL_BYTES - prefix.len() - <span class="number">3</span>) / <span class="number">2</span>));
<a href=#181 id=181 data-nosnippet>181</a> <span class="kw">let </span><span class="kw-2">mut </span>exact = show_create_sql(<span class="string">"TABLE"</span>, <span class="string">"c"</span>, <span class="string">"s"</span>, <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span>name));
<a href=#182 id=182 data-nosnippet>182</a> <span class="kw">let </span>padding = MAX_SQL_BYTES - exact.len();
<a href=#183 id=183 data-nosnippet>183</a> exact = show_create_sql(
<a href=#184 id=184 data-nosnippet>184</a> <span class="string">"TABLE"</span>,
<a href=#185 id=185 data-nosnippet>185</a> <span class="string">"c"</span>,
<a href=#186 id=186 data-nosnippet>186</a> <span class="string">"s"</span>,
<a href=#187 id=187 data-nosnippet>187</a> <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"{name}{}"</span>, <span class="string">"a"</span>.repeat(padding))),
<a href=#188 id=188 data-nosnippet>188</a> );
<a href=#189 id=189 data-nosnippet>189</a> <span class="macro">assert_eq!</span>(exact.len(), MAX_SQL_BYTES);
<a href=#190 id=190 data-nosnippet>190</a> <span class="kw">let </span>small = show_create_sql(<span class="string">"TABLE"</span>, <span class="string">"c"</span>, <span class="string">"s"</span>, <span class="prelude-val">Some</span>(<span class="string">"next"</span>));
<a href=#191 id=191 data-nosnippet>191</a> <span class="kw">let </span><span class="kw-2">mut </span>statements = [exact.clone(), small.clone()].into_iter().peekable();
<a href=#192 id=192 data-nosnippet>192</a> <span class="macro">assert_eq!</span>(next_batch(<span class="kw-2">&amp;mut </span>statements).unwrap(), <span class="macro">vec!</span>[exact.clone()]);
<a href=#193 id=193 data-nosnippet>193</a> <span class="macro">assert_eq!</span>(next_batch(<span class="kw-2">&amp;mut </span>statements).unwrap(), <span class="macro">vec!</span>[small]);
<a href=#194 id=194 data-nosnippet>194</a> <span class="kw">let </span><span class="kw-2">mut </span>oversized = std::iter::once(<span class="macro">format!</span>(<span class="string">"{exact} "</span>)).peekable();
<a href=#195 id=195 data-nosnippet>195</a> <span class="macro">assert!</span>(
<a href=#196 id=196 data-nosnippet>196</a> next_batch(<span class="kw-2">&amp;mut </span>oversized)
<a href=#197 id=197 data-nosnippet>197</a> .unwrap_err()
<a href=#198 id=198 data-nosnippet>198</a> .to_string()
<a href=#199 id=199 data-nosnippet>199</a> .contains(<span class="string">"exceeds 131072"</span>)
<a href=#200 id=200 data-nosnippet>200</a> );
<a href=#201 id=201 data-nosnippet>201</a>
<a href=#202 id=202 data-nosnippet>202</a> <span class="kw">let </span>half = show_create_sql(
<a href=#203 id=203 data-nosnippet>203</a> <span class="string">"TABLE"</span>,
<a href=#204 id=204 data-nosnippet>204</a> <span class="string">"c"</span>,
<a href=#205 id=205 data-nosnippet>205</a> <span class="string">"s"</span>,
<a href=#206 id=206 data-nosnippet>206</a> <span class="prelude-val">Some</span>(<span class="kw-2">&amp;</span><span class="string">"a"</span>.repeat(MAX_SQL_BYTES / <span class="number">2 </span>- prefix.len())),
<a href=#207 id=207 data-nosnippet>207</a> );
<a href=#208 id=208 data-nosnippet>208</a> <span class="kw">let </span><span class="kw-2">mut </span>statements = [half.clone(), half.clone(), prefix.clone()]
<a href=#209 id=209 data-nosnippet>209</a> .into_iter()
<a href=#210 id=210 data-nosnippet>210</a> .peekable();
<a href=#211 id=211 data-nosnippet>211</a> <span class="macro">assert_eq!</span>(
<a href=#212 id=212 data-nosnippet>212</a> next_batch(<span class="kw-2">&amp;mut </span>statements).unwrap(),
<a href=#213 id=213 data-nosnippet>213</a> <span class="macro">vec!</span>[half.clone(), half]
<a href=#214 id=214 data-nosnippet>214</a> );
<a href=#215 id=215 data-nosnippet>215</a> <span class="macro">assert_eq!</span>(next_batch(<span class="kw-2">&amp;mut </span>statements).unwrap(), <span class="macro">vec!</span>[prefix]);
<a href=#216 id=216 data-nosnippet>216</a> }
<a href=#217 id=217 data-nosnippet>217</a>
<a href=#218 id=218 data-nosnippet>218</a> <span class="attr">#[test]
<a href=#219 id=219 data-nosnippet>219</a> </span><span class="kw">fn </span>show_create_requires_exact_record_shape_and_count() {
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">let </span>batch = <span class="macro">vec!</span>[
<a href=#221 id=221 data-nosnippet>221</a> <span class="string">"SHOW CREATE TABLE first"</span>.into(),
<a href=#222 id=222 data-nosnippet>222</a> <span class="string">"SHOW CREATE TABLE middle"</span>.into(),
<a href=#223 id=223 data-nosnippet>223</a> ];
<a href=#224 id=224 data-nosnippet>224</a> <span class="kw">let </span>valid = records(<span class="string">"first"</span>, <span class="string">"CREATE TABLE first"</span>);
<a href=#225 id=225 data-nosnippet>225</a> <span class="kw">for </span>output <span class="kw">in </span>[
<a href=#226 id=226 data-nosnippet>226</a> <span class="macro">vec!</span>[],
<a href=#227 id=227 data-nosnippet>227</a> <span class="macro">vec!</span>[valid.clone()],
<a href=#228 id=228 data-nosnippet>228</a> <span class="macro">vec!</span>[valid.clone(); <span class="number">3</span>],
<a href=#229 id=229 data-nosnippet>229</a> <span class="macro">vec!</span>[valid.clone(), <span class="macro">json!</span>({<span class="string">"affectedrows"</span>: <span class="number">1</span>})],
<a href=#230 id=230 data-nosnippet>230</a> <span class="macro">vec!</span>[valid.clone(), records(<span class="string">"middle"</span>, <span class="string">""</span>)],
<a href=#231 id=231 data-nosnippet>231</a> <span class="macro">vec!</span>[valid.clone(), {
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">let </span><span class="kw-2">mut </span>r = valid.clone();
<a href=#233 id=233 data-nosnippet>233</a> r[<span class="string">"records"</span>][<span class="string">"rows"</span>] = <span class="macro">json!</span>([]);
<a href=#234 id=234 data-nosnippet>234</a> r
<a href=#235 id=235 data-nosnippet>235</a> }],
<a href=#236 id=236 data-nosnippet>236</a> <span class="macro">vec!</span>[valid.clone(), {
<a href=#237 id=237 data-nosnippet>237</a> <span class="kw">let </span><span class="kw-2">mut </span>r = valid.clone();
<a href=#238 id=238 data-nosnippet>238</a> r[<span class="string">"records"</span>][<span class="string">"rows"</span>] = <span class="macro">json!</span>([[<span class="string">"middle"</span>, <span class="number">4</span>]]);
<a href=#239 id=239 data-nosnippet>239</a> r
<a href=#240 id=240 data-nosnippet>240</a> }],
<a href=#241 id=241 data-nosnippet>241</a> <span class="macro">vec!</span>[valid.clone(), {
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">let </span><span class="kw-2">mut </span>r = valid.clone();
<a href=#243 id=243 data-nosnippet>243</a> r[<span class="string">"records"</span>][<span class="string">"rows"</span>] = <span class="macro">json!</span>([[<span class="string">"middle"</span>, <span class="string">"ddl"</span>, <span class="string">"extra"</span>]]);
<a href=#244 id=244 data-nosnippet>244</a> r
<a href=#245 id=245 data-nosnippet>245</a> }],
<a href=#246 id=246 data-nosnippet>246</a> ] {
<a href=#247 id=247 data-nosnippet>247</a> <span class="kw">let </span>response =
<a href=#248 id=248 data-nosnippet>248</a> serde_json::from_value(<span class="macro">json!</span>({<span class="string">"output"</span>: output, <span class="string">"execution_time_ms"</span>: <span class="number">0</span>})).unwrap();
<a href=#249 id=249 data-nosnippet>249</a> <span class="kw">let </span>error = append_results(<span class="kw-2">&amp;</span>batch, <span class="kw-2">&amp;</span>response, <span class="kw-2">&amp;mut </span>String::new()).unwrap_err();
<a href=#250 id=250 data-nosnippet>250</a> <span class="macro">assert!</span>(error.to_string().contains(<span class="string">"middle"</span>), <span class="string">"{error}"</span>);
<a href=#251 id=251 data-nosnippet>251</a> }
<a href=#252 id=252 data-nosnippet>252</a> }
<a href=#253 id=253 data-nosnippet>253</a>
<a href=#254 id=254 data-nosnippet>254</a> <span class="kw">async fn </span>start_mock_sql_server(
<a href=#255 id=255 data-nosnippet>255</a> bodies: Vec&lt;(u16, String)&gt;,
<a href=#256 id=256 data-nosnippet>256</a> ) -&gt; (DatabaseClient, tokio::task::JoinHandle&lt;Vec&lt;String&gt;&gt;) {
<a href=#257 id=257 data-nosnippet>257</a> <span class="kw">let </span>listener = tokio::net::TcpListener::bind(<span class="string">"127.0.0.1:0"</span>).<span class="kw">await</span>.unwrap();
<a href=#258 id=258 data-nosnippet>258</a> <span class="kw">let </span>address = listener.local_addr().unwrap();
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">let </span>server = tokio::spawn(<span class="kw">async move </span>{
<a href=#260 id=260 data-nosnippet>260</a> tokio::time::timeout(std::time::Duration::from_secs(<span class="number">5</span>), <span class="kw">async move </span>{
<a href=#261 id=261 data-nosnippet>261</a> <span class="kw">let </span>(socket, <span class="kw">_</span>) = listener.accept().<span class="kw">await</span>.unwrap();
<a href=#262 id=262 data-nosnippet>262</a> <span class="kw">let </span><span class="kw-2">mut </span>socket = BufReader::new(socket);
<a href=#263 id=263 data-nosnippet>263</a> <span class="kw">let </span><span class="kw-2">mut </span>queries = Vec::new();
<a href=#264 id=264 data-nosnippet>264</a> <span class="kw">for </span>(status, body) <span class="kw">in </span>bodies {
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">let </span><span class="kw-2">mut </span>headers = String::new();
<a href=#266 id=266 data-nosnippet>266</a> <span class="kw">loop </span>{
<a href=#267 id=267 data-nosnippet>267</a> <span class="kw">let </span><span class="kw-2">mut </span>line = String::new();
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw">if </span>socket.read_line(<span class="kw-2">&amp;mut </span>line).<span class="kw">await</span>.unwrap() == <span class="number">0 </span>{
<a href=#269 id=269 data-nosnippet>269</a> <span class="macro">assert!</span>(headers.is_empty());
<a href=#270 id=270 data-nosnippet>270</a> <span class="kw">return </span>queries;
<a href=#271 id=271 data-nosnippet>271</a> }
<a href=#272 id=272 data-nosnippet>272</a> headers.push_str(<span class="kw-2">&amp;</span>line);
<a href=#273 id=273 data-nosnippet>273</a> <span class="kw">if </span>line == <span class="string">"\r\n" </span>{
<a href=#274 id=274 data-nosnippet>274</a> <span class="kw">break</span>;
<a href=#275 id=275 data-nosnippet>275</a> }
<a href=#276 id=276 data-nosnippet>276</a> }
<a href=#277 id=277 data-nosnippet>277</a> <span class="kw">let </span>headers = headers.to_lowercase();
<a href=#278 id=278 data-nosnippet>278</a> <span class="macro">assert!</span>(headers.starts_with(<span class="string">"post /v1/sql "</span>));
<a href=#279 id=279 data-nosnippet>279</a> <span class="macro">assert!</span>(headers.contains(<span class="string">"authorization: basic dxnlcjpwyxnzd29yza=="</span>));
<a href=#280 id=280 data-nosnippet>280</a> <span class="macro">assert!</span>(headers.contains(<span class="string">"x-greptime-timeout: 7s"</span>));
<a href=#281 id=281 data-nosnippet>281</a> <span class="kw">let </span>length: usize = headers
<a href=#282 id=282 data-nosnippet>282</a> .lines()
<a href=#283 id=283 data-nosnippet>283</a> .find_map(|line| line.strip_prefix(<span class="string">"content-length: "</span>))
<a href=#284 id=284 data-nosnippet>284</a> .unwrap()
<a href=#285 id=285 data-nosnippet>285</a> .parse()
<a href=#286 id=286 data-nosnippet>286</a> .unwrap();
<a href=#287 id=287 data-nosnippet>287</a> <span class="kw">let </span><span class="kw-2">mut </span>form = <span class="macro">vec!</span>[<span class="number">0</span>; length];
<a href=#288 id=288 data-nosnippet>288</a> socket.read_exact(<span class="kw-2">&amp;mut </span>form).<span class="kw">await</span>.unwrap();
<a href=#289 id=289 data-nosnippet>289</a> <span class="kw">let </span>params: std::collections::HashMap&lt;<span class="kw">_</span>, <span class="kw">_</span>&gt; =
<a href=#290 id=290 data-nosnippet>290</a> url::form_urlencoded::parse(<span class="kw-2">&amp;</span>form).into_owned().collect();
<a href=#291 id=291 data-nosnippet>291</a> <span class="macro">assert_eq!</span>(params[<span class="string">"db"</span>], <span class="string">"catalog-public"</span>);
<a href=#292 id=292 data-nosnippet>292</a> queries.push(params[<span class="string">"sql"</span>].clone());
<a href=#293 id=293 data-nosnippet>293</a> socket
<a href=#294 id=294 data-nosnippet>294</a> .get_mut()
<a href=#295 id=295 data-nosnippet>295</a> .write_all(
<a href=#296 id=296 data-nosnippet>296</a> <span class="macro">format!</span>(
<a href=#297 id=297 data-nosnippet>297</a> <span class="string">"HTTP/1.1 {status} Response\r\nContent-Length: {}\r\n\r\n{body}"</span>,
<a href=#298 id=298 data-nosnippet>298</a> body.len()
<a href=#299 id=299 data-nosnippet>299</a> )
<a href=#300 id=300 data-nosnippet>300</a> .as_bytes(),
<a href=#301 id=301 data-nosnippet>301</a> )
<a href=#302 id=302 data-nosnippet>302</a> .<span class="kw">await
<a href=#303 id=303 data-nosnippet>303</a> </span>.unwrap();
<a href=#304 id=304 data-nosnippet>304</a> }
<a href=#305 id=305 data-nosnippet>305</a> queries
<a href=#306 id=306 data-nosnippet>306</a> })
<a href=#307 id=307 data-nosnippet>307</a> .<span class="kw">await
<a href=#308 id=308 data-nosnippet>308</a> </span>.expect(<span class="string">"mock SQL exchange timed out"</span>)
<a href=#309 id=309 data-nosnippet>309</a> });
<a href=#310 id=310 data-nosnippet>310</a> <span class="kw">let </span>client = DatabaseClient::new(
<a href=#311 id=311 data-nosnippet>311</a> address.to_string(),
<a href=#312 id=312 data-nosnippet>312</a> <span class="string">"catalog"</span>.into(),
<a href=#313 id=313 data-nosnippet>313</a> <span class="prelude-val">Some</span>(<span class="string">"user:password"</span>.into()),
<a href=#314 id=314 data-nosnippet>314</a> std::time::Duration::from_secs(<span class="number">7</span>),
<a href=#315 id=315 data-nosnippet>315</a> <span class="prelude-val">None</span>,
<a href=#316 id=316 data-nosnippet>316</a> <span class="bool-val">true</span>,
<a href=#317 id=317 data-nosnippet>317</a> );
<a href=#318 id=318 data-nosnippet>318</a> (client, server)
<a href=#319 id=319 data-nosnippet>319</a> }
<a href=#320 id=320 data-nosnippet>320</a>
<a href=#321 id=321 data-nosnippet>321</a> <span class="attr">#[tokio::test]
<a href=#322 id=322 data-nosnippet>322</a> </span><span class="kw">async fn </span>batches_preserve_order_context_and_reuse_connection() {
<a href=#323 id=323 data-nosnippet>323</a> <span class="kw">let </span>names: Vec&lt;<span class="kw">_</span>&gt; = (<span class="number">0</span>..<span class="number">129</span>).map(|i| <span class="macro">format!</span>(<span class="string">"表.{i}\";x"</span>)).collect();
<a href=#324 id=324 data-nosnippet>324</a> <span class="kw">let </span>outputs: Vec&lt;<span class="kw">_</span>&gt; = names
<a href=#325 id=325 data-nosnippet>325</a> .iter()
<a href=#326 id=326 data-nosnippet>326</a> .map(|name| records(name, <span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"DDL {name}"</span>)))
<a href=#327 id=327 data-nosnippet>327</a> .collect();
<a href=#328 id=328 data-nosnippet>328</a> <span class="kw">let </span>bodies = outputs
<a href=#329 id=329 data-nosnippet>329</a> .chunks(<span class="number">128</span>)
<a href=#330 id=330 data-nosnippet>330</a> .map(|chunk| {
<a href=#331 id=331 data-nosnippet>331</a> (
<a href=#332 id=332 data-nosnippet>332</a> <span class="number">200</span>,
<a href=#333 id=333 data-nosnippet>333</a> <span class="macro">json!</span>({<span class="string">"output"</span>: chunk, <span class="string">"execution_time_ms"</span>: <span class="number">0</span>}).to_string(),
<a href=#334 id=334 data-nosnippet>334</a> )
<a href=#335 id=335 data-nosnippet>335</a> })
<a href=#336 id=336 data-nosnippet>336</a> .collect();
<a href=#337 id=337 data-nosnippet>337</a> <span class="kw">let </span>(client, server) = start_mock_sql_server(bodies).<span class="kw">await</span>;
<a href=#338 id=338 data-nosnippet>338</a> <span class="kw">let </span><span class="kw-2">mut </span>ddl = String::new();
<a href=#339 id=339 data-nosnippet>339</a> append_schema_ddl(
<a href=#340 id=340 data-nosnippet>340</a> <span class="kw-2">&amp;</span>client.clone(),
<a href=#341 id=341 data-nosnippet>341</a> <span class="string">"catalog"</span>,
<a href=#342 id=342 data-nosnippet>342</a> <span class="string">"schema"</span>,
<a href=#343 id=343 data-nosnippet>343</a> names.iter().map(|name| (<span class="string">"TABLE"</span>, <span class="prelude-val">Some</span>(name.as_str()))),
<a href=#344 id=344 data-nosnippet>344</a> <span class="kw-2">&amp;mut </span>ddl,
<a href=#345 id=345 data-nosnippet>345</a> )
<a href=#346 id=346 data-nosnippet>346</a> .<span class="kw">await
<a href=#347 id=347 data-nosnippet>347</a> </span>.unwrap();
<a href=#348 id=348 data-nosnippet>348</a> <span class="macro">assert_eq!</span>(
<a href=#349 id=349 data-nosnippet>349</a> ddl,
<a href=#350 id=350 data-nosnippet>350</a> names
<a href=#351 id=351 data-nosnippet>351</a> .iter()
<a href=#352 id=352 data-nosnippet>352</a> .map(|name| <span class="macro">format!</span>(<span class="string">"DDL {name};\n"</span>))
<a href=#353 id=353 data-nosnippet>353</a> .collect::&lt;String&gt;()
<a href=#354 id=354 data-nosnippet>354</a> );
<a href=#355 id=355 data-nosnippet>355</a> <span class="kw">let </span>queries = server.<span class="kw">await</span>.unwrap();
<a href=#356 id=356 data-nosnippet>356</a> <span class="kw">let </span>expected: Vec&lt;<span class="kw">_</span>&gt; = (<span class="number">0</span>..<span class="number">129</span>)
<a href=#357 id=357 data-nosnippet>357</a> .map(|i| <span class="macro">format!</span>(<span class="string">"SHOW CREATE TABLE \"catalog\".\"schema\".\"表.{i}\"\";x\";\n"</span>))
<a href=#358 id=358 data-nosnippet>358</a> .collect();
<a href=#359 id=359 data-nosnippet>359</a> <span class="macro">assert_eq!</span>(
<a href=#360 id=360 data-nosnippet>360</a> queries,
<a href=#361 id=361 data-nosnippet>361</a> <span class="macro">vec!</span>[expected[..<span class="number">128</span>].concat(), expected[<span class="number">128</span>..].concat()]
<a href=#362 id=362 data-nosnippet>362</a> );
<a href=#363 id=363 data-nosnippet>363</a> }
<a href=#364 id=364 data-nosnippet>364</a>
<a href=#365 id=365 data-nosnippet>365</a> <span class="attr">#[tokio::test]
<a href=#366 id=366 data-nosnippet>366</a> </span><span class="kw">async fn </span>legacy_command_stops_before_data_after_schema_failure() {
<a href=#367 id=367 data-nosnippet>367</a> <span class="kw">use </span>clap::Parser;
<a href=#368 id=368 data-nosnippet>368</a>
<a href=#369 id=369 data-nosnippet>369</a> <span class="kw">use </span><span class="kw">crate</span>::data::export::ExportCommand;
<a href=#370 id=370 data-nosnippet>370</a>
<a href=#371 id=371 data-nosnippet>371</a> <span class="kw">let </span>output = |rows: Value, columns: usize| {
<a href=#372 id=372 data-nosnippet>372</a> <span class="macro">json!</span>({<span class="string">"records"</span>: {<span class="string">"schema"</span>: {<span class="string">"column_schemas"</span>: (<span class="number">0</span>..columns)
<a href=#373 id=373 data-nosnippet>373</a> .map(|i| <span class="macro">json!</span>({<span class="string">"name"</span>: i.to_string(), <span class="string">"data_type"</span>: <span class="string">"String"</span>}))
<a href=#374 id=374 data-nosnippet>374</a> .collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;()}, <span class="string">"rows"</span>: rows, <span class="string">"total_rows"</span>: rows.as_array().unwrap().len()}})
<a href=#375 id=375 data-nosnippet>375</a> };
<a href=#376 id=376 data-nosnippet>376</a> <span class="kw">let </span>databases = output(<span class="macro">json!</span>([[<span class="string">"public"</span>]]), <span class="number">1</span>);
<a href=#377 id=377 data-nosnippet>377</a> <span class="kw">let </span><span class="kw-2">mut </span>malformed = records(<span class="string">"middle"</span>, <span class="string">"CREATE TABLE middle"</span>);
<a href=#378 id=378 data-nosnippet>378</a> malformed[<span class="string">"records"</span>][<span class="string">"rows"</span>][<span class="number">0</span>][<span class="number">1</span>] = <span class="macro">json!</span>(<span class="number">42</span>);
<a href=#379 id=379 data-nosnippet>379</a> <span class="kw">let </span>bodies = <span class="macro">vec!</span>[
<a href=#380 id=380 data-nosnippet>380</a> <span class="macro">vec!</span>[databases.clone()],
<a href=#381 id=381 data-nosnippet>381</a> <span class="macro">vec!</span>[records(<span class="string">"public"</span>, <span class="string">"CREATE DATABASE public"</span>)],
<a href=#382 id=382 data-nosnippet>382</a> <span class="macro">vec!</span>[databases.clone()],
<a href=#383 id=383 data-nosnippet>383</a> <span class="macro">vec!</span>[output(<span class="macro">json!</span>([]), <span class="number">3</span>)],
<a href=#384 id=384 data-nosnippet>384</a> <span class="macro">vec!</span>[output(
<a href=#385 id=385 data-nosnippet>385</a> <span class="macro">json!</span>([
<a href=#386 id=386 data-nosnippet>386</a> [<span class="string">"catalog"</span>, <span class="string">"public"</span>, <span class="string">"first"</span>, <span class="string">"BASE TABLE"</span>],
<a href=#387 id=387 data-nosnippet>387</a> [<span class="string">"catalog"</span>, <span class="string">"public"</span>, <span class="string">"middle"</span>, <span class="string">"BASE TABLE"</span>],
<a href=#388 id=388 data-nosnippet>388</a> [<span class="string">"catalog"</span>, <span class="string">"public"</span>, <span class="string">"last"</span>, <span class="string">"BASE TABLE"</span>]
<a href=#389 id=389 data-nosnippet>389</a> ]),
<a href=#390 id=390 data-nosnippet>390</a> <span class="number">4</span>,
<a href=#391 id=391 data-nosnippet>391</a> )],
<a href=#392 id=392 data-nosnippet>392</a> <span class="macro">vec!</span>[
<a href=#393 id=393 data-nosnippet>393</a> records(<span class="string">"first"</span>, <span class="string">"CREATE TABLE first"</span>),
<a href=#394 id=394 data-nosnippet>394</a> malformed,
<a href=#395 id=395 data-nosnippet>395</a> records(<span class="string">"last"</span>, <span class="string">"CREATE TABLE last"</span>),
<a href=#396 id=396 data-nosnippet>396</a> ],
<a href=#397 id=397 data-nosnippet>397</a> <span class="macro">vec!</span>[databases],
<a href=#398 id=398 data-nosnippet>398</a> <span class="macro">vec!</span>[<span class="macro">json!</span>({<span class="string">"affectedrows"</span>: <span class="number">0</span>})],
<a href=#399 id=399 data-nosnippet>399</a> ]
<a href=#400 id=400 data-nosnippet>400</a> .into_iter()
<a href=#401 id=401 data-nosnippet>401</a> .map(|output| {
<a href=#402 id=402 data-nosnippet>402</a> (
<a href=#403 id=403 data-nosnippet>403</a> <span class="number">200</span>,
<a href=#404 id=404 data-nosnippet>404</a> <span class="macro">json!</span>({<span class="string">"output"</span>: output, <span class="string">"execution_time_ms"</span>: <span class="number">0</span>}).to_string(),
<a href=#405 id=405 data-nosnippet>405</a> )
<a href=#406 id=406 data-nosnippet>406</a> })
<a href=#407 id=407 data-nosnippet>407</a> .collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;();
<a href=#408 id=408 data-nosnippet>408</a> <span class="kw">for </span>target <span class="kw">in </span>[<span class="string">"schema"</span>, <span class="string">"all"</span>] {
<a href=#409 id=409 data-nosnippet>409</a> <span class="kw">let </span>(client, server) = start_mock_sql_server(bodies.clone()).<span class="kw">await</span>;
<a href=#410 id=410 data-nosnippet>410</a> <span class="kw">let </span>dir = tempfile::tempdir().unwrap();
<a href=#411 id=411 data-nosnippet>411</a> <span class="kw">let </span>command = ExportCommand::parse_from([
<a href=#412 id=412 data-nosnippet>412</a> <span class="string">"export"</span>,
<a href=#413 id=413 data-nosnippet>413</a> <span class="string">"--addr"</span>,
<a href=#414 id=414 data-nosnippet>414</a> client.addr(),
<a href=#415 id=415 data-nosnippet>415</a> <span class="string">"--database"</span>,
<a href=#416 id=416 data-nosnippet>416</a> <span class="string">"catalog-public"</span>,
<a href=#417 id=417 data-nosnippet>417</a> <span class="string">"--output-dir"</span>,
<a href=#418 id=418 data-nosnippet>418</a> dir.path().to_str().unwrap(),
<a href=#419 id=419 data-nosnippet>419</a> <span class="string">"--target"</span>,
<a href=#420 id=420 data-nosnippet>420</a> target,
<a href=#421 id=421 data-nosnippet>421</a> <span class="string">"--auth-basic"</span>,
<a href=#422 id=422 data-nosnippet>422</a> <span class="string">"user:password"</span>,
<a href=#423 id=423 data-nosnippet>423</a> <span class="string">"--timeout"</span>,
<a href=#424 id=424 data-nosnippet>424</a> <span class="string">"7s"</span>,
<a href=#425 id=425 data-nosnippet>425</a> <span class="string">"--no-proxy"</span>,
<a href=#426 id=426 data-nosnippet>426</a> ]);
<a href=#427 id=427 data-nosnippet>427</a> <span class="kw">let </span>tool = command.build().<span class="kw">await</span>.unwrap();
<a href=#428 id=428 data-nosnippet>428</a> <span class="kw">let </span>result = tool.do_work().<span class="kw">await</span>;
<a href=#429 id=429 data-nosnippet>429</a> drop(tool);
<a href=#430 id=430 data-nosnippet>430</a> <span class="kw">let </span>queries = server.<span class="kw">await</span>.unwrap();
<a href=#431 id=431 data-nosnippet>431</a> <span class="macro">assert!</span>(result.unwrap_err().to_string().contains(<span class="string">"middle"</span>));
<a href=#432 id=432 data-nosnippet>432</a> <span class="macro">assert!</span>(
<a href=#433 id=433 data-nosnippet>433</a> dir.path()
<a href=#434 id=434 data-nosnippet>434</a> .join(<span class="string">"catalog/public/create_database.sql"</span>)
<a href=#435 id=435 data-nosnippet>435</a> .is_file()
<a href=#436 id=436 data-nosnippet>436</a> );
<a href=#437 id=437 data-nosnippet>437</a> <span class="macro">assert!</span>(!dir.path().join(<span class="string">"catalog/public/create_tables.sql"</span>).exists());
<a href=#438 id=438 data-nosnippet>438</a> <span class="macro">assert_eq!</span>(queries.len(), <span class="number">6</span>);
<a href=#439 id=439 data-nosnippet>439</a> <span class="macro">assert!</span>(queries[<span class="number">5</span>].contains(<span class="string">"SHOW CREATE TABLE \"catalog\".\"public\".\"middle\""</span>));
<a href=#440 id=440 data-nosnippet>440</a> <span class="macro">assert!</span>(!queries.iter().any(|sql| sql.starts_with(<span class="string">"COPY"</span>)));
<a href=#441 id=441 data-nosnippet>441</a> }
<a href=#442 id=442 data-nosnippet>442</a> }
<a href=#443 id=443 data-nosnippet>443</a>
<a href=#444 id=444 data-nosnippet>444</a> <span class="attr">#[tokio::test]
<a href=#445 id=445 data-nosnippet>445</a> </span><span class="kw">async fn </span>sql_response_errors_do_not_expose_copy_credentials() {
<a href=#446 id=446 data-nosnippet>446</a> <span class="kw">let </span>secret = <span class="string">"sentinel-connection-secret"</span>;
<a href=#447 id=447 data-nosnippet>447</a> <span class="kw">let </span>echoed = <span class="string">"sentinel-response-secret"</span>;
<a href=#448 id=448 data-nosnippet>448</a> <span class="kw">let </span>sql = <span class="macro">format!</span>(
<a href=#449 id=449 data-nosnippet>449</a> <span class="string">"COPY DATABASE public TO 's3://bucket/' CONNECTION (SECRET_ACCESS_KEY='{secret}')"
<a href=#450 id=450 data-nosnippet>450</a> </span>);
<a href=#451 id=451 data-nosnippet>451</a> <span class="kw">let </span>bodies = <span class="macro">vec!</span>[
<a href=#452 id=452 data-nosnippet>452</a> (<span class="number">200</span>, <span class="macro">format!</span>(<span class="string">"not json {echoed}"</span>)),
<a href=#453 id=453 data-nosnippet>453</a> (<span class="number">200</span>, <span class="macro">json!</span>({<span class="string">"output"</span>: [{<span class="string">"records"</span>: echoed}], <span class="string">"execution_time_ms"</span>: <span class="number">0</span>}).to_string()),
<a href=#454 id=454 data-nosnippet>454</a> (<span class="number">400</span>, <span class="macro">json!</span>({<span class="string">"code"</span>: <span class="number">3001</span>, <span class="string">"error"</span>: echoed}).to_string()),
<a href=#455 id=455 data-nosnippet>455</a> (<span class="number">200</span>, <span class="macro">json!</span>({<span class="string">"error"</span>: echoed}).to_string()),
<a href=#456 id=456 data-nosnippet>456</a> (<span class="number">200</span>, <span class="macro">json!</span>({<span class="string">"code"</span>: <span class="number">3001</span>, <span class="string">"output"</span>: [records(<span class="string">"first"</span>, echoed)], <span class="string">"execution_time_ms"</span>: <span class="number">0</span>}).to_string()),
<a href=#457 id=457 data-nosnippet>457</a> (<span class="number">200</span>, <span class="macro">json!</span>({<span class="string">"output"</span>: [{<span class="string">"error"</span>: echoed}]}).to_string()),
<a href=#458 id=458 data-nosnippet>458</a> (<span class="number">200</span>, <span class="macro">json!</span>({<span class="string">"output"</span>: [{<span class="string">"code"</span>: <span class="number">3001</span>, <span class="string">"records"</span>: records(<span class="string">"first"</span>, echoed)[<span class="string">"records"</span>]}], <span class="string">"execution_time_ms"</span>: <span class="number">0</span>}).to_string()),
<a href=#459 id=459 data-nosnippet>459</a> ];
<a href=#460 id=460 data-nosnippet>460</a> <span class="kw">let </span>count = bodies.len();
<a href=#461 id=461 data-nosnippet>461</a> <span class="kw">let </span>(client, server) = start_mock_sql_server(bodies).<span class="kw">await</span>;
<a href=#462 id=462 data-nosnippet>462</a> <span class="kw">for _ in </span><span class="number">0</span>..count {
<a href=#463 id=463 data-nosnippet>463</a> <span class="kw">let </span>error = client
<a href=#464 id=464 data-nosnippet>464</a> .sql_response(<span class="kw-2">&amp;</span>sql, <span class="string">"public"</span>)
<a href=#465 id=465 data-nosnippet>465</a> .<span class="kw">await
<a href=#466 id=466 data-nosnippet>466</a> </span>.unwrap_err()
<a href=#467 id=467 data-nosnippet>467</a> .to_string();
<a href=#468 id=468 data-nosnippet>468</a> <span class="macro">assert!</span>(error.contains(<span class="string">"SQL"</span>), <span class="string">"{error}"</span>);
<a href=#469 id=469 data-nosnippet>469</a> <span class="macro">assert!</span>(!error.contains(secret), <span class="string">"{error}"</span>);
<a href=#470 id=470 data-nosnippet>470</a> <span class="macro">assert!</span>(!error.contains(echoed), <span class="string">"{error}"</span>);
<a href=#471 id=471 data-nosnippet>471</a> <span class="macro">assert!</span>(!error.contains(<span class="string">"COPY DATABASE"</span>), <span class="string">"{error}"</span>);
<a href=#472 id=472 data-nosnippet>472</a> }
<a href=#473 id=473 data-nosnippet>473</a> <span class="macro">assert_eq!</span>(server.<span class="kw">await</span>.unwrap().len(), count);
<a href=#474 id=474 data-nosnippet>474</a> }
<a href=#475 id=475 data-nosnippet>475</a>
<a href=#476 id=476 data-nosnippet>476</a> <span class="attr">#[tokio::test]
<a href=#477 id=477 data-nosnippet>477</a> </span><span class="kw">async fn </span>rejects_http_and_statement_errors_without_retry() {
<a href=#478 id=478 data-nosnippet>478</a> <span class="kw">let </span>valid = records(<span class="string">"first"</span>, <span class="string">"CREATE TABLE first"</span>);
<a href=#479 id=479 data-nosnippet>479</a> <span class="kw">let </span>bodies = <span class="macro">vec!</span>[
<a href=#480 id=480 data-nosnippet>480</a> (<span class="number">400</span>, <span class="macro">json!</span>({<span class="string">"code"</span>: <span class="number">3001</span>, <span class="string">"error"</span>: <span class="string">"middle not found"</span>, <span class="string">"execution_time_ms"</span>: <span class="number">0</span>}).to_string()),
<a href=#481 id=481 data-nosnippet>481</a> (<span class="number">200</span>, <span class="macro">json!</span>({<span class="string">"code"</span>: <span class="number">3001</span>, <span class="string">"output"</span>: [valid.clone(), valid.clone(), valid.clone()], <span class="string">"execution_time_ms"</span>: <span class="number">0</span>}).to_string()),
<a href=#482 id=482 data-nosnippet>482</a> (<span class="number">200</span>, <span class="macro">json!</span>({<span class="string">"output"</span>: [valid.clone(), {<span class="string">"error"</span>: <span class="string">"middle denied"</span>}, valid.clone()], <span class="string">"execution_time_ms"</span>: <span class="number">0</span>}).to_string()),
<a href=#483 id=483 data-nosnippet>483</a> (<span class="number">200</span>, <span class="macro">json!</span>({<span class="string">"output"</span>: [valid.clone(), {<span class="string">"error"</span>: <span class="string">"middle denied"</span>, <span class="string">"records"</span>: valid[<span class="string">"records"</span>]}, valid], <span class="string">"execution_time_ms"</span>: <span class="number">0</span>}).to_string()),
<a href=#484 id=484 data-nosnippet>484</a> (<span class="number">200</span>, <span class="macro">json!</span>({<span class="string">"output"</span>: [records(<span class="string">"first"</span>, <span class="string">"DDL"</span>), {<span class="string">"code"</span>: <span class="number">3001</span>, <span class="string">"records"</span>: records(<span class="string">"middle"</span>, <span class="string">"DDL"</span>)[<span class="string">"records"</span>]}, records(<span class="string">"last"</span>, <span class="string">"DDL"</span>)], <span class="string">"execution_time_ms"</span>: <span class="number">0</span>}).to_string()),
<a href=#485 id=485 data-nosnippet>485</a> (<span class="number">200</span>, <span class="string">r#"{"execution_time_ms":0}"#</span>.into()),
<a href=#486 id=486 data-nosnippet>486</a> (<span class="number">200</span>, <span class="string">"not json"</span>.into()),
<a href=#487 id=487 data-nosnippet>487</a> ];
<a href=#488 id=488 data-nosnippet>488</a> <span class="kw">let </span>count = bodies.len();
<a href=#489 id=489 data-nosnippet>489</a> <span class="kw">let </span>(client, server) = start_mock_sql_server(bodies).<span class="kw">await</span>;
<a href=#490 id=490 data-nosnippet>490</a> <span class="kw">for _ in </span><span class="number">0</span>..count {
<a href=#491 id=491 data-nosnippet>491</a> <span class="kw">let </span><span class="kw-2">mut </span>ddl = String::new();
<a href=#492 id=492 data-nosnippet>492</a> <span class="kw">let </span>error = append_schema_ddl(
<a href=#493 id=493 data-nosnippet>493</a> <span class="kw-2">&amp;</span>client,
<a href=#494 id=494 data-nosnippet>494</a> <span class="string">"catalog"</span>,
<a href=#495 id=495 data-nosnippet>495</a> <span class="string">"schema"</span>,
<a href=#496 id=496 data-nosnippet>496</a> [<span class="string">"first"</span>, <span class="string">"middle"</span>, <span class="string">"last"</span>]
<a href=#497 id=497 data-nosnippet>497</a> .into_iter()
<a href=#498 id=498 data-nosnippet>498</a> .map(|name| (<span class="string">"TABLE"</span>, <span class="prelude-val">Some</span>(name))),
<a href=#499 id=499 data-nosnippet>499</a> <span class="kw-2">&amp;mut </span>ddl,
<a href=#500 id=500 data-nosnippet>500</a> )
<a href=#501 id=501 data-nosnippet>501</a> .<span class="kw">await
<a href=#502 id=502 data-nosnippet>502</a> </span>.unwrap_err();
<a href=#503 id=503 data-nosnippet>503</a> <span class="macro">assert!</span>(error.to_string().contains(<span class="string">"middle"</span>), <span class="string">"{error}"</span>);
<a href=#504 id=504 data-nosnippet>504</a> <span class="macro">assert!</span>(ddl.is_empty());
<a href=#505 id=505 data-nosnippet>505</a> }
<a href=#506 id=506 data-nosnippet>506</a> <span class="macro">assert_eq!</span>(server.<span class="kw">await</span>.unwrap().len(), count);
<a href=#507 id=507 data-nosnippet>507</a> }
<a href=#508 id=508 data-nosnippet>508</a>}
</code></pre></div></section></main></body></html>
File diff suppressed because it is too large Load Diff
+41
View File
@@ -0,0 +1,41 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/sql.rs`."><title>sql.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/</div>sql.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="doccomment">//! Shared SQL escaping helpers for CLI-generated statements.
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>escape_sql_literal(value: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#18 id=18 data-nosnippet>18</a> value.replace(<span class="string">'\''</span>, <span class="string">"''"</span>)
<a href=#19 id=19 data-nosnippet>19</a>}
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>escape_sql_identifier(value: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#22 id=22 data-nosnippet>22</a> value.replace(<span class="string">'"'</span>, <span class="string">"\"\""</span>)
<a href=#23 id=23 data-nosnippet>23</a>}
<a href=#24 id=24 data-nosnippet>24</a>
<a href=#25 id=25 data-nosnippet>25</a><span class="attr">#[cfg(test)]
<a href=#26 id=26 data-nosnippet>26</a></span><span class="kw">mod </span>tests {
<a href=#27 id=27 data-nosnippet>27</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#28 id=28 data-nosnippet>28</a>
<a href=#29 id=29 data-nosnippet>29</a> <span class="attr">#[test]
<a href=#30 id=30 data-nosnippet>30</a> </span><span class="kw">fn </span>test_escape_sql_literal_escapes_single_quotes() {
<a href=#31 id=31 data-nosnippet>31</a> <span class="macro">assert_eq!</span>(escape_sql_literal(<span class="string">"test_db"</span>), <span class="string">"test_db"</span>);
<a href=#32 id=32 data-nosnippet>32</a> <span class="macro">assert_eq!</span>(escape_sql_literal(<span class="string">"te'st"</span>), <span class="string">"te''st"</span>);
<a href=#33 id=33 data-nosnippet>33</a> }
<a href=#34 id=34 data-nosnippet>34</a>
<a href=#35 id=35 data-nosnippet>35</a> <span class="attr">#[test]
<a href=#36 id=36 data-nosnippet>36</a> </span><span class="kw">fn </span>test_escape_sql_identifier_escapes_double_quotes() {
<a href=#37 id=37 data-nosnippet>37</a> <span class="macro">assert_eq!</span>(escape_sql_identifier(<span class="string">"test_db"</span>), <span class="string">"test_db"</span>);
<a href=#38 id=38 data-nosnippet>38</a> <span class="macro">assert_eq!</span>(escape_sql_identifier(<span class="string">r#"te"st"#</span>), <span class="string">r#"te""st"#</span>);
<a href=#39 id=39 data-nosnippet>39</a> }
<a href=#40 id=40 data-nosnippet>40</a>}
</code></pre></div></section></main></body></html>
+370
View File
@@ -0,0 +1,370 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/data/storage_export.rs`."><title>storage_export.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/data/</div>storage_export.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::path::PathBuf;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_base::secrets::{ExposeSecret, SecretString};
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#19 id=19 data-nosnippet>19</a>
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span><span class="kw">crate</span>::common::{
<a href=#21 id=21 data-nosnippet>21</a> PrefixedAzblobConnection, PrefixedGcsConnection, PrefixedOssConnection, PrefixedS3Connection,
<a href=#22 id=22 data-nosnippet>22</a>};
<a href=#23 id=23 data-nosnippet>23</a>
<a href=#24 id=24 data-nosnippet>24</a><span class="doccomment">/// Helper function to extract secret string from Option&lt;SecretString&gt;.
<a href=#25 id=25 data-nosnippet>25</a>/// Returns empty string if None.
<a href=#26 id=26 data-nosnippet>26</a></span><span class="kw">fn </span>expose_optional_secret(secret: <span class="kw-2">&amp;</span><span class="prelude-ty">Option</span>&lt;SecretString&gt;) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#27 id=27 data-nosnippet>27</a> secret
<a href=#28 id=28 data-nosnippet>28</a> .as_ref()
<a href=#29 id=29 data-nosnippet>29</a> .map(|s| s.expose_secret().as_str())
<a href=#30 id=30 data-nosnippet>30</a> .unwrap_or(<span class="string">""</span>)
<a href=#31 id=31 data-nosnippet>31</a>}
<a href=#32 id=32 data-nosnippet>32</a>
<a href=#33 id=33 data-nosnippet>33</a><span class="doccomment">/// Helper function to format root path with leading slash if non-empty.
<a href=#34 id=34 data-nosnippet>34</a></span><span class="kw">fn </span>format_root_path(root: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#35 id=35 data-nosnippet>35</a> <span class="kw">if </span>root.is_empty() {
<a href=#36 id=36 data-nosnippet>36</a> String::new()
<a href=#37 id=37 data-nosnippet>37</a> } <span class="kw">else </span>{
<a href=#38 id=38 data-nosnippet>38</a> <span class="macro">format!</span>(<span class="string">"/{}"</span>, root)
<a href=#39 id=39 data-nosnippet>39</a> }
<a href=#40 id=40 data-nosnippet>40</a>}
<a href=#41 id=41 data-nosnippet>41</a>
<a href=#42 id=42 data-nosnippet>42</a><span class="doccomment">/// Helper function to mask multiple secrets in a string.
<a href=#43 id=43 data-nosnippet>43</a></span><span class="kw">fn </span>mask_secrets(<span class="kw-2">mut </span>sql: String, secrets: <span class="kw-2">&amp;</span>[<span class="kw-2">&amp;</span>str]) -&gt; String {
<a href=#44 id=44 data-nosnippet>44</a> <span class="kw">for </span>secret <span class="kw">in </span>secrets {
<a href=#45 id=45 data-nosnippet>45</a> <span class="kw">if </span>!secret.is_empty() {
<a href=#46 id=46 data-nosnippet>46</a> sql = sql.replace(secret, <span class="string">"[REDACTED]"</span>);
<a href=#47 id=47 data-nosnippet>47</a> }
<a href=#48 id=48 data-nosnippet>48</a> }
<a href=#49 id=49 data-nosnippet>49</a> sql
<a href=#50 id=50 data-nosnippet>50</a>}
<a href=#51 id=51 data-nosnippet>51</a>
<a href=#52 id=52 data-nosnippet>52</a><span class="doccomment">/// Helper function to format storage URI.
<a href=#53 id=53 data-nosnippet>53</a></span><span class="kw">fn </span>format_uri(scheme: <span class="kw-2">&amp;</span>str, bucket: <span class="kw-2">&amp;</span>str, root: <span class="kw-2">&amp;</span>str, path: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#54 id=54 data-nosnippet>54</a> <span class="kw">let </span>root = format_root_path(root);
<a href=#55 id=55 data-nosnippet>55</a> <span class="macro">format!</span>(<span class="string">"{}://{}{}/{}"</span>, scheme, bucket, root, path)
<a href=#56 id=56 data-nosnippet>56</a>}
<a href=#57 id=57 data-nosnippet>57</a>
<a href=#58 id=58 data-nosnippet>58</a><span class="doccomment">/// Trait for storage backends that can be used for data export.
<a href=#59 id=59 data-nosnippet>59</a></span><span class="kw">pub trait </span>StorageExport: Send + Sync {
<a href=#60 id=60 data-nosnippet>60</a> <span class="doccomment">/// Generate the storage path for COPY DATABASE command.
<a href=#61 id=61 data-nosnippet>61</a> /// Returns (path, connection_string) where connection_string includes CONNECTION clause.
<a href=#62 id=62 data-nosnippet>62</a> </span><span class="kw">fn </span>get_storage_path(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog: <span class="kw-2">&amp;</span>str, schema: <span class="kw-2">&amp;</span>str) -&gt; (String, String);
<a href=#63 id=63 data-nosnippet>63</a>
<a href=#64 id=64 data-nosnippet>64</a> <span class="doccomment">/// Format the output path for logging purposes.
<a href=#65 id=65 data-nosnippet>65</a> </span><span class="kw">fn </span>format_output_path(<span class="kw-2">&amp;</span><span class="self">self</span>, file_path: <span class="kw-2">&amp;</span>str) -&gt; String;
<a href=#66 id=66 data-nosnippet>66</a>
<a href=#67 id=67 data-nosnippet>67</a> <span class="doccomment">/// Mask sensitive information in SQL commands for safe logging.
<a href=#68 id=68 data-nosnippet>68</a> </span><span class="kw">fn </span>mask_sensitive_info(<span class="kw-2">&amp;</span><span class="self">self</span>, sql: <span class="kw-2">&amp;</span>str) -&gt; String;
<a href=#69 id=69 data-nosnippet>69</a>}
<a href=#70 id=70 data-nosnippet>70</a>
<a href=#71 id=71 data-nosnippet>71</a><span class="macro">macro_rules!</span> define_backend {
<a href=#72 id=72 data-nosnippet>72</a> (<span class="macro-nonterminal">$name</span>:ident, <span class="macro-nonterminal">$config</span>:ty) =&gt; {
<a href=#73 id=73 data-nosnippet>73</a> <span class="attr">#[derive(Clone)]
<a href=#74 id=74 data-nosnippet>74</a> </span><span class="kw">pub struct </span><span class="macro-nonterminal">$name </span>{
<a href=#75 id=75 data-nosnippet>75</a> config: <span class="macro-nonterminal">$config</span>,
<a href=#76 id=76 data-nosnippet>76</a> }
<a href=#77 id=77 data-nosnippet>77</a>
<a href=#78 id=78 data-nosnippet>78</a> <span class="kw">impl </span><span class="macro-nonterminal">$name </span>{
<a href=#79 id=79 data-nosnippet>79</a> <span class="kw">pub fn </span>new(config: <span class="macro-nonterminal">$config</span>) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="self">Self</span>, BoxedError&gt; {
<a href=#80 id=80 data-nosnippet>80</a> config.validate()<span class="question-mark">?</span>;
<a href=#81 id=81 data-nosnippet>81</a> <span class="prelude-val">Ok</span>(<span class="self">Self </span>{ config })
<a href=#82 id=82 data-nosnippet>82</a> }
<a href=#83 id=83 data-nosnippet>83</a> }
<a href=#84 id=84 data-nosnippet>84</a> };
<a href=#85 id=85 data-nosnippet>85</a>}
<a href=#86 id=86 data-nosnippet>86</a>
<a href=#87 id=87 data-nosnippet>87</a><span class="doccomment">/// Local file system storage backend.
<a href=#88 id=88 data-nosnippet>88</a></span><span class="attr">#[derive(Clone)]
<a href=#89 id=89 data-nosnippet>89</a></span><span class="kw">pub struct </span>FsBackend {
<a href=#90 id=90 data-nosnippet>90</a> output_dir: String,
<a href=#91 id=91 data-nosnippet>91</a>}
<a href=#92 id=92 data-nosnippet>92</a>
<a href=#93 id=93 data-nosnippet>93</a><span class="kw">impl </span>FsBackend {
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">pub fn </span>new(output_dir: String) -&gt; <span class="self">Self </span>{
<a href=#95 id=95 data-nosnippet>95</a> <span class="self">Self </span>{ output_dir }
<a href=#96 id=96 data-nosnippet>96</a> }
<a href=#97 id=97 data-nosnippet>97</a>}
<a href=#98 id=98 data-nosnippet>98</a>
<a href=#99 id=99 data-nosnippet>99</a><span class="kw">impl </span>StorageExport <span class="kw">for </span>FsBackend {
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">fn </span>get_storage_path(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog: <span class="kw-2">&amp;</span>str, schema: <span class="kw-2">&amp;</span>str) -&gt; (String, String) {
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">if </span><span class="self">self</span>.output_dir.is_empty() {
<a href=#102 id=102 data-nosnippet>102</a> <span class="macro">unreachable!</span>(<span class="string">"output_dir must be set when not using remote storage"</span>)
<a href=#103 id=103 data-nosnippet>103</a> }
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">let </span>path = PathBuf::from(<span class="kw-2">&amp;</span><span class="self">self</span>.output_dir)
<a href=#105 id=105 data-nosnippet>105</a> .join(catalog)
<a href=#106 id=106 data-nosnippet>106</a> .join(<span class="macro">format!</span>(<span class="string">"{schema}/"</span>))
<a href=#107 id=107 data-nosnippet>107</a> .to_string_lossy()
<a href=#108 id=108 data-nosnippet>108</a> .to_string();
<a href=#109 id=109 data-nosnippet>109</a> (path, String::new())
<a href=#110 id=110 data-nosnippet>110</a> }
<a href=#111 id=111 data-nosnippet>111</a>
<a href=#112 id=112 data-nosnippet>112</a> <span class="kw">fn </span>format_output_path(<span class="kw-2">&amp;</span><span class="self">self</span>, file_path: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#113 id=113 data-nosnippet>113</a> <span class="macro">format!</span>(<span class="string">"{}/{}"</span>, <span class="self">self</span>.output_dir, file_path)
<a href=#114 id=114 data-nosnippet>114</a> }
<a href=#115 id=115 data-nosnippet>115</a>
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw">fn </span>mask_sensitive_info(<span class="kw-2">&amp;</span><span class="self">self</span>, sql: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#117 id=117 data-nosnippet>117</a> sql.to_string()
<a href=#118 id=118 data-nosnippet>118</a> }
<a href=#119 id=119 data-nosnippet>119</a>}
<a href=#120 id=120 data-nosnippet>120</a>
<a href=#121 id=121 data-nosnippet>121</a><span class="macro">define_backend!</span>(S3Backend, PrefixedS3Connection);
<a href=#122 id=122 data-nosnippet>122</a>
<a href=#123 id=123 data-nosnippet>123</a><span class="kw">impl </span>StorageExport <span class="kw">for </span>S3Backend {
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">fn </span>get_storage_path(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog: <span class="kw-2">&amp;</span>str, schema: <span class="kw-2">&amp;</span>str) -&gt; (String, String) {
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw">let </span>s3_path = format_uri(
<a href=#126 id=126 data-nosnippet>126</a> <span class="string">"s3"</span>,
<a href=#127 id=127 data-nosnippet>127</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.s3_bucket,
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.s3_root,
<a href=#129 id=129 data-nosnippet>129</a> <span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"{}/{}/"</span>, catalog, schema),
<a href=#130 id=130 data-nosnippet>130</a> );
<a href=#131 id=131 data-nosnippet>131</a>
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">let </span><span class="kw-2">mut </span>connection_options = <span class="macro">vec!</span>[
<a href=#133 id=133 data-nosnippet>133</a> <span class="macro">format!</span>(
<a href=#134 id=134 data-nosnippet>134</a> <span class="string">"ACCESS_KEY_ID='{}'"</span>,
<a href=#135 id=135 data-nosnippet>135</a> expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.s3_access_key_id)
<a href=#136 id=136 data-nosnippet>136</a> ),
<a href=#137 id=137 data-nosnippet>137</a> <span class="macro">format!</span>(
<a href=#138 id=138 data-nosnippet>138</a> <span class="string">"SECRET_ACCESS_KEY='{}'"</span>,
<a href=#139 id=139 data-nosnippet>139</a> expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.s3_secret_access_key)
<a href=#140 id=140 data-nosnippet>140</a> ),
<a href=#141 id=141 data-nosnippet>141</a> ];
<a href=#142 id=142 data-nosnippet>142</a>
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(region) = <span class="kw-2">&amp;</span><span class="self">self</span>.config.s3_region {
<a href=#144 id=144 data-nosnippet>144</a> connection_options.push(<span class="macro">format!</span>(<span class="string">"REGION='{}'"</span>, region));
<a href=#145 id=145 data-nosnippet>145</a> }
<a href=#146 id=146 data-nosnippet>146</a>
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(endpoint) = <span class="kw-2">&amp;</span><span class="self">self</span>.config.s3_endpoint {
<a href=#148 id=148 data-nosnippet>148</a> connection_options.push(<span class="macro">format!</span>(<span class="string">"ENDPOINT='{}'"</span>, endpoint));
<a href=#149 id=149 data-nosnippet>149</a> }
<a href=#150 id=150 data-nosnippet>150</a>
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">let </span>connection_str = <span class="macro">format!</span>(<span class="string">" CONNECTION ({})"</span>, connection_options.join(<span class="string">", "</span>));
<a href=#152 id=152 data-nosnippet>152</a> (s3_path, connection_str)
<a href=#153 id=153 data-nosnippet>153</a> }
<a href=#154 id=154 data-nosnippet>154</a>
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">fn </span>format_output_path(<span class="kw-2">&amp;</span><span class="self">self</span>, file_path: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#156 id=156 data-nosnippet>156</a> format_uri(
<a href=#157 id=157 data-nosnippet>157</a> <span class="string">"s3"</span>,
<a href=#158 id=158 data-nosnippet>158</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.s3_bucket,
<a href=#159 id=159 data-nosnippet>159</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.s3_root,
<a href=#160 id=160 data-nosnippet>160</a> file_path,
<a href=#161 id=161 data-nosnippet>161</a> )
<a href=#162 id=162 data-nosnippet>162</a> }
<a href=#163 id=163 data-nosnippet>163</a>
<a href=#164 id=164 data-nosnippet>164</a> <span class="kw">fn </span>mask_sensitive_info(<span class="kw-2">&amp;</span><span class="self">self</span>, sql: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#165 id=165 data-nosnippet>165</a> mask_secrets(
<a href=#166 id=166 data-nosnippet>166</a> sql.to_string(),
<a href=#167 id=167 data-nosnippet>167</a> <span class="kw-2">&amp;</span>[
<a href=#168 id=168 data-nosnippet>168</a> expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.s3_access_key_id),
<a href=#169 id=169 data-nosnippet>169</a> expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.s3_secret_access_key),
<a href=#170 id=170 data-nosnippet>170</a> ],
<a href=#171 id=171 data-nosnippet>171</a> )
<a href=#172 id=172 data-nosnippet>172</a> }
<a href=#173 id=173 data-nosnippet>173</a>}
<a href=#174 id=174 data-nosnippet>174</a>
<a href=#175 id=175 data-nosnippet>175</a><span class="macro">define_backend!</span>(OssBackend, PrefixedOssConnection);
<a href=#176 id=176 data-nosnippet>176</a>
<a href=#177 id=177 data-nosnippet>177</a><span class="kw">impl </span>StorageExport <span class="kw">for </span>OssBackend {
<a href=#178 id=178 data-nosnippet>178</a> <span class="kw">fn </span>get_storage_path(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog: <span class="kw-2">&amp;</span>str, schema: <span class="kw-2">&amp;</span>str) -&gt; (String, String) {
<a href=#179 id=179 data-nosnippet>179</a> <span class="kw">let </span>oss_path = format_uri(
<a href=#180 id=180 data-nosnippet>180</a> <span class="string">"oss"</span>,
<a href=#181 id=181 data-nosnippet>181</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.oss_bucket,
<a href=#182 id=182 data-nosnippet>182</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.oss_root,
<a href=#183 id=183 data-nosnippet>183</a> <span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"{}/{}/"</span>, catalog, schema),
<a href=#184 id=184 data-nosnippet>184</a> );
<a href=#185 id=185 data-nosnippet>185</a>
<a href=#186 id=186 data-nosnippet>186</a> <span class="kw">let </span>connection_options = [
<a href=#187 id=187 data-nosnippet>187</a> <span class="macro">format!</span>(
<a href=#188 id=188 data-nosnippet>188</a> <span class="string">"ACCESS_KEY_ID='{}'"</span>,
<a href=#189 id=189 data-nosnippet>189</a> expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.oss_access_key_id)
<a href=#190 id=190 data-nosnippet>190</a> ),
<a href=#191 id=191 data-nosnippet>191</a> <span class="macro">format!</span>(
<a href=#192 id=192 data-nosnippet>192</a> <span class="string">"ACCESS_KEY_SECRET='{}'"</span>,
<a href=#193 id=193 data-nosnippet>193</a> expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.oss_access_key_secret)
<a href=#194 id=194 data-nosnippet>194</a> ),
<a href=#195 id=195 data-nosnippet>195</a> ];
<a href=#196 id=196 data-nosnippet>196</a>
<a href=#197 id=197 data-nosnippet>197</a> <span class="kw">let </span>connection_str = <span class="macro">format!</span>(<span class="string">" CONNECTION ({})"</span>, connection_options.join(<span class="string">", "</span>));
<a href=#198 id=198 data-nosnippet>198</a> (oss_path, connection_str)
<a href=#199 id=199 data-nosnippet>199</a> }
<a href=#200 id=200 data-nosnippet>200</a>
<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">fn </span>format_output_path(<span class="kw-2">&amp;</span><span class="self">self</span>, file_path: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#202 id=202 data-nosnippet>202</a> format_uri(
<a href=#203 id=203 data-nosnippet>203</a> <span class="string">"oss"</span>,
<a href=#204 id=204 data-nosnippet>204</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.oss_bucket,
<a href=#205 id=205 data-nosnippet>205</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.oss_root,
<a href=#206 id=206 data-nosnippet>206</a> file_path,
<a href=#207 id=207 data-nosnippet>207</a> )
<a href=#208 id=208 data-nosnippet>208</a> }
<a href=#209 id=209 data-nosnippet>209</a>
<a href=#210 id=210 data-nosnippet>210</a> <span class="kw">fn </span>mask_sensitive_info(<span class="kw-2">&amp;</span><span class="self">self</span>, sql: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#211 id=211 data-nosnippet>211</a> mask_secrets(
<a href=#212 id=212 data-nosnippet>212</a> sql.to_string(),
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw-2">&amp;</span>[
<a href=#214 id=214 data-nosnippet>214</a> expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.oss_access_key_id),
<a href=#215 id=215 data-nosnippet>215</a> expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.oss_access_key_secret),
<a href=#216 id=216 data-nosnippet>216</a> ],
<a href=#217 id=217 data-nosnippet>217</a> )
<a href=#218 id=218 data-nosnippet>218</a> }
<a href=#219 id=219 data-nosnippet>219</a>}
<a href=#220 id=220 data-nosnippet>220</a>
<a href=#221 id=221 data-nosnippet>221</a><span class="macro">define_backend!</span>(GcsBackend, PrefixedGcsConnection);
<a href=#222 id=222 data-nosnippet>222</a>
<a href=#223 id=223 data-nosnippet>223</a><span class="kw">impl </span>StorageExport <span class="kw">for </span>GcsBackend {
<a href=#224 id=224 data-nosnippet>224</a> <span class="kw">fn </span>get_storage_path(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog: <span class="kw-2">&amp;</span>str, schema: <span class="kw-2">&amp;</span>str) -&gt; (String, String) {
<a href=#225 id=225 data-nosnippet>225</a> <span class="kw">let </span>gcs_path = format_uri(
<a href=#226 id=226 data-nosnippet>226</a> <span class="string">"gcs"</span>,
<a href=#227 id=227 data-nosnippet>227</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.gcs_bucket,
<a href=#228 id=228 data-nosnippet>228</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.gcs_root,
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"{}/{}/"</span>, catalog, schema),
<a href=#230 id=230 data-nosnippet>230</a> );
<a href=#231 id=231 data-nosnippet>231</a>
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">let </span><span class="kw-2">mut </span>connection_options = Vec::new();
<a href=#233 id=233 data-nosnippet>233</a> <span class="kw">let </span>credential_path = expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.gcs_credential_path);
<a href=#234 id=234 data-nosnippet>234</a> <span class="kw">if </span>!credential_path.is_empty() {
<a href=#235 id=235 data-nosnippet>235</a> connection_options.push(<span class="macro">format!</span>(<span class="string">"CREDENTIAL_PATH='{}'"</span>, credential_path));
<a href=#236 id=236 data-nosnippet>236</a> }
<a href=#237 id=237 data-nosnippet>237</a>
<a href=#238 id=238 data-nosnippet>238</a> <span class="kw">let </span>credential = expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.gcs_credential);
<a href=#239 id=239 data-nosnippet>239</a> <span class="kw">if </span>!credential.is_empty() {
<a href=#240 id=240 data-nosnippet>240</a> connection_options.push(<span class="macro">format!</span>(<span class="string">"CREDENTIAL='{}'"</span>, credential));
<a href=#241 id=241 data-nosnippet>241</a> }
<a href=#242 id=242 data-nosnippet>242</a>
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">if </span>!<span class="self">self</span>.config.gcs_endpoint.is_empty() {
<a href=#244 id=244 data-nosnippet>244</a> connection_options.push(<span class="macro">format!</span>(<span class="string">"ENDPOINT='{}'"</span>, <span class="self">self</span>.config.gcs_endpoint));
<a href=#245 id=245 data-nosnippet>245</a> }
<a href=#246 id=246 data-nosnippet>246</a>
<a href=#247 id=247 data-nosnippet>247</a> <span class="kw">let </span>connection_str = <span class="kw">if </span>connection_options.is_empty() {
<a href=#248 id=248 data-nosnippet>248</a> String::new()
<a href=#249 id=249 data-nosnippet>249</a> } <span class="kw">else </span>{
<a href=#250 id=250 data-nosnippet>250</a> <span class="macro">format!</span>(<span class="string">" CONNECTION ({})"</span>, connection_options.join(<span class="string">", "</span>))
<a href=#251 id=251 data-nosnippet>251</a> };
<a href=#252 id=252 data-nosnippet>252</a>
<a href=#253 id=253 data-nosnippet>253</a> (gcs_path, connection_str)
<a href=#254 id=254 data-nosnippet>254</a> }
<a href=#255 id=255 data-nosnippet>255</a>
<a href=#256 id=256 data-nosnippet>256</a> <span class="kw">fn </span>format_output_path(<span class="kw-2">&amp;</span><span class="self">self</span>, file_path: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#257 id=257 data-nosnippet>257</a> format_uri(
<a href=#258 id=258 data-nosnippet>258</a> <span class="string">"gcs"</span>,
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.gcs_bucket,
<a href=#260 id=260 data-nosnippet>260</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.gcs_root,
<a href=#261 id=261 data-nosnippet>261</a> file_path,
<a href=#262 id=262 data-nosnippet>262</a> )
<a href=#263 id=263 data-nosnippet>263</a> }
<a href=#264 id=264 data-nosnippet>264</a>
<a href=#265 id=265 data-nosnippet>265</a> <span class="kw">fn </span>mask_sensitive_info(<span class="kw-2">&amp;</span><span class="self">self</span>, sql: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#266 id=266 data-nosnippet>266</a> mask_secrets(
<a href=#267 id=267 data-nosnippet>267</a> sql.to_string(),
<a href=#268 id=268 data-nosnippet>268</a> <span class="kw-2">&amp;</span>[expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.gcs_credential)],
<a href=#269 id=269 data-nosnippet>269</a> )
<a href=#270 id=270 data-nosnippet>270</a> }
<a href=#271 id=271 data-nosnippet>271</a>}
<a href=#272 id=272 data-nosnippet>272</a>
<a href=#273 id=273 data-nosnippet>273</a><span class="macro">define_backend!</span>(AzblobBackend, PrefixedAzblobConnection);
<a href=#274 id=274 data-nosnippet>274</a>
<a href=#275 id=275 data-nosnippet>275</a><span class="kw">impl </span>StorageExport <span class="kw">for </span>AzblobBackend {
<a href=#276 id=276 data-nosnippet>276</a> <span class="kw">fn </span>get_storage_path(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog: <span class="kw-2">&amp;</span>str, schema: <span class="kw-2">&amp;</span>str) -&gt; (String, String) {
<a href=#277 id=277 data-nosnippet>277</a> <span class="kw">let </span>azblob_path = format_uri(
<a href=#278 id=278 data-nosnippet>278</a> <span class="string">"azblob"</span>,
<a href=#279 id=279 data-nosnippet>279</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.azblob_container,
<a href=#280 id=280 data-nosnippet>280</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.azblob_root,
<a href=#281 id=281 data-nosnippet>281</a> <span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"{}/{}/"</span>, catalog, schema),
<a href=#282 id=282 data-nosnippet>282</a> );
<a href=#283 id=283 data-nosnippet>283</a>
<a href=#284 id=284 data-nosnippet>284</a> <span class="kw">let </span><span class="kw-2">mut </span>connection_options = <span class="macro">vec!</span>[
<a href=#285 id=285 data-nosnippet>285</a> <span class="macro">format!</span>(
<a href=#286 id=286 data-nosnippet>286</a> <span class="string">"ACCOUNT_NAME='{}'"</span>,
<a href=#287 id=287 data-nosnippet>287</a> expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.azblob_account_name)
<a href=#288 id=288 data-nosnippet>288</a> ),
<a href=#289 id=289 data-nosnippet>289</a> <span class="macro">format!</span>(
<a href=#290 id=290 data-nosnippet>290</a> <span class="string">"ACCOUNT_KEY='{}'"</span>,
<a href=#291 id=291 data-nosnippet>291</a> expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.azblob_account_key)
<a href=#292 id=292 data-nosnippet>292</a> ),
<a href=#293 id=293 data-nosnippet>293</a> ];
<a href=#294 id=294 data-nosnippet>294</a>
<a href=#295 id=295 data-nosnippet>295</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(sas_token) = <span class="kw-2">&amp;</span><span class="self">self</span>.config.azblob_sas_token {
<a href=#296 id=296 data-nosnippet>296</a> connection_options.push(<span class="macro">format!</span>(<span class="string">"SAS_TOKEN='{}'"</span>, sas_token));
<a href=#297 id=297 data-nosnippet>297</a> }
<a href=#298 id=298 data-nosnippet>298</a>
<a href=#299 id=299 data-nosnippet>299</a> <span class="kw">let </span>connection_str = <span class="macro">format!</span>(<span class="string">" CONNECTION ({})"</span>, connection_options.join(<span class="string">", "</span>));
<a href=#300 id=300 data-nosnippet>300</a> (azblob_path, connection_str)
<a href=#301 id=301 data-nosnippet>301</a> }
<a href=#302 id=302 data-nosnippet>302</a>
<a href=#303 id=303 data-nosnippet>303</a> <span class="kw">fn </span>format_output_path(<span class="kw-2">&amp;</span><span class="self">self</span>, file_path: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#304 id=304 data-nosnippet>304</a> format_uri(
<a href=#305 id=305 data-nosnippet>305</a> <span class="string">"azblob"</span>,
<a href=#306 id=306 data-nosnippet>306</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.azblob_container,
<a href=#307 id=307 data-nosnippet>307</a> <span class="kw-2">&amp;</span><span class="self">self</span>.config.azblob_root,
<a href=#308 id=308 data-nosnippet>308</a> file_path,
<a href=#309 id=309 data-nosnippet>309</a> )
<a href=#310 id=310 data-nosnippet>310</a> }
<a href=#311 id=311 data-nosnippet>311</a>
<a href=#312 id=312 data-nosnippet>312</a> <span class="kw">fn </span>mask_sensitive_info(<span class="kw-2">&amp;</span><span class="self">self</span>, sql: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#313 id=313 data-nosnippet>313</a> mask_secrets(
<a href=#314 id=314 data-nosnippet>314</a> sql.to_string(),
<a href=#315 id=315 data-nosnippet>315</a> <span class="kw-2">&amp;</span>[
<a href=#316 id=316 data-nosnippet>316</a> expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.azblob_account_name),
<a href=#317 id=317 data-nosnippet>317</a> expose_optional_secret(<span class="kw-2">&amp;</span><span class="self">self</span>.config.azblob_account_key),
<a href=#318 id=318 data-nosnippet>318</a> ],
<a href=#319 id=319 data-nosnippet>319</a> )
<a href=#320 id=320 data-nosnippet>320</a> }
<a href=#321 id=321 data-nosnippet>321</a>}
<a href=#322 id=322 data-nosnippet>322</a>
<a href=#323 id=323 data-nosnippet>323</a><span class="attr">#[derive(Clone)]
<a href=#324 id=324 data-nosnippet>324</a></span><span class="kw">pub enum </span>StorageType {
<a href=#325 id=325 data-nosnippet>325</a> Fs(FsBackend),
<a href=#326 id=326 data-nosnippet>326</a> S3(S3Backend),
<a href=#327 id=327 data-nosnippet>327</a> Oss(OssBackend),
<a href=#328 id=328 data-nosnippet>328</a> Gcs(GcsBackend),
<a href=#329 id=329 data-nosnippet>329</a> Azblob(AzblobBackend),
<a href=#330 id=330 data-nosnippet>330</a>}
<a href=#331 id=331 data-nosnippet>331</a>
<a href=#332 id=332 data-nosnippet>332</a><span class="kw">impl </span>StorageExport <span class="kw">for </span>StorageType {
<a href=#333 id=333 data-nosnippet>333</a> <span class="kw">fn </span>get_storage_path(<span class="kw-2">&amp;</span><span class="self">self</span>, catalog: <span class="kw-2">&amp;</span>str, schema: <span class="kw-2">&amp;</span>str) -&gt; (String, String) {
<a href=#334 id=334 data-nosnippet>334</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#335 id=335 data-nosnippet>335</a> StorageType::Fs(backend) =&gt; backend.get_storage_path(catalog, schema),
<a href=#336 id=336 data-nosnippet>336</a> StorageType::S3(backend) =&gt; backend.get_storage_path(catalog, schema),
<a href=#337 id=337 data-nosnippet>337</a> StorageType::Oss(backend) =&gt; backend.get_storage_path(catalog, schema),
<a href=#338 id=338 data-nosnippet>338</a> StorageType::Gcs(backend) =&gt; backend.get_storage_path(catalog, schema),
<a href=#339 id=339 data-nosnippet>339</a> StorageType::Azblob(backend) =&gt; backend.get_storage_path(catalog, schema),
<a href=#340 id=340 data-nosnippet>340</a> }
<a href=#341 id=341 data-nosnippet>341</a> }
<a href=#342 id=342 data-nosnippet>342</a>
<a href=#343 id=343 data-nosnippet>343</a> <span class="kw">fn </span>format_output_path(<span class="kw-2">&amp;</span><span class="self">self</span>, file_path: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#344 id=344 data-nosnippet>344</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#345 id=345 data-nosnippet>345</a> StorageType::Fs(backend) =&gt; backend.format_output_path(file_path),
<a href=#346 id=346 data-nosnippet>346</a> StorageType::S3(backend) =&gt; backend.format_output_path(file_path),
<a href=#347 id=347 data-nosnippet>347</a> StorageType::Oss(backend) =&gt; backend.format_output_path(file_path),
<a href=#348 id=348 data-nosnippet>348</a> StorageType::Gcs(backend) =&gt; backend.format_output_path(file_path),
<a href=#349 id=349 data-nosnippet>349</a> StorageType::Azblob(backend) =&gt; backend.format_output_path(file_path),
<a href=#350 id=350 data-nosnippet>350</a> }
<a href=#351 id=351 data-nosnippet>351</a> }
<a href=#352 id=352 data-nosnippet>352</a>
<a href=#353 id=353 data-nosnippet>353</a> <span class="kw">fn </span>mask_sensitive_info(<span class="kw-2">&amp;</span><span class="self">self</span>, sql: <span class="kw-2">&amp;</span>str) -&gt; String {
<a href=#354 id=354 data-nosnippet>354</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#355 id=355 data-nosnippet>355</a> StorageType::Fs(backend) =&gt; backend.mask_sensitive_info(sql),
<a href=#356 id=356 data-nosnippet>356</a> StorageType::S3(backend) =&gt; backend.mask_sensitive_info(sql),
<a href=#357 id=357 data-nosnippet>357</a> StorageType::Oss(backend) =&gt; backend.mask_sensitive_info(sql),
<a href=#358 id=358 data-nosnippet>358</a> StorageType::Gcs(backend) =&gt; backend.mask_sensitive_info(sql),
<a href=#359 id=359 data-nosnippet>359</a> StorageType::Azblob(backend) =&gt; backend.mask_sensitive_info(sql),
<a href=#360 id=360 data-nosnippet>360</a> }
<a href=#361 id=361 data-nosnippet>361</a> }
<a href=#362 id=362 data-nosnippet>362</a>}
<a href=#363 id=363 data-nosnippet>363</a>
<a href=#364 id=364 data-nosnippet>364</a><span class="kw">impl </span>StorageType {
<a href=#365 id=365 data-nosnippet>365</a> <span class="doccomment">/// Returns true if the storage backend is remote (not local filesystem).
<a href=#366 id=366 data-nosnippet>366</a> </span><span class="kw">pub fn </span>is_remote_storage(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; bool {
<a href=#367 id=367 data-nosnippet>367</a> !<span class="macro">matches!</span>(<span class="self">self</span>, StorageType::Fs(<span class="kw">_</span>))
<a href=#368 id=368 data-nosnippet>368</a> }
<a href=#369 id=369 data-nosnippet>369</a>}
</code></pre></div></section></main></body></html>
+342
View File
@@ -0,0 +1,342 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/database.rs`."><title>database.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/</div>database.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::sync::Arc;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>std::time::Duration;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>base64::Engine;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>base64::engine::general_purpose;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_catalog::consts::{DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME};
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>humantime::format_duration;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>serde_json::Value;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>servers::http::GreptimeQueryOutput;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>servers::http::header::constants::GREPTIME_DB_HEADER_TIMEOUT;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>servers::http::result::greptime_result_v1::GreptimedbV1Response;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>snafu::ResultExt;
<a href=#28 id=28 data-nosnippet>28</a>
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span><span class="kw">crate</span>::error::{
<a href=#30 id=30 data-nosnippet>30</a> BuildClientSnafu, HttpQuerySqlSnafu, ParseProxyOptsSnafu, <span class="prelude-ty">Result</span>, SerdeJsonSnafu,
<a href=#31 id=31 data-nosnippet>31</a>};
<a href=#32 id=32 data-nosnippet>32</a>
<a href=#33 id=33 data-nosnippet>33</a><span class="attr">#[derive(Debug, Clone)]
<a href=#34 id=34 data-nosnippet>34</a></span><span class="kw">pub struct </span>DatabaseClient {
<a href=#35 id=35 data-nosnippet>35</a> addr: String,
<a href=#36 id=36 data-nosnippet>36</a> catalog: String,
<a href=#37 id=37 data-nosnippet>37</a> auth_header: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#38 id=38 data-nosnippet>38</a> timeout: Duration,
<a href=#39 id=39 data-nosnippet>39</a> proxy: <span class="prelude-ty">Option</span>&lt;reqwest::Proxy&gt;,
<a href=#40 id=40 data-nosnippet>40</a> no_proxy: bool,
<a href=#41 id=41 data-nosnippet>41</a> client: Arc&lt;tokio::sync::OnceCell&lt;reqwest::Client&gt;&gt;,
<a href=#42 id=42 data-nosnippet>42</a>}
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="kw">pub fn </span>parse_proxy_opts(
<a href=#45 id=45 data-nosnippet>45</a> proxy: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#46 id=46 data-nosnippet>46</a> no_proxy: bool,
<a href=#47 id=47 data-nosnippet>47</a>) -&gt; std::result::Result&lt;<span class="prelude-ty">Option</span>&lt;reqwest::Proxy&gt;, BoxedError&gt; {
<a href=#48 id=48 data-nosnippet>48</a> <span class="kw">if </span>no_proxy {
<a href=#49 id=49 data-nosnippet>49</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>);
<a href=#50 id=50 data-nosnippet>50</a> }
<a href=#51 id=51 data-nosnippet>51</a> proxy
<a href=#52 id=52 data-nosnippet>52</a> .map(|proxy| {
<a href=#53 id=53 data-nosnippet>53</a> reqwest::Proxy::all(proxy)
<a href=#54 id=54 data-nosnippet>54</a> .context(ParseProxyOptsSnafu)
<a href=#55 id=55 data-nosnippet>55</a> .map_err(BoxedError::new)
<a href=#56 id=56 data-nosnippet>56</a> })
<a href=#57 id=57 data-nosnippet>57</a> .transpose()
<a href=#58 id=58 data-nosnippet>58</a>}
<a href=#59 id=59 data-nosnippet>59</a>
<a href=#60 id=60 data-nosnippet>60</a><span class="kw">impl </span>DatabaseClient {
<a href=#61 id=61 data-nosnippet>61</a> <span class="kw">pub fn </span>new(
<a href=#62 id=62 data-nosnippet>62</a> addr: String,
<a href=#63 id=63 data-nosnippet>63</a> catalog: String,
<a href=#64 id=64 data-nosnippet>64</a> auth_basic: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#65 id=65 data-nosnippet>65</a> timeout: Duration,
<a href=#66 id=66 data-nosnippet>66</a> proxy: <span class="prelude-ty">Option</span>&lt;reqwest::Proxy&gt;,
<a href=#67 id=67 data-nosnippet>67</a> no_proxy: bool,
<a href=#68 id=68 data-nosnippet>68</a> ) -&gt; <span class="self">Self </span>{
<a href=#69 id=69 data-nosnippet>69</a> <span class="kw">let </span>auth_header = <span class="kw">if let </span><span class="prelude-val">Some</span>(basic) = auth_basic {
<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">let </span>encoded = general_purpose::STANDARD.encode(basic);
<a href=#71 id=71 data-nosnippet>71</a> <span class="prelude-val">Some</span>(<span class="macro">format!</span>(<span class="string">"basic {}"</span>, encoded))
<a href=#72 id=72 data-nosnippet>72</a> } <span class="kw">else </span>{
<a href=#73 id=73 data-nosnippet>73</a> <span class="prelude-val">None
<a href=#74 id=74 data-nosnippet>74</a> </span>};
<a href=#75 id=75 data-nosnippet>75</a>
<a href=#76 id=76 data-nosnippet>76</a> <span class="kw">if </span>no_proxy {
<a href=#77 id=77 data-nosnippet>77</a> <span class="macro">common_telemetry::info!</span>(<span class="string">"Proxy disabled"</span>);
<a href=#78 id=78 data-nosnippet>78</a> } <span class="kw">else if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>proxy) = proxy {
<a href=#79 id=79 data-nosnippet>79</a> <span class="macro">common_telemetry::info!</span>(<span class="string">"Using proxy: {:?}"</span>, proxy);
<a href=#80 id=80 data-nosnippet>80</a> } <span class="kw">else </span>{
<a href=#81 id=81 data-nosnippet>81</a> <span class="macro">common_telemetry::info!</span>(<span class="string">"Using system proxy(if any)"</span>);
<a href=#82 id=82 data-nosnippet>82</a> }
<a href=#83 id=83 data-nosnippet>83</a>
<a href=#84 id=84 data-nosnippet>84</a> <span class="self">Self </span>{
<a href=#85 id=85 data-nosnippet>85</a> addr,
<a href=#86 id=86 data-nosnippet>86</a> catalog,
<a href=#87 id=87 data-nosnippet>87</a> auth_header,
<a href=#88 id=88 data-nosnippet>88</a> timeout,
<a href=#89 id=89 data-nosnippet>89</a> proxy,
<a href=#90 id=90 data-nosnippet>90</a> no_proxy,
<a href=#91 id=91 data-nosnippet>91</a> client: Arc::new(tokio::sync::OnceCell::new()),
<a href=#92 id=92 data-nosnippet>92</a> }
<a href=#93 id=93 data-nosnippet>93</a> }
<a href=#94 id=94 data-nosnippet>94</a>
<a href=#95 id=95 data-nosnippet>95</a> <span class="kw">pub fn </span>addr(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span>str {
<a href=#96 id=96 data-nosnippet>96</a> <span class="kw-2">&amp;</span><span class="self">self</span>.addr
<a href=#97 id=97 data-nosnippet>97</a> }
<a href=#98 id=98 data-nosnippet>98</a>
<a href=#99 id=99 data-nosnippet>99</a> <span class="kw">pub async fn </span>sql_in_public(<span class="kw-2">&amp;</span><span class="self">self</span>, sql: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Vec&lt;Vec&lt;Value&gt;&gt;&gt;&gt; {
<a href=#100 id=100 data-nosnippet>100</a> <span class="self">self</span>.sql(sql, DEFAULT_SCHEMA_NAME).<span class="kw">await
<a href=#101 id=101 data-nosnippet>101</a> </span>}
<a href=#102 id=102 data-nosnippet>102</a>
<a href=#103 id=103 data-nosnippet>103</a> <span class="doccomment">/// Requires the explicit packed-import protocol before any restore mutation.
<a href=#104 id=104 data-nosnippet>104</a> </span><span class="kw">pub async fn </span>require_packed_import(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#105 id=105 data-nosnippet>105</a> <span class="self">self</span>.require_packed_capability(<span class="string">"metric_packed_import"</span>).<span class="kw">await
<a href=#106 id=106 data-nosnippet>106</a> </span>}
<a href=#107 id=107 data-nosnippet>107</a>
<a href=#108 id=108 data-nosnippet>108</a> <span class="doccomment">/// Requires packed export support before creating snapshot artifacts.
<a href=#109 id=109 data-nosnippet>109</a> </span><span class="kw">pub async fn </span>require_packed_export(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#110 id=110 data-nosnippet>110</a> <span class="self">self</span>.require_packed_capability(<span class="string">"metric_packed_export"</span>).<span class="kw">await
<a href=#111 id=111 data-nosnippet>111</a> </span>}
<a href=#112 id=112 data-nosnippet>112</a>
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">async fn </span>require_packed_capability(<span class="kw-2">&amp;</span><span class="self">self</span>, capability: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;()&gt; {
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">let </span>url = <span class="macro">format!</span>(<span class="string">"http://{}/v1/capabilities"</span>, <span class="self">self</span>.addr);
<a href=#115 id=115 data-nosnippet>115</a> <span class="kw">let </span><span class="kw-2">mut </span>request = <span class="self">self</span>.http_client().<span class="kw">await</span><span class="question-mark">?</span>.get(<span class="kw-2">&amp;</span>url).timeout(<span class="self">self</span>.timeout);
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(auth) = <span class="kw-2">&amp;</span><span class="self">self</span>.auth_header {
<a href=#117 id=117 data-nosnippet>117</a> request = request.header(<span class="string">"Authorization"</span>, auth);
<a href=#118 id=118 data-nosnippet>118</a> }
<a href=#119 id=119 data-nosnippet>119</a> <span class="kw">let </span>response = request.send().<span class="kw">await</span>.with_context(|<span class="kw">_</span>| HttpQuerySqlSnafu {
<a href=#120 id=120 data-nosnippet>120</a> reason: <span class="string">"packed snapshot capability request failed"</span>,
<a href=#121 id=121 data-nosnippet>121</a> })<span class="question-mark">?</span>;
<a href=#122 id=122 data-nosnippet>122</a> <span class="kw">if </span>response.status() == reqwest::StatusCode::NOT_FOUND {
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">return </span><span class="kw">crate</span>::error::InvalidArgumentsSnafu {
<a href=#124 id=124 data-nosnippet>124</a> msg: <span class="macro">format!</span>(<span class="string">"server does not support {capability}"</span>),
<a href=#125 id=125 data-nosnippet>125</a> }
<a href=#126 id=126 data-nosnippet>126</a> .fail();
<a href=#127 id=127 data-nosnippet>127</a> }
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw">let </span>response = response
<a href=#129 id=129 data-nosnippet>129</a> .error_for_status()
<a href=#130 id=130 data-nosnippet>130</a> .with_context(|<span class="kw">_</span>| HttpQuerySqlSnafu {
<a href=#131 id=131 data-nosnippet>131</a> reason: <span class="string">"packed snapshot capability request rejected"</span>,
<a href=#132 id=132 data-nosnippet>132</a> })<span class="question-mark">?</span>;
<a href=#133 id=133 data-nosnippet>133</a> <span class="kw">let </span>body = response.text().<span class="kw">await</span>.with_context(|<span class="kw">_</span>| HttpQuerySqlSnafu {
<a href=#134 id=134 data-nosnippet>134</a> reason: <span class="string">"cannot read capability response"</span>,
<a href=#135 id=135 data-nosnippet>135</a> })<span class="question-mark">?</span>;
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw">let </span>value: Value = serde_json::from_str(<span class="kw-2">&amp;</span>body).context(SerdeJsonSnafu)<span class="question-mark">?</span>;
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">if </span>!value.is_object() {
<a href=#138 id=138 data-nosnippet>138</a> <span class="kw">return </span><span class="kw">crate</span>::error::UnexpectedSnafu {
<a href=#139 id=139 data-nosnippet>139</a> msg: <span class="string">"invalid capability response: expected JSON object"</span>,
<a href=#140 id=140 data-nosnippet>140</a> }
<a href=#141 id=141 data-nosnippet>141</a> .fail();
<a href=#142 id=142 data-nosnippet>142</a> }
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">if </span>value.get(capability).and_then(Value::as_u64) != <span class="prelude-val">Some</span>(<span class="number">1</span>) {
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">return </span><span class="kw">crate</span>::error::InvalidArgumentsSnafu {
<a href=#145 id=145 data-nosnippet>145</a> msg: <span class="macro">format!</span>(<span class="string">"server does not support {capability} version 1"</span>),
<a href=#146 id=146 data-nosnippet>146</a> }
<a href=#147 id=147 data-nosnippet>147</a> .fail();
<a href=#148 id=148 data-nosnippet>148</a> }
<a href=#149 id=149 data-nosnippet>149</a> <span class="prelude-val">Ok</span>(())
<a href=#150 id=150 data-nosnippet>150</a> }
<a href=#151 id=151 data-nosnippet>151</a>
<a href=#152 id=152 data-nosnippet>152</a> <span class="doccomment">/// Execute sql query.
<a href=#153 id=153 data-nosnippet>153</a> </span><span class="kw">pub async fn </span>sql(<span class="kw-2">&amp;</span><span class="self">self</span>, sql: <span class="kw-2">&amp;</span>str, schema: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="prelude-ty">Option</span>&lt;Vec&lt;Vec&lt;Value&gt;&gt;&gt;&gt; {
<a href=#154 id=154 data-nosnippet>154</a> <span class="kw">let </span>body = <span class="self">self</span>.sql_response(sql, schema).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#155 id=155 data-nosnippet>155</a> <span class="prelude-val">Ok</span>(body.output().first().and_then(|output| <span class="kw">match </span>output {
<a href=#156 id=156 data-nosnippet>156</a> GreptimeQueryOutput::Records(records) =&gt; <span class="prelude-val">Some</span>(records.rows().clone()),
<a href=#157 id=157 data-nosnippet>157</a> GreptimeQueryOutput::AffectedRows(<span class="kw">_</span>) =&gt; <span class="prelude-val">None</span>,
<a href=#158 id=158 data-nosnippet>158</a> }))
<a href=#159 id=159 data-nosnippet>159</a> }
<a href=#160 id=160 data-nosnippet>160</a>
<a href=#161 id=161 data-nosnippet>161</a> <span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">async fn </span>sql_response(
<a href=#162 id=162 data-nosnippet>162</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#163 id=163 data-nosnippet>163</a> sql: <span class="kw-2">&amp;</span>str,
<a href=#164 id=164 data-nosnippet>164</a> schema: <span class="kw-2">&amp;</span>str,
<a href=#165 id=165 data-nosnippet>165</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;GreptimedbV1Response&gt; {
<a href=#166 id=166 data-nosnippet>166</a> <span class="kw">let </span>url = <span class="macro">format!</span>(<span class="string">"http://{}/v1/sql"</span>, <span class="self">self</span>.addr);
<a href=#167 id=167 data-nosnippet>167</a> <span class="kw">let </span>params = [
<a href=#168 id=168 data-nosnippet>168</a> (<span class="string">"db"</span>, <span class="macro">format!</span>(<span class="string">"{}-{}"</span>, <span class="self">self</span>.catalog, schema)),
<a href=#169 id=169 data-nosnippet>169</a> (<span class="string">"sql"</span>, sql.to_string()),
<a href=#170 id=170 data-nosnippet>170</a> ];
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">let </span><span class="kw-2">mut </span>request = <span class="self">self
<a href=#172 id=172 data-nosnippet>172</a> </span>.http_client()
<a href=#173 id=173 data-nosnippet>173</a> .<span class="kw">await</span><span class="question-mark">?
<a href=#174 id=174 data-nosnippet>174</a> </span>.post(<span class="kw-2">&amp;</span>url)
<a href=#175 id=175 data-nosnippet>175</a> .form(<span class="kw-2">&amp;</span>params)
<a href=#176 id=176 data-nosnippet>176</a> .header(<span class="string">"Content-Type"</span>, <span class="string">"application/x-www-form-urlencoded"</span>);
<a href=#177 id=177 data-nosnippet>177</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(<span class="kw-2">ref </span>auth) = <span class="self">self</span>.auth_header {
<a href=#178 id=178 data-nosnippet>178</a> request = request.header(<span class="string">"Authorization"</span>, auth);
<a href=#179 id=179 data-nosnippet>179</a> }
<a href=#180 id=180 data-nosnippet>180</a>
<a href=#181 id=181 data-nosnippet>181</a> request = request.header(
<a href=#182 id=182 data-nosnippet>182</a> GREPTIME_DB_HEADER_TIMEOUT,
<a href=#183 id=183 data-nosnippet>183</a> format_duration(<span class="self">self</span>.timeout).to_string(),
<a href=#184 id=184 data-nosnippet>184</a> );
<a href=#185 id=185 data-nosnippet>185</a>
<a href=#186 id=186 data-nosnippet>186</a> <span class="kw">let </span>response = request.send().<span class="kw">await</span>.with_context(|<span class="kw">_</span>| HttpQuerySqlSnafu {
<a href=#187 id=187 data-nosnippet>187</a> reason: <span class="macro">format!</span>(<span class="string">"bad url: {}"</span>, url),
<a href=#188 id=188 data-nosnippet>188</a> })<span class="question-mark">?</span>;
<a href=#189 id=189 data-nosnippet>189</a> <span class="kw">let </span>status = response.status();
<a href=#190 id=190 data-nosnippet>190</a> <span class="kw">let </span>text = response.text().<span class="kw">await</span>.with_context(|<span class="kw">_</span>| HttpQuerySqlSnafu {
<a href=#191 id=191 data-nosnippet>191</a> reason: <span class="string">"cannot get response text"</span>.to_string(),
<a href=#192 id=192 data-nosnippet>192</a> })<span class="question-mark">?</span>;
<a href=#193 id=193 data-nosnippet>193</a> <span class="kw">let </span>value: Value = serde_json::from_str(<span class="kw-2">&amp;</span>text).map_err(|<span class="kw">_</span>| {
<a href=#194 id=194 data-nosnippet>194</a> <span class="kw">crate</span>::error::UnexpectedSnafu {
<a href=#195 id=195 data-nosnippet>195</a> msg: <span class="macro">format!</span>(<span class="string">"invalid SQL response ({status})"</span>),
<a href=#196 id=196 data-nosnippet>196</a> }
<a href=#197 id=197 data-nosnippet>197</a> .build()
<a href=#198 id=198 data-nosnippet>198</a> })<span class="question-mark">?</span>;
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">if </span>!status.is_success()
<a href=#200 id=200 data-nosnippet>200</a> || value.get(<span class="string">"error"</span>).is_some()
<a href=#201 id=201 data-nosnippet>201</a> || value
<a href=#202 id=202 data-nosnippet>202</a> .get(<span class="string">"code"</span>)
<a href=#203 id=203 data-nosnippet>203</a> .is_some_and(|code| code.as_u64() != <span class="prelude-val">Some</span>(<span class="number">0</span>))
<a href=#204 id=204 data-nosnippet>204</a> {
<a href=#205 id=205 data-nosnippet>205</a> <span class="kw">return </span><span class="kw">crate</span>::error::UnexpectedSnafu {
<a href=#206 id=206 data-nosnippet>206</a> msg: <span class="macro">format!</span>(
<a href=#207 id=207 data-nosnippet>207</a> <span class="string">"SQL request failed ({status}, code {:?})"</span>,
<a href=#208 id=208 data-nosnippet>208</a> value.get(<span class="string">"code"</span>).and_then(Value::as_u64)
<a href=#209 id=209 data-nosnippet>209</a> ),
<a href=#210 id=210 data-nosnippet>210</a> }
<a href=#211 id=211 data-nosnippet>211</a> .fail();
<a href=#212 id=212 data-nosnippet>212</a> }
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(outputs) = value.get(<span class="string">"output"</span>).and_then(Value::as_array) {
<a href=#214 id=214 data-nosnippet>214</a> <span class="kw">for </span>(index, output) <span class="kw">in </span>outputs.iter().enumerate() {
<a href=#215 id=215 data-nosnippet>215</a> <span class="kw">if </span>output.get(<span class="string">"error"</span>).is_some()
<a href=#216 id=216 data-nosnippet>216</a> || output
<a href=#217 id=217 data-nosnippet>217</a> .get(<span class="string">"code"</span>)
<a href=#218 id=218 data-nosnippet>218</a> .is_some_and(|code| code.as_u64() != <span class="prelude-val">Some</span>(<span class="number">0</span>))
<a href=#219 id=219 data-nosnippet>219</a> {
<a href=#220 id=220 data-nosnippet>220</a> <span class="kw">return </span><span class="kw">crate</span>::error::UnexpectedSnafu {
<a href=#221 id=221 data-nosnippet>221</a> msg: <span class="macro">format!</span>(
<a href=#222 id=222 data-nosnippet>222</a> <span class="string">"SQL statement {} failed (code {:?})"</span>,
<a href=#223 id=223 data-nosnippet>223</a> index + <span class="number">1</span>,
<a href=#224 id=224 data-nosnippet>224</a> output.get(<span class="string">"code"</span>).and_then(Value::as_u64)
<a href=#225 id=225 data-nosnippet>225</a> ),
<a href=#226 id=226 data-nosnippet>226</a> }
<a href=#227 id=227 data-nosnippet>227</a> .fail();
<a href=#228 id=228 data-nosnippet>228</a> }
<a href=#229 id=229 data-nosnippet>229</a> }
<a href=#230 id=230 data-nosnippet>230</a> }
<a href=#231 id=231 data-nosnippet>231</a> serde_json::from_value(value).map_err(|<span class="kw">_</span>| {
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">crate</span>::error::UnexpectedSnafu {
<a href=#233 id=233 data-nosnippet>233</a> msg: <span class="macro">format!</span>(<span class="string">"invalid SQL response ({status})"</span>),
<a href=#234 id=234 data-nosnippet>234</a> }
<a href=#235 id=235 data-nosnippet>235</a> .build()
<a href=#236 id=236 data-nosnippet>236</a> })
<a href=#237 id=237 data-nosnippet>237</a> }
<a href=#238 id=238 data-nosnippet>238</a>
<a href=#239 id=239 data-nosnippet>239</a> <span class="kw">async fn </span>http_client(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;<span class="kw-2">&amp;</span>reqwest::Client&gt; {
<a href=#240 id=240 data-nosnippet>240</a> <span class="self">self</span>.client
<a href=#241 id=241 data-nosnippet>241</a> .get_or_try_init(|| <span class="kw">async </span>{
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">let </span><span class="kw-2">mut </span>builder = reqwest::Client::builder();
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(proxy) = <span class="self">self</span>.proxy.clone() {
<a href=#244 id=244 data-nosnippet>244</a> builder = builder.proxy(proxy);
<a href=#245 id=245 data-nosnippet>245</a> }
<a href=#246 id=246 data-nosnippet>246</a> <span class="kw">if </span><span class="self">self</span>.no_proxy {
<a href=#247 id=247 data-nosnippet>247</a> builder = builder.no_proxy();
<a href=#248 id=248 data-nosnippet>248</a> }
<a href=#249 id=249 data-nosnippet>249</a> builder.build().context(BuildClientSnafu)
<a href=#250 id=250 data-nosnippet>250</a> })
<a href=#251 id=251 data-nosnippet>251</a> .<span class="kw">await
<a href=#252 id=252 data-nosnippet>252</a> </span>}
<a href=#253 id=253 data-nosnippet>253</a>}
<a href=#254 id=254 data-nosnippet>254</a>
<a href=#255 id=255 data-nosnippet>255</a><span class="doccomment">/// Split at `-`.
<a href=#256 id=256 data-nosnippet>256</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">fn </span>split_database(database: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;(String, <span class="prelude-ty">Option</span>&lt;String&gt;)&gt; {
<a href=#257 id=257 data-nosnippet>257</a> <span class="kw">let </span>(catalog, schema) = <span class="kw">match </span>database.split_once(<span class="string">'-'</span>) {
<a href=#258 id=258 data-nosnippet>258</a> <span class="prelude-val">Some</span>((catalog, schema)) =&gt; (catalog, schema),
<a href=#259 id=259 data-nosnippet>259</a> <span class="prelude-val">None </span>=&gt; (DEFAULT_CATALOG_NAME, database),
<a href=#260 id=260 data-nosnippet>260</a> };
<a href=#261 id=261 data-nosnippet>261</a>
<a href=#262 id=262 data-nosnippet>262</a> <span class="kw">if </span>schema == <span class="string">"*" </span>{
<a href=#263 id=263 data-nosnippet>263</a> <span class="prelude-val">Ok</span>((catalog.to_string(), <span class="prelude-val">None</span>))
<a href=#264 id=264 data-nosnippet>264</a> } <span class="kw">else </span>{
<a href=#265 id=265 data-nosnippet>265</a> <span class="prelude-val">Ok</span>((catalog.to_string(), <span class="prelude-val">Some</span>(schema.to_string())))
<a href=#266 id=266 data-nosnippet>266</a> }
<a href=#267 id=267 data-nosnippet>267</a>}
<a href=#268 id=268 data-nosnippet>268</a>
<a href=#269 id=269 data-nosnippet>269</a><span class="attr">#[cfg(test)]
<a href=#270 id=270 data-nosnippet>270</a></span><span class="kw">mod </span>tests {
<a href=#271 id=271 data-nosnippet>271</a> <span class="attr">#[tokio::test]
<a href=#272 id=272 data-nosnippet>272</a> </span><span class="kw">async fn </span>packed_capability_probe_checks_auth_and_protocol_version() {
<a href=#273 id=273 data-nosnippet>273</a> <span class="kw">use </span>tokio::io::{AsyncReadExt, AsyncWriteExt};
<a href=#274 id=274 data-nosnippet>274</a> <span class="kw">for </span>export <span class="kw">in </span>[<span class="bool-val">false</span>, <span class="bool-val">true</span>] {
<a href=#275 id=275 data-nosnippet>275</a> <span class="kw">for </span>(status, body, supported) <span class="kw">in </span>[
<a href=#276 id=276 data-nosnippet>276</a> (<span class="number">200</span>, <span class="string">r#"{"metric_packed_import":1,"future":2}"#</span>, <span class="bool-val">true</span>),
<a href=#277 id=277 data-nosnippet>277</a> (<span class="number">200</span>, <span class="string">"{}"</span>, <span class="bool-val">false</span>),
<a href=#278 id=278 data-nosnippet>278</a> (<span class="number">200</span>, <span class="string">r#"{"metric_packed_import":2}"#</span>, <span class="bool-val">false</span>),
<a href=#279 id=279 data-nosnippet>279</a> (<span class="number">404</span>, <span class="string">"{}"</span>, <span class="bool-val">false</span>),
<a href=#280 id=280 data-nosnippet>280</a> (<span class="number">401</span>, <span class="string">"{}"</span>, <span class="bool-val">false</span>),
<a href=#281 id=281 data-nosnippet>281</a> (<span class="number">403</span>, <span class="string">"{}"</span>, <span class="bool-val">false</span>),
<a href=#282 id=282 data-nosnippet>282</a> (<span class="number">200</span>, <span class="string">"[]"</span>, <span class="bool-val">false</span>),
<a href=#283 id=283 data-nosnippet>283</a> (<span class="number">200</span>, <span class="string">"invalid-json"</span>, <span class="bool-val">false</span>),
<a href=#284 id=284 data-nosnippet>284</a> ] {
<a href=#285 id=285 data-nosnippet>285</a> <span class="kw">let </span>body = <span class="kw">if </span>export {
<a href=#286 id=286 data-nosnippet>286</a> body.replace(<span class="string">"metric_packed_import"</span>, <span class="string">"metric_packed_export"</span>)
<a href=#287 id=287 data-nosnippet>287</a> } <span class="kw">else </span>{
<a href=#288 id=288 data-nosnippet>288</a> body.to_string()
<a href=#289 id=289 data-nosnippet>289</a> };
<a href=#290 id=290 data-nosnippet>290</a> <span class="kw">let </span>response_body = body.clone();
<a href=#291 id=291 data-nosnippet>291</a> <span class="kw">let </span>listener = tokio::net::TcpListener::bind(<span class="string">"127.0.0.1:0"</span>).<span class="kw">await</span>.unwrap();
<a href=#292 id=292 data-nosnippet>292</a> <span class="kw">let </span>address = listener.local_addr().unwrap();
<a href=#293 id=293 data-nosnippet>293</a> <span class="kw">let </span>server = tokio::spawn(<span class="kw">async move </span>{
<a href=#294 id=294 data-nosnippet>294</a> <span class="kw">let </span>body = response_body;
<a href=#295 id=295 data-nosnippet>295</a> <span class="kw">let </span>(<span class="kw-2">mut </span>socket, <span class="kw">_</span>) = listener.accept().<span class="kw">await</span>.unwrap();
<a href=#296 id=296 data-nosnippet>296</a> <span class="kw">let </span><span class="kw-2">mut </span>request = <span class="macro">vec!</span>[<span class="number">0</span>; <span class="number">4096</span>];
<a href=#297 id=297 data-nosnippet>297</a> <span class="kw">let </span>n = socket.read(<span class="kw-2">&amp;mut </span>request).<span class="kw">await</span>.unwrap();
<a href=#298 id=298 data-nosnippet>298</a> <span class="kw">let </span>request = String::from_utf8_lossy(<span class="kw-2">&amp;</span>request[..n]).to_lowercase();
<a href=#299 id=299 data-nosnippet>299</a> <span class="macro">assert!</span>(request.starts_with(<span class="string">"get /v1/capabilities "</span>));
<a href=#300 id=300 data-nosnippet>300</a> <span class="macro">assert!</span>(request.contains(<span class="string">"authorization: basic dxnlcjpwyxnzd29yza=="</span>));
<a href=#301 id=301 data-nosnippet>301</a> socket.write_all(<span class="macro">format!</span>(<span class="string">"HTTP/1.1 {status} Response\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{body}"</span>, body.len()).as_bytes()).<span class="kw">await</span>.unwrap();
<a href=#302 id=302 data-nosnippet>302</a> });
<a href=#303 id=303 data-nosnippet>303</a> <span class="kw">let </span>client = <span class="kw">super</span>::DatabaseClient::new(
<a href=#304 id=304 data-nosnippet>304</a> address.to_string(),
<a href=#305 id=305 data-nosnippet>305</a> <span class="string">"greptime"</span>.into(),
<a href=#306 id=306 data-nosnippet>306</a> <span class="prelude-val">Some</span>(<span class="string">"user:password"</span>.into()),
<a href=#307 id=307 data-nosnippet>307</a> std::time::Duration::from_secs(<span class="number">5</span>),
<a href=#308 id=308 data-nosnippet>308</a> <span class="prelude-val">None</span>,
<a href=#309 id=309 data-nosnippet>309</a> <span class="bool-val">true</span>,
<a href=#310 id=310 data-nosnippet>310</a> );
<a href=#311 id=311 data-nosnippet>311</a> <span class="macro">assert_eq!</span>(
<a href=#312 id=312 data-nosnippet>312</a> <span class="kw">if </span>export {
<a href=#313 id=313 data-nosnippet>313</a> client.require_packed_export().<span class="kw">await</span>.is_ok()
<a href=#314 id=314 data-nosnippet>314</a> } <span class="kw">else </span>{
<a href=#315 id=315 data-nosnippet>315</a> client.require_packed_import().<span class="kw">await</span>.is_ok()
<a href=#316 id=316 data-nosnippet>316</a> },
<a href=#317 id=317 data-nosnippet>317</a> supported,
<a href=#318 id=318 data-nosnippet>318</a> <span class="string">"{status}: {body}"
<a href=#319 id=319 data-nosnippet>319</a> </span>);
<a href=#320 id=320 data-nosnippet>320</a> server.<span class="kw">await</span>.unwrap();
<a href=#321 id=321 data-nosnippet>321</a> }
<a href=#322 id=322 data-nosnippet>322</a> }
<a href=#323 id=323 data-nosnippet>323</a> }
<a href=#324 id=324 data-nosnippet>324</a>
<a href=#325 id=325 data-nosnippet>325</a> <span class="kw">use </span>super::<span class="kw-2">*</span>;
<a href=#326 id=326 data-nosnippet>326</a>
<a href=#327 id=327 data-nosnippet>327</a> <span class="attr">#[test]
<a href=#328 id=328 data-nosnippet>328</a> </span><span class="kw">fn </span>test_split_database() {
<a href=#329 id=329 data-nosnippet>329</a> <span class="kw">let </span>result = split_database(<span class="string">"catalog-schema"</span>).unwrap();
<a href=#330 id=330 data-nosnippet>330</a> <span class="macro">assert_eq!</span>(result, (<span class="string">"catalog"</span>.to_string(), <span class="prelude-val">Some</span>(<span class="string">"schema"</span>.to_string())));
<a href=#331 id=331 data-nosnippet>331</a>
<a href=#332 id=332 data-nosnippet>332</a> <span class="kw">let </span>result = split_database(<span class="string">"schema"</span>).unwrap();
<a href=#333 id=333 data-nosnippet>333</a> <span class="macro">assert_eq!</span>(result, (<span class="string">"greptime"</span>.to_string(), <span class="prelude-val">Some</span>(<span class="string">"schema"</span>.to_string())));
<a href=#334 id=334 data-nosnippet>334</a>
<a href=#335 id=335 data-nosnippet>335</a> <span class="kw">let </span>result = split_database(<span class="string">"catalog-*"</span>).unwrap();
<a href=#336 id=336 data-nosnippet>336</a> <span class="macro">assert_eq!</span>(result, (<span class="string">"catalog"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#337 id=337 data-nosnippet>337</a>
<a href=#338 id=338 data-nosnippet>338</a> <span class="kw">let </span>result = split_database(<span class="string">"*"</span>).unwrap();
<a href=#339 id=339 data-nosnippet>339</a> <span class="macro">assert_eq!</span>(result, (<span class="string">"greptime"</span>.to_string(), <span class="prelude-val">None</span>));
<a href=#340 id=340 data-nosnippet>340</a> }
<a href=#341 id=341 data-nosnippet>341</a>}
</code></pre></div></section></main></body></html>
+389
View File
@@ -0,0 +1,389 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/error.rs`."><title>error.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/</div>error.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::any::Any;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_error::ext::{BoxedError, ErrorExt};
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_error::status_code::StatusCode;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_macro::stack_trace_debug;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::peer::Peer;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>object_store::Error <span class="kw">as </span>ObjectStoreError;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>snafu::{Location, Snafu};
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>store_api::storage::{RegionId, TableId};
<a href=#24 id=24 data-nosnippet>24</a>
<a href=#25 id=25 data-nosnippet>25</a><span class="attr">#[derive(Snafu)]
<a href=#26 id=26 data-nosnippet>26</a>#[snafu(visibility(<span class="kw">pub</span>))]
<a href=#27 id=27 data-nosnippet>27</a>#[stack_trace_debug]
<a href=#28 id=28 data-nosnippet>28</a></span><span class="kw">pub enum </span>Error {
<a href=#29 id=29 data-nosnippet>29</a> <span class="attr">#[snafu(display(<span class="string">"Failed to install ring crypto provider: {}"</span>, msg))]
<a href=#30 id=30 data-nosnippet>30</a> </span>InitTlsProvider {
<a href=#31 id=31 data-nosnippet>31</a> <span class="attr">#[snafu(implicit)]
<a href=#32 id=32 data-nosnippet>32</a> </span>location: Location,
<a href=#33 id=33 data-nosnippet>33</a> msg: String,
<a href=#34 id=34 data-nosnippet>34</a> },
<a href=#35 id=35 data-nosnippet>35</a>
<a href=#36 id=36 data-nosnippet>36</a> <span class="attr">#[snafu(display(<span class="string">"Failed to create default catalog and schema"</span>))]
<a href=#37 id=37 data-nosnippet>37</a> </span>InitMetadata {
<a href=#38 id=38 data-nosnippet>38</a> <span class="attr">#[snafu(implicit)]
<a href=#39 id=39 data-nosnippet>39</a> </span>location: Location,
<a href=#40 id=40 data-nosnippet>40</a> source: common_meta::error::Error,
<a href=#41 id=41 data-nosnippet>41</a> },
<a href=#42 id=42 data-nosnippet>42</a>
<a href=#43 id=43 data-nosnippet>43</a> <span class="attr">#[snafu(display(<span class="string">"Failed to init DDL manager"</span>))]
<a href=#44 id=44 data-nosnippet>44</a> </span>InitDdlManager {
<a href=#45 id=45 data-nosnippet>45</a> <span class="attr">#[snafu(implicit)]
<a href=#46 id=46 data-nosnippet>46</a> </span>location: Location,
<a href=#47 id=47 data-nosnippet>47</a> source: common_meta::error::Error,
<a href=#48 id=48 data-nosnippet>48</a> },
<a href=#49 id=49 data-nosnippet>49</a>
<a href=#50 id=50 data-nosnippet>50</a> <span class="attr">#[snafu(display(<span class="string">"Failed to init default timezone"</span>))]
<a href=#51 id=51 data-nosnippet>51</a> </span>InitTimezone {
<a href=#52 id=52 data-nosnippet>52</a> <span class="attr">#[snafu(implicit)]
<a href=#53 id=53 data-nosnippet>53</a> </span>location: Location,
<a href=#54 id=54 data-nosnippet>54</a> source: common_time::error::Error,
<a href=#55 id=55 data-nosnippet>55</a> },
<a href=#56 id=56 data-nosnippet>56</a>
<a href=#57 id=57 data-nosnippet>57</a> <span class="attr">#[snafu(display(<span class="string">"Failed to start procedure manager"</span>))]
<a href=#58 id=58 data-nosnippet>58</a> </span>StartProcedureManager {
<a href=#59 id=59 data-nosnippet>59</a> <span class="attr">#[snafu(implicit)]
<a href=#60 id=60 data-nosnippet>60</a> </span>location: Location,
<a href=#61 id=61 data-nosnippet>61</a> source: common_procedure::error::Error,
<a href=#62 id=62 data-nosnippet>62</a> },
<a href=#63 id=63 data-nosnippet>63</a>
<a href=#64 id=64 data-nosnippet>64</a> <span class="attr">#[snafu(display(<span class="string">"Failed to stop procedure manager"</span>))]
<a href=#65 id=65 data-nosnippet>65</a> </span>StopProcedureManager {
<a href=#66 id=66 data-nosnippet>66</a> <span class="attr">#[snafu(implicit)]
<a href=#67 id=67 data-nosnippet>67</a> </span>location: Location,
<a href=#68 id=68 data-nosnippet>68</a> source: common_procedure::error::Error,
<a href=#69 id=69 data-nosnippet>69</a> },
<a href=#70 id=70 data-nosnippet>70</a>
<a href=#71 id=71 data-nosnippet>71</a> <span class="attr">#[snafu(display(<span class="string">"Failed to start wal provider"</span>))]
<a href=#72 id=72 data-nosnippet>72</a> </span>StartWalProvider {
<a href=#73 id=73 data-nosnippet>73</a> <span class="attr">#[snafu(implicit)]
<a href=#74 id=74 data-nosnippet>74</a> </span>location: Location,
<a href=#75 id=75 data-nosnippet>75</a> source: common_meta::error::Error,
<a href=#76 id=76 data-nosnippet>76</a> },
<a href=#77 id=77 data-nosnippet>77</a>
<a href=#78 id=78 data-nosnippet>78</a> <span class="attr">#[snafu(display(<span class="string">"Failed to get table metadata"</span>))]
<a href=#79 id=79 data-nosnippet>79</a> </span>TableMetadata {
<a href=#80 id=80 data-nosnippet>80</a> <span class="attr">#[snafu(implicit)]
<a href=#81 id=81 data-nosnippet>81</a> </span>location: Location,
<a href=#82 id=82 data-nosnippet>82</a> source: common_meta::error::Error,
<a href=#83 id=83 data-nosnippet>83</a> },
<a href=#84 id=84 data-nosnippet>84</a>
<a href=#85 id=85 data-nosnippet>85</a> <span class="attr">#[snafu(display(<span class="string">"Failed to build create region request for region: {region_id}"</span>))]
<a href=#86 id=86 data-nosnippet>86</a> </span>BuildCreateRegionRequest {
<a href=#87 id=87 data-nosnippet>87</a> region_id: RegionId,
<a href=#88 id=88 data-nosnippet>88</a> <span class="attr">#[snafu(implicit)]
<a href=#89 id=89 data-nosnippet>89</a> </span>location: Location,
<a href=#90 id=90 data-nosnippet>90</a> source: common_meta::error::Error,
<a href=#91 id=91 data-nosnippet>91</a> },
<a href=#92 id=92 data-nosnippet>92</a>
<a href=#93 id=93 data-nosnippet>93</a> <span class="attr">#[snafu(display(<span class="string">"Unexpected error: {}"</span>, msg))]
<a href=#94 id=94 data-nosnippet>94</a> </span>Unexpected {
<a href=#95 id=95 data-nosnippet>95</a> msg: String,
<a href=#96 id=96 data-nosnippet>96</a> <span class="attr">#[snafu(implicit)]
<a href=#97 id=97 data-nosnippet>97</a> </span>location: Location,
<a href=#98 id=98 data-nosnippet>98</a> },
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> <span class="attr">#[snafu(display(<span class="string">"Missing config, msg: {}"</span>, msg))]
<a href=#101 id=101 data-nosnippet>101</a> </span>MissingConfig {
<a href=#102 id=102 data-nosnippet>102</a> msg: String,
<a href=#103 id=103 data-nosnippet>103</a> <span class="attr">#[snafu(implicit)]
<a href=#104 id=104 data-nosnippet>104</a> </span>location: Location,
<a href=#105 id=105 data-nosnippet>105</a> },
<a href=#106 id=106 data-nosnippet>106</a>
<a href=#107 id=107 data-nosnippet>107</a> <span class="attr">#[snafu(display(<span class="string">"Illegal config: {}"</span>, msg))]
<a href=#108 id=108 data-nosnippet>108</a> </span>IllegalConfig {
<a href=#109 id=109 data-nosnippet>109</a> msg: String,
<a href=#110 id=110 data-nosnippet>110</a> <span class="attr">#[snafu(implicit)]
<a href=#111 id=111 data-nosnippet>111</a> </span>location: Location,
<a href=#112 id=112 data-nosnippet>112</a> },
<a href=#113 id=113 data-nosnippet>113</a>
<a href=#114 id=114 data-nosnippet>114</a> <span class="attr">#[snafu(display(<span class="string">"Failed to parse proxy options: {}"</span>, error))]
<a href=#115 id=115 data-nosnippet>115</a> </span>ParseProxyOpts {
<a href=#116 id=116 data-nosnippet>116</a> <span class="attr">#[snafu(source)]
<a href=#117 id=117 data-nosnippet>117</a> </span>error: reqwest::Error,
<a href=#118 id=118 data-nosnippet>118</a> <span class="attr">#[snafu(implicit)]
<a href=#119 id=119 data-nosnippet>119</a> </span>location: Location,
<a href=#120 id=120 data-nosnippet>120</a> },
<a href=#121 id=121 data-nosnippet>121</a>
<a href=#122 id=122 data-nosnippet>122</a> <span class="attr">#[snafu(display(<span class="string">"Failed to build reqwest client: {}"</span>, error))]
<a href=#123 id=123 data-nosnippet>123</a> </span>BuildClient {
<a href=#124 id=124 data-nosnippet>124</a> <span class="attr">#[snafu(implicit)]
<a href=#125 id=125 data-nosnippet>125</a> </span>location: Location,
<a href=#126 id=126 data-nosnippet>126</a> <span class="attr">#[snafu(source)]
<a href=#127 id=127 data-nosnippet>127</a> </span>error: reqwest::Error,
<a href=#128 id=128 data-nosnippet>128</a> },
<a href=#129 id=129 data-nosnippet>129</a>
<a href=#130 id=130 data-nosnippet>130</a> <span class="attr">#[snafu(display(<span class="string">"Failed to parse SQL: {}"</span>, sql))]
<a href=#131 id=131 data-nosnippet>131</a> </span>ParseSql {
<a href=#132 id=132 data-nosnippet>132</a> sql: String,
<a href=#133 id=133 data-nosnippet>133</a> <span class="attr">#[snafu(implicit)]
<a href=#134 id=134 data-nosnippet>134</a> </span>location: Location,
<a href=#135 id=135 data-nosnippet>135</a> source: query::error::Error,
<a href=#136 id=136 data-nosnippet>136</a> },
<a href=#137 id=137 data-nosnippet>137</a>
<a href=#138 id=138 data-nosnippet>138</a> <span class="attr">#[snafu(display(<span class="string">"Failed to plan statement"</span>))]
<a href=#139 id=139 data-nosnippet>139</a> </span>PlanStatement {
<a href=#140 id=140 data-nosnippet>140</a> <span class="attr">#[snafu(implicit)]
<a href=#141 id=141 data-nosnippet>141</a> </span>location: Location,
<a href=#142 id=142 data-nosnippet>142</a> source: query::error::Error,
<a href=#143 id=143 data-nosnippet>143</a> },
<a href=#144 id=144 data-nosnippet>144</a>
<a href=#145 id=145 data-nosnippet>145</a> <span class="attr">#[snafu(display(<span class="string">"Failed to load layered config"</span>))]
<a href=#146 id=146 data-nosnippet>146</a> </span>LoadLayeredConfig {
<a href=#147 id=147 data-nosnippet>147</a> <span class="attr">#[snafu(source(from(common_config::error::Error, Box::new)))]
<a href=#148 id=148 data-nosnippet>148</a> </span>source: Box&lt;common_config::error::Error&gt;,
<a href=#149 id=149 data-nosnippet>149</a> <span class="attr">#[snafu(implicit)]
<a href=#150 id=150 data-nosnippet>150</a> </span>location: Location,
<a href=#151 id=151 data-nosnippet>151</a> },
<a href=#152 id=152 data-nosnippet>152</a>
<a href=#153 id=153 data-nosnippet>153</a> <span class="attr">#[snafu(display(<span class="string">"Failed to connect to Etcd at {etcd_addr}"</span>))]
<a href=#154 id=154 data-nosnippet>154</a> </span>ConnectEtcd {
<a href=#155 id=155 data-nosnippet>155</a> etcd_addr: String,
<a href=#156 id=156 data-nosnippet>156</a> <span class="attr">#[snafu(source)]
<a href=#157 id=157 data-nosnippet>157</a> </span>error: etcd_client::Error,
<a href=#158 id=158 data-nosnippet>158</a> <span class="attr">#[snafu(implicit)]
<a href=#159 id=159 data-nosnippet>159</a> </span>location: Location,
<a href=#160 id=160 data-nosnippet>160</a> },
<a href=#161 id=161 data-nosnippet>161</a>
<a href=#162 id=162 data-nosnippet>162</a> <span class="attr">#[snafu(display(<span class="string">"Failed to serde json"</span>))]
<a href=#163 id=163 data-nosnippet>163</a> </span>SerdeJson {
<a href=#164 id=164 data-nosnippet>164</a> <span class="attr">#[snafu(source)]
<a href=#165 id=165 data-nosnippet>165</a> </span>error: serde_json::error::Error,
<a href=#166 id=166 data-nosnippet>166</a> <span class="attr">#[snafu(implicit)]
<a href=#167 id=167 data-nosnippet>167</a> </span>location: Location,
<a href=#168 id=168 data-nosnippet>168</a> },
<a href=#169 id=169 data-nosnippet>169</a>
<a href=#170 id=170 data-nosnippet>170</a> <span class="attr">#[snafu(display(<span class="string">"Failed to run http request: {reason}"</span>))]
<a href=#171 id=171 data-nosnippet>171</a> </span>HttpQuerySql {
<a href=#172 id=172 data-nosnippet>172</a> reason: String,
<a href=#173 id=173 data-nosnippet>173</a> <span class="attr">#[snafu(source)]
<a href=#174 id=174 data-nosnippet>174</a> </span>error: reqwest::Error,
<a href=#175 id=175 data-nosnippet>175</a> <span class="attr">#[snafu(implicit)]
<a href=#176 id=176 data-nosnippet>176</a> </span>location: Location,
<a href=#177 id=177 data-nosnippet>177</a> },
<a href=#178 id=178 data-nosnippet>178</a>
<a href=#179 id=179 data-nosnippet>179</a> <span class="attr">#[snafu(display(<span class="string">"Empty result from output"</span>))]
<a href=#180 id=180 data-nosnippet>180</a> </span>EmptyResult {
<a href=#181 id=181 data-nosnippet>181</a> <span class="attr">#[snafu(implicit)]
<a href=#182 id=182 data-nosnippet>182</a> </span>location: Location,
<a href=#183 id=183 data-nosnippet>183</a> },
<a href=#184 id=184 data-nosnippet>184</a>
<a href=#185 id=185 data-nosnippet>185</a> <span class="attr">#[snafu(display(<span class="string">"Failed to manipulate file"</span>))]
<a href=#186 id=186 data-nosnippet>186</a> </span>FileIo {
<a href=#187 id=187 data-nosnippet>187</a> <span class="attr">#[snafu(implicit)]
<a href=#188 id=188 data-nosnippet>188</a> </span>location: Location,
<a href=#189 id=189 data-nosnippet>189</a> <span class="attr">#[snafu(source)]
<a href=#190 id=190 data-nosnippet>190</a> </span>error: std::io::Error,
<a href=#191 id=191 data-nosnippet>191</a> },
<a href=#192 id=192 data-nosnippet>192</a>
<a href=#193 id=193 data-nosnippet>193</a> <span class="attr">#[snafu(display(<span class="string">"Failed to create directory {}"</span>, dir))]
<a href=#194 id=194 data-nosnippet>194</a> </span>CreateDir {
<a href=#195 id=195 data-nosnippet>195</a> dir: String,
<a href=#196 id=196 data-nosnippet>196</a> <span class="attr">#[snafu(source)]
<a href=#197 id=197 data-nosnippet>197</a> </span>error: std::io::Error,
<a href=#198 id=198 data-nosnippet>198</a> },
<a href=#199 id=199 data-nosnippet>199</a>
<a href=#200 id=200 data-nosnippet>200</a> <span class="attr">#[snafu(display(<span class="string">"Failed to spawn thread"</span>))]
<a href=#201 id=201 data-nosnippet>201</a> </span>SpawnThread {
<a href=#202 id=202 data-nosnippet>202</a> <span class="attr">#[snafu(source)]
<a href=#203 id=203 data-nosnippet>203</a> </span>error: std::io::Error,
<a href=#204 id=204 data-nosnippet>204</a> },
<a href=#205 id=205 data-nosnippet>205</a>
<a href=#206 id=206 data-nosnippet>206</a> <span class="attr">#[snafu(display(<span class="string">"Other error"</span>))]
<a href=#207 id=207 data-nosnippet>207</a> </span>Other {
<a href=#208 id=208 data-nosnippet>208</a> source: BoxedError,
<a href=#209 id=209 data-nosnippet>209</a> <span class="attr">#[snafu(implicit)]
<a href=#210 id=210 data-nosnippet>210</a> </span>location: Location,
<a href=#211 id=211 data-nosnippet>211</a> },
<a href=#212 id=212 data-nosnippet>212</a>
<a href=#213 id=213 data-nosnippet>213</a> <span class="attr">#[snafu(display(<span class="string">"Failed to build runtime"</span>))]
<a href=#214 id=214 data-nosnippet>214</a> </span>BuildRuntime {
<a href=#215 id=215 data-nosnippet>215</a> <span class="attr">#[snafu(implicit)]
<a href=#216 id=216 data-nosnippet>216</a> </span>location: Location,
<a href=#217 id=217 data-nosnippet>217</a> source: common_runtime::error::Error,
<a href=#218 id=218 data-nosnippet>218</a> },
<a href=#219 id=219 data-nosnippet>219</a>
<a href=#220 id=220 data-nosnippet>220</a> <span class="attr">#[snafu(display(<span class="string">"Failed to get cache from cache registry: {}"</span>, name))]
<a href=#221 id=221 data-nosnippet>221</a> </span>CacheRequired {
<a href=#222 id=222 data-nosnippet>222</a> <span class="attr">#[snafu(implicit)]
<a href=#223 id=223 data-nosnippet>223</a> </span>location: Location,
<a href=#224 id=224 data-nosnippet>224</a> name: String,
<a href=#225 id=225 data-nosnippet>225</a> },
<a href=#226 id=226 data-nosnippet>226</a>
<a href=#227 id=227 data-nosnippet>227</a> <span class="attr">#[snafu(display(<span class="string">"Failed to build cache registry"</span>))]
<a href=#228 id=228 data-nosnippet>228</a> </span>BuildCacheRegistry {
<a href=#229 id=229 data-nosnippet>229</a> <span class="attr">#[snafu(implicit)]
<a href=#230 id=230 data-nosnippet>230</a> </span>location: Location,
<a href=#231 id=231 data-nosnippet>231</a> source: cache::error::Error,
<a href=#232 id=232 data-nosnippet>232</a> },
<a href=#233 id=233 data-nosnippet>233</a>
<a href=#234 id=234 data-nosnippet>234</a> <span class="attr">#[snafu(display(<span class="string">"Failed to initialize meta client"</span>))]
<a href=#235 id=235 data-nosnippet>235</a> </span>MetaClientInit {
<a href=#236 id=236 data-nosnippet>236</a> <span class="attr">#[snafu(implicit)]
<a href=#237 id=237 data-nosnippet>237</a> </span>location: Location,
<a href=#238 id=238 data-nosnippet>238</a> source: meta_client::error::Error,
<a href=#239 id=239 data-nosnippet>239</a> },
<a href=#240 id=240 data-nosnippet>240</a>
<a href=#241 id=241 data-nosnippet>241</a> <span class="attr">#[snafu(display(<span class="string">"Cannot find schema {schema} in catalog {catalog}"</span>))]
<a href=#242 id=242 data-nosnippet>242</a> </span>SchemaNotFound {
<a href=#243 id=243 data-nosnippet>243</a> catalog: String,
<a href=#244 id=244 data-nosnippet>244</a> schema: String,
<a href=#245 id=245 data-nosnippet>245</a> <span class="attr">#[snafu(implicit)]
<a href=#246 id=246 data-nosnippet>246</a> </span>location: Location,
<a href=#247 id=247 data-nosnippet>247</a> },
<a href=#248 id=248 data-nosnippet>248</a>
<a href=#249 id=249 data-nosnippet>249</a> <span class="attr">#[snafu(display(<span class="string">"Table not found: {table_id}"</span>))]
<a href=#250 id=250 data-nosnippet>250</a> </span>TableNotFound {
<a href=#251 id=251 data-nosnippet>251</a> table_id: TableId,
<a href=#252 id=252 data-nosnippet>252</a> <span class="attr">#[snafu(implicit)]
<a href=#253 id=253 data-nosnippet>253</a> </span>location: Location,
<a href=#254 id=254 data-nosnippet>254</a> },
<a href=#255 id=255 data-nosnippet>255</a>
<a href=#256 id=256 data-nosnippet>256</a> <span class="attr">#[snafu(display(<span class="string">"OpenDAL operator failed"</span>))]
<a href=#257 id=257 data-nosnippet>257</a> </span>OpenDal {
<a href=#258 id=258 data-nosnippet>258</a> <span class="attr">#[snafu(implicit)]
<a href=#259 id=259 data-nosnippet>259</a> </span>location: Location,
<a href=#260 id=260 data-nosnippet>260</a> <span class="attr">#[snafu(source)]
<a href=#261 id=261 data-nosnippet>261</a> </span>error: ObjectStoreError,
<a href=#262 id=262 data-nosnippet>262</a> },
<a href=#263 id=263 data-nosnippet>263</a>
<a href=#264 id=264 data-nosnippet>264</a> <span class="attr">#[snafu(display(<span class="string">"Output directory not set"</span>))]
<a href=#265 id=265 data-nosnippet>265</a> </span>OutputDirNotSet {
<a href=#266 id=266 data-nosnippet>266</a> <span class="attr">#[snafu(implicit)]
<a href=#267 id=267 data-nosnippet>267</a> </span>location: Location,
<a href=#268 id=268 data-nosnippet>268</a> },
<a href=#269 id=269 data-nosnippet>269</a>
<a href=#270 id=270 data-nosnippet>270</a> <span class="attr">#[snafu(display(<span class="string">"Empty store addresses"</span>))]
<a href=#271 id=271 data-nosnippet>271</a> </span>EmptyStoreAddrs {
<a href=#272 id=272 data-nosnippet>272</a> <span class="attr">#[snafu(implicit)]
<a href=#273 id=273 data-nosnippet>273</a> </span>location: Location,
<a href=#274 id=274 data-nosnippet>274</a> },
<a href=#275 id=275 data-nosnippet>275</a>
<a href=#276 id=276 data-nosnippet>276</a> <span class="attr">#[snafu(display(<span class="string">"Unsupported memory backend"</span>))]
<a href=#277 id=277 data-nosnippet>277</a> </span>UnsupportedMemoryBackend {
<a href=#278 id=278 data-nosnippet>278</a> <span class="attr">#[snafu(implicit)]
<a href=#279 id=279 data-nosnippet>279</a> </span>location: Location,
<a href=#280 id=280 data-nosnippet>280</a> },
<a href=#281 id=281 data-nosnippet>281</a>
<a href=#282 id=282 data-nosnippet>282</a> <span class="attr">#[snafu(display(<span class="string">"File path invalid: {}"</span>, msg))]
<a href=#283 id=283 data-nosnippet>283</a> </span>InvalidFilePath {
<a href=#284 id=284 data-nosnippet>284</a> msg: String,
<a href=#285 id=285 data-nosnippet>285</a> <span class="attr">#[snafu(implicit)]
<a href=#286 id=286 data-nosnippet>286</a> </span>location: Location,
<a href=#287 id=287 data-nosnippet>287</a> },
<a href=#288 id=288 data-nosnippet>288</a>
<a href=#289 id=289 data-nosnippet>289</a> <span class="attr">#[snafu(display(<span class="string">"Invalid arguments: {}"</span>, msg))]
<a href=#290 id=290 data-nosnippet>290</a> </span>InvalidArguments {
<a href=#291 id=291 data-nosnippet>291</a> msg: String,
<a href=#292 id=292 data-nosnippet>292</a> <span class="attr">#[snafu(implicit)]
<a href=#293 id=293 data-nosnippet>293</a> </span>location: Location,
<a href=#294 id=294 data-nosnippet>294</a> },
<a href=#295 id=295 data-nosnippet>295</a>
<a href=#296 id=296 data-nosnippet>296</a> <span class="attr">#[snafu(display(<span class="string">"Failed to init backend"</span>))]
<a href=#297 id=297 data-nosnippet>297</a> </span>InitBackend {
<a href=#298 id=298 data-nosnippet>298</a> <span class="attr">#[snafu(implicit)]
<a href=#299 id=299 data-nosnippet>299</a> </span>location: Location,
<a href=#300 id=300 data-nosnippet>300</a> <span class="attr">#[snafu(source)]
<a href=#301 id=301 data-nosnippet>301</a> </span>error: ObjectStoreError,
<a href=#302 id=302 data-nosnippet>302</a> },
<a href=#303 id=303 data-nosnippet>303</a>
<a href=#304 id=304 data-nosnippet>304</a> <span class="attr">#[snafu(display(<span class="string">"Covert column schemas to defs failed"</span>))]
<a href=#305 id=305 data-nosnippet>305</a> </span>CovertColumnSchemasToDefs {
<a href=#306 id=306 data-nosnippet>306</a> <span class="attr">#[snafu(implicit)]
<a href=#307 id=307 data-nosnippet>307</a> </span>location: Location,
<a href=#308 id=308 data-nosnippet>308</a> source: operator::error::Error,
<a href=#309 id=309 data-nosnippet>309</a> },
<a href=#310 id=310 data-nosnippet>310</a>
<a href=#311 id=311 data-nosnippet>311</a> <span class="attr">#[snafu(display(<span class="string">"Failed to send request to datanode: {}"</span>, peer))]
<a href=#312 id=312 data-nosnippet>312</a> </span>SendRequestToDatanode {
<a href=#313 id=313 data-nosnippet>313</a> peer: Peer,
<a href=#314 id=314 data-nosnippet>314</a> <span class="attr">#[snafu(implicit)]
<a href=#315 id=315 data-nosnippet>315</a> </span>location: Location,
<a href=#316 id=316 data-nosnippet>316</a> source: common_meta::error::Error,
<a href=#317 id=317 data-nosnippet>317</a> },
<a href=#318 id=318 data-nosnippet>318</a>
<a href=#319 id=319 data-nosnippet>319</a> <span class="attr">#[snafu(display(<span class="string">"Failed to get current directory"</span>))]
<a href=#320 id=320 data-nosnippet>320</a> </span>GetCurrentDir {
<a href=#321 id=321 data-nosnippet>321</a> <span class="attr">#[snafu(implicit)]
<a href=#322 id=322 data-nosnippet>322</a> </span>location: Location,
<a href=#323 id=323 data-nosnippet>323</a> <span class="attr">#[snafu(source)]
<a href=#324 id=324 data-nosnippet>324</a> </span>error: std::io::Error,
<a href=#325 id=325 data-nosnippet>325</a> },
<a href=#326 id=326 data-nosnippet>326</a>}
<a href=#327 id=327 data-nosnippet>327</a>
<a href=#328 id=328 data-nosnippet>328</a><span class="kw">pub type </span><span class="prelude-ty">Result</span>&lt;T&gt; = std::result::Result&lt;T, Error&gt;;
<a href=#329 id=329 data-nosnippet>329</a>
<a href=#330 id=330 data-nosnippet>330</a><span class="kw">impl </span>ErrorExt <span class="kw">for </span>Error {
<a href=#331 id=331 data-nosnippet>331</a> <span class="kw">fn </span>status_code(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; StatusCode {
<a href=#332 id=332 data-nosnippet>332</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#333 id=333 data-nosnippet>333</a> Error::InitMetadata { source, .. }
<a href=#334 id=334 data-nosnippet>334</a> | Error::InitDdlManager { source, .. }
<a href=#335 id=335 data-nosnippet>335</a> | Error::TableMetadata { source, .. }
<a href=#336 id=336 data-nosnippet>336</a> | Error::BuildCreateRegionRequest { source, .. } =&gt; source.status_code(),
<a href=#337 id=337 data-nosnippet>337</a>
<a href=#338 id=338 data-nosnippet>338</a> Error::MissingConfig { .. }
<a href=#339 id=339 data-nosnippet>339</a> | Error::LoadLayeredConfig { .. }
<a href=#340 id=340 data-nosnippet>340</a> | Error::IllegalConfig { .. }
<a href=#341 id=341 data-nosnippet>341</a> | Error::InitTimezone { .. }
<a href=#342 id=342 data-nosnippet>342</a> | Error::ConnectEtcd { .. }
<a href=#343 id=343 data-nosnippet>343</a> | Error::CreateDir { .. }
<a href=#344 id=344 data-nosnippet>344</a> | Error::EmptyResult { .. }
<a href=#345 id=345 data-nosnippet>345</a> | Error::InvalidFilePath { .. }
<a href=#346 id=346 data-nosnippet>346</a> | Error::UnsupportedMemoryBackend { .. }
<a href=#347 id=347 data-nosnippet>347</a> | Error::InvalidArguments { .. }
<a href=#348 id=348 data-nosnippet>348</a> | Error::ParseProxyOpts { .. } =&gt; StatusCode::InvalidArguments,
<a href=#349 id=349 data-nosnippet>349</a>
<a href=#350 id=350 data-nosnippet>350</a> Error::CovertColumnSchemasToDefs { source, .. } =&gt; source.status_code(),
<a href=#351 id=351 data-nosnippet>351</a> Error::SendRequestToDatanode { source, .. } =&gt; source.status_code(),
<a href=#352 id=352 data-nosnippet>352</a>
<a href=#353 id=353 data-nosnippet>353</a> Error::StartProcedureManager { source, .. }
<a href=#354 id=354 data-nosnippet>354</a> | Error::StopProcedureManager { source, .. } =&gt; source.status_code(),
<a href=#355 id=355 data-nosnippet>355</a> Error::StartWalProvider { source, .. } =&gt; source.status_code(),
<a href=#356 id=356 data-nosnippet>356</a> Error::HttpQuerySql { .. } =&gt; StatusCode::Internal,
<a href=#357 id=357 data-nosnippet>357</a> Error::ParseSql { source, .. } | Error::PlanStatement { source, .. } =&gt; {
<a href=#358 id=358 data-nosnippet>358</a> source.status_code()
<a href=#359 id=359 data-nosnippet>359</a> }
<a href=#360 id=360 data-nosnippet>360</a> Error::Unexpected { .. } =&gt; StatusCode::Unexpected,
<a href=#361 id=361 data-nosnippet>361</a>
<a href=#362 id=362 data-nosnippet>362</a> Error::SerdeJson { .. }
<a href=#363 id=363 data-nosnippet>363</a> | Error::FileIo { .. }
<a href=#364 id=364 data-nosnippet>364</a> | Error::SpawnThread { .. }
<a href=#365 id=365 data-nosnippet>365</a> | Error::InitTlsProvider { .. }
<a href=#366 id=366 data-nosnippet>366</a> | Error::BuildClient { .. } =&gt; StatusCode::Unexpected,
<a href=#367 id=367 data-nosnippet>367</a>
<a href=#368 id=368 data-nosnippet>368</a> Error::Other { source, .. } =&gt; source.status_code(),
<a href=#369 id=369 data-nosnippet>369</a> Error::OpenDal { .. } | Error::InitBackend { .. } =&gt; StatusCode::Internal,
<a href=#370 id=370 data-nosnippet>370</a> Error::OutputDirNotSet { .. } | Error::EmptyStoreAddrs { .. } =&gt; {
<a href=#371 id=371 data-nosnippet>371</a> StatusCode::InvalidArguments
<a href=#372 id=372 data-nosnippet>372</a> }
<a href=#373 id=373 data-nosnippet>373</a>
<a href=#374 id=374 data-nosnippet>374</a> Error::BuildRuntime { source, .. } =&gt; source.status_code(),
<a href=#375 id=375 data-nosnippet>375</a>
<a href=#376 id=376 data-nosnippet>376</a> Error::CacheRequired { .. }
<a href=#377 id=377 data-nosnippet>377</a> | Error::BuildCacheRegistry { .. }
<a href=#378 id=378 data-nosnippet>378</a> | Error::GetCurrentDir { .. } =&gt; StatusCode::Internal,
<a href=#379 id=379 data-nosnippet>379</a> Error::MetaClientInit { source, .. } =&gt; source.status_code(),
<a href=#380 id=380 data-nosnippet>380</a> Error::TableNotFound { .. } =&gt; StatusCode::TableNotFound,
<a href=#381 id=381 data-nosnippet>381</a> Error::SchemaNotFound { .. } =&gt; StatusCode::DatabaseNotFound,
<a href=#382 id=382 data-nosnippet>382</a> }
<a href=#383 id=383 data-nosnippet>383</a> }
<a href=#384 id=384 data-nosnippet>384</a>
<a href=#385 id=385 data-nosnippet>385</a> <span class="kw">fn </span>as_any(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="kw-2">&amp;</span><span class="kw">dyn </span>Any {
<a href=#386 id=386 data-nosnippet>386</a> <span class="self">self
<a href=#387 id=387 data-nosnippet>387</a> </span>}
<a href=#388 id=388 data-nosnippet>388</a>}
</code></pre></div></section></main></body></html>
+56
View File
@@ -0,0 +1,56 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/lib.rs`."><title>lib.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/</div>lib.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="attr">#![allow(clippy::print_stdout)]
<a href=#16 id=16 data-nosnippet>16</a></span><span class="kw">mod </span>bench;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">mod </span>common;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">mod </span>data;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">mod </span>database;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">pub mod </span>error;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">mod </span>metadata;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">pub mod </span>utils;
<a href=#23 id=23 data-nosnippet>23</a>
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>async_trait::async_trait;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>clap::Parser;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">pub use </span>common::{ObjectStoreConfig, StoreConfig};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">pub use </span>database::DatabaseClient;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>error::Result;
<a href=#30 id=30 data-nosnippet>30</a>
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">pub use </span><span class="kw">crate</span>::bench::BenchTableMetadataCommand;
<a href=#32 id=32 data-nosnippet>32</a><span class="kw">pub use </span><span class="kw">crate</span>::data::{DataCommand, export_v2, import_v2};
<a href=#33 id=33 data-nosnippet>33</a><span class="kw">pub use </span><span class="kw">crate</span>::metadata::MetadataCommand;
<a href=#34 id=34 data-nosnippet>34</a>
<a href=#35 id=35 data-nosnippet>35</a><span class="attr">#[async_trait]
<a href=#36 id=36 data-nosnippet>36</a></span><span class="kw">pub trait </span>Tool: Send + Sync {
<a href=#37 id=37 data-nosnippet>37</a> <span class="kw">async fn </span>do_work(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; std::result::Result&lt;(), BoxedError&gt;;
<a href=#38 id=38 data-nosnippet>38</a>}
<a href=#39 id=39 data-nosnippet>39</a>
<a href=#40 id=40 data-nosnippet>40</a><span class="attr">#[derive(Debug, Parser)]
<a href=#41 id=41 data-nosnippet>41</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">struct </span>AttachCommand {
<a href=#42 id=42 data-nosnippet>42</a> <span class="attr">#[clap(long)]
<a href=#43 id=43 data-nosnippet>43</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) grpc_addr: String,
<a href=#44 id=44 data-nosnippet>44</a> <span class="attr">#[clap(long)]
<a href=#45 id=45 data-nosnippet>45</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) meta_addr: <span class="prelude-ty">Option</span>&lt;String&gt;,
<a href=#46 id=46 data-nosnippet>46</a> <span class="attr">#[clap(long, action)]
<a href=#47 id=47 data-nosnippet>47</a> </span><span class="kw">pub</span>(<span class="kw">crate</span>) disable_helper: bool,
<a href=#48 id=48 data-nosnippet>48</a>}
<a href=#49 id=49 data-nosnippet>49</a>
<a href=#50 id=50 data-nosnippet>50</a><span class="kw">impl </span>AttachCommand {
<a href=#51 id=51 data-nosnippet>51</a> <span class="attr">#[allow(dead_code)]
<a href=#52 id=52 data-nosnippet>52</a> </span><span class="kw">async fn </span>build(<span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;&gt; {
<a href=#53 id=53 data-nosnippet>53</a> <span class="macro">unimplemented!</span>(<span class="string">"Wait for https://github.com/GreptimeTeam/greptimedb/issues/2373"</span>)
<a href=#54 id=54 data-nosnippet>54</a> }
<a href=#55 id=55 data-nosnippet>55</a>}
</code></pre></div></section></main></body></html>
+56
View File
@@ -0,0 +1,56 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/metadata.rs`."><title>metadata.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../" data-static-root-path="../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../static.files/storage-41dd4d93.js"></script><script defer src="../../static.files/src-script-813739b1.js"></script><script defer src="../../src-files.js"></script><script defer src="../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/</div>metadata.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">mod </span>control;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">mod </span>repair;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">mod </span>snapshot;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">mod </span>utils;
<a href=#19 id=19 data-nosnippet>19</a>
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>clap::Subcommand;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span><span class="kw">crate</span>::Tool;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span><span class="kw">crate</span>::metadata::control::{DelCommand, GetCommand, PutCommand};
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span><span class="kw">crate</span>::metadata::repair::RepairCommand;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span><span class="kw">crate</span>::metadata::snapshot::SnapshotCommand;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="doccomment">/// Command for managing metadata operations,
<a href=#29 id=29 data-nosnippet>29</a>/// including saving and restoring metadata snapshots,
<a href=#30 id=30 data-nosnippet>30</a>/// controlling metadata operations, and diagnosing and repairing metadata.
<a href=#31 id=31 data-nosnippet>31</a></span><span class="attr">#[derive(Subcommand)]
<a href=#32 id=32 data-nosnippet>32</a></span><span class="kw">pub enum </span>MetadataCommand {
<a href=#33 id=33 data-nosnippet>33</a> <span class="attr">#[clap(subcommand)]
<a href=#34 id=34 data-nosnippet>34</a> </span>Snapshot(SnapshotCommand),
<a href=#35 id=35 data-nosnippet>35</a> <span class="attr">#[clap(subcommand)]
<a href=#36 id=36 data-nosnippet>36</a> </span>Get(GetCommand),
<a href=#37 id=37 data-nosnippet>37</a> <span class="attr">#[clap(subcommand)]
<a href=#38 id=38 data-nosnippet>38</a> </span>Del(DelCommand),
<a href=#39 id=39 data-nosnippet>39</a> <span class="attr">#[clap(subcommand)]
<a href=#40 id=40 data-nosnippet>40</a> </span>Put(PutCommand),
<a href=#41 id=41 data-nosnippet>41</a> <span class="attr">#[clap(subcommand)]
<a href=#42 id=42 data-nosnippet>42</a> </span>Repair(RepairCommand),
<a href=#43 id=43 data-nosnippet>43</a>}
<a href=#44 id=44 data-nosnippet>44</a>
<a href=#45 id=45 data-nosnippet>45</a><span class="kw">impl </span>MetadataCommand {
<a href=#46 id=46 data-nosnippet>46</a> <span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt; {
<a href=#47 id=47 data-nosnippet>47</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#48 id=48 data-nosnippet>48</a> MetadataCommand::Snapshot(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#49 id=49 data-nosnippet>49</a> MetadataCommand::Repair(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#50 id=50 data-nosnippet>50</a> MetadataCommand::Get(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#51 id=51 data-nosnippet>51</a> MetadataCommand::Del(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#52 id=52 data-nosnippet>52</a> MetadataCommand::Put(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#53 id=53 data-nosnippet>53</a> }
<a href=#54 id=54 data-nosnippet>54</a> }
<a href=#55 id=55 data-nosnippet>55</a>}
</code></pre></div></section></main></body></html>
+26
View File
@@ -0,0 +1,26 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/metadata/control.rs`."><title>control.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../static.files/src-script-813739b1.js"></script><script defer src="../../../src-files.js"></script><script defer src="../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/metadata/</div>control.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">mod </span>del;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">mod </span>get;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">mod </span>put;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">mod </span>selector;
<a href=#19 id=19 data-nosnippet>19</a><span class="attr">#[cfg(test)]
<a href=#20 id=20 data-nosnippet>20</a></span><span class="kw">mod </span>test_utils;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">mod </span>utils;
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">use </span>del::DelCommand;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">use </span>get::GetCommand;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">use </span>put::PutCommand;
</code></pre></div></section></main></body></html>
+43
View File
@@ -0,0 +1,43 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/metadata/control/del.rs`."><title>del.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/metadata/control/</div>del.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">mod </span>key;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">mod </span>table;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>clap::Subcommand;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#20 id=20 data-nosnippet>20</a>
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span><span class="kw">crate</span>::Tool;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span><span class="kw">crate</span>::metadata::control::del::key::DelKeyCommand;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span><span class="kw">crate</span>::metadata::control::del::table::DelTableCommand;
<a href=#24 id=24 data-nosnippet>24</a>
<a href=#25 id=25 data-nosnippet>25</a><span class="doccomment">/// The prefix of the tombstone keys.
<a href=#26 id=26 data-nosnippet>26</a></span><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">const </span>CLI_TOMBSTONE_PREFIX: <span class="kw-2">&amp;</span>str = <span class="string">"__cli_tombstone/"</span>;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="doccomment">/// Subcommand for deleting metadata from the metadata store.
<a href=#29 id=29 data-nosnippet>29</a></span><span class="attr">#[derive(Subcommand)]
<a href=#30 id=30 data-nosnippet>30</a></span><span class="kw">pub enum </span>DelCommand {
<a href=#31 id=31 data-nosnippet>31</a> Key(DelKeyCommand),
<a href=#32 id=32 data-nosnippet>32</a> Table(DelTableCommand),
<a href=#33 id=33 data-nosnippet>33</a>}
<a href=#34 id=34 data-nosnippet>34</a>
<a href=#35 id=35 data-nosnippet>35</a><span class="kw">impl </span>DelCommand {
<a href=#36 id=36 data-nosnippet>36</a> <span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt; {
<a href=#37 id=37 data-nosnippet>37</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#38 id=38 data-nosnippet>38</a> DelCommand::Key(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#39 id=39 data-nosnippet>39</a> DelCommand::Table(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#40 id=40 data-nosnippet>40</a> }
<a href=#41 id=41 data-nosnippet>41</a> }
<a href=#42 id=42 data-nosnippet>42</a>}
</code></pre></div></section></main></body></html>
+133
View File
@@ -0,0 +1,133 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/metadata/control/del/key.rs`."><title>key.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../../" data-static-root-path="../../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../../src-files.js"></script><script defer src="../../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/metadata/control/del/</div>key.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>async_trait::async_trait;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>clap::Parser;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_meta::key::tombstone::TombstoneManager;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_meta::kv_backend::KvBackendRef;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::rpc::store::RangeRequest;
<a href=#21 id=21 data-nosnippet>21</a>
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span><span class="kw">crate</span>::Tool;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span><span class="kw">crate</span>::common::StoreConfig;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span><span class="kw">crate</span>::metadata::control::del::CLI_TOMBSTONE_PREFIX;
<a href=#25 id=25 data-nosnippet>25</a>
<a href=#26 id=26 data-nosnippet>26</a><span class="doccomment">/// Delete key-value pairs logically from the metadata store.
<a href=#27 id=27 data-nosnippet>27</a></span><span class="attr">#[derive(Debug, Default, Parser)]
<a href=#28 id=28 data-nosnippet>28</a></span><span class="kw">pub struct </span>DelKeyCommand {
<a href=#29 id=29 data-nosnippet>29</a> <span class="doccomment">/// The key to delete from the metadata store.
<a href=#30 id=30 data-nosnippet>30</a> </span>key: String,
<a href=#31 id=31 data-nosnippet>31</a>
<a href=#32 id=32 data-nosnippet>32</a> <span class="doccomment">/// Delete key-value pairs with the given prefix.
<a href=#33 id=33 data-nosnippet>33</a> </span><span class="attr">#[clap(long)]
<a href=#34 id=34 data-nosnippet>34</a> </span>prefix: bool,
<a href=#35 id=35 data-nosnippet>35</a>
<a href=#36 id=36 data-nosnippet>36</a> <span class="attr">#[clap(flatten)]
<a href=#37 id=37 data-nosnippet>37</a> </span>store: StoreConfig,
<a href=#38 id=38 data-nosnippet>38</a>}
<a href=#39 id=39 data-nosnippet>39</a>
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">impl </span>DelKeyCommand {
<a href=#41 id=41 data-nosnippet>41</a> <span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt; {
<a href=#42 id=42 data-nosnippet>42</a> <span class="kw">let </span>kv_backend = <span class="self">self</span>.store.build().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#43 id=43 data-nosnippet>43</a> <span class="prelude-val">Ok</span>(Box::new(DelKeyTool {
<a href=#44 id=44 data-nosnippet>44</a> key: <span class="self">self</span>.key.clone(),
<a href=#45 id=45 data-nosnippet>45</a> prefix: <span class="self">self</span>.prefix,
<a href=#46 id=46 data-nosnippet>46</a> key_deleter: KeyDeleter::new(kv_backend),
<a href=#47 id=47 data-nosnippet>47</a> }))
<a href=#48 id=48 data-nosnippet>48</a> }
<a href=#49 id=49 data-nosnippet>49</a>}
<a href=#50 id=50 data-nosnippet>50</a>
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">struct </span>KeyDeleter {
<a href=#52 id=52 data-nosnippet>52</a> kv_backend: KvBackendRef,
<a href=#53 id=53 data-nosnippet>53</a> tombstone_manager: TombstoneManager,
<a href=#54 id=54 data-nosnippet>54</a>}
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a><span class="kw">impl </span>KeyDeleter {
<a href=#57 id=57 data-nosnippet>57</a> <span class="kw">fn </span>new(kv_backend: KvBackendRef) -&gt; <span class="self">Self </span>{
<a href=#58 id=58 data-nosnippet>58</a> <span class="self">Self </span>{
<a href=#59 id=59 data-nosnippet>59</a> kv_backend: kv_backend.clone(),
<a href=#60 id=60 data-nosnippet>60</a> tombstone_manager: TombstoneManager::new_with_prefix(kv_backend, CLI_TOMBSTONE_PREFIX),
<a href=#61 id=61 data-nosnippet>61</a> }
<a href=#62 id=62 data-nosnippet>62</a> }
<a href=#63 id=63 data-nosnippet>63</a>
<a href=#64 id=64 data-nosnippet>64</a> <span class="kw">async fn </span>delete(<span class="kw-2">&amp;</span><span class="self">self</span>, key: <span class="kw-2">&amp;</span>str, prefix: bool) -&gt; <span class="prelude-ty">Result</span>&lt;usize, BoxedError&gt; {
<a href=#65 id=65 data-nosnippet>65</a> <span class="kw">let </span><span class="kw-2">mut </span>req = RangeRequest::default().with_keys_only();
<a href=#66 id=66 data-nosnippet>66</a> <span class="kw">if </span>prefix {
<a href=#67 id=67 data-nosnippet>67</a> req = req.with_prefix(key.as_bytes());
<a href=#68 id=68 data-nosnippet>68</a> } <span class="kw">else </span>{
<a href=#69 id=69 data-nosnippet>69</a> req = req.with_key(key.as_bytes());
<a href=#70 id=70 data-nosnippet>70</a> }
<a href=#71 id=71 data-nosnippet>71</a> <span class="kw">let </span>resp = <span class="self">self</span>.kv_backend.range(req).<span class="kw">await</span>.map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#72 id=72 data-nosnippet>72</a> <span class="kw">let </span>keys = resp.kvs.iter().map(|kv| kv.key.clone()).collect::&lt;Vec&lt;<span class="kw">_</span>&gt;&gt;();
<a href=#73 id=73 data-nosnippet>73</a> <span class="self">self</span>.tombstone_manager
<a href=#74 id=74 data-nosnippet>74</a> .create(keys)
<a href=#75 id=75 data-nosnippet>75</a> .<span class="kw">await
<a href=#76 id=76 data-nosnippet>76</a> </span>.map_err(BoxedError::new)
<a href=#77 id=77 data-nosnippet>77</a> }
<a href=#78 id=78 data-nosnippet>78</a>}
<a href=#79 id=79 data-nosnippet>79</a>
<a href=#80 id=80 data-nosnippet>80</a><span class="kw">struct </span>DelKeyTool {
<a href=#81 id=81 data-nosnippet>81</a> key: String,
<a href=#82 id=82 data-nosnippet>82</a> prefix: bool,
<a href=#83 id=83 data-nosnippet>83</a> key_deleter: KeyDeleter,
<a href=#84 id=84 data-nosnippet>84</a>}
<a href=#85 id=85 data-nosnippet>85</a>
<a href=#86 id=86 data-nosnippet>86</a><span class="attr">#[async_trait]
<a href=#87 id=87 data-nosnippet>87</a></span><span class="kw">impl </span>Tool <span class="kw">for </span>DelKeyTool {
<a href=#88 id=88 data-nosnippet>88</a> <span class="kw">async fn </span>do_work(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#89 id=89 data-nosnippet>89</a> <span class="kw">let </span>deleted = <span class="self">self</span>.key_deleter.delete(<span class="kw-2">&amp;</span><span class="self">self</span>.key, <span class="self">self</span>.prefix).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#90 id=90 data-nosnippet>90</a> <span class="comment">// Print the number of deleted keys.
<a href=#91 id=91 data-nosnippet>91</a> </span><span class="macro">println!</span>(<span class="string">"{}"</span>, deleted);
<a href=#92 id=92 data-nosnippet>92</a> <span class="prelude-val">Ok</span>(())
<a href=#93 id=93 data-nosnippet>93</a> }
<a href=#94 id=94 data-nosnippet>94</a>}
<a href=#95 id=95 data-nosnippet>95</a>
<a href=#96 id=96 data-nosnippet>96</a><span class="attr">#[cfg(test)]
<a href=#97 id=97 data-nosnippet>97</a></span><span class="kw">mod </span>tests {
<a href=#98 id=98 data-nosnippet>98</a> <span class="kw">use </span>std::sync::Arc;
<a href=#99 id=99 data-nosnippet>99</a>
<a href=#100 id=100 data-nosnippet>100</a> <span class="kw">use </span>common_meta::kv_backend::chroot::ChrootKvBackend;
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">use </span>common_meta::kv_backend::memory::MemoryKvBackend;
<a href=#102 id=102 data-nosnippet>102</a> <span class="kw">use </span>common_meta::kv_backend::{KvBackend, KvBackendRef};
<a href=#103 id=103 data-nosnippet>103</a> <span class="kw">use </span>common_meta::rpc::store::RangeRequest;
<a href=#104 id=104 data-nosnippet>104</a>
<a href=#105 id=105 data-nosnippet>105</a> <span class="kw">use </span><span class="kw">crate</span>::metadata::control::del::CLI_TOMBSTONE_PREFIX;
<a href=#106 id=106 data-nosnippet>106</a> <span class="kw">use </span><span class="kw">crate</span>::metadata::control::del::key::KeyDeleter;
<a href=#107 id=107 data-nosnippet>107</a> <span class="kw">use </span><span class="kw">crate</span>::metadata::control::test_utils::put_key;
<a href=#108 id=108 data-nosnippet>108</a>
<a href=#109 id=109 data-nosnippet>109</a> <span class="attr">#[tokio::test]
<a href=#110 id=110 data-nosnippet>110</a> </span><span class="kw">async fn </span>test_delete_keys() {
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">let </span>kv_backend = Arc::new(MemoryKvBackend::new()) <span class="kw">as </span>KvBackendRef;
<a href=#112 id=112 data-nosnippet>112</a> <span class="kw">let </span>key_deleter = KeyDeleter::new(kv_backend.clone());
<a href=#113 id=113 data-nosnippet>113</a> put_key(<span class="kw-2">&amp;</span>kv_backend, <span class="string">"foo"</span>, <span class="string">"bar"</span>).<span class="kw">await</span>;
<a href=#114 id=114 data-nosnippet>114</a> put_key(<span class="kw-2">&amp;</span>kv_backend, <span class="string">"foo/bar"</span>, <span class="string">"baz"</span>).<span class="kw">await</span>;
<a href=#115 id=115 data-nosnippet>115</a> put_key(<span class="kw-2">&amp;</span>kv_backend, <span class="string">"foo/baz"</span>, <span class="string">"qux"</span>).<span class="kw">await</span>;
<a href=#116 id=116 data-nosnippet>116</a> <span class="kw">let </span>deleted = key_deleter.delete(<span class="string">"foo"</span>, <span class="bool-val">true</span>).<span class="kw">await</span>.unwrap();
<a href=#117 id=117 data-nosnippet>117</a> <span class="macro">assert_eq!</span>(deleted, <span class="number">3</span>);
<a href=#118 id=118 data-nosnippet>118</a> <span class="kw">let </span>deleted = key_deleter.delete(<span class="string">"foo/bar"</span>, <span class="bool-val">false</span>).<span class="kw">await</span>.unwrap();
<a href=#119 id=119 data-nosnippet>119</a> <span class="macro">assert_eq!</span>(deleted, <span class="number">0</span>);
<a href=#120 id=120 data-nosnippet>120</a>
<a href=#121 id=121 data-nosnippet>121</a> <span class="kw">let </span>chroot = ChrootKvBackend::new(CLI_TOMBSTONE_PREFIX.as_bytes().to_vec(), kv_backend);
<a href=#122 id=122 data-nosnippet>122</a> <span class="kw">let </span>req = RangeRequest::default().with_prefix(<span class="string">b"foo"</span>);
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw">let </span>resp = chroot.range(req).<span class="kw">await</span>.unwrap();
<a href=#124 id=124 data-nosnippet>124</a> <span class="macro">assert_eq!</span>(resp.kvs.len(), <span class="number">3</span>);
<a href=#125 id=125 data-nosnippet>125</a> <span class="macro">assert_eq!</span>(resp.kvs[<span class="number">0</span>].key, <span class="string">b"foo"</span>);
<a href=#126 id=126 data-nosnippet>126</a> <span class="macro">assert_eq!</span>(resp.kvs[<span class="number">0</span>].value, <span class="string">b"bar"</span>);
<a href=#127 id=127 data-nosnippet>127</a> <span class="macro">assert_eq!</span>(resp.kvs[<span class="number">1</span>].key, <span class="string">b"foo/bar"</span>);
<a href=#128 id=128 data-nosnippet>128</a> <span class="macro">assert_eq!</span>(resp.kvs[<span class="number">1</span>].value, <span class="string">b"baz"</span>);
<a href=#129 id=129 data-nosnippet>129</a> <span class="macro">assert_eq!</span>(resp.kvs[<span class="number">2</span>].key, <span class="string">b"foo/baz"</span>);
<a href=#130 id=130 data-nosnippet>130</a> <span class="macro">assert_eq!</span>(resp.kvs[<span class="number">2</span>].value, <span class="string">b"qux"</span>);
<a href=#131 id=131 data-nosnippet>131</a> }
<a href=#132 id=132 data-nosnippet>132</a>}
</code></pre></div></section></main></body></html>
+266
View File
@@ -0,0 +1,266 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/metadata/control/del/table.rs`."><title>table.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../../" data-static-root-path="../../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../../src-files.js"></script><script defer src="../../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/metadata/control/del/</div>table.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>async_trait::async_trait;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>clap::Parser;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_meta::ddl::utils::get_region_wal_options;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_meta::key::TableMetadataManager;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::kv_backend::KvBackendRef;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>store_api::storage::TableId;
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span><span class="kw">crate</span>::Tool;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span><span class="kw">crate</span>::common::StoreConfig;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span><span class="kw">crate</span>::error::TableNotFoundSnafu;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span><span class="kw">crate</span>::metadata::control::del::CLI_TOMBSTONE_PREFIX;
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span><span class="kw">crate</span>::metadata::control::selector::TableSelector;
<a href=#28 id=28 data-nosnippet>28</a>
<a href=#29 id=29 data-nosnippet>29</a><span class="doccomment">/// Delete table metadata logically from the metadata store.
<a href=#30 id=30 data-nosnippet>30</a></span><span class="attr">#[derive(Debug, Default, Parser)]
<a href=#31 id=31 data-nosnippet>31</a></span><span class="kw">pub struct </span>DelTableCommand {
<a href=#32 id=32 data-nosnippet>32</a> <span class="attr">#[clap(flatten)]
<a href=#33 id=33 data-nosnippet>33</a> </span>selector: TableSelector,
<a href=#34 id=34 data-nosnippet>34</a>
<a href=#35 id=35 data-nosnippet>35</a> <span class="doccomment">/// The store config.
<a href=#36 id=36 data-nosnippet>36</a> </span><span class="attr">#[clap(flatten)]
<a href=#37 id=37 data-nosnippet>37</a> </span>store: StoreConfig,
<a href=#38 id=38 data-nosnippet>38</a>}
<a href=#39 id=39 data-nosnippet>39</a>
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">impl </span>DelTableCommand {
<a href=#41 id=41 data-nosnippet>41</a> <span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt; {
<a href=#42 id=42 data-nosnippet>42</a> <span class="self">self</span>.selector.validate()<span class="question-mark">?</span>;
<a href=#43 id=43 data-nosnippet>43</a> <span class="kw">let </span>kv_backend = <span class="self">self</span>.store.build().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#44 id=44 data-nosnippet>44</a> <span class="prelude-val">Ok</span>(Box::new(DelTableTool {
<a href=#45 id=45 data-nosnippet>45</a> selector: <span class="self">self</span>.selector.clone(),
<a href=#46 id=46 data-nosnippet>46</a> table_metadata_deleter: TableMetadataDeleter::new(kv_backend),
<a href=#47 id=47 data-nosnippet>47</a> }))
<a href=#48 id=48 data-nosnippet>48</a> }
<a href=#49 id=49 data-nosnippet>49</a>}
<a href=#50 id=50 data-nosnippet>50</a>
<a href=#51 id=51 data-nosnippet>51</a><span class="kw">struct </span>DelTableTool {
<a href=#52 id=52 data-nosnippet>52</a> selector: TableSelector,
<a href=#53 id=53 data-nosnippet>53</a> table_metadata_deleter: TableMetadataDeleter,
<a href=#54 id=54 data-nosnippet>54</a>}
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a><span class="attr">#[async_trait]
<a href=#57 id=57 data-nosnippet>57</a></span><span class="kw">impl </span>Tool <span class="kw">for </span>DelTableTool {
<a href=#58 id=58 data-nosnippet>58</a> <span class="kw">async fn </span>do_work(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#59 id=59 data-nosnippet>59</a> <span class="kw">let </span><span class="prelude-val">Some</span>(table_id) = <span class="self">self
<a href=#60 id=60 data-nosnippet>60</a> </span>.selector
<a href=#61 id=61 data-nosnippet>61</a> .resolve_table_id(
<a href=#62 id=62 data-nosnippet>62</a> <span class="self">self</span>.table_metadata_deleter
<a href=#63 id=63 data-nosnippet>63</a> .table_metadata_manager
<a href=#64 id=64 data-nosnippet>64</a> .table_name_manager(),
<a href=#65 id=65 data-nosnippet>65</a> )
<a href=#66 id=66 data-nosnippet>66</a> .<span class="kw">await</span><span class="question-mark">?
<a href=#67 id=67 data-nosnippet>67</a> </span><span class="kw">else </span>{
<a href=#68 id=68 data-nosnippet>68</a> <span class="macro">println!</span>(<span class="string">"Table({}) not found"</span>, <span class="self">self</span>.selector.formatted_table_name());
<a href=#69 id=69 data-nosnippet>69</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#70 id=70 data-nosnippet>70</a> };
<a href=#71 id=71 data-nosnippet>71</a> <span class="self">self</span>.table_metadata_deleter.delete(table_id).<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#72 id=72 data-nosnippet>72</a> <span class="macro">println!</span>(<span class="string">"Table({}) deleted"</span>, table_id);
<a href=#73 id=73 data-nosnippet>73</a>
<a href=#74 id=74 data-nosnippet>74</a> <span class="prelude-val">Ok</span>(())
<a href=#75 id=75 data-nosnippet>75</a> }
<a href=#76 id=76 data-nosnippet>76</a>}
<a href=#77 id=77 data-nosnippet>77</a>
<a href=#78 id=78 data-nosnippet>78</a><span class="kw">struct </span>TableMetadataDeleter {
<a href=#79 id=79 data-nosnippet>79</a> table_metadata_manager: TableMetadataManager,
<a href=#80 id=80 data-nosnippet>80</a>}
<a href=#81 id=81 data-nosnippet>81</a>
<a href=#82 id=82 data-nosnippet>82</a><span class="kw">impl </span>TableMetadataDeleter {
<a href=#83 id=83 data-nosnippet>83</a> <span class="kw">fn </span>new(kv_backend: KvBackendRef) -&gt; <span class="self">Self </span>{
<a href=#84 id=84 data-nosnippet>84</a> <span class="self">Self </span>{
<a href=#85 id=85 data-nosnippet>85</a> table_metadata_manager: TableMetadataManager::new_with_custom_tombstone_prefix(
<a href=#86 id=86 data-nosnippet>86</a> kv_backend,
<a href=#87 id=87 data-nosnippet>87</a> CLI_TOMBSTONE_PREFIX,
<a href=#88 id=88 data-nosnippet>88</a> ),
<a href=#89 id=89 data-nosnippet>89</a> }
<a href=#90 id=90 data-nosnippet>90</a> }
<a href=#91 id=91 data-nosnippet>91</a>
<a href=#92 id=92 data-nosnippet>92</a> <span class="kw">async fn </span>delete(<span class="kw-2">&amp;</span><span class="self">self</span>, table_id: TableId) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#93 id=93 data-nosnippet>93</a> <span class="kw">let </span>(table_info, table_route) = <span class="self">self
<a href=#94 id=94 data-nosnippet>94</a> </span>.table_metadata_manager
<a href=#95 id=95 data-nosnippet>95</a> .get_full_table_info(table_id)
<a href=#96 id=96 data-nosnippet>96</a> .<span class="kw">await
<a href=#97 id=97 data-nosnippet>97</a> </span>.map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#98 id=98 data-nosnippet>98</a> <span class="kw">let </span><span class="prelude-val">Some</span>(table_info) = table_info <span class="kw">else </span>{
<a href=#99 id=99 data-nosnippet>99</a> <span class="kw">return </span><span class="prelude-val">Err</span>(BoxedError::new(TableNotFoundSnafu { table_id }.build()));
<a href=#100 id=100 data-nosnippet>100</a> };
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">let </span><span class="prelude-val">Some</span>(table_route) = table_route <span class="kw">else </span>{
<a href=#102 id=102 data-nosnippet>102</a> <span class="kw">return </span><span class="prelude-val">Err</span>(BoxedError::new(TableNotFoundSnafu { table_id }.build()));
<a href=#103 id=103 data-nosnippet>103</a> };
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">let </span>physical_table_id = <span class="self">self
<a href=#105 id=105 data-nosnippet>105</a> </span>.table_metadata_manager
<a href=#106 id=106 data-nosnippet>106</a> .table_route_manager()
<a href=#107 id=107 data-nosnippet>107</a> .get_physical_table_id(table_id)
<a href=#108 id=108 data-nosnippet>108</a> .<span class="kw">await
<a href=#109 id=109 data-nosnippet>109</a> </span>.map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#110 id=110 data-nosnippet>110</a>
<a href=#111 id=111 data-nosnippet>111</a> <span class="kw">let </span>table_name = table_info.table_name();
<a href=#112 id=112 data-nosnippet>112</a> <span class="kw">let </span>region_wal_options = get_region_wal_options(
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw-2">&amp;</span><span class="self">self</span>.table_metadata_manager,
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw-2">&amp;</span>table_route,
<a href=#115 id=115 data-nosnippet>115</a> physical_table_id,
<a href=#116 id=116 data-nosnippet>116</a> )
<a href=#117 id=117 data-nosnippet>117</a> .<span class="kw">await
<a href=#118 id=118 data-nosnippet>118</a> </span>.map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#119 id=119 data-nosnippet>119</a>
<a href=#120 id=120 data-nosnippet>120</a> <span class="self">self</span>.table_metadata_manager
<a href=#121 id=121 data-nosnippet>121</a> .delete_table_metadata(
<a href=#122 id=122 data-nosnippet>122</a> table_id,
<a href=#123 id=123 data-nosnippet>123</a> <span class="kw-2">&amp;</span>table_name,
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw-2">&amp;</span>table_route,
<a href=#125 id=125 data-nosnippet>125</a> <span class="kw-2">&amp;</span>region_wal_options,
<a href=#126 id=126 data-nosnippet>126</a> <span class="prelude-val">None</span>,
<a href=#127 id=127 data-nosnippet>127</a> )
<a href=#128 id=128 data-nosnippet>128</a> .<span class="kw">await
<a href=#129 id=129 data-nosnippet>129</a> </span>.map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#130 id=130 data-nosnippet>130</a> <span class="prelude-val">Ok</span>(())
<a href=#131 id=131 data-nosnippet>131</a> }
<a href=#132 id=132 data-nosnippet>132</a>}
<a href=#133 id=133 data-nosnippet>133</a>
<a href=#134 id=134 data-nosnippet>134</a><span class="attr">#[cfg(test)]
<a href=#135 id=135 data-nosnippet>135</a></span><span class="kw">mod </span>tests {
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw">use </span>std::collections::HashMap;
<a href=#137 id=137 data-nosnippet>137</a> <span class="kw">use </span>std::sync::Arc;
<a href=#138 id=138 data-nosnippet>138</a>
<a href=#139 id=139 data-nosnippet>139</a> <span class="kw">use </span>clap::Parser;
<a href=#140 id=140 data-nosnippet>140</a> <span class="kw">use </span>common_error::ext::ErrorExt;
<a href=#141 id=141 data-nosnippet>141</a> <span class="kw">use </span>common_error::status_code::StatusCode;
<a href=#142 id=142 data-nosnippet>142</a> <span class="kw">use </span>common_meta::key::TableMetadataManager;
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">use </span>common_meta::key::table_route::TableRouteValue;
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">use </span>common_meta::kv_backend::chroot::ChrootKvBackend;
<a href=#145 id=145 data-nosnippet>145</a> <span class="kw">use </span>common_meta::kv_backend::memory::MemoryKvBackend;
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">use </span>common_meta::kv_backend::{KvBackend, KvBackendRef};
<a href=#147 id=147 data-nosnippet>147</a> <span class="kw">use </span>common_meta::rpc::store::RangeRequest;
<a href=#148 id=148 data-nosnippet>148</a>
<a href=#149 id=149 data-nosnippet>149</a> <span class="kw">use </span><span class="kw">crate</span>::metadata::control::del::CLI_TOMBSTONE_PREFIX;
<a href=#150 id=150 data-nosnippet>150</a> <span class="kw">use </span><span class="kw">crate</span>::metadata::control::del::table::{DelTableCommand, TableMetadataDeleter};
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">use </span><span class="kw">crate</span>::metadata::control::test_utils::prepare_physical_table_metadata;
<a href=#152 id=152 data-nosnippet>152</a>
<a href=#153 id=153 data-nosnippet>153</a> <span class="attr">#[tokio::test]
<a href=#154 id=154 data-nosnippet>154</a> </span><span class="kw">async fn </span>test_del_table_selector_requires_single_target() {
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">let </span>command = DelTableCommand::parse_from([
<a href=#156 id=156 data-nosnippet>156</a> <span class="string">"table"</span>,
<a href=#157 id=157 data-nosnippet>157</a> <span class="string">"--backend"</span>,
<a href=#158 id=158 data-nosnippet>158</a> <span class="string">"memory-store"</span>,
<a href=#159 id=159 data-nosnippet>159</a> <span class="string">"--store-addrs"</span>,
<a href=#160 id=160 data-nosnippet>160</a> <span class="string">"memory://"</span>,
<a href=#161 id=161 data-nosnippet>161</a> ]);
<a href=#162 id=162 data-nosnippet>162</a>
<a href=#163 id=163 data-nosnippet>163</a> <span class="kw">let </span>err = <span class="kw">match </span>command.build().<span class="kw">await </span>{
<a href=#164 id=164 data-nosnippet>164</a> <span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; <span class="macro">panic!</span>(<span class="string">"expected validation failure"</span>),
<a href=#165 id=165 data-nosnippet>165</a> <span class="prelude-val">Err</span>(err) =&gt; err,
<a href=#166 id=166 data-nosnippet>166</a> };
<a href=#167 id=167 data-nosnippet>167</a> <span class="macro">assert!</span>(
<a href=#168 id=168 data-nosnippet>168</a> err.output_msg()
<a href=#169 id=169 data-nosnippet>169</a> .contains(<span class="string">"You must specify either --table-id or --table-name."</span>)
<a href=#170 id=170 data-nosnippet>170</a> );
<a href=#171 id=171 data-nosnippet>171</a> }
<a href=#172 id=172 data-nosnippet>172</a>
<a href=#173 id=173 data-nosnippet>173</a> <span class="attr">#[tokio::test]
<a href=#174 id=174 data-nosnippet>174</a> </span><span class="kw">async fn </span>test_del_table_selector_rejects_both_targets() {
<a href=#175 id=175 data-nosnippet>175</a> <span class="kw">let </span>command = DelTableCommand::parse_from([
<a href=#176 id=176 data-nosnippet>176</a> <span class="string">"table"</span>,
<a href=#177 id=177 data-nosnippet>177</a> <span class="string">"--table-id"</span>,
<a href=#178 id=178 data-nosnippet>178</a> <span class="string">"1024"</span>,
<a href=#179 id=179 data-nosnippet>179</a> <span class="string">"--table-name"</span>,
<a href=#180 id=180 data-nosnippet>180</a> <span class="string">"my_table"</span>,
<a href=#181 id=181 data-nosnippet>181</a> <span class="string">"--backend"</span>,
<a href=#182 id=182 data-nosnippet>182</a> <span class="string">"memory-store"</span>,
<a href=#183 id=183 data-nosnippet>183</a> <span class="string">"--store-addrs"</span>,
<a href=#184 id=184 data-nosnippet>184</a> <span class="string">"memory://"</span>,
<a href=#185 id=185 data-nosnippet>185</a> ]);
<a href=#186 id=186 data-nosnippet>186</a>
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">let </span>err = <span class="kw">match </span>command.build().<span class="kw">await </span>{
<a href=#188 id=188 data-nosnippet>188</a> <span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; <span class="macro">panic!</span>(<span class="string">"expected validation failure"</span>),
<a href=#189 id=189 data-nosnippet>189</a> <span class="prelude-val">Err</span>(err) =&gt; err,
<a href=#190 id=190 data-nosnippet>190</a> };
<a href=#191 id=191 data-nosnippet>191</a> <span class="macro">assert!</span>(
<a href=#192 id=192 data-nosnippet>192</a> err.output_msg()
<a href=#193 id=193 data-nosnippet>193</a> .contains(<span class="string">"You must specify either --table-id or --table-name."</span>)
<a href=#194 id=194 data-nosnippet>194</a> );
<a href=#195 id=195 data-nosnippet>195</a> }
<a href=#196 id=196 data-nosnippet>196</a>
<a href=#197 id=197 data-nosnippet>197</a> <span class="attr">#[tokio::test]
<a href=#198 id=198 data-nosnippet>198</a> </span><span class="kw">async fn </span>test_del_table_command_builds_tool_with_table_id() {
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">let </span>command = DelTableCommand::parse_from([
<a href=#200 id=200 data-nosnippet>200</a> <span class="string">"table"</span>,
<a href=#201 id=201 data-nosnippet>201</a> <span class="string">"--table-id"</span>,
<a href=#202 id=202 data-nosnippet>202</a> <span class="string">"1024"</span>,
<a href=#203 id=203 data-nosnippet>203</a> <span class="string">"--backend"</span>,
<a href=#204 id=204 data-nosnippet>204</a> <span class="string">"memory-store"</span>,
<a href=#205 id=205 data-nosnippet>205</a> <span class="string">"--store-addrs"</span>,
<a href=#206 id=206 data-nosnippet>206</a> <span class="string">"memory://"</span>,
<a href=#207 id=207 data-nosnippet>207</a> ]);
<a href=#208 id=208 data-nosnippet>208</a>
<a href=#209 id=209 data-nosnippet>209</a> <span class="kw">let </span>_tool = command.build().<span class="kw">await</span>.unwrap();
<a href=#210 id=210 data-nosnippet>210</a> }
<a href=#211 id=211 data-nosnippet>211</a>
<a href=#212 id=212 data-nosnippet>212</a> <span class="attr">#[tokio::test]
<a href=#213 id=213 data-nosnippet>213</a> </span><span class="kw">async fn </span>test_del_table_command_builds_tool_with_table_name() {
<a href=#214 id=214 data-nosnippet>214</a> <span class="kw">let </span>command = DelTableCommand::parse_from([
<a href=#215 id=215 data-nosnippet>215</a> <span class="string">"table"</span>,
<a href=#216 id=216 data-nosnippet>216</a> <span class="string">"--table-name"</span>,
<a href=#217 id=217 data-nosnippet>217</a> <span class="string">"my_table"</span>,
<a href=#218 id=218 data-nosnippet>218</a> <span class="string">"--backend"</span>,
<a href=#219 id=219 data-nosnippet>219</a> <span class="string">"memory-store"</span>,
<a href=#220 id=220 data-nosnippet>220</a> <span class="string">"--store-addrs"</span>,
<a href=#221 id=221 data-nosnippet>221</a> <span class="string">"memory://"</span>,
<a href=#222 id=222 data-nosnippet>222</a> ]);
<a href=#223 id=223 data-nosnippet>223</a>
<a href=#224 id=224 data-nosnippet>224</a> <span class="kw">let </span>_tool = command.build().<span class="kw">await</span>.unwrap();
<a href=#225 id=225 data-nosnippet>225</a> }
<a href=#226 id=226 data-nosnippet>226</a>
<a href=#227 id=227 data-nosnippet>227</a> <span class="attr">#[tokio::test]
<a href=#228 id=228 data-nosnippet>228</a> </span><span class="kw">async fn </span>test_delete_table_not_found() {
<a href=#229 id=229 data-nosnippet>229</a> <span class="kw">let </span>kv_backend = Arc::new(MemoryKvBackend::new()) <span class="kw">as </span>KvBackendRef;
<a href=#230 id=230 data-nosnippet>230</a>
<a href=#231 id=231 data-nosnippet>231</a> <span class="kw">let </span>table_metadata_deleter = TableMetadataDeleter::new(kv_backend);
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">let </span>table_id = <span class="number">1</span>;
<a href=#233 id=233 data-nosnippet>233</a> <span class="kw">let </span>err = table_metadata_deleter.delete(table_id).<span class="kw">await</span>.unwrap_err();
<a href=#234 id=234 data-nosnippet>234</a> <span class="macro">assert_eq!</span>(err.status_code(), StatusCode::TableNotFound);
<a href=#235 id=235 data-nosnippet>235</a> }
<a href=#236 id=236 data-nosnippet>236</a>
<a href=#237 id=237 data-nosnippet>237</a> <span class="attr">#[tokio::test]
<a href=#238 id=238 data-nosnippet>238</a> </span><span class="kw">async fn </span>test_delete_table_metadata() {
<a href=#239 id=239 data-nosnippet>239</a> <span class="kw">let </span>kv_backend = Arc::new(MemoryKvBackend::new());
<a href=#240 id=240 data-nosnippet>240</a> <span class="kw">let </span>table_metadata_manager = TableMetadataManager::new(kv_backend.clone());
<a href=#241 id=241 data-nosnippet>241</a> <span class="kw">let </span>table_id = <span class="number">1024</span>;
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">let </span>(table_info, table_route) = prepare_physical_table_metadata(<span class="string">"my_table"</span>, table_id).<span class="kw">await</span>;
<a href=#243 id=243 data-nosnippet>243</a> table_metadata_manager
<a href=#244 id=244 data-nosnippet>244</a> .create_table_metadata(
<a href=#245 id=245 data-nosnippet>245</a> table_info,
<a href=#246 id=246 data-nosnippet>246</a> TableRouteValue::Physical(table_route),
<a href=#247 id=247 data-nosnippet>247</a> HashMap::new(),
<a href=#248 id=248 data-nosnippet>248</a> )
<a href=#249 id=249 data-nosnippet>249</a> .<span class="kw">await
<a href=#250 id=250 data-nosnippet>250</a> </span>.unwrap();
<a href=#251 id=251 data-nosnippet>251</a>
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw">let </span>total_keys = kv_backend.len();
<a href=#253 id=253 data-nosnippet>253</a> <span class="macro">assert!</span>(total_keys &gt; <span class="number">0</span>);
<a href=#254 id=254 data-nosnippet>254</a>
<a href=#255 id=255 data-nosnippet>255</a> <span class="kw">let </span>table_metadata_deleter = TableMetadataDeleter::new(kv_backend.clone());
<a href=#256 id=256 data-nosnippet>256</a> table_metadata_deleter.delete(table_id).<span class="kw">await</span>.unwrap();
<a href=#257 id=257 data-nosnippet>257</a>
<a href=#258 id=258 data-nosnippet>258</a> <span class="comment">// Check the tombstone keys are deleted
<a href=#259 id=259 data-nosnippet>259</a> </span><span class="kw">let </span>chroot =
<a href=#260 id=260 data-nosnippet>260</a> ChrootKvBackend::new(CLI_TOMBSTONE_PREFIX.as_bytes().to_vec(), kv_backend.clone());
<a href=#261 id=261 data-nosnippet>261</a> <span class="kw">let </span>req = RangeRequest::default().with_range(<span class="macro">vec!</span>[<span class="number">0</span>], <span class="macro">vec!</span>[<span class="number">0</span>]);
<a href=#262 id=262 data-nosnippet>262</a> <span class="kw">let </span>resp = chroot.range(req).<span class="kw">await</span>.unwrap();
<a href=#263 id=263 data-nosnippet>263</a> <span class="macro">assert_eq!</span>(resp.kvs.len(), total_keys);
<a href=#264 id=264 data-nosnippet>264</a> }
<a href=#265 id=265 data-nosnippet>265</a>}
</code></pre></div></section></main></body></html>
+277
View File
@@ -0,0 +1,277 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/metadata/control/get.rs`."><title>get.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/metadata/control/</div>get.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>std::cmp::min;
<a href=#16 id=16 data-nosnippet>16</a>
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>async_trait::async_trait;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>clap::{Parser, Subcommand};
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::key::TableMetadataManager;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>common_meta::key::table_info::TableInfoKey;
<a href=#22 id=22 data-nosnippet>22</a><span class="kw">use </span>common_meta::key::table_route::TableRouteKey;
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span>common_meta::kv_backend::KvBackendRef;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_meta::range_stream::{DEFAULT_PAGE_SIZE, PaginationStream};
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>common_meta::rpc::store::RangeRequest;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>futures::TryStreamExt;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span><span class="kw">crate</span>::Tool;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span><span class="kw">crate</span>::common::StoreConfig;
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span><span class="kw">crate</span>::metadata::control::selector::TableSelector;
<a href=#31 id=31 data-nosnippet>31</a><span class="kw">use </span><span class="kw">crate</span>::metadata::control::utils::{decode_key_value, json_formatter};
<a href=#32 id=32 data-nosnippet>32</a>
<a href=#33 id=33 data-nosnippet>33</a><span class="doccomment">/// Getting metadata from metadata store.
<a href=#34 id=34 data-nosnippet>34</a></span><span class="attr">#[derive(Subcommand)]
<a href=#35 id=35 data-nosnippet>35</a></span><span class="kw">pub enum </span>GetCommand {
<a href=#36 id=36 data-nosnippet>36</a> Key(GetKeyCommand),
<a href=#37 id=37 data-nosnippet>37</a> Table(GetTableCommand),
<a href=#38 id=38 data-nosnippet>38</a>}
<a href=#39 id=39 data-nosnippet>39</a>
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">impl </span>GetCommand {
<a href=#41 id=41 data-nosnippet>41</a> <span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt; {
<a href=#42 id=42 data-nosnippet>42</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#43 id=43 data-nosnippet>43</a> GetCommand::Key(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#44 id=44 data-nosnippet>44</a> GetCommand::Table(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#45 id=45 data-nosnippet>45</a> }
<a href=#46 id=46 data-nosnippet>46</a> }
<a href=#47 id=47 data-nosnippet>47</a>}
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a><span class="doccomment">/// Get key-value pairs from the metadata store.
<a href=#50 id=50 data-nosnippet>50</a></span><span class="attr">#[derive(Debug, Default, Parser)]
<a href=#51 id=51 data-nosnippet>51</a></span><span class="kw">pub struct </span>GetKeyCommand {
<a href=#52 id=52 data-nosnippet>52</a> <span class="doccomment">/// The key to get from the metadata store.
<a href=#53 id=53 data-nosnippet>53</a> </span><span class="attr">#[clap(default_value = <span class="string">""</span>)]
<a href=#54 id=54 data-nosnippet>54</a> </span>key: String,
<a href=#55 id=55 data-nosnippet>55</a>
<a href=#56 id=56 data-nosnippet>56</a> <span class="doccomment">/// Whether to perform a prefix query. If true, returns all key-value pairs where the key starts with the given prefix.
<a href=#57 id=57 data-nosnippet>57</a> </span><span class="attr">#[clap(long, default_value = <span class="string">"false"</span>)]
<a href=#58 id=58 data-nosnippet>58</a> </span>prefix: bool,
<a href=#59 id=59 data-nosnippet>59</a>
<a href=#60 id=60 data-nosnippet>60</a> <span class="doccomment">/// The maximum number of key-value pairs to return. If 0, returns all key-value pairs.
<a href=#61 id=61 data-nosnippet>61</a> </span><span class="attr">#[clap(long, default_value = <span class="string">"0"</span>)]
<a href=#62 id=62 data-nosnippet>62</a> </span>limit: u64,
<a href=#63 id=63 data-nosnippet>63</a>
<a href=#64 id=64 data-nosnippet>64</a> <span class="attr">#[clap(flatten)]
<a href=#65 id=65 data-nosnippet>65</a> </span>store: StoreConfig,
<a href=#66 id=66 data-nosnippet>66</a>}
<a href=#67 id=67 data-nosnippet>67</a>
<a href=#68 id=68 data-nosnippet>68</a><span class="kw">impl </span>GetKeyCommand {
<a href=#69 id=69 data-nosnippet>69</a> <span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt; {
<a href=#70 id=70 data-nosnippet>70</a> <span class="kw">let </span>kvbackend = <span class="self">self</span>.store.build().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#71 id=71 data-nosnippet>71</a> <span class="prelude-val">Ok</span>(Box::new(GetKeyTool {
<a href=#72 id=72 data-nosnippet>72</a> kvbackend,
<a href=#73 id=73 data-nosnippet>73</a> key: <span class="self">self</span>.key.clone(),
<a href=#74 id=74 data-nosnippet>74</a> prefix: <span class="self">self</span>.prefix,
<a href=#75 id=75 data-nosnippet>75</a> limit: <span class="self">self</span>.limit,
<a href=#76 id=76 data-nosnippet>76</a> }))
<a href=#77 id=77 data-nosnippet>77</a> }
<a href=#78 id=78 data-nosnippet>78</a>}
<a href=#79 id=79 data-nosnippet>79</a>
<a href=#80 id=80 data-nosnippet>80</a><span class="kw">struct </span>GetKeyTool {
<a href=#81 id=81 data-nosnippet>81</a> kvbackend: KvBackendRef,
<a href=#82 id=82 data-nosnippet>82</a> key: String,
<a href=#83 id=83 data-nosnippet>83</a> prefix: bool,
<a href=#84 id=84 data-nosnippet>84</a> limit: u64,
<a href=#85 id=85 data-nosnippet>85</a>}
<a href=#86 id=86 data-nosnippet>86</a>
<a href=#87 id=87 data-nosnippet>87</a><span class="attr">#[async_trait]
<a href=#88 id=88 data-nosnippet>88</a></span><span class="kw">impl </span>Tool <span class="kw">for </span>GetKeyTool {
<a href=#89 id=89 data-nosnippet>89</a> <span class="kw">async fn </span>do_work(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#90 id=90 data-nosnippet>90</a> <span class="kw">let </span><span class="kw-2">mut </span>req = RangeRequest::default();
<a href=#91 id=91 data-nosnippet>91</a> <span class="kw">if </span><span class="self">self</span>.prefix {
<a href=#92 id=92 data-nosnippet>92</a> req = req.with_prefix(<span class="self">self</span>.key.as_bytes());
<a href=#93 id=93 data-nosnippet>93</a> } <span class="kw">else </span>{
<a href=#94 id=94 data-nosnippet>94</a> req = req.with_key(<span class="self">self</span>.key.as_bytes());
<a href=#95 id=95 data-nosnippet>95</a> }
<a href=#96 id=96 data-nosnippet>96</a> <span class="kw">let </span>page_size = <span class="kw">if </span><span class="self">self</span>.limit &gt; <span class="number">0 </span>{
<a href=#97 id=97 data-nosnippet>97</a> min(<span class="self">self</span>.limit <span class="kw">as </span>usize, DEFAULT_PAGE_SIZE)
<a href=#98 id=98 data-nosnippet>98</a> } <span class="kw">else </span>{
<a href=#99 id=99 data-nosnippet>99</a> DEFAULT_PAGE_SIZE
<a href=#100 id=100 data-nosnippet>100</a> };
<a href=#101 id=101 data-nosnippet>101</a> <span class="kw">let </span>pagination_stream =
<a href=#102 id=102 data-nosnippet>102</a> PaginationStream::new(<span class="self">self</span>.kvbackend.clone(), req, page_size, decode_key_value);
<a href=#103 id=103 data-nosnippet>103</a> <span class="kw">let </span><span class="kw-2">mut </span>stream = Box::pin(pagination_stream.into_stream());
<a href=#104 id=104 data-nosnippet>104</a> <span class="kw">let </span><span class="kw-2">mut </span>counter = <span class="number">0</span>;
<a href=#105 id=105 data-nosnippet>105</a>
<a href=#106 id=106 data-nosnippet>106</a> <span class="kw">while let </span><span class="prelude-val">Some</span>((key, value)) = stream.try_next().<span class="kw">await</span>.map_err(BoxedError::new)<span class="question-mark">? </span>{
<a href=#107 id=107 data-nosnippet>107</a> <span class="macro">print!</span>(<span class="string">"{}\n{}\n"</span>, key, value);
<a href=#108 id=108 data-nosnippet>108</a> counter += <span class="number">1</span>;
<a href=#109 id=109 data-nosnippet>109</a> <span class="kw">if </span><span class="self">self</span>.limit &gt; <span class="number">0 </span>&amp;&amp; counter &gt;= <span class="self">self</span>.limit {
<a href=#110 id=110 data-nosnippet>110</a> <span class="kw">break</span>;
<a href=#111 id=111 data-nosnippet>111</a> }
<a href=#112 id=112 data-nosnippet>112</a> }
<a href=#113 id=113 data-nosnippet>113</a>
<a href=#114 id=114 data-nosnippet>114</a> <span class="prelude-val">Ok</span>(())
<a href=#115 id=115 data-nosnippet>115</a> }
<a href=#116 id=116 data-nosnippet>116</a>}
<a href=#117 id=117 data-nosnippet>117</a>
<a href=#118 id=118 data-nosnippet>118</a><span class="doccomment">/// Get table metadata from the metadata store via table id.
<a href=#119 id=119 data-nosnippet>119</a></span><span class="attr">#[derive(Debug, Default, Parser)]
<a href=#120 id=120 data-nosnippet>120</a></span><span class="kw">pub struct </span>GetTableCommand {
<a href=#121 id=121 data-nosnippet>121</a> <span class="attr">#[clap(flatten)]
<a href=#122 id=122 data-nosnippet>122</a> </span>selector: TableSelector,
<a href=#123 id=123 data-nosnippet>123</a>
<a href=#124 id=124 data-nosnippet>124</a> <span class="doccomment">/// Pretty print the output.
<a href=#125 id=125 data-nosnippet>125</a> </span><span class="attr">#[clap(long, default_value = <span class="string">"false"</span>)]
<a href=#126 id=126 data-nosnippet>126</a> </span>pretty: bool,
<a href=#127 id=127 data-nosnippet>127</a>
<a href=#128 id=128 data-nosnippet>128</a> <span class="attr">#[clap(flatten)]
<a href=#129 id=129 data-nosnippet>129</a> </span>store: StoreConfig,
<a href=#130 id=130 data-nosnippet>130</a>}
<a href=#131 id=131 data-nosnippet>131</a>
<a href=#132 id=132 data-nosnippet>132</a><span class="kw">struct </span>GetTableTool {
<a href=#133 id=133 data-nosnippet>133</a> kvbackend: KvBackendRef,
<a href=#134 id=134 data-nosnippet>134</a> selector: TableSelector,
<a href=#135 id=135 data-nosnippet>135</a> pretty: bool,
<a href=#136 id=136 data-nosnippet>136</a>}
<a href=#137 id=137 data-nosnippet>137</a>
<a href=#138 id=138 data-nosnippet>138</a><span class="attr">#[async_trait]
<a href=#139 id=139 data-nosnippet>139</a></span><span class="kw">impl </span>Tool <span class="kw">for </span>GetTableTool {
<a href=#140 id=140 data-nosnippet>140</a> <span class="kw">async fn </span>do_work(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#141 id=141 data-nosnippet>141</a> <span class="kw">let </span>table_metadata_manager = TableMetadataManager::new(<span class="self">self</span>.kvbackend.clone());
<a href=#142 id=142 data-nosnippet>142</a> <span class="kw">let </span>table_name_manager = table_metadata_manager.table_name_manager();
<a href=#143 id=143 data-nosnippet>143</a> <span class="kw">let </span>table_info_manager = table_metadata_manager.table_info_manager();
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">let </span>table_route_manager = table_metadata_manager.table_route_manager();
<a href=#145 id=145 data-nosnippet>145</a>
<a href=#146 id=146 data-nosnippet>146</a> <span class="kw">let </span><span class="prelude-val">Some</span>(table_id) = <span class="self">self</span>.selector.resolve_table_id(table_name_manager).<span class="kw">await</span><span class="question-mark">? </span><span class="kw">else </span>{
<a href=#147 id=147 data-nosnippet>147</a> <span class="macro">println!</span>(<span class="string">"Table({}) not found"</span>, <span class="self">self</span>.selector.formatted_table_name());
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#149 id=149 data-nosnippet>149</a> };
<a href=#150 id=150 data-nosnippet>150</a>
<a href=#151 id=151 data-nosnippet>151</a> <span class="kw">let </span>table_info = table_info_manager
<a href=#152 id=152 data-nosnippet>152</a> .get(table_id)
<a href=#153 id=153 data-nosnippet>153</a> .<span class="kw">await
<a href=#154 id=154 data-nosnippet>154</a> </span>.map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#155 id=155 data-nosnippet>155</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table_info) = table_info {
<a href=#156 id=156 data-nosnippet>156</a> <span class="macro">println!</span>(
<a href=#157 id=157 data-nosnippet>157</a> <span class="string">"{}\n{}"</span>,
<a href=#158 id=158 data-nosnippet>158</a> TableInfoKey::new(table_id),
<a href=#159 id=159 data-nosnippet>159</a> json_formatter(<span class="self">self</span>.pretty, <span class="kw-2">&amp;*</span>table_info)
<a href=#160 id=160 data-nosnippet>160</a> );
<a href=#161 id=161 data-nosnippet>161</a> } <span class="kw">else </span>{
<a href=#162 id=162 data-nosnippet>162</a> <span class="macro">println!</span>(<span class="string">"Table info not found"</span>);
<a href=#163 id=163 data-nosnippet>163</a> }
<a href=#164 id=164 data-nosnippet>164</a>
<a href=#165 id=165 data-nosnippet>165</a> <span class="kw">let </span>table_route = table_route_manager
<a href=#166 id=166 data-nosnippet>166</a> .table_route_storage()
<a href=#167 id=167 data-nosnippet>167</a> .get(table_id)
<a href=#168 id=168 data-nosnippet>168</a> .<span class="kw">await
<a href=#169 id=169 data-nosnippet>169</a> </span>.map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(table_route) = table_route {
<a href=#171 id=171 data-nosnippet>171</a> <span class="macro">println!</span>(
<a href=#172 id=172 data-nosnippet>172</a> <span class="string">"{}\n{}"</span>,
<a href=#173 id=173 data-nosnippet>173</a> TableRouteKey::new(table_id),
<a href=#174 id=174 data-nosnippet>174</a> json_formatter(<span class="self">self</span>.pretty, <span class="kw-2">&amp;</span>table_route)
<a href=#175 id=175 data-nosnippet>175</a> );
<a href=#176 id=176 data-nosnippet>176</a> } <span class="kw">else </span>{
<a href=#177 id=177 data-nosnippet>177</a> <span class="macro">println!</span>(<span class="string">"Table route not found"</span>);
<a href=#178 id=178 data-nosnippet>178</a> }
<a href=#179 id=179 data-nosnippet>179</a>
<a href=#180 id=180 data-nosnippet>180</a> <span class="prelude-val">Ok</span>(())
<a href=#181 id=181 data-nosnippet>181</a> }
<a href=#182 id=182 data-nosnippet>182</a>}
<a href=#183 id=183 data-nosnippet>183</a>
<a href=#184 id=184 data-nosnippet>184</a><span class="kw">impl </span>GetTableCommand {
<a href=#185 id=185 data-nosnippet>185</a> <span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt; {
<a href=#186 id=186 data-nosnippet>186</a> <span class="self">self</span>.selector.validate()<span class="question-mark">?</span>;
<a href=#187 id=187 data-nosnippet>187</a> <span class="kw">let </span>kvbackend = <span class="self">self</span>.store.build().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#188 id=188 data-nosnippet>188</a> <span class="prelude-val">Ok</span>(Box::new(GetTableTool {
<a href=#189 id=189 data-nosnippet>189</a> kvbackend,
<a href=#190 id=190 data-nosnippet>190</a> selector: <span class="self">self</span>.selector.clone(),
<a href=#191 id=191 data-nosnippet>191</a> pretty: <span class="self">self</span>.pretty,
<a href=#192 id=192 data-nosnippet>192</a> }))
<a href=#193 id=193 data-nosnippet>193</a> }
<a href=#194 id=194 data-nosnippet>194</a>}
<a href=#195 id=195 data-nosnippet>195</a>
<a href=#196 id=196 data-nosnippet>196</a><span class="attr">#[cfg(test)]
<a href=#197 id=197 data-nosnippet>197</a></span><span class="kw">mod </span>tests {
<a href=#198 id=198 data-nosnippet>198</a> <span class="kw">use </span>clap::Parser;
<a href=#199 id=199 data-nosnippet>199</a> <span class="kw">use </span>common_error::ext::ErrorExt;
<a href=#200 id=200 data-nosnippet>200</a>
<a href=#201 id=201 data-nosnippet>201</a> <span class="kw">use </span><span class="kw">super</span>::GetTableCommand;
<a href=#202 id=202 data-nosnippet>202</a>
<a href=#203 id=203 data-nosnippet>203</a> <span class="attr">#[tokio::test]
<a href=#204 id=204 data-nosnippet>204</a> </span><span class="kw">async fn </span>test_get_table_selector_requires_single_target() {
<a href=#205 id=205 data-nosnippet>205</a> <span class="kw">let </span>command = GetTableCommand::parse_from([
<a href=#206 id=206 data-nosnippet>206</a> <span class="string">"table"</span>,
<a href=#207 id=207 data-nosnippet>207</a> <span class="string">"--backend"</span>,
<a href=#208 id=208 data-nosnippet>208</a> <span class="string">"memory-store"</span>,
<a href=#209 id=209 data-nosnippet>209</a> <span class="string">"--store-addrs"</span>,
<a href=#210 id=210 data-nosnippet>210</a> <span class="string">"memory://"</span>,
<a href=#211 id=211 data-nosnippet>211</a> ]);
<a href=#212 id=212 data-nosnippet>212</a>
<a href=#213 id=213 data-nosnippet>213</a> <span class="kw">let </span>err = <span class="kw">match </span>command.build().<span class="kw">await </span>{
<a href=#214 id=214 data-nosnippet>214</a> <span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; <span class="macro">panic!</span>(<span class="string">"expected validation failure"</span>),
<a href=#215 id=215 data-nosnippet>215</a> <span class="prelude-val">Err</span>(err) =&gt; err,
<a href=#216 id=216 data-nosnippet>216</a> };
<a href=#217 id=217 data-nosnippet>217</a> <span class="macro">assert!</span>(
<a href=#218 id=218 data-nosnippet>218</a> err.output_msg()
<a href=#219 id=219 data-nosnippet>219</a> .contains(<span class="string">"You must specify either --table-id or --table-name."</span>)
<a href=#220 id=220 data-nosnippet>220</a> );
<a href=#221 id=221 data-nosnippet>221</a> }
<a href=#222 id=222 data-nosnippet>222</a>
<a href=#223 id=223 data-nosnippet>223</a> <span class="attr">#[tokio::test]
<a href=#224 id=224 data-nosnippet>224</a> </span><span class="kw">async fn </span>test_get_table_selector_rejects_both_targets() {
<a href=#225 id=225 data-nosnippet>225</a> <span class="kw">let </span>command = GetTableCommand::parse_from([
<a href=#226 id=226 data-nosnippet>226</a> <span class="string">"table"</span>,
<a href=#227 id=227 data-nosnippet>227</a> <span class="string">"--table-id"</span>,
<a href=#228 id=228 data-nosnippet>228</a> <span class="string">"1024"</span>,
<a href=#229 id=229 data-nosnippet>229</a> <span class="string">"--table-name"</span>,
<a href=#230 id=230 data-nosnippet>230</a> <span class="string">"my_table"</span>,
<a href=#231 id=231 data-nosnippet>231</a> <span class="string">"--backend"</span>,
<a href=#232 id=232 data-nosnippet>232</a> <span class="string">"memory-store"</span>,
<a href=#233 id=233 data-nosnippet>233</a> <span class="string">"--store-addrs"</span>,
<a href=#234 id=234 data-nosnippet>234</a> <span class="string">"memory://"</span>,
<a href=#235 id=235 data-nosnippet>235</a> ]);
<a href=#236 id=236 data-nosnippet>236</a>
<a href=#237 id=237 data-nosnippet>237</a> <span class="kw">let </span>err = <span class="kw">match </span>command.build().<span class="kw">await </span>{
<a href=#238 id=238 data-nosnippet>238</a> <span class="prelude-val">Ok</span>(<span class="kw">_</span>) =&gt; <span class="macro">panic!</span>(<span class="string">"expected validation failure"</span>),
<a href=#239 id=239 data-nosnippet>239</a> <span class="prelude-val">Err</span>(err) =&gt; err,
<a href=#240 id=240 data-nosnippet>240</a> };
<a href=#241 id=241 data-nosnippet>241</a> <span class="macro">assert!</span>(
<a href=#242 id=242 data-nosnippet>242</a> err.output_msg()
<a href=#243 id=243 data-nosnippet>243</a> .contains(<span class="string">"You must specify either --table-id or --table-name."</span>)
<a href=#244 id=244 data-nosnippet>244</a> );
<a href=#245 id=245 data-nosnippet>245</a> }
<a href=#246 id=246 data-nosnippet>246</a>
<a href=#247 id=247 data-nosnippet>247</a> <span class="attr">#[tokio::test]
<a href=#248 id=248 data-nosnippet>248</a> </span><span class="kw">async fn </span>test_get_table_command_builds_tool_with_table_id() {
<a href=#249 id=249 data-nosnippet>249</a> <span class="kw">let </span>command = GetTableCommand::parse_from([
<a href=#250 id=250 data-nosnippet>250</a> <span class="string">"table"</span>,
<a href=#251 id=251 data-nosnippet>251</a> <span class="string">"--table-id"</span>,
<a href=#252 id=252 data-nosnippet>252</a> <span class="string">"1024"</span>,
<a href=#253 id=253 data-nosnippet>253</a> <span class="string">"--backend"</span>,
<a href=#254 id=254 data-nosnippet>254</a> <span class="string">"memory-store"</span>,
<a href=#255 id=255 data-nosnippet>255</a> <span class="string">"--store-addrs"</span>,
<a href=#256 id=256 data-nosnippet>256</a> <span class="string">"memory://"</span>,
<a href=#257 id=257 data-nosnippet>257</a> ]);
<a href=#258 id=258 data-nosnippet>258</a>
<a href=#259 id=259 data-nosnippet>259</a> <span class="kw">let </span>_tool = command.build().<span class="kw">await</span>.unwrap();
<a href=#260 id=260 data-nosnippet>260</a> }
<a href=#261 id=261 data-nosnippet>261</a>
<a href=#262 id=262 data-nosnippet>262</a> <span class="attr">#[tokio::test]
<a href=#263 id=263 data-nosnippet>263</a> </span><span class="kw">async fn </span>test_get_table_command_builds_tool_with_table_name() {
<a href=#264 id=264 data-nosnippet>264</a> <span class="kw">let </span>command = GetTableCommand::parse_from([
<a href=#265 id=265 data-nosnippet>265</a> <span class="string">"table"</span>,
<a href=#266 id=266 data-nosnippet>266</a> <span class="string">"--table-name"</span>,
<a href=#267 id=267 data-nosnippet>267</a> <span class="string">"my_table"</span>,
<a href=#268 id=268 data-nosnippet>268</a> <span class="string">"--backend"</span>,
<a href=#269 id=269 data-nosnippet>269</a> <span class="string">"memory-store"</span>,
<a href=#270 id=270 data-nosnippet>270</a> <span class="string">"--store-addrs"</span>,
<a href=#271 id=271 data-nosnippet>271</a> <span class="string">"memory://"</span>,
<a href=#272 id=272 data-nosnippet>272</a> ]);
<a href=#273 id=273 data-nosnippet>273</a>
<a href=#274 id=274 data-nosnippet>274</a> <span class="kw">let </span>_tool = command.build().<span class="kw">await</span>.unwrap();
<a href=#275 id=275 data-nosnippet>275</a> }
<a href=#276 id=276 data-nosnippet>276</a>}
</code></pre></div></section></main></body></html>
+57
View File
@@ -0,0 +1,57 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/metadata/control/put.rs`."><title>put.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../" data-static-root-path="../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../src-files.js"></script><script defer src="../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/metadata/control/</div>put.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-2"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">mod </span>key;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">mod </span>table;
<a href=#17 id=17 data-nosnippet>17</a>
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>clap::Subcommand;
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>snafu::ResultExt;
<a href=#21 id=21 data-nosnippet>21</a><span class="kw">use </span>tokio::io::{AsyncRead, AsyncReadExt};
<a href=#22 id=22 data-nosnippet>22</a>
<a href=#23 id=23 data-nosnippet>23</a><span class="kw">use </span><span class="kw">crate</span>::Tool;
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span><span class="kw">crate</span>::error::FileIoSnafu;
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span><span class="kw">crate</span>::metadata::control::put::key::PutKeyCommand;
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span><span class="kw">crate</span>::metadata::control::put::table::PutTableCommand;
<a href=#27 id=27 data-nosnippet>27</a>
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">pub</span>(<span class="kw">crate</span>) <span class="kw">async fn </span>read_value&lt;R&gt;(<span class="kw-2">mut </span>reader: R) -&gt; <span class="prelude-ty">Result</span>&lt;Vec&lt;u8&gt;, BoxedError&gt;
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">where
<a href=#30 id=30 data-nosnippet>30</a> </span>R: AsyncRead + Unpin,
<a href=#31 id=31 data-nosnippet>31</a>{
<a href=#32 id=32 data-nosnippet>32</a> <span class="kw">let </span><span class="kw-2">mut </span>value = Vec::new();
<a href=#33 id=33 data-nosnippet>33</a> reader
<a href=#34 id=34 data-nosnippet>34</a> .read_to_end(<span class="kw-2">&amp;mut </span>value)
<a href=#35 id=35 data-nosnippet>35</a> .<span class="kw">await
<a href=#36 id=36 data-nosnippet>36</a> </span>.context(FileIoSnafu)
<a href=#37 id=37 data-nosnippet>37</a> .map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#38 id=38 data-nosnippet>38</a> <span class="prelude-val">Ok</span>(value)
<a href=#39 id=39 data-nosnippet>39</a>}
<a href=#40 id=40 data-nosnippet>40</a>
<a href=#41 id=41 data-nosnippet>41</a><span class="doccomment">/// Subcommand for putting metadata into the metadata store.
<a href=#42 id=42 data-nosnippet>42</a></span><span class="attr">#[derive(Subcommand)]
<a href=#43 id=43 data-nosnippet>43</a></span><span class="kw">pub enum </span>PutCommand {
<a href=#44 id=44 data-nosnippet>44</a> Key(PutKeyCommand),
<a href=#45 id=45 data-nosnippet>45</a> <span class="attr">#[clap(subcommand)]
<a href=#46 id=46 data-nosnippet>46</a> </span>Table(PutTableCommand),
<a href=#47 id=47 data-nosnippet>47</a>}
<a href=#48 id=48 data-nosnippet>48</a>
<a href=#49 id=49 data-nosnippet>49</a><span class="kw">impl </span>PutCommand {
<a href=#50 id=50 data-nosnippet>50</a> <span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt; {
<a href=#51 id=51 data-nosnippet>51</a> <span class="kw">match </span><span class="self">self </span>{
<a href=#52 id=52 data-nosnippet>52</a> PutCommand::Key(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#53 id=53 data-nosnippet>53</a> PutCommand::Table(cmd) =&gt; cmd.build().<span class="kw">await</span>,
<a href=#54 id=54 data-nosnippet>54</a> }
<a href=#55 id=55 data-nosnippet>55</a> }
<a href=#56 id=56 data-nosnippet>56</a>}
</code></pre></div></section></main></body></html>
+443
View File
@@ -0,0 +1,443 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Source of the Rust file `src/cli/src/metadata/control/put/key.rs`."><title>key.rs - source</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../../../" data-static-root-path="../../../../../static.files/" data-current-crate="cli" data-themes="" data-resource-suffix="" data-rustdoc-version="1.96.1 (31fca3adb 2026-06-26)" data-channel="1.96.1" data-search-js="search-b5634cc7.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../../../static.files/storage-41dd4d93.js"></script><script defer src="../../../../../static.files/src-script-813739b1.js"></script><script defer src="../../../../../src-files.js"></script><script defer src="../../../../../static.files/main-5013f961.js"></script><noscript><link rel="stylesheet" href="../../../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../../../static.files/favicon-044be391.svg"></head><body class="rustdoc src"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><nav class="sidebar"><div class="src-sidebar-title"><h2>Files</h2></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1><div class="sub-heading">cli/metadata/control/put/</div>key.rs</h1><rustdoc-toolbar></rustdoc-toolbar></div><div class="example-wrap digits-3"><pre class="rust"><code><a href=#1 id=1 data-nosnippet>1</a><span class="comment">// Copyright 2023 Greptime Team
<a href=#2 id=2 data-nosnippet>2</a>//
<a href=#3 id=3 data-nosnippet>3</a>// Licensed under the Apache License, Version 2.0 (the "License");
<a href=#4 id=4 data-nosnippet>4</a>// you may not use this file except in compliance with the License.
<a href=#5 id=5 data-nosnippet>5</a>// You may obtain a copy of the License at
<a href=#6 id=6 data-nosnippet>6</a>//
<a href=#7 id=7 data-nosnippet>7</a>// http://www.apache.org/licenses/LICENSE-2.0
<a href=#8 id=8 data-nosnippet>8</a>//
<a href=#9 id=9 data-nosnippet>9</a>// Unless required by applicable law or agreed to in writing, software
<a href=#10 id=10 data-nosnippet>10</a>// distributed under the License is distributed on an "AS IS" BASIS,
<a href=#11 id=11 data-nosnippet>11</a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a href=#12 id=12 data-nosnippet>12</a>// See the License for the specific language governing permissions and
<a href=#13 id=13 data-nosnippet>13</a>// limitations under the License.
<a href=#14 id=14 data-nosnippet>14</a>
<a href=#15 id=15 data-nosnippet>15</a></span><span class="kw">use </span>async_trait::async_trait;
<a href=#16 id=16 data-nosnippet>16</a><span class="kw">use </span>clap::Parser;
<a href=#17 id=17 data-nosnippet>17</a><span class="kw">use </span>common_error::ext::BoxedError;
<a href=#18 id=18 data-nosnippet>18</a><span class="kw">use </span>common_meta::key::catalog_name::{CatalogNameKey, CatalogNameValue};
<a href=#19 id=19 data-nosnippet>19</a><span class="kw">use </span>common_meta::key::flow::flow_state::FlowStateValue;
<a href=#20 id=20 data-nosnippet>20</a><span class="kw">use </span>common_meta::key::flow::{
<a href=#21 id=21 data-nosnippet>21</a> flow_info_key_prefix, flow_name_key_prefix, flow_route_key_prefix, flow_state_full_key,
<a href=#22 id=22 data-nosnippet>22</a> flownode_flow_key_prefix, table_flow_key_prefix,
<a href=#23 id=23 data-nosnippet>23</a>};
<a href=#24 id=24 data-nosnippet>24</a><span class="kw">use </span>common_meta::key::node_address::{NodeAddressKey, NodeAddressValue};
<a href=#25 id=25 data-nosnippet>25</a><span class="kw">use </span>common_meta::key::schema_name::{SchemaNameKey, SchemaNameValue};
<a href=#26 id=26 data-nosnippet>26</a><span class="kw">use </span>common_meta::key::table_repart::{TableRepartKey, TableRepartValue};
<a href=#27 id=27 data-nosnippet>27</a><span class="kw">use </span>common_meta::key::topic_name::{TopicNameKey, TopicNameValue};
<a href=#28 id=28 data-nosnippet>28</a><span class="kw">use </span>common_meta::key::topic_region::{TopicRegionKey, TopicRegionValue};
<a href=#29 id=29 data-nosnippet>29</a><span class="kw">use </span>common_meta::key::view_info::{ViewInfoKey, ViewInfoValue};
<a href=#30 id=30 data-nosnippet>30</a><span class="kw">use </span>common_meta::key::{
<a href=#31 id=31 data-nosnippet>31</a> CATALOG_NAME_KEY_PREFIX, DATANODE_TABLE_KEY_PREFIX, KAFKA_TOPIC_KEY_PREFIX, MetadataKey,
<a href=#32 id=32 data-nosnippet>32</a> MetadataValue, NODE_ADDRESS_PREFIX, SCHEMA_NAME_KEY_PREFIX, TABLE_INFO_KEY_PREFIX,
<a href=#33 id=33 data-nosnippet>33</a> TABLE_NAME_KEY_PREFIX, TABLE_REPART_PREFIX, TABLE_ROUTE_PREFIX, TOPIC_REGION_PREFIX,
<a href=#34 id=34 data-nosnippet>34</a> VIEW_INFO_KEY_PREFIX,
<a href=#35 id=35 data-nosnippet>35</a>};
<a href=#36 id=36 data-nosnippet>36</a><span class="kw">use </span>common_meta::kv_backend::KvBackendRef;
<a href=#37 id=37 data-nosnippet>37</a><span class="kw">use </span>common_meta::rpc::store::PutRequest;
<a href=#38 id=38 data-nosnippet>38</a>
<a href=#39 id=39 data-nosnippet>39</a><span class="kw">use </span><span class="kw">crate</span>::Tool;
<a href=#40 id=40 data-nosnippet>40</a><span class="kw">use </span><span class="kw">crate</span>::common::StoreConfig;
<a href=#41 id=41 data-nosnippet>41</a><span class="kw">use </span><span class="kw">crate</span>::error::InvalidArgumentsSnafu;
<a href=#42 id=42 data-nosnippet>42</a><span class="kw">use </span><span class="kw">crate</span>::metadata::control::put::read_value;
<a href=#43 id=43 data-nosnippet>43</a>
<a href=#44 id=44 data-nosnippet>44</a><span class="doccomment">/// Put a key-value pair into the metadata store.
<a href=#45 id=45 data-nosnippet>45</a></span><span class="attr">#[derive(Debug, Default, Parser)]
<a href=#46 id=46 data-nosnippet>46</a></span><span class="kw">pub struct </span>PutKeyCommand {
<a href=#47 id=47 data-nosnippet>47</a> <span class="doccomment">/// The key to put into the metadata store.
<a href=#48 id=48 data-nosnippet>48</a> </span>key: String,
<a href=#49 id=49 data-nosnippet>49</a>
<a href=#50 id=50 data-nosnippet>50</a> <span class="doccomment">/// Read the value to put into the metadata store from standard input.
<a href=#51 id=51 data-nosnippet>51</a> </span><span class="attr">#[clap(long, required = <span class="bool-val">true</span>)]
<a href=#52 id=52 data-nosnippet>52</a> </span>value_stdin: bool,
<a href=#53 id=53 data-nosnippet>53</a>
<a href=#54 id=54 data-nosnippet>54</a> <span class="doccomment">/// Skip metadata validation before writing.
<a href=#55 id=55 data-nosnippet>55</a> </span><span class="attr">#[clap(long)]
<a href=#56 id=56 data-nosnippet>56</a> </span>no_validate: bool,
<a href=#57 id=57 data-nosnippet>57</a>
<a href=#58 id=58 data-nosnippet>58</a> <span class="attr">#[clap(flatten)]
<a href=#59 id=59 data-nosnippet>59</a> </span>store: StoreConfig,
<a href=#60 id=60 data-nosnippet>60</a>}
<a href=#61 id=61 data-nosnippet>61</a>
<a href=#62 id=62 data-nosnippet>62</a><span class="kw">impl </span>PutKeyCommand {
<a href=#63 id=63 data-nosnippet>63</a> <span class="kw">pub async fn </span>build(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt; {
<a href=#64 id=64 data-nosnippet>64</a> <span class="kw">let </span>kv_backend = <span class="self">self</span>.store.build().<span class="kw">await</span><span class="question-mark">?</span>;
<a href=#65 id=65 data-nosnippet>65</a> <span class="self">self</span>.build_tool(tokio::io::stdin(), kv_backend).<span class="kw">await
<a href=#66 id=66 data-nosnippet>66</a> </span>}
<a href=#67 id=67 data-nosnippet>67</a>
<a href=#68 id=68 data-nosnippet>68</a> <span class="kw">async fn </span>build_tool&lt;R&gt;(
<a href=#69 id=69 data-nosnippet>69</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#70 id=70 data-nosnippet>70</a> reader: R,
<a href=#71 id=71 data-nosnippet>71</a> kv_backend: KvBackendRef,
<a href=#72 id=72 data-nosnippet>72</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt;
<a href=#73 id=73 data-nosnippet>73</a> <span class="kw">where
<a href=#74 id=74 data-nosnippet>74</a> </span>R: tokio::io::AsyncRead + Unpin,
<a href=#75 id=75 data-nosnippet>75</a> {
<a href=#76 id=76 data-nosnippet>76</a> <span class="prelude-val">Ok</span>(Box::new(PutKeyTool {
<a href=#77 id=77 data-nosnippet>77</a> kv_backend,
<a href=#78 id=78 data-nosnippet>78</a> key: <span class="self">self</span>.key.clone(),
<a href=#79 id=79 data-nosnippet>79</a> value: read_value(reader).<span class="kw">await</span><span class="question-mark">?</span>,
<a href=#80 id=80 data-nosnippet>80</a> no_validate: <span class="self">self</span>.no_validate,
<a href=#81 id=81 data-nosnippet>81</a> }))
<a href=#82 id=82 data-nosnippet>82</a> }
<a href=#83 id=83 data-nosnippet>83</a>}
<a href=#84 id=84 data-nosnippet>84</a>
<a href=#85 id=85 data-nosnippet>85</a><span class="kw">struct </span>PutKeyTool {
<a href=#86 id=86 data-nosnippet>86</a> kv_backend: KvBackendRef,
<a href=#87 id=87 data-nosnippet>87</a> key: String,
<a href=#88 id=88 data-nosnippet>88</a> value: Vec&lt;u8&gt;,
<a href=#89 id=89 data-nosnippet>89</a> no_validate: bool,
<a href=#90 id=90 data-nosnippet>90</a>}
<a href=#91 id=91 data-nosnippet>91</a>
<a href=#92 id=92 data-nosnippet>92</a><span class="attr">#[async_trait]
<a href=#93 id=93 data-nosnippet>93</a></span><span class="kw">impl </span>Tool <span class="kw">for </span>PutKeyTool {
<a href=#94 id=94 data-nosnippet>94</a> <span class="kw">async fn </span>do_work(<span class="kw-2">&amp;</span><span class="self">self</span>) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#95 id=95 data-nosnippet>95</a> <span class="kw">if </span>!<span class="self">self</span>.no_validate {
<a href=#96 id=96 data-nosnippet>96</a> validate_metadata_value(<span class="kw-2">&amp;</span><span class="self">self</span>.key, <span class="kw-2">&amp;</span><span class="self">self</span>.value)<span class="question-mark">?</span>;
<a href=#97 id=97 data-nosnippet>97</a> }
<a href=#98 id=98 data-nosnippet>98</a>
<a href=#99 id=99 data-nosnippet>99</a> <span class="kw">let </span>request = PutRequest::new()
<a href=#100 id=100 data-nosnippet>100</a> .with_key(<span class="self">self</span>.key.as_bytes())
<a href=#101 id=101 data-nosnippet>101</a> .with_value(<span class="self">self</span>.value.clone());
<a href=#102 id=102 data-nosnippet>102</a> <span class="self">self</span>.kv_backend
<a href=#103 id=103 data-nosnippet>103</a> .put(request)
<a href=#104 id=104 data-nosnippet>104</a> .<span class="kw">await
<a href=#105 id=105 data-nosnippet>105</a> </span>.map_err(BoxedError::new)<span class="question-mark">?</span>;
<a href=#106 id=106 data-nosnippet>106</a>
<a href=#107 id=107 data-nosnippet>107</a> <span class="macro">println!</span>(<span class="string">"Key({}) updated"</span>, <span class="self">self</span>.key);
<a href=#108 id=108 data-nosnippet>108</a> <span class="prelude-val">Ok</span>(())
<a href=#109 id=109 data-nosnippet>109</a> }
<a href=#110 id=110 data-nosnippet>110</a>}
<a href=#111 id=111 data-nosnippet>111</a>
<a href=#112 id=112 data-nosnippet>112</a><span class="kw">fn </span>validate_metadata_value(key: <span class="kw-2">&amp;</span>str, value: <span class="kw-2">&amp;</span>[u8]) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#113 id=113 data-nosnippet>113</a> <span class="kw">if let </span><span class="prelude-val">Some</span>(reason) = unsupported_direct_put_reason(key) {
<a href=#114 id=114 data-nosnippet>114</a> <span class="kw">return </span><span class="prelude-val">Err</span>(BoxedError::new(
<a href=#115 id=115 data-nosnippet>115</a> InvalidArgumentsSnafu {
<a href=#116 id=116 data-nosnippet>116</a> msg: <span class="macro">format!</span>(<span class="string">"{reason}, use --no-validate to bypass"</span>),
<a href=#117 id=117 data-nosnippet>117</a> }
<a href=#118 id=118 data-nosnippet>118</a> .build(),
<a href=#119 id=119 data-nosnippet>119</a> ));
<a href=#120 id=120 data-nosnippet>120</a> }
<a href=#121 id=121 data-nosnippet>121</a>
<a href=#122 id=122 data-nosnippet>122</a> <span class="kw">if </span>key == flow_state_full_key() {
<a href=#123 id=123 data-nosnippet>123</a> validate_value(key, value, FlowStateValue::try_from_raw_value)<span class="question-mark">?</span>;
<a href=#124 id=124 data-nosnippet>124</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#125 id=125 data-nosnippet>125</a> } <span class="kw">else if </span>matches_key_prefix(key, VIEW_INFO_KEY_PREFIX) {
<a href=#126 id=126 data-nosnippet>126</a> validate_key(ViewInfoKey::from_bytes(key.as_bytes()), key)<span class="question-mark">?</span>;
<a href=#127 id=127 data-nosnippet>127</a> validate_value(key, value, ViewInfoValue::try_from_raw_value)<span class="question-mark">?</span>;
<a href=#128 id=128 data-nosnippet>128</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#129 id=129 data-nosnippet>129</a> } <span class="kw">else if </span>matches_key_prefix(key, CATALOG_NAME_KEY_PREFIX) {
<a href=#130 id=130 data-nosnippet>130</a> validate_key(CatalogNameKey::from_bytes(key.as_bytes()), key)<span class="question-mark">?</span>;
<a href=#131 id=131 data-nosnippet>131</a> validate_value(key, value, CatalogNameValue::try_from_raw_value)<span class="question-mark">?</span>;
<a href=#132 id=132 data-nosnippet>132</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#133 id=133 data-nosnippet>133</a> } <span class="kw">else if </span>matches_key_prefix(key, SCHEMA_NAME_KEY_PREFIX) {
<a href=#134 id=134 data-nosnippet>134</a> validate_key(SchemaNameKey::from_bytes(key.as_bytes()), key)<span class="question-mark">?</span>;
<a href=#135 id=135 data-nosnippet>135</a> validate_value(key, value, SchemaNameValue::try_from_raw_value)<span class="question-mark">?</span>;
<a href=#136 id=136 data-nosnippet>136</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#137 id=137 data-nosnippet>137</a> } <span class="kw">else if </span>matches_key_prefix(key, TABLE_REPART_PREFIX) {
<a href=#138 id=138 data-nosnippet>138</a> validate_key(TableRepartKey::from_bytes(key.as_bytes()), key)<span class="question-mark">?</span>;
<a href=#139 id=139 data-nosnippet>139</a> validate_value(key, value, TableRepartValue::try_from_raw_value)<span class="question-mark">?</span>;
<a href=#140 id=140 data-nosnippet>140</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#141 id=141 data-nosnippet>141</a> } <span class="kw">else if </span>matches_key_prefix(key, NODE_ADDRESS_PREFIX) {
<a href=#142 id=142 data-nosnippet>142</a> validate_key(NodeAddressKey::from_bytes(key.as_bytes()), key)<span class="question-mark">?</span>;
<a href=#143 id=143 data-nosnippet>143</a> validate_value(key, value, NodeAddressValue::try_from_raw_value)<span class="question-mark">?</span>;
<a href=#144 id=144 data-nosnippet>144</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#145 id=145 data-nosnippet>145</a> } <span class="kw">else if </span>matches_key_prefix(key, KAFKA_TOPIC_KEY_PREFIX) {
<a href=#146 id=146 data-nosnippet>146</a> validate_key(TopicNameKey::from_bytes(key.as_bytes()), key)<span class="question-mark">?</span>;
<a href=#147 id=147 data-nosnippet>147</a> validate_value(key, value, TopicNameValue::try_from_raw_value)<span class="question-mark">?</span>;
<a href=#148 id=148 data-nosnippet>148</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#149 id=149 data-nosnippet>149</a> } <span class="kw">else if </span>matches_key_prefix(key, TOPIC_REGION_PREFIX) {
<a href=#150 id=150 data-nosnippet>150</a> validate_key(TopicRegionKey::from_bytes(key.as_bytes()), key)<span class="question-mark">?</span>;
<a href=#151 id=151 data-nosnippet>151</a> validate_value(key, value, TopicRegionValue::try_from_raw_value)<span class="question-mark">?</span>;
<a href=#152 id=152 data-nosnippet>152</a> <span class="kw">return </span><span class="prelude-val">Ok</span>(());
<a href=#153 id=153 data-nosnippet>153</a> }
<a href=#154 id=154 data-nosnippet>154</a>
<a href=#155 id=155 data-nosnippet>155</a> <span class="prelude-val">Err</span>(BoxedError::new(
<a href=#156 id=156 data-nosnippet>156</a> InvalidArgumentsSnafu {
<a href=#157 id=157 data-nosnippet>157</a> msg: <span class="macro">format!</span>(
<a href=#158 id=158 data-nosnippet>158</a> <span class="string">"Unsupported metadata key for validation: {key}, use --no-validate to bypass"
<a href=#159 id=159 data-nosnippet>159</a> </span>),
<a href=#160 id=160 data-nosnippet>160</a> }
<a href=#161 id=161 data-nosnippet>161</a> .build(),
<a href=#162 id=162 data-nosnippet>162</a> ))
<a href=#163 id=163 data-nosnippet>163</a>}
<a href=#164 id=164 data-nosnippet>164</a>
<a href=#165 id=165 data-nosnippet>165</a><span class="doccomment">/// Returns the rejection reason for keys that should not be updated by `put key`.
<a href=#166 id=166 data-nosnippet>166</a>///
<a href=#167 id=167 data-nosnippet>167</a>/// These keys may be decodable, but they are not safe to update via raw KV writes.
<a href=#168 id=168 data-nosnippet>168</a>/// `__table_route/*` is the canonical example.
<a href=#169 id=169 data-nosnippet>169</a></span><span class="kw">fn </span>unsupported_direct_put_reason(key: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Option</span>&lt;String&gt; {
<a href=#170 id=170 data-nosnippet>170</a> <span class="kw">let </span>flow_info_prefix = flow_info_key_prefix();
<a href=#171 id=171 data-nosnippet>171</a> <span class="kw">let </span>flow_name_prefix = flow_name_key_prefix();
<a href=#172 id=172 data-nosnippet>172</a> <span class="kw">let </span>flow_route_prefix = flow_route_key_prefix();
<a href=#173 id=173 data-nosnippet>173</a> <span class="kw">let </span>table_flow_prefix = table_flow_key_prefix();
<a href=#174 id=174 data-nosnippet>174</a> <span class="kw">let </span>flownode_flow_prefix = flownode_flow_key_prefix();
<a href=#175 id=175 data-nosnippet>175</a>
<a href=#176 id=176 data-nosnippet>176</a> <span class="kw">let </span>(prefix, target) = [
<a href=#177 id=177 data-nosnippet>177</a> (TABLE_ROUTE_PREFIX, <span class="string">"table route metadata"</span>),
<a href=#178 id=178 data-nosnippet>178</a> (TABLE_INFO_KEY_PREFIX, <span class="string">"table info metadata"</span>),
<a href=#179 id=179 data-nosnippet>179</a> (TABLE_NAME_KEY_PREFIX, <span class="string">"table name metadata"</span>),
<a href=#180 id=180 data-nosnippet>180</a> (DATANODE_TABLE_KEY_PREFIX, <span class="string">"datanode table metadata"</span>),
<a href=#181 id=181 data-nosnippet>181</a> (<span class="kw-2">&amp;</span>flow_info_prefix, <span class="string">"flow info metadata"</span>),
<a href=#182 id=182 data-nosnippet>182</a> (<span class="kw-2">&amp;</span>flow_name_prefix, <span class="string">"flow name metadata"</span>),
<a href=#183 id=183 data-nosnippet>183</a> (<span class="kw-2">&amp;</span>flow_route_prefix, <span class="string">"flow route metadata"</span>),
<a href=#184 id=184 data-nosnippet>184</a> (<span class="kw-2">&amp;</span>table_flow_prefix, <span class="string">"flow source table metadata"</span>),
<a href=#185 id=185 data-nosnippet>185</a> (<span class="kw-2">&amp;</span>flownode_flow_prefix, <span class="string">"flownode flow metadata"</span>),
<a href=#186 id=186 data-nosnippet>186</a> ]
<a href=#187 id=187 data-nosnippet>187</a> .into_iter()
<a href=#188 id=188 data-nosnippet>188</a> .find(|(prefix, <span class="kw">_</span>)| matches_key_prefix(key, prefix))<span class="question-mark">?</span>;
<a href=#189 id=189 data-nosnippet>189</a>
<a href=#190 id=190 data-nosnippet>190</a> <span class="prelude-val">Some</span>(<span class="macro">format!</span>(
<a href=#191 id=191 data-nosnippet>191</a> <span class="string">"Direct put is not supported for {target} ({prefix}*); use a dedicated metadata update interface instead"
<a href=#192 id=192 data-nosnippet>192</a> </span>))
<a href=#193 id=193 data-nosnippet>193</a>}
<a href=#194 id=194 data-nosnippet>194</a>
<a href=#195 id=195 data-nosnippet>195</a><span class="kw">fn </span>matches_key_prefix(key: <span class="kw-2">&amp;</span>str, prefix: <span class="kw-2">&amp;</span>str) -&gt; bool {
<a href=#196 id=196 data-nosnippet>196</a> key == prefix
<a href=#197 id=197 data-nosnippet>197</a> || key
<a href=#198 id=198 data-nosnippet>198</a> .strip_prefix(prefix)
<a href=#199 id=199 data-nosnippet>199</a> .is_some_and(|rest| rest.starts_with(<span class="string">'/'</span>))
<a href=#200 id=200 data-nosnippet>200</a>}
<a href=#201 id=201 data-nosnippet>201</a>
<a href=#202 id=202 data-nosnippet>202</a><span class="kw">fn </span>validate_value&lt;T, F&gt;(key: <span class="kw-2">&amp;</span>str, value: <span class="kw-2">&amp;</span>[u8], parser: F) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt;
<a href=#203 id=203 data-nosnippet>203</a><span class="kw">where
<a href=#204 id=204 data-nosnippet>204</a> </span>F: FnOnce(<span class="kw-2">&amp;</span>[u8]) -&gt; common_meta::error::Result&lt;T&gt;,
<a href=#205 id=205 data-nosnippet>205</a>{
<a href=#206 id=206 data-nosnippet>206</a> parser(value).map_err(|e| {
<a href=#207 id=207 data-nosnippet>207</a> BoxedError::new(
<a href=#208 id=208 data-nosnippet>208</a> InvalidArgumentsSnafu {
<a href=#209 id=209 data-nosnippet>209</a> msg: <span class="macro">format!</span>(<span class="string">"Invalid metadata value for key: {key}: {e}"</span>),
<a href=#210 id=210 data-nosnippet>210</a> }
<a href=#211 id=211 data-nosnippet>211</a> .build(),
<a href=#212 id=212 data-nosnippet>212</a> )
<a href=#213 id=213 data-nosnippet>213</a> })<span class="question-mark">?</span>;
<a href=#214 id=214 data-nosnippet>214</a> <span class="prelude-val">Ok</span>(())
<a href=#215 id=215 data-nosnippet>215</a>}
<a href=#216 id=216 data-nosnippet>216</a>
<a href=#217 id=217 data-nosnippet>217</a><span class="kw">fn </span>validate_key&lt;T&gt;(result: common_meta::error::Result&lt;T&gt;, key: <span class="kw-2">&amp;</span>str) -&gt; <span class="prelude-ty">Result</span>&lt;(), BoxedError&gt; {
<a href=#218 id=218 data-nosnippet>218</a> result.map_err(|e| {
<a href=#219 id=219 data-nosnippet>219</a> BoxedError::new(
<a href=#220 id=220 data-nosnippet>220</a> InvalidArgumentsSnafu {
<a href=#221 id=221 data-nosnippet>221</a> msg: <span class="macro">format!</span>(<span class="string">"Invalid metadata key: {key}: {e}"</span>),
<a href=#222 id=222 data-nosnippet>222</a> }
<a href=#223 id=223 data-nosnippet>223</a> .build(),
<a href=#224 id=224 data-nosnippet>224</a> )
<a href=#225 id=225 data-nosnippet>225</a> })<span class="question-mark">?</span>;
<a href=#226 id=226 data-nosnippet>226</a> <span class="prelude-val">Ok</span>(())
<a href=#227 id=227 data-nosnippet>227</a>}
<a href=#228 id=228 data-nosnippet>228</a>
<a href=#229 id=229 data-nosnippet>229</a><span class="attr">#[cfg(test)]
<a href=#230 id=230 data-nosnippet>230</a></span><span class="kw">mod </span>tests {
<a href=#231 id=231 data-nosnippet>231</a> <span class="kw">use </span>std::collections::BTreeMap;
<a href=#232 id=232 data-nosnippet>232</a> <span class="kw">use </span>std::sync::Arc;
<a href=#233 id=233 data-nosnippet>233</a>
<a href=#234 id=234 data-nosnippet>234</a> <span class="kw">use </span>clap::Parser;
<a href=#235 id=235 data-nosnippet>235</a> <span class="kw">use </span>common_error::ext::{BoxedError, ErrorExt};
<a href=#236 id=236 data-nosnippet>236</a> <span class="kw">use </span>common_meta::key::flow::flow_state::FlowStateValue;
<a href=#237 id=237 data-nosnippet>237</a> <span class="kw">use </span>common_meta::key::flow::flow_state_full_key;
<a href=#238 id=238 data-nosnippet>238</a> <span class="kw">use </span>common_meta::key::schema_name::SchemaNameValue;
<a href=#239 id=239 data-nosnippet>239</a> <span class="kw">use </span>common_meta::key::topic_name::TopicNameValue;
<a href=#240 id=240 data-nosnippet>240</a> <span class="kw">use </span>common_meta::key::{KAFKA_TOPIC_KEY_PREFIX, MetadataValue, SCHEMA_NAME_KEY_PREFIX};
<a href=#241 id=241 data-nosnippet>241</a> <span class="kw">use </span>common_meta::kv_backend::KvBackendRef;
<a href=#242 id=242 data-nosnippet>242</a> <span class="kw">use </span>common_meta::kv_backend::memory::MemoryKvBackend;
<a href=#243 id=243 data-nosnippet>243</a> <span class="kw">use </span>tokio::io::BufReader;
<a href=#244 id=244 data-nosnippet>244</a>
<a href=#245 id=245 data-nosnippet>245</a> <span class="kw">use </span>super::{
<a href=#246 id=246 data-nosnippet>246</a> PutKeyCommand, PutKeyTool, TABLE_ROUTE_PREFIX, matches_key_prefix,
<a href=#247 id=247 data-nosnippet>247</a> unsupported_direct_put_reason, validate_metadata_value,
<a href=#248 id=248 data-nosnippet>248</a> };
<a href=#249 id=249 data-nosnippet>249</a> <span class="kw">use </span><span class="kw">crate</span>::Tool;
<a href=#250 id=250 data-nosnippet>250</a>
<a href=#251 id=251 data-nosnippet>251</a> <span class="kw">impl </span>PutKeyCommand {
<a href=#252 id=252 data-nosnippet>252</a> <span class="kw">async fn </span>build_for_test&lt;R&gt;(
<a href=#253 id=253 data-nosnippet>253</a> <span class="kw-2">&amp;</span><span class="self">self</span>,
<a href=#254 id=254 data-nosnippet>254</a> reader: R,
<a href=#255 id=255 data-nosnippet>255</a> kv_backend: KvBackendRef,
<a href=#256 id=256 data-nosnippet>256</a> ) -&gt; <span class="prelude-ty">Result</span>&lt;Box&lt;<span class="kw">dyn </span>Tool&gt;, BoxedError&gt;
<a href=#257 id=257 data-nosnippet>257</a> <span class="kw">where
<a href=#258 id=258 data-nosnippet>258</a> </span>R: tokio::io::AsyncRead + Unpin,
<a href=#259 id=259 data-nosnippet>259</a> {
<a href=#260 id=260 data-nosnippet>260</a> <span class="self">self</span>.build_tool(reader, kv_backend).<span class="kw">await
<a href=#261 id=261 data-nosnippet>261</a> </span>}
<a href=#262 id=262 data-nosnippet>262</a> }
<a href=#263 id=263 data-nosnippet>263</a>
<a href=#264 id=264 data-nosnippet>264</a> <span class="attr">#[test]
<a href=#265 id=265 data-nosnippet>265</a> </span><span class="kw">fn </span>test_validate_supported_key_success() {
<a href=#266 id=266 data-nosnippet>266</a> <span class="kw">let </span>value = SchemaNameValue::default().try_as_raw_value().unwrap();
<a href=#267 id=267 data-nosnippet>267</a>
<a href=#268 id=268 data-nosnippet>268</a> validate_metadata_value(<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"{SCHEMA_NAME_KEY_PREFIX}/greptime/public"</span>), <span class="kw-2">&amp;</span>value)
<a href=#269 id=269 data-nosnippet>269</a> .unwrap();
<a href=#270 id=270 data-nosnippet>270</a> }
<a href=#271 id=271 data-nosnippet>271</a>
<a href=#272 id=272 data-nosnippet>272</a> <span class="attr">#[test]
<a href=#273 id=273 data-nosnippet>273</a> </span><span class="kw">fn </span>test_validate_supported_key_invalid_value() {
<a href=#274 id=274 data-nosnippet>274</a> <span class="kw">let </span>err = validate_metadata_value(
<a href=#275 id=275 data-nosnippet>275</a> <span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"{KAFKA_TOPIC_KEY_PREFIX}/test-topic"</span>),
<a href=#276 id=276 data-nosnippet>276</a> <span class="string">b"not-a-valid-json-value"</span>,
<a href=#277 id=277 data-nosnippet>277</a> )
<a href=#278 id=278 data-nosnippet>278</a> .unwrap_err();
<a href=#279 id=279 data-nosnippet>279</a>
<a href=#280 id=280 data-nosnippet>280</a> <span class="macro">assert!</span>(err.output_msg().contains(<span class="string">"Invalid metadata value for key"</span>));
<a href=#281 id=281 data-nosnippet>281</a> }
<a href=#282 id=282 data-nosnippet>282</a>
<a href=#283 id=283 data-nosnippet>283</a> <span class="attr">#[test]
<a href=#284 id=284 data-nosnippet>284</a> </span><span class="kw">fn </span>test_validate_complex_key_fails() {
<a href=#285 id=285 data-nosnippet>285</a> <span class="kw">let </span>value = serde_json::to_vec(<span class="kw-2">&amp;</span>BTreeMap::&lt;u32, u32&gt;::new()).unwrap();
<a href=#286 id=286 data-nosnippet>286</a> <span class="kw">let </span>err =
<a href=#287 id=287 data-nosnippet>287</a> validate_metadata_value(<span class="kw-2">&amp;</span><span class="macro">format!</span>(<span class="string">"{TABLE_ROUTE_PREFIX}/1024"</span>), <span class="kw-2">&amp;</span>value).unwrap_err();
<a href=#288 id=288 data-nosnippet>288</a>
<a href=#289 id=289 data-nosnippet>289</a> <span class="macro">assert!</span>(
<a href=#290 id=290 data-nosnippet>290</a> err.output_msg()
<a href=#291 id=291 data-nosnippet>291</a> .contains(<span class="string">"Direct put is not supported for table route metadata"</span>)
<a href=#292 id=292 data-nosnippet>292</a> );
<a href=#293 id=293 data-nosnippet>293</a> }
<a href=#294 id=294 data-nosnippet>294</a>
<a href=#295 id=295 data-nosnippet>295</a> <span class="attr">#[test]
<a href=#296 id=296 data-nosnippet>296</a> </span><span class="kw">fn </span>test_validate_unknown_key_fails() {
<a href=#297 id=297 data-nosnippet>297</a> <span class="kw">let </span>err = validate_metadata_value(<span class="string">"__unknown/foo"</span>, <span class="string">b"{}"</span>).unwrap_err();
<a href=#298 id=298 data-nosnippet>298</a>
<a href=#299 id=299 data-nosnippet>299</a> <span class="macro">assert!</span>(
<a href=#300 id=300 data-nosnippet>300</a> err.output_msg()
<a href=#301 id=301 data-nosnippet>301</a> .contains(<span class="string">"Unsupported metadata key for validation"</span>)
<a href=#302 id=302 data-nosnippet>302</a> );
<a href=#303 id=303 data-nosnippet>303</a> }
<a href=#304 id=304 data-nosnippet>304</a>
<a href=#305 id=305 data-nosnippet>305</a> <span class="attr">#[test]
<a href=#306 id=306 data-nosnippet>306</a> </span><span class="kw">fn </span>test_validate_invalid_supported_key_fails() {
<a href=#307 id=307 data-nosnippet>307</a> <span class="kw">let </span>value = SchemaNameValue::default().try_as_raw_value().unwrap();
<a href=#308 id=308 data-nosnippet>308</a> <span class="kw">let </span>err = validate_metadata_value(<span class="string">"__schema_name/greptime"</span>, <span class="kw-2">&amp;</span>value).unwrap_err();
<a href=#309 id=309 data-nosnippet>309</a>
<a href=#310 id=310 data-nosnippet>310</a> <span class="macro">assert!</span>(
<a href=#311 id=311 data-nosnippet>311</a> err.output_msg()
<a href=#312 id=312 data-nosnippet>312</a> .contains(<span class="string">"Invalid metadata key: __schema_name/greptime"</span>)
<a href=#313 id=313 data-nosnippet>313</a> );
<a href=#314 id=314 data-nosnippet>314</a> }
<a href=#315 id=315 data-nosnippet>315</a>
<a href=#316 id=316 data-nosnippet>316</a> <span class="attr">#[test]
<a href=#317 id=317 data-nosnippet>317</a> </span><span class="kw">fn </span>test_unsupported_direct_put_reason_covers_complex_keys() {
<a href=#318 id=318 data-nosnippet>318</a> <span class="kw">let </span>cases = [
<a href=#319 id=319 data-nosnippet>319</a> <span class="string">"__table_route/1024"</span>,
<a href=#320 id=320 data-nosnippet>320</a> <span class="string">"__table_info/1024"</span>,
<a href=#321 id=321 data-nosnippet>321</a> <span class="string">"__table_name/greptime/public/demo"</span>,
<a href=#322 id=322 data-nosnippet>322</a> <span class="string">"__dn_table/1/1024"</span>,
<a href=#323 id=323 data-nosnippet>323</a> <span class="string">"__flow/route/1/1"</span>,
<a href=#324 id=324 data-nosnippet>324</a> ];
<a href=#325 id=325 data-nosnippet>325</a>
<a href=#326 id=326 data-nosnippet>326</a> <span class="kw">for </span>key <span class="kw">in </span>cases {
<a href=#327 id=327 data-nosnippet>327</a> <span class="macro">assert!</span>(unsupported_direct_put_reason(key).is_some(), <span class="string">"key: {key}"</span>);
<a href=#328 id=328 data-nosnippet>328</a> }
<a href=#329 id=329 data-nosnippet>329</a> }
<a href=#330 id=330 data-nosnippet>330</a>
<a href=#331 id=331 data-nosnippet>331</a> <span class="attr">#[test]
<a href=#332 id=332 data-nosnippet>332</a> </span><span class="kw">fn </span>test_matches_key_prefix() {
<a href=#333 id=333 data-nosnippet>333</a> <span class="macro">assert!</span>(matches_key_prefix(<span class="string">"__table_route"</span>, <span class="string">"__table_route"</span>));
<a href=#334 id=334 data-nosnippet>334</a> <span class="macro">assert!</span>(matches_key_prefix(<span class="string">"__table_route/1024"</span>, <span class="string">"__table_route"</span>));
<a href=#335 id=335 data-nosnippet>335</a> <span class="macro">assert!</span>(!matches_key_prefix(
<a href=#336 id=336 data-nosnippet>336</a> <span class="string">"__table_route_extra/1024"</span>,
<a href=#337 id=337 data-nosnippet>337</a> <span class="string">"__table_route"
<a href=#338 id=338 data-nosnippet>338</a> </span>));
<a href=#339 id=339 data-nosnippet>339</a> <span class="macro">assert!</span>(!matches_key_prefix(<span class="string">"__table_routex"</span>, <span class="string">"__table_route"</span>));
<a href=#340 id=340 data-nosnippet>340</a> <span class="macro">assert!</span>(!matches_key_prefix(
<a href=#341 id=341 data-nosnippet>341</a> <span class="string">"__topic_name/kafka_backup/foo"</span>,
<a href=#342 id=342 data-nosnippet>342</a> <span class="string">"__topic_name/kafka"
<a href=#343 id=343 data-nosnippet>343</a> </span>));
<a href=#344 id=344 data-nosnippet>344</a> }
<a href=#345 id=345 data-nosnippet>345</a>
<a href=#346 id=346 data-nosnippet>346</a> <span class="attr">#[test]
<a href=#347 id=347 data-nosnippet>347</a> </span><span class="kw">fn </span>test_validate_exact_flow_state_key() {
<a href=#348 id=348 data-nosnippet>348</a> <span class="kw">let </span>value = FlowStateValue::default().try_as_raw_value().unwrap();
<a href=#349 id=349 data-nosnippet>349</a>
<a href=#350 id=350 data-nosnippet>350</a> validate_metadata_value(<span class="kw-2">&amp;</span>flow_state_full_key(), <span class="kw-2">&amp;</span>value).unwrap();
<a href=#351 id=351 data-nosnippet>351</a> }
<a href=#352 id=352 data-nosnippet>352</a>
<a href=#353 id=353 data-nosnippet>353</a> <span class="attr">#[tokio::test]
<a href=#354 id=354 data-nosnippet>354</a> </span><span class="kw">async fn </span>test_put_key_tool_writes_supported_key() {
<a href=#355 id=355 data-nosnippet>355</a> <span class="kw">let </span>kv_backend = Arc::new(MemoryKvBackend::new()) <span class="kw">as </span>KvBackendRef;
<a href=#356 id=356 data-nosnippet>356</a> <span class="kw">let </span>value = TopicNameValue::new(<span class="number">42</span>).try_as_raw_value().unwrap();
<a href=#357 id=357 data-nosnippet>357</a> <span class="kw">let </span>key = <span class="macro">format!</span>(<span class="string">"{KAFKA_TOPIC_KEY_PREFIX}/test-topic"</span>);
<a href=#358 id=358 data-nosnippet>358</a> <span class="kw">let </span>tool = PutKeyTool {
<a href=#359 id=359 data-nosnippet>359</a> kv_backend: kv_backend.clone(),
<a href=#360 id=360 data-nosnippet>360</a> key: key.clone(),
<a href=#361 id=361 data-nosnippet>361</a> value: value.clone(),
<a href=#362 id=362 data-nosnippet>362</a> no_validate: <span class="bool-val">false</span>,
<a href=#363 id=363 data-nosnippet>363</a> };
<a href=#364 id=364 data-nosnippet>364</a>
<a href=#365 id=365 data-nosnippet>365</a> tool.do_work().<span class="kw">await</span>.unwrap();
<a href=#366 id=366 data-nosnippet>366</a>
<a href=#367 id=367 data-nosnippet>367</a> <span class="kw">let </span>stored = kv_backend.get(key.as_bytes()).<span class="kw">await</span>.unwrap().unwrap();
<a href=#368 id=368 data-nosnippet>368</a> <span class="macro">assert_eq!</span>(stored.value, value);
<a href=#369 id=369 data-nosnippet>369</a> }
<a href=#370 id=370 data-nosnippet>370</a>
<a href=#371 id=371 data-nosnippet>371</a> <span class="attr">#[tokio::test]
<a href=#372 id=372 data-nosnippet>372</a> </span><span class="kw">async fn </span>test_put_key_tool_bypasses_validation() {
<a href=#373 id=373 data-nosnippet>373</a> <span class="kw">let </span>kv_backend = Arc::new(MemoryKvBackend::new()) <span class="kw">as </span>KvBackendRef;
<a href=#374 id=374 data-nosnippet>374</a> <span class="kw">let </span>key = <span class="macro">format!</span>(<span class="string">"{TABLE_ROUTE_PREFIX}/1024"</span>);
<a href=#375 id=375 data-nosnippet>375</a> <span class="kw">let </span>value = <span class="string">b"not-json"</span>.to_vec();
<a href=#376 id=376 data-nosnippet>376</a> <span class="kw">let </span>tool = PutKeyTool {
<a href=#377 id=377 data-nosnippet>377</a> kv_backend: kv_backend.clone(),
<a href=#378 id=378 data-nosnippet>378</a> key: key.clone(),
<a href=#379 id=379 data-nosnippet>379</a> value: value.clone(),
<a href=#380 id=380 data-nosnippet>380</a> no_validate: <span class="bool-val">true</span>,
<a href=#381 id=381 data-nosnippet>381</a> };
<a href=#382 id=382 data-nosnippet>382</a>
<a href=#383 id=383 data-nosnippet>383</a> tool.do_work().<span class="kw">await</span>.unwrap();
<a href=#384 id=384 data-nosnippet>384</a>
<a href=#385 id=385 data-nosnippet>385</a> <span class="kw">let </span>stored = kv_backend.get(key.as_bytes()).<span class="kw">await</span>.unwrap().unwrap();
<a href=#386 id=386 data-nosnippet>386</a> <span class="macro">assert_eq!</span>(stored.value, value);
<a href=#387 id=387 data-nosnippet>387</a> }
<a href=#388 id=388 data-nosnippet>388</a>
<a href=#389 id=389 data-nosnippet>389</a> <span class="attr">#[test]
<a href=#390 id=390 data-nosnippet>390</a> </span><span class="kw">fn </span>test_put_key_command_requires_value_stdin() {
<a href=#391 id=391 data-nosnippet>391</a> <span class="kw">let </span>err = PutKeyCommand::try_parse_from([
<a href=#392 id=392 data-nosnippet>392</a> <span class="string">"key"</span>,
<a href=#393 id=393 data-nosnippet>393</a> <span class="string">"__topic_name/kafka/test-cli-topic"</span>,
<a href=#394 id=394 data-nosnippet>394</a> <span class="string">"--backend"</span>,
<a href=#395 id=395 data-nosnippet>395</a> <span class="string">"memory-store"</span>,
<a href=#396 id=396 data-nosnippet>396</a> <span class="string">"--store-addrs"</span>,
<a href=#397 id=397 data-nosnippet>397</a> <span class="string">"memory://"</span>,
<a href=#398 id=398 data-nosnippet>398</a> ])
<a href=#399 id=399 data-nosnippet>399</a> .unwrap_err();
<a href=#400 id=400 data-nosnippet>400</a>
<a href=#401 id=401 data-nosnippet>401</a> <span class="macro">assert_eq!</span>(err.kind(), clap::error::ErrorKind::MissingRequiredArgument);
<a href=#402 id=402 data-nosnippet>402</a> }
<a href=#403 id=403 data-nosnippet>403</a>
<a href=#404 id=404 data-nosnippet>404</a> <span class="attr">#[tokio::test]
<a href=#405 id=405 data-nosnippet>405</a> </span><span class="kw">async fn </span>test_put_key_command_builds_tool_with_stdin() {
<a href=#406 id=406 data-nosnippet>406</a> <span class="kw">let </span>value = TopicNameValue::new(<span class="number">7</span>).try_as_raw_value().unwrap();
<a href=#407 id=407 data-nosnippet>407</a> <span class="kw">let </span>command = PutKeyCommand::parse_from([
<a href=#408 id=408 data-nosnippet>408</a> <span class="string">"key"</span>,
<a href=#409 id=409 data-nosnippet>409</a> <span class="string">"__topic_name/kafka/test-cli-topic"</span>,
<a href=#410 id=410 data-nosnippet>410</a> <span class="string">"--value-stdin"</span>,
<a href=#411 id=411 data-nosnippet>411</a> <span class="string">"--backend"</span>,
<a href=#412 id=412 data-nosnippet>412</a> <span class="string">"memory-store"</span>,
<a href=#413 id=413 data-nosnippet>413</a> <span class="string">"--store-addrs"</span>,
<a href=#414 id=414 data-nosnippet>414</a> <span class="string">"memory://"</span>,
<a href=#415 id=415 data-nosnippet>415</a> ]);
<a href=#416 id=416 data-nosnippet>416</a>
<a href=#417 id=417 data-nosnippet>417</a> <span class="kw">let </span>tool = command
<a href=#418 id=418 data-nosnippet>418</a> .build_for_test(
<a href=#419 id=419 data-nosnippet>419</a> BufReader::new(value.as_slice()),
<a href=#420 id=420 data-nosnippet>420</a> Arc::new(MemoryKvBackend::new()) <span class="kw">as </span>KvBackendRef,
<a href=#421 id=421 data-nosnippet>421</a> )
<a href=#422 id=422 data-nosnippet>422</a> .<span class="kw">await
<a href=#423 id=423 data-nosnippet>423</a> </span>.unwrap();
<a href=#424 id=424 data-nosnippet>424</a> tool.do_work().<span class="kw">await</span>.unwrap();
<a href=#425 id=425 data-nosnippet>425</a> }
<a href=#426 id=426 data-nosnippet>426</a>
<a href=#427 id=427 data-nosnippet>427</a> <span class="attr">#[tokio::test]
<a href=#428 id=428 data-nosnippet>428</a> </span><span class="kw">async fn </span>test_put_key_command_validate_failure() {
<a href=#429 id=429 data-nosnippet>429</a> <span class="kw">let </span>tool = PutKeyTool {
<a href=#430 id=430 data-nosnippet>430</a> kv_backend: Arc::new(MemoryKvBackend::new()) <span class="kw">as </span>KvBackendRef,
<a href=#431 id=431 data-nosnippet>431</a> key: <span class="string">"__table_route/1024"</span>.to_string(),
<a href=#432 id=432 data-nosnippet>432</a> value: <span class="string">b"{}"</span>.to_vec(),
<a href=#433 id=433 data-nosnippet>433</a> no_validate: <span class="bool-val">false</span>,
<a href=#434 id=434 data-nosnippet>434</a> };
<a href=#435 id=435 data-nosnippet>435</a> <span class="kw">let </span>err = tool.do_work().<span class="kw">await</span>.unwrap_err();
<a href=#436 id=436 data-nosnippet>436</a>
<a href=#437 id=437 data-nosnippet>437</a> <span class="macro">assert!</span>(
<a href=#438 id=438 data-nosnippet>438</a> err.output_msg()
<a href=#439 id=439 data-nosnippet>439</a> .contains(<span class="string">"Direct put is not supported for table route metadata"</span>)
<a href=#440 id=440 data-nosnippet>440</a> );
<a href=#441 id=441 data-nosnippet>441</a> }
<a href=#442 id=442 data-nosnippet>442</a>}
</code></pre></div></section></main></body></html>

Some files were not shown because too many files have changed in this diff Show More