github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/delegate/show_table.go (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package delegate
    12  
    13  import (
    14  	"fmt"
    15  
    16  	"github.com/cockroachdb/cockroach/pkg/sql/lex"
    17  	"github.com/cockroachdb/cockroach/pkg/sql/opt/cat"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry"
    20  )
    21  
    22  func (d *delegator) delegateShowCreate(n *tree.ShowCreate) (tree.Statement, error) {
    23  	sqltelemetry.IncrementShowCounter(sqltelemetry.Create)
    24  
    25  	const showCreateQuery = `
    26      WITH zone_configs AS (
    27        SELECT string_agg(raw_config_sql, e';\n') FROM crdb_internal.zones
    28        WHERE database_name = %[1]s
    29        AND table_name = %[2]s 
    30        AND raw_config_yaml IS NOT NULL
    31        AND raw_config_sql IS NOT NULL
    32      )
    33      SELECT
    34  			%[3]s AS table_name,
    35        concat(create_statement,
    36               CASE
    37                 WHEN NOT has_partitions
    38                 THEN NULL
    39                 WHEN (SELECT * FROM zone_configs) IS NULL
    40                 THEN e'\n-- Warning: Partitioned table with no zone configurations.'
    41                 ELSE concat(e';\n', (SELECT * FROM zone_configs))
    42               END
    43  			) AS create_statement
    44  		FROM
    45  			%[4]s.crdb_internal.create_statements
    46  		WHERE
    47        descriptor_id = %[6]d
    48  	`
    49  
    50  	return d.showTableDetails(n.Name, showCreateQuery)
    51  }
    52  
    53  func (d *delegator) delegateShowIndexes(n *tree.ShowIndexes) (tree.Statement, error) {
    54  	sqltelemetry.IncrementShowCounter(sqltelemetry.Indexes)
    55  	getIndexesQuery := `
    56  SELECT
    57  	s.table_name,
    58  	s.index_name,
    59  	non_unique::BOOL,
    60  	seq_in_index,
    61  	column_name,
    62  	direction,
    63  	storing::BOOL,
    64  	implicit::BOOL`
    65  
    66  	if n.WithComment {
    67  		getIndexesQuery += `,
    68  	obj_description(pg_indexes.crdb_oid) AS comment`
    69  	}
    70  
    71  	getIndexesQuery += `
    72  FROM
    73  	%[4]s.information_schema.statistics AS s`
    74  
    75  	if n.WithComment {
    76  		getIndexesQuery += `
    77  	LEFT JOIN pg_indexes ON
    78  		pg_indexes.tablename = s.table_name AND
    79  		pg_indexes.indexname = s.index_name
    80  	`
    81  	}
    82  
    83  	getIndexesQuery += `
    84  WHERE
    85  	table_catalog=%[1]s
    86  	AND table_schema=%[5]s
    87  	AND table_name=%[2]s`
    88  
    89  	return d.showTableDetails(n.Table, getIndexesQuery)
    90  }
    91  
    92  func (d *delegator) delegateShowColumns(n *tree.ShowColumns) (tree.Statement, error) {
    93  	getColumnsQuery := `
    94  SELECT
    95    column_name AS column_name,
    96    crdb_sql_type AS data_type,
    97    is_nullable::BOOL,
    98    column_default,
    99    generation_expression,
   100    IF(inames[1] IS NULL, ARRAY[]:::STRING[], inames) AS indices,
   101    is_hidden::BOOL`
   102  
   103  	if n.WithComment {
   104  		getColumnsQuery += `,
   105    col_description(%[6]d, attnum) AS comment`
   106  	}
   107  
   108  	getColumnsQuery += `
   109  FROM
   110    (SELECT column_name, crdb_sql_type, is_nullable, column_default, generation_expression,
   111  	        ordinal_position, is_hidden, array_agg(index_name) AS inames
   112       FROM
   113           (SELECT column_name, crdb_sql_type, is_nullable, column_default, generation_expression,
   114  				         ordinal_position, is_hidden
   115              FROM %[4]s.information_schema.columns
   116             WHERE (length(%[1]s)=0 OR table_catalog=%[1]s) AND table_schema=%[5]s AND table_name=%[2]s)
   117           LEFT OUTER JOIN
   118           (SELECT column_name, index_name
   119              FROM %[4]s.information_schema.statistics
   120             WHERE (length(%[1]s)=0 OR table_catalog=%[1]s) AND table_schema=%[5]s AND table_name=%[2]s)
   121           USING(column_name)
   122      GROUP BY column_name, crdb_sql_type, is_nullable, column_default, generation_expression,
   123  		         ordinal_position, is_hidden
   124     )`
   125  
   126  	if n.WithComment {
   127  		getColumnsQuery += `
   128           LEFT OUTER JOIN pg_attribute 
   129             ON column_name = pg_attribute.attname
   130             AND attrelid = %[6]d`
   131  	}
   132  
   133  	getColumnsQuery += `
   134  ORDER BY ordinal_position`
   135  
   136  	return d.showTableDetails(n.Table, getColumnsQuery)
   137  }
   138  
   139  func (d *delegator) delegateShowConstraints(n *tree.ShowConstraints) (tree.Statement, error) {
   140  	sqltelemetry.IncrementShowCounter(sqltelemetry.Constraints)
   141  	const getConstraintsQuery = `
   142      SELECT
   143          t.relname AS table_name,
   144          c.conname AS constraint_name,
   145          CASE c.contype
   146             WHEN 'p' THEN 'PRIMARY KEY'
   147             WHEN 'u' THEN 'UNIQUE'
   148             WHEN 'c' THEN 'CHECK'
   149             WHEN 'f' THEN 'FOREIGN KEY'
   150             ELSE c.contype
   151          END AS constraint_type,
   152          c.condef AS details,
   153          c.convalidated AS validated
   154      FROM
   155         %[4]s.pg_catalog.pg_class t,
   156         %[4]s.pg_catalog.pg_namespace n,
   157         %[4]s.pg_catalog.pg_constraint c
   158      WHERE t.relname = %[2]s
   159        AND n.nspname = %[5]s AND t.relnamespace = n.oid
   160        AND t.oid = c.conrelid
   161      ORDER BY 1, 2`
   162  
   163  	return d.showTableDetails(n.Table, getConstraintsQuery)
   164  }
   165  
   166  // showTableDetails returns the AST of a query which extracts information about
   167  // the given table using the given query patterns in SQL. The query pattern must
   168  // accept the following formatting parameters:
   169  //   %[1]s the database name as SQL string literal.
   170  //   %[2]s the unqualified table name as SQL string literal.
   171  //   %[3]s the given table name as SQL string literal.
   172  //   %[4]s the database name as SQL identifier.
   173  //   %[5]s the schema name as SQL string literal.
   174  //   %[6]s the table ID.
   175  func (d *delegator) showTableDetails(
   176  	name *tree.UnresolvedObjectName, query string,
   177  ) (tree.Statement, error) {
   178  	// We avoid the cache so that we can observe the details without
   179  	// taking a lease, like other SHOW commands.
   180  	flags := cat.Flags{AvoidDescriptorCaches: true, NoTableStats: true}
   181  	tn := name.ToTableName()
   182  	dataSource, resName, err := d.catalog.ResolveDataSource(d.ctx, flags, &tn)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	if err := d.catalog.CheckAnyPrivilege(d.ctx, dataSource); err != nil {
   187  		return nil, err
   188  	}
   189  
   190  	fullQuery := fmt.Sprintf(query,
   191  		lex.EscapeSQLString(resName.Catalog()),
   192  		lex.EscapeSQLString(resName.Table()),
   193  		lex.EscapeSQLString(resName.String()),
   194  		resName.CatalogName.String(), // note: CatalogName.String() != Catalog()
   195  		lex.EscapeSQLString(resName.Schema()),
   196  		dataSource.PostgresDescriptorID(),
   197  	)
   198  
   199  	return parse(fullQuery)
   200  }