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

     1  // Copyright 2017 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 sql
    12  
    13  import (
    14  	"context"
    15  	"strings"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/geo/geopb"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/sessiondata"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    22  	"github.com/cockroachdb/errors"
    23  )
    24  
    25  // pgExtension is virtual schema which contains virtual tables and/or views
    26  // which are used by postgres extensions. Postgres extensions typically install
    27  // these tables and views on the public schema, but we instead do it in
    28  // our own defined virtual table / schema.
    29  var pgExtension = virtualSchema{
    30  	name: sessiondata.PgExtensionSchemaName,
    31  	tableDefs: map[sqlbase.ID]virtualSchemaDef{
    32  		sqlbase.PgExtensionGeographyColumnsTableID: pgExtensionGeographyColumnsTable,
    33  		sqlbase.PgExtensionGeometryColumnsTableID:  pgExtensionGeometryColumnsTable,
    34  		sqlbase.PgExtensionSpatialRefSysTableID:    pgExtensionSpatialRefSysTable,
    35  	},
    36  	validWithNoDatabaseContext: false,
    37  }
    38  
    39  func postgisColumnsTablePopulator(
    40  	matchingFamily types.Family,
    41  ) func(context.Context, *planner, *DatabaseDescriptor, func(...tree.Datum) error) error {
    42  	return func(ctx context.Context, p *planner, dbContext *DatabaseDescriptor, addRow func(...tree.Datum) error) error {
    43  		return forEachTableDesc(
    44  			ctx,
    45  			p,
    46  			dbContext,
    47  			hideVirtual,
    48  			func(db *sqlbase.DatabaseDescriptor, scName string, table *sqlbase.TableDescriptor) error {
    49  				if !table.IsPhysicalTable() {
    50  					return nil
    51  				}
    52  				if p.CheckAnyPrivilege(ctx, table) != nil {
    53  					return nil
    54  				}
    55  				for _, colDesc := range table.Columns {
    56  					if colDesc.Type.Family() != matchingFamily {
    57  						continue
    58  					}
    59  					m, err := colDesc.Type.GeoMetadata()
    60  					if err != nil {
    61  						return err
    62  					}
    63  
    64  					var datumNDims tree.Datum
    65  					switch m.Shape {
    66  					case geopb.Shape_Point, geopb.Shape_LineString, geopb.Shape_Polygon,
    67  						geopb.Shape_MultiPoint, geopb.Shape_MultiLineString, geopb.Shape_MultiPolygon,
    68  						geopb.Shape_GeometryCollection:
    69  						datumNDims = tree.NewDInt(2)
    70  					case geopb.Shape_Geometry, geopb.Shape_Unset:
    71  						// For geometry_columns, the query in PostGIS COALESCES the value to 2.
    72  						// Otherwise, the value is NULL.
    73  						if matchingFamily == types.GeometryFamily {
    74  							datumNDims = tree.NewDInt(2)
    75  						} else {
    76  							datumNDims = tree.DNull
    77  						}
    78  					}
    79  
    80  					shapeName := m.Shape.String()
    81  					if m.Shape == geopb.Shape_Unset {
    82  						shapeName = geopb.Shape_Geometry.String()
    83  					}
    84  
    85  					if err := addRow(
    86  						tree.NewDString(db.GetName()),
    87  						tree.NewDString(scName),
    88  						tree.NewDString(table.GetName()),
    89  						tree.NewDString(colDesc.Name),
    90  						datumNDims,
    91  						tree.NewDInt(tree.DInt(m.SRID)),
    92  						tree.NewDString(strings.ToUpper(shapeName)),
    93  					); err != nil {
    94  						return err
    95  					}
    96  				}
    97  				return nil
    98  			},
    99  		)
   100  	}
   101  }
   102  
   103  var pgExtensionGeographyColumnsTable = virtualSchemaTable{
   104  	comment: `Shows all defined geography columns. Matches PostGIS' geography_columns functionality.`,
   105  	schema: `
   106  CREATE TABLE pg_extension.geography_columns (
   107  	f_table_catalog name,
   108  	f_table_schema name,
   109  	f_table_name name,
   110  	f_geography_column name,
   111  	coord_dimension integer,
   112  	srid integer,
   113  	type text
   114  )`,
   115  	populate: postgisColumnsTablePopulator(types.GeographyFamily),
   116  }
   117  
   118  var pgExtensionGeometryColumnsTable = virtualSchemaTable{
   119  	comment: `Shows all defined geometry columns. Matches PostGIS' geometry_columns functionality.`,
   120  	schema: `
   121  CREATE TABLE pg_extension.geometry_columns (
   122  	f_table_catalog name,
   123  	f_table_schema name,
   124  	f_table_name name,
   125  	f_geometry_column name,
   126  	coord_dimension integer,
   127  	srid integer,
   128  	type text
   129  )`,
   130  	populate: postgisColumnsTablePopulator(types.GeometryFamily),
   131  }
   132  
   133  var pgExtensionSpatialRefSysTable = virtualSchemaTable{
   134  	comment: `Shows all defined Spatial Reference Identifiers (SRIDs). Matches PostGIS' spatial_ref_sys table.`,
   135  	schema: `
   136  CREATE TABLE pg_extension.spatial_ref_sys (
   137  	srid integer,
   138  	auth_name varchar(256),
   139  	auth_srid integer,
   140  	srtext varchar(2048),
   141  	proj4text varchar(2048)
   142  )`,
   143  	generator: func(ctx context.Context, p *planner, db *DatabaseDescriptor) (virtualTableGenerator, cleanupFunc, error) {
   144  		return nil, func() {}, errors.Newf("not yet implemented")
   145  	},
   146  }