def __init__(self, columns, rows=None): if not isinstance(columns, ColumnSet): raise ProgrammingError('%s must be ColumnSet' % columns) if columns.empty: raise ProgrammingError('columns must not be empty') self.columns = columns if rows: self.rows = rows for row in self.rows: self._update_print_width(row) else: self.rows = [] self._pos = 0
def get_table_row(self, tree, pk): db = self._get_current_db(tree) table = tree.table if pk: key = "/{db}/{tbl}/{pk}".format(db=db, tbl=table, pk=pk) etcd_response = self.connection.client.read(key) full_row = json.loads(etcd_response.node['value']) row = () for e in tree.expressions: field_name = e['name'] field = None if e['type'] == 'function': field = self._eval_function(e['name'], db=db, tbl=table) if e['type'] == 'variable': field = self._eval_variable(e['name']) if e['type'] == 'field': try: field = full_row[field_name] except KeyError: raise ProgrammingError('Error: Field %s not found' % field_name) row += (field, ) return row else: # One row if pk is None row = () for e in tree.expressions: field = None if e['type'] == 'function': field = self._eval_function(e['name'], db=db, tbl=table) if e['type'] == 'variable': field = self._eval_variable(e['name']) row += (field, ) return row
def __init__(self, row, etcd_index=0, modified_index=0): if not isinstance(row, tuple): raise ProgrammingError('%s must be tuple') self._row = row self._field_position = 0 self._etcd_index = etcd_index self._modified_index = modified_index
def add(self, column): """Add column to ColumnSet :param column: Column instance :type column: Column :return: Updated CoulmnSet instance :rtype: ColumnSet """ if isinstance(column, Column): self._columns.append(column) else: raise ProgrammingError('%s must be Column type' % column) return self
def create_database(etcd_client, tree): """ Create database. :param etcd_client: Etcd client :type etcd_client: Client :param tree: Parsing tree :type tree: SQLTree """ try: etcd_client.mkdir('/%s' % tree.db) except EtcdNodeExist: raise ProgrammingError("Can't create database '%s'; database exists" % tree.db)
def create_table(etcd_client, tree, db=None): """ Create table. :param etcd_client: Etcd client :type etcd_client: Client :param tree: Parsing tree :type tree: SQLTree :param db: Database name to use if not defined in the parsing tree. :type db: str :raise ProgrammingError: If primary key is not defined, or the primary key is NULL-able. :raise OperationalError: if database is not selected or table exists. """ database_exists_or_raise(etcd_client, db) pk_field = None for field_name, value in tree.fields.iteritems(): try: if value['options']['primary']: pk_field = field_name except KeyError: pass if not pk_field: raise ProgrammingError('Primary key must be defined') if tree.fields[pk_field]['options']['nullable']: raise ProgrammingError('Primary key must be NOT NULL') try: full_table_name = '/%s/%s' % (db, tree.table) etcd_client.mkdir(full_table_name) etcd_client.write(full_table_name + "/_fields", json.dumps(tree.fields)) except EtcdNodeExist: raise OperationalError("Table '%s' already exists" % tree.table)
def _execute_create_table(self, tree): db = self._get_current_db(tree) pk_field = None for field_name, value in tree.fields.iteritems(): try: if value['options']['primary']: pk_field = field_name except KeyError: pass if not pk_field: raise ProgrammingError('Primary key must be defined') if tree.fields[pk_field]['options']['nullable']: raise ProgrammingError('Primary key must be NOT NULL') try: table_name = '/%s/%s' % (db, tree.table) self.connection.client.mkdir(table_name) self.connection.client.write(table_name + "/_fields", json.dumps(tree.fields)) except EtcdNodeExist as err: raise ProgrammingError("Failed to create table: %s" % err)
def _execute_desc_table(self, tree): db = self._get_current_db(tree) table = tree.table key = '/{db}/{table}/_fields'.format(db=db, table=table) try: etcd_result = self.connection.client.read(key) except EtcdKeyNotFound: raise ProgrammingError( 'Table `{db}`.`{table}` doesn\'t exist'.format(db=db, table=table)) fields = json.loads(etcd_result.node['value']) rows = () for k, v in fields.iteritems(): field_type = v['type'] if v['options']['nullable']: nullable = 'YES' else: nullable = 'NO' indexes = '' if 'primary' in v['options'] and v['options']['primary']: indexes = 'PRI' if 'unique' in v['options'] and v['options']['unique']: indexes = 'UNI' try: default_value = v['options']['default'] except KeyError: default_value = '' extra = '' if 'auto_increment' in v['options'] and v['options'][ 'auto_increment']: extra = 'auto_increment' row = (k, field_type, nullable, indexes, default_value, extra) rows += (row, ) return ('Field', 'Type', 'Null', 'Key', 'Default', 'Extra'), rows
def get_table_columns(etcd_client, db, tbl): """ Get primary key column for table db.tbl. :param etcd_client: Etcd client. :param db: database name. :param tbl: table name. :return: Primary key column. :rtype: ColumnSet :raise ProgrammingError: if table or database doesn't exist """ try: response = etcd_client.read('/{db}/{tbl}/_fields'.format(db=db, tbl=tbl)) _fields = response.node['value'] return ColumnSet(json.loads(_fields)) except EtcdKeyNotFound: raise ProgrammingError("Table %s.%s doesn't exist" % (db, tbl))
def execute(self, query, args=None): """Prepare and execute a database operation (query or command).""" if args: query %= tuple(["'%s'" % a for a in args]) self._rows = () try: tree = self._sql_parser.parse(query) except SQLParserError as err: raise ProgrammingError(err) if tree.query_type == 'SELECT': self._column_names, self._rows = self._execute_select(tree) elif tree.query_type == "USE_DATABASE": self._db = tree.db elif tree.query_type == "SHOW_DATABASES": self._column_names, self._rows = self._execute_show_databases() elif tree.query_type == "SHOW_TABLES": self._column_names, self._rows = self._execute_show_tables(tree) elif tree.query_type == "CREATE_DATABASE": self._execute_create_database(tree.db) elif tree.query_type == "DROP_DATABASE": self._execute_drop_database(tree.db) elif tree.query_type == "CREATE_TABLE": self._execute_create_table(tree) elif tree.query_type == "DESC_TABLE": self._column_names, self._rows = self._execute_desc_table(tree) elif tree.query_type == "INSERT": self._execute_insert(tree) elif tree.query_type == "UPDATE": return self._execute_update(tree) elif tree.query_type == "WAIT": self._column_names, self._rows = self._execute_wait(tree) self._col_infos = self._update_columns(self._column_names, self._rows) return len(self._rows)
def execute(self, query, args=None): """Prepare and execute a database operation (query or command). :param query: Query text. :type query: str :param args: Optional query arguments. :type args: tuple :raise ProgrammingError: if query can't be parsed.""" query = self.morgify(query, args) LOG.debug('Executing: %s', query) try: tree = self._sql_parser.parse(query) except SQLParserError as err: raise ProgrammingError(err) if not self._db: self._db = tree.db self._result_set = None self._rowcount = 0 if tree.query_type == "SHOW_DATABASES": self._result_set = show_databases(self.connection.client) elif tree.query_type == "CREATE_DATABASE": create_database(self.connection.client, tree) elif tree.query_type == "DROP_DATABASE": drop_database(self.connection.client, tree) elif tree.query_type == "USE_DATABASE": self._db = use_database(self.connection.client, tree) elif tree.query_type == "CREATE_TABLE": create_table(self.connection.client, tree, db=self._db) elif tree.query_type == "DROP_TABLE": drop_table(self.connection.client, tree, db=self._db) elif tree.query_type == "SHOW_TABLES": self._result_set = show_tables(self.connection.client, tree, db=self._db) elif tree.query_type == "DESC_TABLE": self._result_set = desc_table(self.connection.client, tree, db=self._db) elif tree.query_type == "INSERT": self._rowcount = insert(self.connection.client, tree, db=self._db) elif tree.query_type == 'SELECT': self._result_set = execute_select(self.connection.client, tree, db=self._db) elif tree.query_type == 'WAIT': self._result_set = execute_wait(self.connection.client, tree, db=self._db) elif tree.query_type == "UPDATE": self._rowcount = execute_update(self.connection.client, tree, db=self._db) elif tree.query_type == "DELETE": self._rowcount = execute_delete(self.connection.client, tree, db=self._db) if self._result_set is not None: self._rowcount = self._result_set.n_rows
def _execute_create_database(self, db): try: self.connection.client.mkdir('/%s' % db) except EtcdNodeExist as err: raise ProgrammingError("Failed to create database: %s" % err)
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