metadata.go 23 KB

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