metadata.go 23 KB

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