diff --git a/cbt.go b/cbt.go index 75753c4..d5ee365 100755 --- a/cbt.go +++ b/cbt.go @@ -870,9 +870,18 @@ var commands = []struct { Name: "sql", Desc: "Execute a SQL query on an Instance", do: doSql, - Usage: "cbt sql \n\n" + - "See https://cloud.google.com/bigtable/docs/reference/sql/googlesql-reference-overview for more information.\n" + - "Note that this does not support parameterized queries.\n", + Usage: "cbt sql [args ...]\n\n" + + " table-format= Whether to return the results in a table format (Default: true)\n\n" + + " Examples:\n" + + " cbt sql 'SELECT cell_data[\"os_build\"] as os_build, cell_data[\"os_name\"] as os_name FROM mobile-time-series LIMIT 10'\n" + + " cbt sql 'SELECT FORMAT(\"%s,%s,%s\",\n" + + " SAFE_CONVERT_BYTES_TO_STRING(cell_data[\"os_build\"]),\n" + + " SAFE_CONVERT_BYTES_TO_STRING(cell_data[\"os_name\"]),\n" + + " SAFE_CONVERT_BYTES_TO_STRING(cell_data[\"os_version\"])\n" + + " ) AS osBuild_osName_osVersion\n" + + " FROM mobile-time-series' table-format=false\n\n" + + " See https://cloud.google.com/bigtable/docs/reference/sql/googlesql-reference-overview for more information.\n" + + " Note that this does not support parameterized queries.\n", Required: ProjectAndInstanceRequired, }, } @@ -2057,8 +2066,8 @@ func getFormattedValue(row bigtable.ResultRow, index int) (string, error) { } func doSql(ctx context.Context, args ...string) { - if len(args) != 1 { - log.Fatalf("usage: cbt sql ") + if len(args) < 1 { + log.Fatalf("usage: cbt sql [args ...]") } query := args[0] @@ -2071,6 +2080,17 @@ func doSql(ctx context.Context, args ...string) { if err != nil { log.Fatalf("While binding statement: %v", err) } + parsed, err := parseArgs(args[1:], []string{"table-format"}) + if err != nil { + log.Fatal(err) + } + tableFormat := true + if tableFormatStr := parsed["table-format"]; tableFormatStr != "" { + tableFormat, err = strconv.ParseBool(tableFormatStr) + if err != nil { + log.Fatal(err) + } + } // Execute the query, writing the result into the table util. table := tablewriter.NewWriter(os.Stdout) @@ -2079,13 +2099,24 @@ func doSql(ctx context.Context, args ...string) { table.SetAlignment(tablewriter.ALIGN_LEFT) table.SetAutoWrapText(false) + var headerSeen bool boundStmt.Execute(ctx, func(row bigtable.ResultRow) bool { - // Okay to output the header multiple times, only the first one has an effect. hs := make([]string, len(row.Metadata.Columns)) - for i := 0; i < len(row.Metadata.Columns); i++ { - hs[i] = row.Metadata.Columns[i].Name + if !headerSeen { + for i := 0; i < len(row.Metadata.Columns); i++ { + hs[i] = row.Metadata.Columns[i].Name + if !tableFormat { + fmt.Print(hs[i]) + } + } + } + if !headerSeen { + table.SetHeader(hs) + if !tableFormat { + fmt.Print("\n") + } + headerSeen = true } - table.SetHeader(hs) // Write out all values in the table. vs := make([]string, len(row.Metadata.Columns)) @@ -2095,11 +2126,19 @@ func doSql(ctx context.Context, args ...string) { log.Fatalf("Could not get formatted value for column %v: %v", row.Metadata.Columns[i], err) } vs[i] = v + if !tableFormat { + fmt.Print(v) + } } table.Append(vs) + if !tableFormat { + fmt.Print("\n") + } return true }) - table.Render() + if tableFormat { + table.Render() + } } func doSampleRowKeys(ctx context.Context, args ...string) { diff --git a/cbtdoc.go b/cbtdoc.go index b65f5f9..532dc7e 100644 --- a/cbtdoc.go +++ b/cbtdoc.go @@ -17,7 +17,7 @@ //go:generate go run cbt.go gcpolicy.go cbtconfig.go valueformatting.go -o cbtdoc.go doc /* -The `cbt` CLI is a command-line interface that lets you interact with Cloud Bigtable. +The `cbt` CLI is a command-line interface that lets you interact with Bigtable. See the [cbt CLI overview](https://cloud.google.com/bigtable/docs/cbt-overview) to learn how to install the `cbt` CLI. Before you use the `cbt` CLI, you should be familiar with the [Bigtable overview](https://cloud.google.com/bigtable/docs/overview). @@ -30,6 +30,7 @@ Usage: The commands are: + addtocell Add a value to an aggregate cell (write) count Count rows in a table createappprofile Create app profile for an instance createcluster Create a cluster in the configured instance @@ -57,12 +58,16 @@ The commands are: notices Display licence information for any third-party dependencies read Read rows set Set value of a cell (write) - addtocell Add a value to an aggregate cell (write) + checkandmutate Set a value based on the presence of any cell that matches the constraints + readmodifywrite Update a cell with incremental operations based on the latest value of the cell setgcpolicy Set the garbage-collection policy (age, versions) for a column family + setvaluetype Update column family's value type. updateappprofile Update app profile for an instance updatecluster Update a cluster in the configured instance version Print the current cbt version waitforreplication Block until all the completed writes have been replicated to all the clusters + samplerowkeys Sample the row keys in a table + sql Execute a SQL query on an Instance The options are: @@ -79,8 +84,8 @@ Example: cbt -instance=my-instance ls Use "cbt help \" for more information about a command. -Preview features are not currently available to most Cloud Bigtable customers. Alpha -features might be changed in backward-incompatible ways and are not recommended +Preview features are not available to most Bigtable customers, they +might be changed in backward-incompatible ways and are not recommended for production use. They are not subject to any SLA or deprecation policy. Syntax rules for the Bash shell apply to the `cbt` CLI. This means, for example, @@ -104,6 +109,23 @@ options to your ~/.cbtrc file in the following format: All values are optional and can be overridden at the command prompt. +Add a value to an aggregate cell (write) + +Usage: + + cbt addtocell [app-profile=] :=[@] ... + + app-profile= The app profile ID to use for the request + :=[@] may be repeated to set multiple cells. + + If can be parsed as an integer it will be used as one, otherwise the call will fail. + timestamp is an optional integer. + If the timestamp cannot be parsed, '@' will be interpreted as part of the value. + For most uses, a timestamp is the number of microseconds since 1970-01-01 00:00:00 UTC. + + Examples: + cbt addtocell table1 user1 sum_cf:col1=1@12345 + # Count rows in a table Usage: @@ -126,6 +148,7 @@ Usage: Usage: cbt createcluster + cluster-id Permanent, unique ID for the cluster in the instance zone The zone in which to create the cluster num-nodes The number of nodes to create @@ -146,6 +169,7 @@ Usage: Usage: cbt createinstance + instance-id Permanent, unique ID for the instance display-name Description of the instance cluster-id Permanent, unique ID for the cluster in the instance @@ -161,10 +185,11 @@ Usage: cbt createtable [families=::,...] [splits=,,...] + families Column families and their associated garbage collection (gc) policies and types. Put gc policies in quotes when they include shell operators && and ||. For gcpolicy, see "setgcpolicy". - Currently only the type "intsum" is supported. + Types "intsum", "intmin", "intmax", and "inthll" are supported. splits Row key(s) where the table should initially be split Example: cbt createtable mobile-time-series "families=stats_summary:maxage=10d||maxversions=1,stats_detail:maxage=10d||maxversions=1" splits=tablet,phone @@ -198,6 +223,7 @@ Usage: Usage: cbt deletecolumn [app-profile=] + app-profile= The app profile ID to use for the request Example: cbt deletecolumn mobile-time-series phone#4c410523#20190501 stats_summary os_name @@ -223,6 +249,7 @@ Usage: Usage: cbt deleterow [app-profile=] + app-profile= The app profile ID to use for the request Example: cbt deleterow mobile-time-series phone#4c410523#20190501 @@ -260,6 +287,7 @@ Usage: Usage: cbt import [app-profile=] [column-family=] [batch-size=<500>] [workers=<1>] [timestamp=] + app-profile= The app profile ID to use for the request column-family= The column family label to use batch-size=<500> The max number of rows per batch write request @@ -314,6 +342,7 @@ Usage: Usage: cbt lookup [columns=:,...] [cells-per-column=] [app-profile=] + row-key String or raw bytes. Raw bytes must be enclosed in single quotes and have a dollar-sign prefix columns=:,... Read only these columns, comma-separated cells-per-column= Read only this number of cells per column @@ -351,6 +380,7 @@ Usage: Usage: cbt read [authorized-view=] [start=] [end=] [prefix=] [regex=] [columns=:,...] [count=] [cells-per-column=] [app-profile=] + authorized-view= Read from the specified authorized view of the table start= Start reading at this row end= Stop reading before this row @@ -379,6 +409,7 @@ Set value of a cell (write) Usage: cbt set [authorized-view=] [app-profile=] :=[@] ... + authorized-view= Write to the specified authorized view of the table app-profile= The app profile ID to use for the request :=[@] may be repeated to set multiple cells. @@ -391,27 +422,49 @@ Usage: cbt set mobile-time-series phone#4c410523#20190501 stats_summary:connected_cell=1@12345 stats_summary:connected_cell=0@1570041766 cbt set mobile-time-series phone#4c410523#20190501 stats_summary:os_build=PQ2A.190405.003 stats_summary:os_name=android -Add a value to an aggregate cell (write) +# Set a value based on the presence of any cell that matches the constraints Usage: - cbt addtocell [app-profile=] :=[@] ... - app-profile= The app profile ID to use for the request - :=[@] may be repeated to set multiple cells. + cbt checkandmutate [columns=,...] [true=:=[@]] [false=:=[@]] + row-key String or raw bytes. Raw bytes must be enclosed in single quotes and have a dollar-sign prefix + columns=:,... Test for values in these columns, comma-separated (optional) + :=[@] A mutation to set if the lookup returned a cell value If can be parsed as an integer it will be used as one, otherwise the call will fail. timestamp is an optional integer. If the timestamp cannot be parsed, '@' will be interpreted as part of the value. For most uses, a timestamp is the number of microseconds since 1970-01-01 00:00:00 UTC. - Examples: - cbt addtocell table1 user1 sum_cf:col1=1@12345 + At least one or both true=... or false=... must be provided. Optionally columns=... will restrict the existence test to the indicated columns. + + Examples: + cbt checkandmutate mobile-time-series phone#4c410523#20190501 false=presence:=1 + cbt checkandmutate mobile-time-series phone#4c410523#20190501 columns=stats_summary:os_build true=stats_summary:connected_cell=1@12345 + +# Update a cell with incremental operations based on the latest value of the cell + +Usage: + + cbt readmodifywrite [append=] [increment=] + + row-key String or raw bytes. Raw bytes must be enclosed in single quotes and have a dollar-sign prefix + family Column family + qualifier Column qualifier + append= Append the given value to the cell + If the cell is unset, it will be treated as an empty value. + increment= Increment the cell by the given integer delta + If the cell is unset, it will be treated as zero. If the cell is set and is not an 8-byte value, the operation will fail. + + Examples: + cbt readmodifywrite mobile-time-series phone#4c410523#20190501 stats_summary boot_count increment=1 # Set the garbage-collection policy (age, versions) for a column family Usage: cbt setgcpolicy ((maxage= | maxversions=) [(and|or) (maxage= | maxversions=),...] | never) [force] + force: Optional flag to override warnings when relaxing the garbage-collection policy on replicated clusters. This may cause your clusters to be temporarily inconsistent, make sure you understand the risks listed at https://cloud.google.com/bigtable/docs/garbage-collection#increasing @@ -424,11 +477,23 @@ Usage: cbt setgcpolicy mobile-time-series stats_detail maxage=10d cbt setgcpolicy mobile-time-series stats_summary maxage=10d or maxversions=1 force +Update column family's value type. + +Usage: + + cbt setvaluetype
+ type: The type to be updated. + Supported type(s): stringutf8bytes: UTF8 encoded string + Updating to or from aggregate types is currently unsupported. + Example: + cbt setvaluetype mobile-time-series vendor-info stringutf8bytes + # Update app profile for an instance Usage: cbt updateappprofile (route-any | [ route-to= : transactional-writes]) [-force] + force: Optional flag to override any warnings causing the command to fail Example: cbt updateappprofile my-instance multi-cluster-app-profile-1 "Use this one." route-any @@ -438,6 +503,7 @@ Usage: Usage: cbt updatecluster [num-nodes=] + cluster-id Permanent, unique ID for the cluster in the instance num-nodes The new number of nodes @@ -454,5 +520,31 @@ Usage: Usage: cbt waitforreplication + +# Sample the row keys in a table + +Usage: + + cbt samplerowkeys + +# Execute a SQL query on an Instance + +Usage: + + cbt sql [args ...] + + table-format= Whether to return the results in a table format (Default: true) + + Examples: + cbt sql 'SELECT cell_data["os_build"] as os_build, cell_data["os_name"] as os_name FROM mobile-time-series LIMIT 10' + cbt sql 'SELECT FORMAT("%s,%s,%s", + SAFE_CONVERT_BYTES_TO_STRING(cell_data["os_build"]), + SAFE_CONVERT_BYTES_TO_STRING(cell_data["os_name"]), + SAFE_CONVERT_BYTES_TO_STRING(cell_data["os_version"]) + ) AS osBuild_osName_osVersion + FROM mobile-time-series' table-format=false + + See https://cloud.google.com/bigtable/docs/reference/sql/googlesql-reference-overview for more information. + Note that this does not support parameterized queries. */ package main