metadata.go 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. // Copyright (c) 2015 The gocql Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package gocql
  5. import (
  6. "encoding/hex"
  7. "encoding/json"
  8. "fmt"
  9. "log"
  10. "strconv"
  11. "strings"
  12. "sync"
  13. )
  14. // schema metadata for a keyspace
  15. type KeyspaceMetadata struct {
  16. Name string
  17. DurableWrites bool
  18. StrategyClass string
  19. StrategyOptions map[string]interface{}
  20. Tables map[string]*TableMetadata
  21. }
  22. // schema metadata for a table (a.k.a. column family)
  23. type TableMetadata struct {
  24. Keyspace string
  25. Name string
  26. KeyValidator string
  27. Comparator string
  28. DefaultValidator string
  29. KeyAliases []string
  30. ColumnAliases []string
  31. ValueAlias string
  32. PartitionKey []*ColumnMetadata
  33. ClusteringColumns []*ColumnMetadata
  34. Columns map[string]*ColumnMetadata
  35. OrderedColumns []string
  36. }
  37. // schema metadata for a column
  38. type ColumnMetadata struct {
  39. Keyspace string
  40. Table string
  41. Name string
  42. ComponentIndex int
  43. Kind ColumnKind
  44. Validator string
  45. Type TypeInfo
  46. ClusteringOrder string
  47. Order ColumnOrder
  48. Index ColumnIndexMetadata
  49. }
  50. // the ordering of the column with regard to its comparator
  51. type ColumnOrder bool
  52. const (
  53. ASC ColumnOrder = false
  54. DESC = true
  55. )
  56. type ColumnIndexMetadata struct {
  57. Name string
  58. Type string
  59. Options map[string]interface{}
  60. }
  61. type ColumnKind int
  62. const (
  63. ColumnUnkownKind ColumnKind = iota
  64. ColumnPartitionKey
  65. ColumnClusteringKey
  66. ColumnRegular
  67. ColumnCompact
  68. )
  69. func (c ColumnKind) String() string {
  70. switch c {
  71. case ColumnPartitionKey:
  72. return "partition_key"
  73. case ColumnClusteringKey:
  74. return "clustering_key"
  75. case ColumnRegular:
  76. return "regular"
  77. case ColumnCompact:
  78. return "compact"
  79. default:
  80. return fmt.Sprintf("unkown_column_%d", c)
  81. }
  82. }
  83. func (c *ColumnKind) UnmarshalCQL(typ TypeInfo, p []byte) error {
  84. if typ.Type() != TypeVarchar {
  85. return unmarshalErrorf("unable to marshall %s into ColumnKind, expected Varchar", typ)
  86. }
  87. kind, err := columnKindFromSchema(string(p))
  88. if err != nil {
  89. return err
  90. }
  91. *c = kind
  92. return nil
  93. }
  94. func columnKindFromSchema(kind string) (ColumnKind, error) {
  95. switch kind {
  96. case "partition_key":
  97. return ColumnPartitionKey, nil
  98. case "clustering_key", "clustering":
  99. return ColumnClusteringKey, nil
  100. case "regular":
  101. return ColumnRegular, nil
  102. case "compact_value":
  103. return ColumnCompact, nil
  104. default:
  105. return -1, fmt.Errorf("unknown column kind: %q", kind)
  106. }
  107. }
  108. // default alias values
  109. const (
  110. DEFAULT_KEY_ALIAS = "key"
  111. DEFAULT_COLUMN_ALIAS = "column"
  112. DEFAULT_VALUE_ALIAS = "value"
  113. )
  114. // queries the cluster for schema information for a specific keyspace
  115. type schemaDescriber struct {
  116. session *Session
  117. mu sync.Mutex
  118. cache map[string]*KeyspaceMetadata
  119. }
  120. // creates a session bound schema describer which will query and cache
  121. // keyspace metadata
  122. func newSchemaDescriber(session *Session) *schemaDescriber {
  123. return &schemaDescriber{
  124. session: session,
  125. cache: map[string]*KeyspaceMetadata{},
  126. }
  127. }
  128. // returns the cached KeyspaceMetadata held by the describer for the named
  129. // keyspace.
  130. func (s *schemaDescriber) getSchema(keyspaceName string) (*KeyspaceMetadata, error) {
  131. s.mu.Lock()
  132. defer s.mu.Unlock()
  133. metadata, found := s.cache[keyspaceName]
  134. if !found {
  135. // refresh the cache for this keyspace
  136. err := s.refreshSchema(keyspaceName)
  137. if err != nil {
  138. return nil, err
  139. }
  140. metadata = s.cache[keyspaceName]
  141. }
  142. return metadata, nil
  143. }
  144. // clears the already cached keyspace metadata
  145. func (s *schemaDescriber) clearSchema(keyspaceName string) {
  146. s.mu.Lock()
  147. defer s.mu.Unlock()
  148. delete(s.cache, keyspaceName)
  149. }
  150. // forcibly updates the current KeyspaceMetadata held by the schema describer
  151. // for a given named keyspace.
  152. func (s *schemaDescriber) refreshSchema(keyspaceName string) error {
  153. var err error
  154. // query the system keyspace for schema data
  155. // TODO retrieve concurrently
  156. keyspace, err := getKeyspaceMetadata(s.session, keyspaceName)
  157. if err != nil {
  158. return err
  159. }
  160. tables, err := getTableMetadata(s.session, keyspaceName)
  161. if err != nil {
  162. return err
  163. }
  164. columns, err := getColumnMetadata(s.session, keyspaceName)
  165. if err != nil {
  166. return err
  167. }
  168. // organize the schema data
  169. compileMetadata(s.session.cfg.ProtoVersion, keyspace, tables, columns)
  170. // update the cache
  171. s.cache[keyspaceName] = keyspace
  172. return nil
  173. }
  174. // "compiles" derived information about keyspace, table, and column metadata
  175. // for a keyspace from the basic queried metadata objects returned by
  176. // getKeyspaceMetadata, getTableMetadata, and getColumnMetadata respectively;
  177. // Links the metadata objects together and derives the column composition of
  178. // the partition key and clustering key for a table.
  179. func compileMetadata(
  180. protoVersion int,
  181. keyspace *KeyspaceMetadata,
  182. tables []TableMetadata,
  183. columns []ColumnMetadata,
  184. ) {
  185. keyspace.Tables = make(map[string]*TableMetadata)
  186. for i := range tables {
  187. tables[i].Columns = make(map[string]*ColumnMetadata)
  188. keyspace.Tables[tables[i].Name] = &tables[i]
  189. }
  190. // add columns from the schema data
  191. for i := range columns {
  192. // decode the validator for TypeInfo and order
  193. if columns[i].ClusteringOrder != "" { // Cassandra 3.x+
  194. columns[i].Type = NativeType{typ: getCassandraType(columns[i].Validator)}
  195. columns[i].Order = ASC
  196. if columns[i].ClusteringOrder == "desc" {
  197. columns[i].Order = DESC
  198. }
  199. } else {
  200. validatorParsed := parseType(columns[i].Validator)
  201. columns[i].Type = validatorParsed.types[0]
  202. columns[i].Order = ASC
  203. if validatorParsed.reversed[0] {
  204. columns[i].Order = DESC
  205. }
  206. }
  207. table := keyspace.Tables[columns[i].Table]
  208. table.Columns[columns[i].Name] = &columns[i]
  209. table.OrderedColumns = append(table.OrderedColumns, columns[i].Name)
  210. }
  211. if protoVersion == 1 {
  212. compileV1Metadata(tables)
  213. } else {
  214. compileV2Metadata(tables)
  215. }
  216. }
  217. // Compiles derived information from TableMetadata which have had
  218. // ColumnMetadata added already. V1 protocol does not return as much
  219. // column metadata as V2+ (because V1 doesn't support the "type" column in the
  220. // system.schema_columns table) so determining PartitionKey and ClusterColumns
  221. // is more complex.
  222. func compileV1Metadata(tables []TableMetadata) {
  223. for i := range tables {
  224. table := &tables[i]
  225. // decode the key validator
  226. keyValidatorParsed := parseType(table.KeyValidator)
  227. // decode the comparator
  228. comparatorParsed := parseType(table.Comparator)
  229. // the partition key length is the same as the number of types in the
  230. // key validator
  231. table.PartitionKey = make([]*ColumnMetadata, len(keyValidatorParsed.types))
  232. // V1 protocol only returns "regular" columns from
  233. // system.schema_columns (there is no type field for columns)
  234. // so the alias information is used to
  235. // create the partition key and clustering columns
  236. // construct the partition key from the alias
  237. for i := range table.PartitionKey {
  238. var alias string
  239. if len(table.KeyAliases) > i {
  240. alias = table.KeyAliases[i]
  241. } else if i == 0 {
  242. alias = DEFAULT_KEY_ALIAS
  243. } else {
  244. alias = DEFAULT_KEY_ALIAS + strconv.Itoa(i+1)
  245. }
  246. column := &ColumnMetadata{
  247. Keyspace: table.Keyspace,
  248. Table: table.Name,
  249. Name: alias,
  250. Type: keyValidatorParsed.types[i],
  251. Kind: ColumnPartitionKey,
  252. ComponentIndex: i,
  253. }
  254. table.PartitionKey[i] = column
  255. table.Columns[alias] = column
  256. }
  257. // determine the number of clustering columns
  258. size := len(comparatorParsed.types)
  259. if comparatorParsed.isComposite {
  260. if len(comparatorParsed.collections) != 0 ||
  261. (len(table.ColumnAliases) == size-1 &&
  262. comparatorParsed.types[size-1].Type() == TypeVarchar) {
  263. size = size - 1
  264. }
  265. } else {
  266. if !(len(table.ColumnAliases) != 0 || len(table.Columns) == 0) {
  267. size = 0
  268. }
  269. }
  270. table.ClusteringColumns = make([]*ColumnMetadata, size)
  271. for i := range table.ClusteringColumns {
  272. var alias string
  273. if len(table.ColumnAliases) > i {
  274. alias = table.ColumnAliases[i]
  275. } else if i == 0 {
  276. alias = DEFAULT_COLUMN_ALIAS
  277. } else {
  278. alias = DEFAULT_COLUMN_ALIAS + strconv.Itoa(i+1)
  279. }
  280. order := ASC
  281. if comparatorParsed.reversed[i] {
  282. order = DESC
  283. }
  284. column := &ColumnMetadata{
  285. Keyspace: table.Keyspace,
  286. Table: table.Name,
  287. Name: alias,
  288. Type: comparatorParsed.types[i],
  289. Order: order,
  290. Kind: ColumnClusteringKey,
  291. ComponentIndex: i,
  292. }
  293. table.ClusteringColumns[i] = column
  294. table.Columns[alias] = column
  295. }
  296. if size != len(comparatorParsed.types)-1 {
  297. alias := DEFAULT_VALUE_ALIAS
  298. if len(table.ValueAlias) > 0 {
  299. alias = table.ValueAlias
  300. }
  301. // decode the default validator
  302. defaultValidatorParsed := parseType(table.DefaultValidator)
  303. column := &ColumnMetadata{
  304. Keyspace: table.Keyspace,
  305. Table: table.Name,
  306. Name: alias,
  307. Type: defaultValidatorParsed.types[0],
  308. Kind: ColumnRegular,
  309. }
  310. table.Columns[alias] = column
  311. }
  312. }
  313. }
  314. // The simpler compile case for V2+ protocol
  315. func compileV2Metadata(tables []TableMetadata) {
  316. for i := range tables {
  317. table := &tables[i]
  318. clusteringColumnCount := componentColumnCountOfType(table.Columns, ColumnClusteringKey)
  319. table.ClusteringColumns = make([]*ColumnMetadata, clusteringColumnCount)
  320. if table.KeyValidator != "" {
  321. keyValidatorParsed := parseType(table.KeyValidator)
  322. table.PartitionKey = make([]*ColumnMetadata, len(keyValidatorParsed.types))
  323. } else { // Cassandra 3.x+
  324. partitionKeyCount := componentColumnCountOfType(table.Columns, ColumnPartitionKey)
  325. table.PartitionKey = make([]*ColumnMetadata, partitionKeyCount)
  326. }
  327. for _, columnName := range table.OrderedColumns {
  328. column := table.Columns[columnName]
  329. if column.Kind == ColumnPartitionKey {
  330. table.PartitionKey[column.ComponentIndex] = column
  331. } else if column.Kind == ColumnClusteringKey {
  332. table.ClusteringColumns[column.ComponentIndex] = column
  333. }
  334. }
  335. }
  336. }
  337. // returns the count of coluns with the given "kind" value.
  338. func componentColumnCountOfType(columns map[string]*ColumnMetadata, kind ColumnKind) int {
  339. maxComponentIndex := -1
  340. for _, column := range columns {
  341. if column.Kind == kind && column.ComponentIndex > maxComponentIndex {
  342. maxComponentIndex = column.ComponentIndex
  343. }
  344. }
  345. return maxComponentIndex + 1
  346. }
  347. // query only for the keyspace metadata for the specified keyspace from system.schema_keyspace
  348. func getKeyspaceMetadata(session *Session, keyspaceName string) (*KeyspaceMetadata, error) {
  349. keyspace := &KeyspaceMetadata{Name: keyspaceName}
  350. if session.useSystemSchema { // Cassandra 3.x+
  351. const stmt = `
  352. SELECT durable_writes, replication
  353. FROM system_schema.keyspaces
  354. WHERE keyspace_name = ?`
  355. var replication map[string]string
  356. iter := session.control.query(stmt, keyspaceName)
  357. iter.Scan(&keyspace.DurableWrites, &replication)
  358. err := iter.Close()
  359. if err != nil {
  360. return nil, fmt.Errorf("Error querying keyspace schema: %v", err)
  361. }
  362. keyspace.StrategyClass = replication["class"]
  363. keyspace.StrategyOptions = make(map[string]interface{})
  364. for k, v := range replication {
  365. keyspace.StrategyOptions[k] = v
  366. }
  367. } else {
  368. const stmt = `
  369. SELECT durable_writes, strategy_class, strategy_options
  370. FROM system.schema_keyspaces
  371. WHERE keyspace_name = ?`
  372. var strategyOptionsJSON []byte
  373. iter := session.control.query(stmt, keyspaceName)
  374. iter.Scan(&keyspace.DurableWrites, &keyspace.StrategyClass, &strategyOptionsJSON)
  375. err := iter.Close()
  376. if err != nil {
  377. return nil, fmt.Errorf("Error querying keyspace schema: %v", err)
  378. }
  379. err = json.Unmarshal(strategyOptionsJSON, &keyspace.StrategyOptions)
  380. if err != nil {
  381. return nil, fmt.Errorf(
  382. "Invalid JSON value '%s' as strategy_options for in keyspace '%s': %v",
  383. strategyOptionsJSON, keyspace.Name, err,
  384. )
  385. }
  386. }
  387. return keyspace, nil
  388. }
  389. // query for only the table metadata in the specified keyspace from system.schema_columnfamilies
  390. func getTableMetadata(session *Session, keyspaceName string) ([]TableMetadata, error) {
  391. var (
  392. iter *Iter
  393. scan func(iter *Iter, table *TableMetadata) bool
  394. stmt string
  395. keyAliasesJSON []byte
  396. columnAliasesJSON []byte
  397. )
  398. if session.useSystemSchema { // Cassandra 3.x+
  399. stmt = `
  400. SELECT
  401. table_name
  402. FROM system_schema.tables
  403. WHERE keyspace_name = ?`
  404. switchIter := func() *Iter {
  405. iter.Close()
  406. stmt = `
  407. SELECT
  408. view_name
  409. FROM system_schema.views
  410. WHERE keyspace_name = ?`
  411. iter = session.control.query(stmt, keyspaceName)
  412. return iter
  413. }
  414. scan = func(iter *Iter, table *TableMetadata) bool {
  415. r := iter.Scan(
  416. &table.Name,
  417. )
  418. if !r {
  419. iter = switchIter()
  420. if iter != nil {
  421. switchIter = func() *Iter { return nil }
  422. r = iter.Scan(&table.Name)
  423. }
  424. }
  425. return r
  426. }
  427. } else if session.cfg.ProtoVersion < protoVersion4 {
  428. // we have key aliases
  429. // TODO: Do we need key_aliases?
  430. stmt = `
  431. SELECT
  432. columnfamily_name,
  433. key_validator,
  434. comparator,
  435. default_validator,
  436. key_aliases,
  437. column_aliases,
  438. value_alias
  439. FROM system.schema_columnfamilies
  440. WHERE keyspace_name = ?`
  441. scan = func(iter *Iter, table *TableMetadata) bool {
  442. return iter.Scan(
  443. &table.Name,
  444. &table.KeyValidator,
  445. &table.Comparator,
  446. &table.DefaultValidator,
  447. &keyAliasesJSON,
  448. &columnAliasesJSON,
  449. &table.ValueAlias,
  450. )
  451. }
  452. } else {
  453. stmt = `
  454. SELECT
  455. columnfamily_name,
  456. key_validator,
  457. comparator,
  458. default_validator
  459. FROM system.schema_columnfamilies
  460. WHERE keyspace_name = ?`
  461. scan = func(iter *Iter, table *TableMetadata) bool {
  462. return iter.Scan(
  463. &table.Name,
  464. &table.KeyValidator,
  465. &table.Comparator,
  466. &table.DefaultValidator,
  467. )
  468. }
  469. }
  470. iter = session.control.query(stmt, keyspaceName)
  471. tables := []TableMetadata{}
  472. table := TableMetadata{Keyspace: keyspaceName}
  473. for scan(iter, &table) {
  474. var err error
  475. // decode the key aliases
  476. if keyAliasesJSON != nil {
  477. table.KeyAliases = []string{}
  478. err = json.Unmarshal(keyAliasesJSON, &table.KeyAliases)
  479. if err != nil {
  480. iter.Close()
  481. return nil, fmt.Errorf(
  482. "Invalid JSON value '%s' as key_aliases for in table '%s': %v",
  483. keyAliasesJSON, table.Name, err,
  484. )
  485. }
  486. }
  487. // decode the column aliases
  488. if columnAliasesJSON != nil {
  489. table.ColumnAliases = []string{}
  490. err = json.Unmarshal(columnAliasesJSON, &table.ColumnAliases)
  491. if err != nil {
  492. iter.Close()
  493. return nil, fmt.Errorf(
  494. "Invalid JSON value '%s' as column_aliases for in table '%s': %v",
  495. columnAliasesJSON, table.Name, err,
  496. )
  497. }
  498. }
  499. tables = append(tables, table)
  500. table = TableMetadata{Keyspace: keyspaceName}
  501. }
  502. err := iter.Close()
  503. if err != nil && err != ErrNotFound {
  504. return nil, fmt.Errorf("Error querying table schema: %v", err)
  505. }
  506. return tables, nil
  507. }
  508. func (s *Session) scanColumnMetadataV1(keyspace string) ([]ColumnMetadata, error) {
  509. // V1 does not support the type column, and all returned rows are
  510. // of kind "regular".
  511. const stmt = `
  512. SELECT
  513. columnfamily_name,
  514. column_name,
  515. component_index,
  516. validator,
  517. index_name,
  518. index_type,
  519. index_options
  520. FROM system.schema_columns
  521. WHERE keyspace_name = ?`
  522. var columns []ColumnMetadata
  523. rows := s.control.query(stmt, keyspace).Scanner()
  524. for rows.Next() {
  525. var (
  526. column = ColumnMetadata{Keyspace: keyspace}
  527. indexOptionsJSON []byte
  528. )
  529. // all columns returned by V1 are regular
  530. column.Kind = ColumnRegular
  531. err := rows.Scan(&column.Table,
  532. &column.Name,
  533. &column.ComponentIndex,
  534. &column.Validator,
  535. &column.Index.Name,
  536. &column.Index.Type,
  537. &indexOptionsJSON)
  538. if err != nil {
  539. return nil, err
  540. }
  541. if len(indexOptionsJSON) > 0 {
  542. err := json.Unmarshal(indexOptionsJSON, &column.Index.Options)
  543. if err != nil {
  544. return nil, fmt.Errorf(
  545. "Invalid JSON value '%s' as index_options for column '%s' in table '%s': %v",
  546. indexOptionsJSON,
  547. column.Name,
  548. column.Table,
  549. err)
  550. }
  551. }
  552. columns = append(columns, column)
  553. }
  554. if err := rows.Err(); err != nil {
  555. return nil, err
  556. }
  557. return columns, nil
  558. }
  559. func (s *Session) scanColumnMetadataV2(keyspace string) ([]ColumnMetadata, error) {
  560. // V2+ supports the type column
  561. const stmt = `
  562. SELECT
  563. columnfamily_name,
  564. column_name,
  565. component_index,
  566. validator,
  567. index_name,
  568. index_type,
  569. index_options,
  570. type
  571. FROM system.schema_columns
  572. WHERE keyspace_name = ?`
  573. var columns []ColumnMetadata
  574. rows := s.control.query(stmt, keyspace).Scanner()
  575. for rows.Next() {
  576. var (
  577. column = ColumnMetadata{Keyspace: keyspace}
  578. indexOptionsJSON []byte
  579. )
  580. err := rows.Scan(&column.Table,
  581. &column.Name,
  582. &column.ComponentIndex,
  583. &column.Validator,
  584. &column.Index.Name,
  585. &column.Index.Type,
  586. &indexOptionsJSON,
  587. &column.Kind,
  588. )
  589. if err != nil {
  590. return nil, err
  591. }
  592. if len(indexOptionsJSON) > 0 {
  593. err := json.Unmarshal(indexOptionsJSON, &column.Index.Options)
  594. if err != nil {
  595. return nil, fmt.Errorf(
  596. "Invalid JSON value '%s' as index_options for column '%s' in table '%s': %v",
  597. indexOptionsJSON,
  598. column.Name,
  599. column.Table,
  600. err)
  601. }
  602. }
  603. columns = append(columns, column)
  604. }
  605. if err := rows.Err(); err != nil {
  606. return nil, err
  607. }
  608. return columns, nil
  609. }
  610. func (s *Session) scanColumnMetadataSystem(keyspace string) ([]ColumnMetadata, error) {
  611. const stmt = `
  612. SELECT
  613. table_name,
  614. column_name,
  615. clustering_order,
  616. type,
  617. kind,
  618. position
  619. FROM system_schema.columns
  620. WHERE keyspace_name = ?`
  621. var columns []ColumnMetadata
  622. rows := s.control.query(stmt, keyspace).Scanner()
  623. for rows.Next() {
  624. column := ColumnMetadata{Keyspace: keyspace}
  625. err := rows.Scan(&column.Table,
  626. &column.Name,
  627. &column.ClusteringOrder,
  628. &column.Validator,
  629. &column.Kind,
  630. &column.ComponentIndex,
  631. )
  632. if err != nil {
  633. return nil, err
  634. }
  635. columns = append(columns, column)
  636. }
  637. if err := rows.Err(); err != nil {
  638. return nil, err
  639. }
  640. // TODO(zariel): get column index info from system_schema.indexes
  641. return columns, nil
  642. }
  643. // query for only the column metadata in the specified keyspace from system.schema_columns
  644. func getColumnMetadata(session *Session, keyspaceName string) ([]ColumnMetadata, error) {
  645. var (
  646. columns []ColumnMetadata
  647. err error
  648. )
  649. // Deal with differences in protocol versions
  650. if session.cfg.ProtoVersion == 1 {
  651. columns, err = session.scanColumnMetadataV1(keyspaceName)
  652. } else if session.useSystemSchema { // Cassandra 3.x+
  653. columns, err = session.scanColumnMetadataSystem(keyspaceName)
  654. } else {
  655. columns, err = session.scanColumnMetadataV2(keyspaceName)
  656. }
  657. if err != nil && err != ErrNotFound {
  658. return nil, fmt.Errorf("Error querying column schema: %v", err)
  659. }
  660. return columns, nil
  661. }
  662. // type definition parser state
  663. type typeParser struct {
  664. input string
  665. index int
  666. }
  667. // the type definition parser result
  668. type typeParserResult struct {
  669. isComposite bool
  670. types []TypeInfo
  671. reversed []bool
  672. collections map[string]TypeInfo
  673. }
  674. // Parse the type definition used for validator and comparator schema data
  675. func parseType(def string) typeParserResult {
  676. parser := &typeParser{input: def}
  677. return parser.parse()
  678. }
  679. const (
  680. REVERSED_TYPE = "org.apache.cassandra.db.marshal.ReversedType"
  681. COMPOSITE_TYPE = "org.apache.cassandra.db.marshal.CompositeType"
  682. COLLECTION_TYPE = "org.apache.cassandra.db.marshal.ColumnToCollectionType"
  683. LIST_TYPE = "org.apache.cassandra.db.marshal.ListType"
  684. SET_TYPE = "org.apache.cassandra.db.marshal.SetType"
  685. MAP_TYPE = "org.apache.cassandra.db.marshal.MapType"
  686. )
  687. // represents a class specification in the type def AST
  688. type typeParserClassNode struct {
  689. name string
  690. params []typeParserParamNode
  691. // this is the segment of the input string that defined this node
  692. input string
  693. }
  694. // represents a class parameter in the type def AST
  695. type typeParserParamNode struct {
  696. name *string
  697. class typeParserClassNode
  698. }
  699. func (t *typeParser) parse() typeParserResult {
  700. // parse the AST
  701. ast, ok := t.parseClassNode()
  702. if !ok {
  703. // treat this is a custom type
  704. return typeParserResult{
  705. isComposite: false,
  706. types: []TypeInfo{
  707. NativeType{
  708. typ: TypeCustom,
  709. custom: t.input,
  710. },
  711. },
  712. reversed: []bool{false},
  713. collections: nil,
  714. }
  715. }
  716. // interpret the AST
  717. if strings.HasPrefix(ast.name, COMPOSITE_TYPE) {
  718. count := len(ast.params)
  719. // look for a collections param
  720. last := ast.params[count-1]
  721. collections := map[string]TypeInfo{}
  722. if strings.HasPrefix(last.class.name, COLLECTION_TYPE) {
  723. count--
  724. for _, param := range last.class.params {
  725. // decode the name
  726. var name string
  727. decoded, err := hex.DecodeString(*param.name)
  728. if err != nil {
  729. log.Printf(
  730. "Error parsing type '%s', contains collection name '%s' with an invalid format: %v",
  731. t.input,
  732. *param.name,
  733. err,
  734. )
  735. // just use the provided name
  736. name = *param.name
  737. } else {
  738. name = string(decoded)
  739. }
  740. collections[name] = param.class.asTypeInfo()
  741. }
  742. }
  743. types := make([]TypeInfo, count)
  744. reversed := make([]bool, count)
  745. for i, param := range ast.params[:count] {
  746. class := param.class
  747. reversed[i] = strings.HasPrefix(class.name, REVERSED_TYPE)
  748. if reversed[i] {
  749. class = class.params[0].class
  750. }
  751. types[i] = class.asTypeInfo()
  752. }
  753. return typeParserResult{
  754. isComposite: true,
  755. types: types,
  756. reversed: reversed,
  757. collections: collections,
  758. }
  759. } else {
  760. // not composite, so one type
  761. class := *ast
  762. reversed := strings.HasPrefix(class.name, REVERSED_TYPE)
  763. if reversed {
  764. class = class.params[0].class
  765. }
  766. typeInfo := class.asTypeInfo()
  767. return typeParserResult{
  768. isComposite: false,
  769. types: []TypeInfo{typeInfo},
  770. reversed: []bool{reversed},
  771. }
  772. }
  773. }
  774. func (class *typeParserClassNode) asTypeInfo() TypeInfo {
  775. if strings.HasPrefix(class.name, LIST_TYPE) {
  776. elem := class.params[0].class.asTypeInfo()
  777. return CollectionType{
  778. NativeType: NativeType{
  779. typ: TypeList,
  780. },
  781. Elem: elem,
  782. }
  783. }
  784. if strings.HasPrefix(class.name, SET_TYPE) {
  785. elem := class.params[0].class.asTypeInfo()
  786. return CollectionType{
  787. NativeType: NativeType{
  788. typ: TypeSet,
  789. },
  790. Elem: elem,
  791. }
  792. }
  793. if strings.HasPrefix(class.name, MAP_TYPE) {
  794. key := class.params[0].class.asTypeInfo()
  795. elem := class.params[1].class.asTypeInfo()
  796. return CollectionType{
  797. NativeType: NativeType{
  798. typ: TypeMap,
  799. },
  800. Key: key,
  801. Elem: elem,
  802. }
  803. }
  804. // must be a simple type or custom type
  805. info := NativeType{typ: getApacheCassandraType(class.name)}
  806. if info.typ == TypeCustom {
  807. // add the entire class definition
  808. info.custom = class.input
  809. }
  810. return info
  811. }
  812. // CLASS := ID [ PARAMS ]
  813. func (t *typeParser) parseClassNode() (node *typeParserClassNode, ok bool) {
  814. t.skipWhitespace()
  815. startIndex := t.index
  816. name, ok := t.nextIdentifier()
  817. if !ok {
  818. return nil, false
  819. }
  820. params, ok := t.parseParamNodes()
  821. if !ok {
  822. return nil, false
  823. }
  824. endIndex := t.index
  825. node = &typeParserClassNode{
  826. name: name,
  827. params: params,
  828. input: t.input[startIndex:endIndex],
  829. }
  830. return node, true
  831. }
  832. // PARAMS := "(" PARAM { "," PARAM } ")"
  833. // PARAM := [ PARAM_NAME ":" ] CLASS
  834. // PARAM_NAME := ID
  835. func (t *typeParser) parseParamNodes() (params []typeParserParamNode, ok bool) {
  836. t.skipWhitespace()
  837. // the params are optional
  838. if t.index == len(t.input) || t.input[t.index] != '(' {
  839. return nil, true
  840. }
  841. params = []typeParserParamNode{}
  842. // consume the '('
  843. t.index++
  844. t.skipWhitespace()
  845. for t.input[t.index] != ')' {
  846. // look for a named param, but if no colon, then we want to backup
  847. backupIndex := t.index
  848. // name will be a hex encoded version of a utf-8 string
  849. name, ok := t.nextIdentifier()
  850. if !ok {
  851. return nil, false
  852. }
  853. hasName := true
  854. // TODO handle '=>' used for DynamicCompositeType
  855. t.skipWhitespace()
  856. if t.input[t.index] == ':' {
  857. // there is a name for this parameter
  858. // consume the ':'
  859. t.index++
  860. t.skipWhitespace()
  861. } else {
  862. // no name, backup
  863. hasName = false
  864. t.index = backupIndex
  865. }
  866. // parse the next full parameter
  867. classNode, ok := t.parseClassNode()
  868. if !ok {
  869. return nil, false
  870. }
  871. if hasName {
  872. params = append(
  873. params,
  874. typeParserParamNode{name: &name, class: *classNode},
  875. )
  876. } else {
  877. params = append(
  878. params,
  879. typeParserParamNode{class: *classNode},
  880. )
  881. }
  882. t.skipWhitespace()
  883. if t.input[t.index] == ',' {
  884. // consume the comma
  885. t.index++
  886. t.skipWhitespace()
  887. }
  888. }
  889. // consume the ')'
  890. t.index++
  891. return params, true
  892. }
  893. func (t *typeParser) skipWhitespace() {
  894. for t.index < len(t.input) && isWhitespaceChar(t.input[t.index]) {
  895. t.index++
  896. }
  897. }
  898. func isWhitespaceChar(c byte) bool {
  899. return c == ' ' || c == '\n' || c == '\t'
  900. }
  901. // ID := LETTER { LETTER }
  902. // LETTER := "0"..."9" | "a"..."z" | "A"..."Z" | "-" | "+" | "." | "_" | "&"
  903. func (t *typeParser) nextIdentifier() (id string, found bool) {
  904. startIndex := t.index
  905. for t.index < len(t.input) && isIdentifierChar(t.input[t.index]) {
  906. t.index++
  907. }
  908. if startIndex == t.index {
  909. return "", false
  910. }
  911. return t.input[startIndex:t.index], true
  912. }
  913. func isIdentifierChar(c byte) bool {
  914. return (c >= '0' && c <= '9') ||
  915. (c >= 'a' && c <= 'z') ||
  916. (c >= 'A' && c <= 'Z') ||
  917. c == '-' ||
  918. c == '+' ||
  919. c == '.' ||
  920. c == '_' ||
  921. c == '&'
  922. }