metadata.go 21 KB

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