def execute_select_plain(etcd_client, tree, db): """Execute SELECT that reads rows from table.""" result_columns = prepare_columns(tree) result_set = ResultSet(result_columns) table_columns = get_table_columns(etcd_client, db, tree.table) last_row = None for primary_key in list_table(etcd_client, db, tree.table): table_row = get_row_by_primary_key(etcd_client, db, tree.table, primary_key) if tree.where: expr = tree.where if eval_expr((table_columns, table_row), expr)[1]: row = Row(eval_row(table_columns, table_row, tree), etcd_index=table_row.etcd_index, modified_index=table_row.modified_index) result_set.add_row(row) last_row = table_row else: row = Row(eval_row(table_columns, table_row, tree), etcd_index=table_row.etcd_index, modified_index=table_row.modified_index) result_set.add_row(row) last_row = table_row g_function, pos = group_function(table_columns, last_row, tree) if g_function: result_set = group_result_set(g_function, result_set, last_row, tree, pos) return result_set
def execute_wait(etcd_client, tree, db): """Execute WAIT. :param etcd_client: Etcd client. :type etcd_client: Client :param tree: Parsing tree. :type tree: SQLTree :param db: Current database. :type db: str """ result_columns = prepare_columns(tree) result_set = ResultSet(result_columns) table_columns = get_table_columns(etcd_client, db, tree.table) for primary_key in list_table(etcd_client, db, tree.table): table_row = get_row_by_primary_key(etcd_client, db, tree.table, primary_key) etcd_index = table_row.etcd_index if tree.where: expr = tree.where try: wait_index = tree.options['after'] except KeyError: wait_index = etcd_index + 1 if eval_expr((table_columns, table_row), expr)[1]: start = time.time() while True: if time.time() > start + WAIT_WAIT_TIMEOUT: raise InternalError('Wait timeout %d ' 'seconds expired' % WAIT_WAIT_TIMEOUT) try: new_row = get_row_by_primary_key(etcd_client, db, tree.table, primary_key, wait=True, wait_index=wait_index) break except KeyError: wait_index += 1 row = Row(eval_row(table_columns, new_row, tree), etcd_index=new_row.etcd_index, modified_index=new_row.modified_index) result_set.add_row(row) else: row = Row(eval_row(table_columns, table_row, tree), etcd_index=etcd_index, modified_index=etcd_index) result_set.add_row(row) return result_set
def execute_select_no_table(tree): """Execute SELECT that doesn't read from a table. SELECT VERSION() or similar.""" result_columns = prepare_columns(tree) result_set = ResultSet(result_columns) result_row = Row(eval_row(result_columns, Row(()), tree)) result_set.add_row(result_row) return result_set
def show_tables(etcd_client, tree, db): """ Execute SHOW [FULL] TABLES query# :param etcd_client: etcd client :type etcd_client: pyetcd.client.Client :param db: Current database :type db: str :param tree: Parse tree :type tree: SQLTree :return: ResultSet instance :rtype: ResultSet """ columns = ColumnSet().add(Column('Tables_in_%s' % db)) if tree.options['full']: columns.add(Column('Table_type')) result_set = ResultSet(columns) try: etcd_response = etcd_client.read('/%s' % db) except EtcdKeyNotFound: raise OperationalError('No database selected') try: for node in etcd_response.node['nodes']: table_name = node['key'].replace('/%s/' % db, '', 1) row = (table_name, ) if tree.options['full']: row += ('BASE TABLE', ) result_set.add_row(Row(row)) except KeyError: pass return result_set
def test_eval_identifier(): cs = ColumnSet() cs.add(Column('id')) cs.add(Column('name')) row = Row((5, 'aaa')) assert eval_identifier((cs, row), 'id')[1] == 5 assert eval_identifier((cs, row), 'name')[1] == 'aaa'
def test_cursor_fetchone(etcdb_connection): cursor = etcdb_connection.cursor() columns = ColumnSet().add(Column('VERSION()')) rs = ResultSet(columns) rs.add_row(Row(('2.3.7', ))) cursor._result_set = rs row = cursor.fetchone() assert isinstance(row, tuple) assert row == ('2.3.7', )
def get_row_by_primary_key( etcd_client, db, table, primary_key, # pylint: disable=too-many-arguments wait=False, wait_index=None): """ Read row from etcd by its primary key value. :param etcd_client: :type etcd_client: Client :param db: :param table: :param primary_key: Primary key value. :param wait: If True it will wait for a change in the key :type wait: bool :param wait_index: When waiting you can specify index to wait for. :type wait_index: int :return: Row :rtype: Row """ key = "/{db}/{tbl}/{pk}".format(db=db, tbl=table, pk=primary_key) kwargs = {} if wait: kwargs['wait'] = True if wait_index: kwargs['waitIndex'] = wait_index if kwargs: etcd_response = etcd_client.read(key, **kwargs) else: etcd_response = etcd_client.read(key) row = () for _, value in json.loads(etcd_response.node['value']).iteritems(): row += (value, ) try: etcd_index = etcd_response.x_etcd_index except AttributeError: etcd_index = 0 return Row(row, etcd_index=etcd_index, modified_index=etcd_response.node['modifiedIndex'])
def show_databases(etcd_client): """ Execute SHOW [FULL] TABLES query :param etcd_client: etcd client :type etcd_client: pyetcd.client.Client :return: ResultSet instance :rtype: ResultSet """ etcd_response = etcd_client.read('/') columns = ColumnSet().add(Column('Database')) result_set = ResultSet(columns) try: for node in etcd_response.node['nodes']: val = node['key'].lstrip('/') result_set.add_row(Row((val, ))) except KeyError: pass return result_set
def group_result_set(func, result_set, table_row, tree, pos): """Apply a group function to result set and return an aggregated row. :param func: Aggregation function. :type func: callable :param result_set: Result set to aggregate. :type result_set: ResultSet :param table_row: Table row to base aggregated row on. :type table_row: Row :param tree: Parsing tree. :type tree: SQLTree :param pos: Aggregate function position in the resulting row. :type pos: int :return: Result set with aggregated row. :rtype: ResultSet""" group_value = func(result_set) values = list(eval_row(result_set.columns, table_row, tree)) values[pos] = group_value row = Row(tuple(values)) return ResultSet(prepare_columns(tree), [row])
import mock import pytest from pyetcd import EtcdResult, EtcdKeyNotFound from etcdb import ProgrammingError from etcdb.execute.dml.show import show_databases, show_tables, desc_table from etcdb.resultset import ResultSet, ColumnSet, Column, Row from etcdb.sqlparser.sql_tree import SQLTree @pytest.mark.parametrize('content, rows', [( '{"action":"get","node":{"dir":true,"nodes":[{"key":"/foo","dir":true,"modifiedIndex":2102,"createdIndex":2102},{"key":"/bar","dir":true,"modifiedIndex":2152,"createdIndex":2152}]}}', [Row(('foo', )), Row( ('bar', ))]), ('{"action":"get","node":{"dir":true}}', [])]) def test_show_databases(content, rows): response = mock.Mock() response.content = content etcd_response = EtcdResult(response) etcd_client = mock.Mock() etcd_client.read.return_value = etcd_response cols = ColumnSet() cols.add(Column('Database')) # print(cols) rs = ResultSet(cols, rows) # noinspection PyTypeChecker result = show_databases(etcd_client)
def desc_table(etcd_client, tree, db): """ Execute DESC table query# :param etcd_client: etcd client :type etcd_client: pyetcd.client.Client :param tree: Parse tree :type tree: SQLTree :param db: Current database :type db: str :return: ResultSet instance :rtype: ResultSet """ key = '/{db}/{table}/_fields'.format(db=db, table=tree.table) try: etcd_result = etcd_client.read(key) except EtcdKeyNotFound: raise ProgrammingError('Table `{db}`.`{table}` ' 'doesn\'t exist'.format(db=db, table=tree.table)) columns = ColumnSet() columns.add(Column('Field')) columns.add(Column('Type')) columns.add(Column('Null')) columns.add(Column('Key')) columns.add(Column('Default')) columns.add(Column('Extra')) result_set = ResultSet(columns) fields = json.loads(etcd_result.node['value']) for key, value in fields.iteritems(): field_type = value['type'] if value['options']['nullable']: nullable = 'YES' else: nullable = 'NO' indexes = '' if 'primary' in value['options'] and value['options']['primary']: indexes = 'PRI' if 'unique' in value['options'] and value['options']['unique']: indexes = 'UNI' try: default_value = value['options']['default'] except KeyError: default_value = '' extra = '' if 'auto_increment' in value['options'] \ and value['options']['auto_increment']: extra = 'auto_increment' result_set.add_row( Row((key, field_type, nullable, indexes, default_value, extra))) return result_set
ColumnSet().add(Column('id')).add(Column('COUNT(*)')) ) ]) def test_prepare_columns(expressions, cs): tree = SQLTree() tree.expressions = expressions actual_cs = prepare_columns(tree) print('Expected: %s' % cs) print('Actual: %s' % actual_cs) assert actual_cs == cs @pytest.mark.parametrize('cs, row, expressions, result', [ ( ColumnSet().add(Column('id')).add(Column('name')), Row((1, 'aaa')), [ ( ('bool_primary', ('predicate', ('bit_expr', ('simple_expr', ('IDENTIFIER', 'id') ) ) ) ), None), ( ('bool_primary', ('predicate',
rows = () while True: row = cursor.fetchone() if row: assert isinstance(row, tuple) rows += (row, ) else: break assert result == rows @pytest.mark.parametrize('rows, result', [ ( [ Row(('information_schema',)), Row(('mysql',)), Row(('performance_schema',)), Row(('sys',)), Row(('test',)) ], ( ('information_schema',), ('mysql',), ('performance_schema',), ('sys',), ('test',) ), ), ( [],
import pytest from etcdb.eval_expr import etcdb_count, eval_expr from etcdb.resultset import ResultSet, ColumnSet, Column, Row from etcdb.sqlparser.sql_tree import SQLTree @pytest.mark.parametrize('rows, count', [([], 0), (None, 0), ([Row( ('1', ))], 1), ([ Row(('1', )), Row(('2', )), Row(('3', )), ], 3)]) def test_etcdb_count(rows, count): cs = ColumnSet().add(Column('id')) rs = ResultSet(cs, rows) assert etcdb_count(rs) == count def test_expr_in_simple_expr(): tree = SQLTree() tree.expressions = [(('bool_primary', ('predicate', ('bit_expr', ('simple_expr', ('expr', ('bool_primary', ('predicate', ('bit_expr', ('simple_expr', ('literal', '1')))))))))), 'a')]