mirror of https://github.com/apache/cassandra
cqlsh: Fix handling of CAS statement results
Patch by Tyler Hobbs; reviewed by Aleksey Yeschenko for CASSANDRA-7671
This commit is contained in:
parent
f36d1b51b7
commit
d586ea8980
|
|
@ -1,4 +1,5 @@
|
||||||
2.1.1
|
2.1.1
|
||||||
|
* (cqlsh) Fix handling of CAS statement results (CASSANDRA-7671)
|
||||||
* (cqlsh) COPY TO/FROM improvements (CASSANDRA-7405)
|
* (cqlsh) COPY TO/FROM improvements (CASSANDRA-7405)
|
||||||
* Support list index operations with conditions (CASSANDRA-7499)
|
* Support list index operations with conditions (CASSANDRA-7499)
|
||||||
* Add max live/tombstoned cells to nodetool cfstats output (CASSANDRA-7731)
|
* Add max live/tombstoned cells to nodetool cfstats output (CASSANDRA-7731)
|
||||||
|
|
|
||||||
34
bin/cqlsh
34
bin/cqlsh
|
|
@ -585,13 +585,13 @@ class Shell(cmd.Cmd):
|
||||||
self.decoding_errors.append(err)
|
self.decoding_errors.append(err)
|
||||||
return format_value(err, self.output_codec.name, addcolor=self.color)
|
return format_value(err, self.output_codec.name, addcolor=self.color)
|
||||||
|
|
||||||
def myformat_colname(self, name, cfMetaData = None):
|
def myformat_colname(self, name, table_meta=None):
|
||||||
column_colors = COLUMN_NAME_COLORS.copy()
|
column_colors = COLUMN_NAME_COLORS.copy()
|
||||||
# check column role and color appropriately
|
# check column role and color appropriately
|
||||||
if cfMetaData:
|
if table_meta:
|
||||||
if name in [col.name for col in cfMetaData.partition_key]:
|
if name in [col.name for col in table_meta.partition_key]:
|
||||||
column_colors.default_factory = lambda : RED
|
column_colors.default_factory = lambda : RED
|
||||||
elif name in [col.name for col in cfMetaData.clustering_key]:
|
elif name in [col.name for col in table_meta.clustering_key]:
|
||||||
column_colors.default_factory = lambda : CYAN
|
column_colors.default_factory = lambda : CYAN
|
||||||
return self.myformat_value(name, colormap=column_colors)
|
return self.myformat_value(name, colormap=column_colors)
|
||||||
|
|
||||||
|
|
@ -913,6 +913,12 @@ class Shell(cmd.Cmd):
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def parse_for_table_meta(self, query_string):
|
||||||
|
parsed = cqlruleset.cql_parse(query_string)[1]
|
||||||
|
ks = self.cql_unprotect_name(parsed.get_binding('ksname', None))
|
||||||
|
cf = self.cql_unprotect_name(parsed.get_binding('cfname'))
|
||||||
|
return self.get_table_meta(ks, cf)
|
||||||
|
|
||||||
def perform_simple_statement(self, statement, with_default_limit=False):
|
def perform_simple_statement(self, statement, with_default_limit=False):
|
||||||
if not statement:
|
if not statement:
|
||||||
return False
|
return False
|
||||||
|
|
@ -930,25 +936,21 @@ class Shell(cmd.Cmd):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if statement.query_string[:6].lower() == 'select' or statement.query_string.lower().startswith("list"):
|
if statement.query_string[:6].lower() == 'select' or statement.query_string.lower().startswith("list"):
|
||||||
parsed = cqlruleset.cql_parse(statement.query_string)[1]
|
self.print_result(rows, with_default_limit, self.parse_for_table_meta(statement.query_string))
|
||||||
ks = self.cql_unprotect_name(parsed.get_binding('ksname', None))
|
|
||||||
cf = self.cql_unprotect_name(parsed.get_binding('cfname'))
|
|
||||||
cfMetaData = self.get_table_meta(ks, cf)
|
|
||||||
self.print_result(rows, with_default_limit, cfMetaData)
|
|
||||||
elif rows:
|
elif rows:
|
||||||
# CAS INSERT/UPDATE
|
# CAS INSERT/UPDATE
|
||||||
self.writeresult("")
|
self.writeresult("")
|
||||||
self.print_static_result(rows)
|
self.print_static_result(rows, self.parse_for_table_meta(statement.query_string))
|
||||||
self.flush_output()
|
self.flush_output()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def print_result(self, rows, with_default_limit, cfMetaData):
|
def print_result(self, rows, with_default_limit, table_meta):
|
||||||
self.decoding_errors = []
|
self.decoding_errors = []
|
||||||
|
|
||||||
self.writeresult("")
|
self.writeresult("")
|
||||||
if rows:
|
if rows:
|
||||||
rows = list(rows) # this may be an iterator if the result is large enough to page
|
rows = list(rows) # this may be an iterator if the result is large enough to page
|
||||||
self.print_static_result(rows, cfMetaData)
|
self.print_static_result(rows, table_meta)
|
||||||
self.writeresult("(%d rows)" % len(rows or []))
|
self.writeresult("(%d rows)" % len(rows or []))
|
||||||
|
|
||||||
if self.decoding_errors:
|
if self.decoding_errors:
|
||||||
|
|
@ -965,16 +967,16 @@ class Shell(cmd.Cmd):
|
||||||
% DEFAULT_SELECT_LIMIT, color=RED)
|
% DEFAULT_SELECT_LIMIT, color=RED)
|
||||||
self.writeresult("")
|
self.writeresult("")
|
||||||
|
|
||||||
def print_static_result(self, rows, cfMetaData):
|
def print_static_result(self, rows, table_meta):
|
||||||
if not rows:
|
if not rows:
|
||||||
# print header only
|
# print header only
|
||||||
colnames = cfMetaData.columns.keys() # full header
|
colnames = table_meta.columns.keys() # full header
|
||||||
formatted_names = [self.myformat_colname(name, cfMetaData) for name in colnames]
|
formatted_names = [self.myformat_colname(name, table_meta) for name in colnames]
|
||||||
self.print_formatted_result(formatted_names, None)
|
self.print_formatted_result(formatted_names, None)
|
||||||
return
|
return
|
||||||
|
|
||||||
colnames = rows[0].keys()
|
colnames = rows[0].keys()
|
||||||
formatted_names = [self.myformat_colname(name, cfMetaData) for name in colnames]
|
formatted_names = [self.myformat_colname(name, table_meta) for name in colnames]
|
||||||
formatted_values = [map(self.myformat_value, row.values()) for row in rows]
|
formatted_values = [map(self.myformat_value, row.values()) for row in rows]
|
||||||
|
|
||||||
if self.expand_enabled:
|
if self.expand_enabled:
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,7 @@ JUNK ::= /([ \t\r\f\v]+|(--|[/][/])[^\n\r]*([\n\r]|$)|[/][*].*?[*][/])/ ;
|
||||||
| <blobLiteral>
|
| <blobLiteral>
|
||||||
| <collectionLiteral>
|
| <collectionLiteral>
|
||||||
| <functionName> <functionArguments>
|
| <functionName> <functionArguments>
|
||||||
|
| "NULL"
|
||||||
;
|
;
|
||||||
|
|
||||||
<functionArguments> ::= "(" ( <term> ( "," <term> )* )? ")"
|
<functionArguments> ::= "(" ( <term> ( "," <term> )* )? ")"
|
||||||
|
|
@ -673,6 +674,7 @@ syntax_rules += r'''
|
||||||
( "," [colname]=<cident> )* ")"
|
( "," [colname]=<cident> )* ")"
|
||||||
"VALUES" "(" [newval]=<term> valcomma="," [newval]=<term>
|
"VALUES" "(" [newval]=<term> valcomma="," [newval]=<term>
|
||||||
( valcomma="," [newval]=<term> )* valcomma=")"
|
( valcomma="," [newval]=<term> )* valcomma=")"
|
||||||
|
( "IF" "NOT" "EXISTS")?
|
||||||
( "USING" [insertopt]=<usingOption>
|
( "USING" [insertopt]=<usingOption>
|
||||||
( "AND" [insertopt]=<usingOption> )* )?
|
( "AND" [insertopt]=<usingOption> )* )?
|
||||||
;
|
;
|
||||||
|
|
@ -741,13 +743,19 @@ syntax_rules += r'''
|
||||||
( "AND" [updateopt]=<usingOption> )* )?
|
( "AND" [updateopt]=<usingOption> )* )?
|
||||||
"SET" <assignment> ( "," <assignment> )*
|
"SET" <assignment> ( "," <assignment> )*
|
||||||
"WHERE" <whereClause>
|
"WHERE" <whereClause>
|
||||||
|
( "IF" <conditions> )?
|
||||||
;
|
;
|
||||||
<assignment> ::= updatecol=<cident>
|
<assignment> ::= updatecol=<cident>
|
||||||
( "=" update_rhs=( <value> | <cident> )
|
( "=" update_rhs=( <term> | <cident> )
|
||||||
( counterop=( "+" | "-" ) inc=<wholenumber>
|
( counterop=( "+" | "-" ) inc=<wholenumber>
|
||||||
| listadder="+" listcol=<cident> )
|
| listadder="+" listcol=<cident> )?
|
||||||
| indexbracket="[" <term> "]" "=" <term> )
|
| indexbracket="[" <term> "]" "=" <term> )
|
||||||
;
|
;
|
||||||
|
<conditions> ::= <condition> ( "AND" <condition> )*
|
||||||
|
;
|
||||||
|
<condition> ::= <cident> ( "[" <term> "]" )? ( ( "=" | "<" | ">" | "<=" | ">=" | "!=" ) <term>
|
||||||
|
| "IN" "(" <term> ( "," <term> )* ")")
|
||||||
|
;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@completer_for('updateStatement', 'updateopt')
|
@completer_for('updateStatement', 'updateopt')
|
||||||
|
|
@ -819,6 +827,7 @@ syntax_rules += r'''
|
||||||
"FROM" cf=<columnFamilyName>
|
"FROM" cf=<columnFamilyName>
|
||||||
( "USING" [delopt]=<deleteOption> )?
|
( "USING" [delopt]=<deleteOption> )?
|
||||||
"WHERE" <whereClause>
|
"WHERE" <whereClause>
|
||||||
|
( "IF" ( "EXISTS" | <conditions> ) )?
|
||||||
;
|
;
|
||||||
<deleteSelector> ::= delcol=<cident> ( memberbracket="[" memberselector=<term> "]" )?
|
<deleteSelector> ::= delcol=<cident> ( memberbracket="[" memberselector=<term> "]" )?
|
||||||
;
|
;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from functools import partial
|
|
||||||
import re
|
import re
|
||||||
from .saferscanner import SaferScanner
|
from .saferscanner import SaferScanner
|
||||||
|
|
||||||
|
|
@ -24,6 +23,9 @@ class LexingError(Exception):
|
||||||
bad_char = len(rulestr) - len(unmatched)
|
bad_char = len(rulestr) - len(unmatched)
|
||||||
linenum = rulestr[:bad_char].count('\n') + 1
|
linenum = rulestr[:bad_char].count('\n') + 1
|
||||||
charnum = len(rulestr[:bad_char].rsplit('\n', 1)[-1]) + 1
|
charnum = len(rulestr[:bad_char].rsplit('\n', 1)[-1]) + 1
|
||||||
|
snippet_start = max(0, min(len(rulestr), bad_char - 10))
|
||||||
|
snippet_end = max(0, min(len(rulestr), bad_char + 10))
|
||||||
|
msg += " (Error at: '...%s...')" % (rulestr[snippet_start:snippet_end],)
|
||||||
raise cls(linenum, charnum, msg)
|
raise cls(linenum, charnum, msg)
|
||||||
|
|
||||||
def __init__(self, linenum, charnum, msg='Lexing error'):
|
def __init__(self, linenum, charnum, msg='Lexing error'):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue