| /* | |
| * Copyright (C) 2023 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "src/trace_processor/sqlite/sql_source.h" | |
| #include "test/gtest_and_gmock.h" | |
| namespace perfetto { | |
| namespace trace_processor { | |
| namespace { | |
| TEST(SqlSourceTest, Factory) { | |
| SqlSource source = SqlSource::FromExecuteQuery("SELECT * FROM slice"); | |
| ASSERT_EQ(source.AsTraceback(0), | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 1\n" | |
| " SELECT * FROM slice\n" | |
| " ^\n"); | |
| ASSERT_EQ(source.AsTraceback(7), | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 8\n" | |
| " SELECT * FROM slice\n" | |
| " ^\n"); | |
| } | |
| TEST(SqlSourceTest, Substr) { | |
| SqlSource source = | |
| SqlSource::FromExecuteQuery("SELECT * FROM slice").Substr(9, 10); | |
| ASSERT_EQ(source.sql(), "FROM slice"); | |
| ASSERT_EQ(source.AsTraceback(0), | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 10\n" | |
| " FROM slice\n" | |
| " ^\n"); | |
| ASSERT_EQ(source.AsTraceback(6), | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 16\n" | |
| " FROM slice\n" | |
| " ^\n"); | |
| } | |
| TEST(SqlSourceTest, RewriteAllIgnoreExisting) { | |
| SqlSource source = | |
| SqlSource::FromExecuteQuery("macro!()") | |
| .RewriteAllIgnoreExisting(SqlSource::FromTraceProcessorImplementation( | |
| "SELECT * FROM slice")); | |
| ASSERT_EQ(source.sql(), "SELECT * FROM slice"); | |
| ASSERT_EQ(source.AsTraceback(0), | |
| "Fully expanded statement\n" | |
| " SELECT * FROM slice\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 1\n" | |
| " macro!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 1\n" | |
| " SELECT * FROM slice\n" | |
| " ^\n"); | |
| ASSERT_EQ(source.AsTraceback(7), | |
| "Fully expanded statement\n" | |
| " SELECT * FROM slice\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 1\n" | |
| " macro!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 8\n" | |
| " SELECT * FROM slice\n" | |
| " ^\n"); | |
| } | |
| TEST(SqlSourceTest, NestedFullRewrite) { | |
| SqlSource nested = | |
| SqlSource::FromTraceProcessorImplementation("nested!()") | |
| .RewriteAllIgnoreExisting(SqlSource::FromTraceProcessorImplementation( | |
| "SELECT * FROM slice")); | |
| ASSERT_EQ(nested.sql(), "SELECT * FROM slice"); | |
| SqlSource source = SqlSource::FromExecuteQuery("macro!()") | |
| .RewriteAllIgnoreExisting(std::move(nested)); | |
| ASSERT_EQ(source.sql(), "SELECT * FROM slice"); | |
| ASSERT_EQ(source.AsTraceback(0), | |
| "Fully expanded statement\n" | |
| " SELECT * FROM slice\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 1\n" | |
| " macro!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 1\n" | |
| " nested!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 1\n" | |
| " SELECT * FROM slice\n" | |
| " ^\n"); | |
| ASSERT_EQ(source.AsTraceback(7), | |
| "Fully expanded statement\n" | |
| " SELECT * FROM slice\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 1\n" | |
| " macro!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 1\n" | |
| " nested!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 8\n" | |
| " SELECT * FROM slice\n" | |
| " ^\n"); | |
| } | |
| TEST(SqlSourceTest, RewriteAllIgnoresExistingCorrectly) { | |
| SqlSource foo = | |
| SqlSource::FromExecuteQuery("foo!()").RewriteAllIgnoreExisting( | |
| SqlSource::FromTraceProcessorImplementation("SELECT * FROM slice")); | |
| SqlSource source = foo.RewriteAllIgnoreExisting( | |
| SqlSource::FromTraceProcessorImplementation("SELECT 0 WHERE 0")); | |
| ASSERT_EQ(source.sql(), "SELECT 0 WHERE 0"); | |
| ASSERT_EQ(source.AsTraceback(0), | |
| "Fully expanded statement\n" | |
| " SELECT 0 WHERE 0\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 1\n" | |
| " foo!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 1\n" | |
| " SELECT 0 WHERE 0\n" | |
| " ^\n"); | |
| ASSERT_EQ(source.AsTraceback(4), | |
| "Fully expanded statement\n" | |
| " SELECT 0 WHERE 0\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 1\n" | |
| " foo!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 5\n" | |
| " SELECT 0 WHERE 0\n" | |
| " ^\n"); | |
| } | |
| TEST(SqlSourceTest, Rewriter) { | |
| SqlSource::Rewriter rewriter( | |
| SqlSource::FromExecuteQuery("SELECT cols!() FROM slice")); | |
| rewriter.Rewrite(7, 14, | |
| SqlSource::FromTraceProcessorImplementation( | |
| "ts, dur, ts + dur AS ts_end")); | |
| SqlSource rewritten = std::move(rewriter).Build(); | |
| ASSERT_EQ(rewritten.sql(), "SELECT ts, dur, ts + dur AS ts_end FROM slice"); | |
| // Offset points at the top level source. | |
| ASSERT_EQ(rewritten.AsTraceback(0), | |
| "Fully expanded statement\n" | |
| " SELECT ts, dur, ts + dur AS ts_end FROM slice\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 1\n" | |
| " SELECT cols!() FROM slice\n" | |
| " ^\n"); | |
| ASSERT_EQ(rewritten.AsTraceback(40), | |
| "Fully expanded statement\n" | |
| " SELECT ts, dur, ts + dur AS ts_end FROM slice\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 21\n" | |
| " SELECT cols!() FROM slice\n" | |
| " ^\n"); | |
| // Offset points at the nested source. | |
| ASSERT_EQ(rewritten.AsTraceback(16), | |
| "Fully expanded statement\n" | |
| " SELECT ts, dur, ts + dur AS ts_end FROM slice\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 8\n" | |
| " SELECT cols!() FROM slice\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 10\n" | |
| " ts, dur, ts + dur AS ts_end\n" | |
| " ^\n"); | |
| } | |
| TEST(SqlSourceTest, NestedRewriter) { | |
| SqlSource::Rewriter nested_rewrite( | |
| SqlSource::FromTraceProcessorImplementation( | |
| "id, common_cols!(), other_cols!(), name")); | |
| nested_rewrite.Rewrite( | |
| 4, 18, SqlSource::FromTraceProcessorImplementation("ts, dur")); | |
| nested_rewrite.Rewrite(20, 33, | |
| SqlSource::FromTraceProcessorImplementation("depth")); | |
| SqlSource::Rewriter rewriter( | |
| SqlSource::FromExecuteQuery("SELECT cols!() FROM slice")); | |
| rewriter.Rewrite(7, 14, std::move(nested_rewrite).Build()); | |
| SqlSource rewritten = std::move(rewriter).Build(); | |
| ASSERT_EQ(rewritten.sql(), "SELECT id, ts, dur, depth, name FROM slice"); | |
| // Offset points at the top level source. | |
| ASSERT_EQ(rewritten.AsTraceback(0), | |
| "Fully expanded statement\n" | |
| " SELECT id, ts, dur, depth, name FROM slice\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 1\n" | |
| " SELECT cols!() FROM slice\n" | |
| " ^\n"); | |
| ASSERT_EQ(rewritten.AsTraceback(37), | |
| "Fully expanded statement\n" | |
| " SELECT id, ts, dur, depth, name FROM slice\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 21\n" | |
| " SELECT cols!() FROM slice\n" | |
| " ^\n"); | |
| // Offset points at the first nested source. | |
| ASSERT_EQ(rewritten.AsTraceback(15), | |
| "Fully expanded statement\n" | |
| " SELECT id, ts, dur, depth, name FROM slice\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 8\n" | |
| " SELECT cols!() FROM slice\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 5\n" | |
| " id, common_cols!(), other_cols!(), name\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 5\n" | |
| " ts, dur\n" | |
| " ^\n"); | |
| // Offset points at the second nested source. | |
| ASSERT_EQ(rewritten.AsTraceback(20), | |
| "Fully expanded statement\n" | |
| " SELECT id, ts, dur, depth, name FROM slice\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 8\n" | |
| " SELECT cols!() FROM slice\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 21\n" | |
| " id, common_cols!(), other_cols!(), name\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 1\n" | |
| " depth\n" | |
| " ^\n"); | |
| ASSERT_EQ(rewritten.AsTraceback(22), | |
| "Fully expanded statement\n" | |
| " SELECT id, ts, dur, depth, name FROM slice\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 8\n" | |
| " SELECT cols!() FROM slice\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 21\n" | |
| " id, common_cols!(), other_cols!(), name\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 3\n" | |
| " depth\n" | |
| " ^\n"); | |
| } | |
| TEST(SqlSourceTest, NestedRewriteSubstr) { | |
| SqlSource::Rewriter nested_rewrite( | |
| SqlSource::FromTraceProcessorImplementation( | |
| "id, common_cols!(), other_cols!(), name")); | |
| nested_rewrite.Rewrite( | |
| 4, 18, SqlSource::FromTraceProcessorImplementation("ts, dur")); | |
| nested_rewrite.Rewrite(20, 33, | |
| SqlSource::FromTraceProcessorImplementation("depth")); | |
| SqlSource::Rewriter rewriter( | |
| SqlSource::FromExecuteQuery("SELECT cols!() FROM slice")); | |
| rewriter.Rewrite(7, 14, std::move(nested_rewrite).Build()); | |
| SqlSource rewritten = std::move(rewriter).Build(); | |
| ASSERT_EQ(rewritten.sql(), "SELECT id, ts, dur, depth, name FROM slice"); | |
| // Full macro cover. | |
| SqlSource cols = rewritten.Substr(7, 24); | |
| ASSERT_EQ(cols.sql(), "id, ts, dur, depth, name"); | |
| ASSERT_EQ(cols.AsTraceback(0), | |
| "Fully expanded statement\n" | |
| " id, ts, dur, depth, name\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 8\n" | |
| " cols!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 1\n" | |
| " id, common_cols!(), other_cols!(), name\n" | |
| " ^\n"); | |
| ASSERT_EQ(cols.AsTraceback(5), | |
| "Fully expanded statement\n" | |
| " id, ts, dur, depth, name\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 8\n" | |
| " cols!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 5\n" | |
| " id, common_cols!(), other_cols!(), name\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 2\n" | |
| " ts, dur\n" | |
| " ^\n"); | |
| ASSERT_EQ(cols.AsTraceback(14), | |
| "Fully expanded statement\n" | |
| " id, ts, dur, depth, name\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 8\n" | |
| " cols!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 21\n" | |
| " id, common_cols!(), other_cols!(), name\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 2\n" | |
| " depth\n" | |
| " ^\n"); | |
| // Intersect with nested. | |
| SqlSource intersect = rewritten.Substr(8, 13); | |
| ASSERT_EQ(intersect.sql(), "d, ts, dur, d"); | |
| ASSERT_EQ(intersect.AsTraceback(0), | |
| "Fully expanded statement\n" | |
| " d, ts, dur, d\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 8\n" | |
| " cols!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 2\n" | |
| " d, common_cols!(), other_cols!()\n" | |
| " ^\n"); | |
| ASSERT_EQ(intersect.AsTraceback(4), | |
| "Fully expanded statement\n" | |
| " d, ts, dur, d\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 8\n" | |
| " cols!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 5\n" | |
| " d, common_cols!(), other_cols!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 2\n" | |
| " ts, dur\n" | |
| " ^\n"); | |
| ASSERT_EQ(intersect.AsTraceback(12), | |
| "Fully expanded statement\n" | |
| " d, ts, dur, d\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 8\n" | |
| " cols!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 21\n" | |
| " d, common_cols!(), other_cols!()\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 1\n" | |
| " d\n" | |
| " ^\n"); | |
| } | |
| TEST(SqlSourceTest, Rerewrites) { | |
| SqlSource::Rewriter rewriter( | |
| SqlSource::FromExecuteQuery("SELECT foo!(a) FROM bar!(slice) a")); | |
| rewriter.Rewrite(7, 14, | |
| SqlSource::FromTraceProcessorImplementation("a.x, a.y")); | |
| rewriter.Rewrite(20, 31, | |
| SqlSource::FromTraceProcessorImplementation( | |
| "(SELECT slice.x, slice.y, slice.z FROM slice)")); | |
| SqlSource rewritten = std::move(rewriter).Build(); | |
| ASSERT_EQ( | |
| rewritten.sql(), | |
| "SELECT a.x, a.y FROM (SELECT slice.x, slice.y, slice.z FROM slice) a"); | |
| SqlSource::Rewriter rerewriter(std::move(rewritten)); | |
| rerewriter.Rewrite(0, 7, | |
| SqlSource::FromTraceProcessorImplementation("INSERT ")); | |
| rerewriter.Rewrite(7, 14, | |
| SqlSource::FromTraceProcessorImplementation("a.z, ")); | |
| SqlSource rerewritten = std::move(rerewriter).Build(); | |
| ASSERT_EQ( | |
| rerewritten.sql(), | |
| "INSERT a.z, y FROM (SELECT slice.x, slice.y, slice.z FROM slice) a"); | |
| ASSERT_EQ( | |
| rerewritten.AsTraceback(0), | |
| "Fully expanded statement\n" | |
| " INSERT a.z, y FROM (SELECT slice.x, slice.y, slice.z FROM slice) a\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 1\n" | |
| " SELECT foo!(a) FROM bar!(slice) a\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 1\n" | |
| " INSERT \n" | |
| " ^\n"); | |
| ASSERT_EQ( | |
| rerewritten.AsTraceback(8), | |
| "Fully expanded statement\n" | |
| " INSERT a.z, y FROM (SELECT slice.x, slice.y, slice.z FROM slice) a\n" | |
| " ^\n" | |
| "Traceback (most recent call last):\n" | |
| " File \"stdin\" line 1 col 8\n" | |
| " SELECT foo!(a) FROM bar!(slice) a\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 1\n" | |
| " a.x, a.y\n" | |
| " ^\n" | |
| " Trace Processor Internal line 1 col 2\n" | |
| " a.z, \n" | |
| " ^\n"); | |
| } | |
| } // namespace | |
| } // namespace trace_processor | |
| } // namespace perfetto |