Skip to content

yuhaijun999/ClickHouse-pretty-printer

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Support pretty print STL and variables in ClickHouse

0. Prerequisite

To generate full debug info using clang, we should add option -fno-limit-debug-info. And to get full valid .gdb_index section, we should add option -ggnu-pubnames. My cmake command:

$ git clone --recursive https://github.com/ClickHouse/ClickHouse.git
$ cd ClickHouse
$ mkdir build
$ cd build
$ cmake ../src/ -DENABLE_TESTS=0 -DCLICKHOUSE_SPLIT_BINARY=1 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-ggnu-pubnames -fno-limit-debug-info" -DCMAKE_CXX_COMPILER=clang++-10 -DCMAKE_C_COMPILER=clang-10 -DCMAKE_EXE_LINKER_FLAGS="-Wl,--dynamic-linker,/lib64/ld-linux-x86-64.so.2"

otherwise when gdb print types defined in Clickhouse shows:

(gdb) p col_array
$1 = (const DB::ColumnArray *) 0x7fff0527e100
(gdb) p *col_array
$2 = <incomplete type>

1. How to use it?

  1. Install gdb and verify that it supports Python scripting (invoke gdb --version and check for --with-python=... lines).
  2. mv gdbinit ~/.gdbinit

Note: the .gdbinit file will make gdb register libcxx pretty printer, libcxx pretty printer and ClickHouse pretty printer when gdb started.

  1. Run gdb and type info pretty-printer. You should see something like that:
(gdb) info pretty-printer 
global pretty-printers:
  ...
  clickhouse
    PODArray
    ...
  libstdc++-v6
    ...

2. What does it do?

Adds some nice representation of ClickHouse's internal data structures in GDB.

2.1 IAST

For example, when printing the DB::IAST's contents, you can get the type of ast and the sql:

(gdb) p *ast                                                                                                           │           q
type=ASTSelectWithUnionQuery, sql="SELECT 1"

2.2 IColumn

When printing the DB::Columnxxx's contents, instead of

(gdb) p *col_map
$10 = {<COWHelper<DB::IColumn, DB::ColumnMap>> = {<DB::IColumn> = {<COW<DB::IColumn>> = {<boost::sp_adl_block::intrusive_ref_counter<DB::IColumn, boost::sp_adl_block::thread_safe_counter>> = {m_ref_counter = {
            value_ = {<std::__1::__atomic_base<int, true>> = {<std::__1::__atomic_base<int, false>> = {__a_ = {<std::__1::__cxx_atomic_base_impl<int>> = {__a_value = 9}, <No data fields>},
                  static is_always_lock_free = <optimized out>}, <No data fields>}, <No data fields>}}}, <No data fields>}, _vptr$IColumn = 0x9f8fcd8 <vtable for DB::ColumnMap+16>}, <No data fields>}, nested = {
    value = {<boost::intrusive_ptr<DB::IColumn const>> = {px = 0x7fff30e9c200}, <No data fields>}}}
(gdb) p keys_data
$8 = (const DB::IColumn &) @0x7fff2985af30: {<COW<DB::IColumn>> = {<boost::sp_adl_block::intrusive_ref_counter<DB::IColumn, boost::sp_adl_block::thread_safe_counter>> = {m_ref_counter = {
        value_ = {<std::__1::__atomic_base<int, true>> = {<std::__1::__atomic_base<int, false>> = {__a_ = {<std::__1::__cxx_atomic_base_impl<int>> = {__a_value = 1}, <No data fields>},
              static is_always_lock_free = <optimized out>}, <No data fields>}, <No data fields>}}}, <No data fields>}, _vptr$IColumn = 0x9f925d0 <vtable for DB::ColumnVector<char8_t>+16>}
(gdb) p nested_column
$9 = (const DB::ColumnArray &) @0x7fff30e9c200: {<COWHelper<DB::IColumn, DB::ColumnArray>> = {<DB::IColumn> = {<COW<DB::IColumn>> = {<boost::sp_adl_block::intrusive_ref_counter<DB::IColumn, boost::sp_adl_block::thread_safe_counter>> = {
          m_ref_counter = {value_ = {<std::__1::__atomic_base<int, true>> = {<std::__1::__atomic_base<int, false>> = {__a_ = {<std::__1::__cxx_atomic_base_impl<int>> = {__a_value = 1}, <No data fields>},
                  static is_always_lock_free = <optimized out>}, <No data fields>}, <No data fields>}}}, <No data fields>}, _vptr$IColumn = 0x9f8b230 <vtable for DB::ColumnArray+16>}, <No data fields>}, data = {
    value = {<boost::intrusive_ptr<DB::IColumn const>> = {px = 0x7fff2d3148e0}, <No data fields>}}, offsets = {value = {<boost::intrusive_ptr<DB::IColumn const>> = {px = 0x7fff30e745c0}, <No data fields>}}}
(gdb)

you would see this:

(gdb) p *col_map
$5 = {<COWHelper<DB::IColumn, DB::ColumnMap>> = {<DB::IColumn> = type="Map(UInt8, Int32)", size=0., <No data fields>}, nested = {value = {<boost::intrusive_ptr<DB::IColumn const>> = {px = 0x7fff30e9c200}, <No data fields>}}}

(gdb) p nested_column
$6 = ColumnArray size=0
(gdb) p keys_data
$7 = type="UInt8", size=0.

2.3 IDataType

When printing the DB::DataTypexxx's contents, instead of

(gdb) p map_type
$1 = (const DB::DataTypeMap *) 0x7fff1a40d018
(gdb) p *map_type
$2 = {<DB::DataTypeWithSimpleSerialization> = {<DB::IDataType> = {<boost::noncopyable_::noncopyable> = {<boost::noncopyable_::base_token> = {<No data fields>}, <No data fields>},
      _vptr$IDataType = 0x9f50740 <vtable for DB::DataTypeMap+16>, custom_name = {__ptr_ = {<std::__1::__compressed_pair_elem<DB::IDataTypeCustomName const*, 0, false>> = {__value_ =
    0x0}, <std::__1::__compressed_pair_elem<std::__1::default_delete<DB::IDataTypeCustomName const>, 1, true>> = {<std::__1::default_delete<DB::IDataTypeCustomName const>> = {<No data fields>}, <No data fields>}, <No data fields>}},
      custom_text_serialization = {__ptr_ = {<std::__1::__compressed_pair_elem<DB::IDataTypeCustomTextSerialization const*, 0, false>> = {
            __value_ = 0x0}, <std::__1::__compressed_pair_elem<std::__1::default_delete<DB::IDataTypeCustomTextSerialization const>, 1, true>> = {<std::__1::default_delete<DB::IDataTypeCustomTextSerialization const>> = {<No data fields>}, <No data fields>}, <No data fields>}}, custom_streams = {__ptr_ = {<std::__1::__compressed_pair_elem<DB::IDataTypeCustomStreams const*, 0, false>> = {
            __value_ = 0x0}, <std::__1::__compressed_pair_elem<std::__1::default_delete<DB::IDataTypeCustomStreams const>, 1, true>> = {<std::__1::default_delete<DB::IDataTypeCustomStreams const>> = {<No data fields>}, <No data fields>}, <No data fields>}}}, <No data fields>}, key_type = {__ptr_ = 0x7ffff6477218, __cntrl_ = 0x7ffff6477200}, value_type = {__ptr_ = 0x7ffff6477258, __cntrl_ = 0x7ffff6477240}, nested = {__ptr_ = 0x7ffff61a7758, __cntrl_ = 0x7ffff61a7740},
  static is_parametric = true}
(gdb)

you would see this:

(gdb) source /home/hewenting/workspace/gdb/ClickHouse-pretty-printer/gdbinit
(gdb) p *map_type
$3 = {<DB::DataTypeWithSimpleSerialization> = {<DB::IDataType> = IDataType = "Map(UInt8,Int32)", <No data fields>}, key_type = std::shared_ptr (count 4, weak 0) = 0x7ffff6477218 => IDataType = "UInt8", value_type =
    std::shared_ptr (count 4, weak 0) = 0x7ffff6477258 => IDataType = "Int32", nested = std::shared_ptr (count 1, weak 0) = 0x7ffff61a7758 => IDataType = "Array(Tuple(keys UInt8, values Int32))", static is_parametric = true}
(gdb)

2.4 PaddedPODArray

when printing the DB::PaddedPODArray's contents, instead of

$1 = (DB::PaddedPODArray<DB::ArrayIndexNumImpl<unsigned long, unsigned long, DB::Index
ToOne, false>::ResultType> &) @0x7ffff7847030: {<DB::PODArrayBase<1, 4096, Allocator<f711 alse, false>, 15, 16>> = {
<boost::noncopyable_::noncopyable> = {<boost::noncopyable_:: base_token> = {<No data fields>}, <No data fields>}, 
<Allocator<false, false>> = {stat713 ic clear_memory = false, static mmap_flags = 34}, static pad_right = 15, 
static pad_left = 16, static null = <optimized out>, c_start = 0x7ffff78a5c10 "", 
c_end = 0x7ffff78a5c42 '\245' <repeats 62 times>, 'Z' <repeats 128 times>, "\202\031", 
c_end_of_storage= 0x7ffff78a5c71 '\245' <repeats 15 times>, 'Z' <repeats 128 times>, "\202\031", 
mprotected = false}, <No data fields>}    

you would see this:

$1 = DB::PaddedPODArray<DB::ArrayIndexNumImpl<unsigned
long, unsigned long, DB::IndexToOne, false> of length 50, capacity 97 = 
{0 '\000', 0 '\000', 0
'\000', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 0 '\000
', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 0
'\000', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 0 '\000
', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 0
'\000', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 0 '\000
', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 0
'\000', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 0 '\000
', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 0 '\000', 0
'\000', 0 '\000', 0 '\000', 0 '\000'}

Note:

  • You can write your own pretty printer for some clickhouse classes, If there is some difficuties, let me know(create an issue), I will help you.

3. Gdb useful commands related

(gdb) info pretty-printer
...........
(gdb) python
>import gdb
>sn=gdb.selected_frame()
>symbol_table_adn_line=sn.find_sal()
>symtab=symbol_table_adn_line.symtab
>print(symtab.filename, symtab.objfile)
>global_block=symtab.global_block()
>super_block=global_block.superblock
>print(global_block, super_block, global_block.is_global)
>
>### get each symbol in the block
>for sym in global_block:
>    if "ColumnArray" in sym.name:
>        print(sym.name, "     ##########     " , sym.symtab)
>end

(gdb) info vtbl ast
vtable for 'DB::IAST' @ 0xbecac50 (subobject @ 0x7fff30ea5458):
[0]: 0x1a3d5840 <DB::ASTSelectWithUnionQuery::~ASTSelectWithUnionQuery()>
[1]: 0x1daecb70 <DB::ASTSelectWithUnionQuery::~ASTSelectWithUnionQuery()>
[2]: 0x18fd17f0 <DB::IAST::appendColumnName(DB::WriteBuffer&) const>
[3]: 0x18fd18f0 <DB::IAST::appendColumnNameWithoutAlias(DB::WriteBuffer&) const>
[4]: 0x18fd19f0 <DB::IAST::getAliasOrColumnName() const>
[5]: 0x18fd1a20 <DB::IAST::tryGetAlias() const>
[6]: 0x18fd1a50 <DB::IAST::setAlias(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)>
[7]: 0x1daecbb0 <DB::ASTSelectWithUnionQuery::getID(char) const>
[8]: 0x1daec170 <DB::ASTSelectWithUnionQuery::clone() const>
[9]: 0x1db2bf50 <DB::IAST::updateTreeHashImpl(SipHash&) const>
[10]: 0x18fd1b40 <DB::IAST::collectIdentifierNames(std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&) const>
[11]: 0x1dade2c0 <DB::ASTQueryWithOutput::formatImpl(DB::IAST::FormatSettings const&, DB::IAST::FormatState&, DB::IAST::FormatStateStacked) const>
(gdb)

4. links:

About

This is a demo for pretty print ClickHouse variables

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 100.0%