From 48be2ee14e360758541f88dd72c74babf502d247 Mon Sep 17 00:00:00 2001 From: d h Date: Wed, 27 Nov 2024 16:10:04 +0800 Subject: [PATCH] support create tempporay table & ibis tutorial --- catalog/database.go | 149 ++++++++++++----------- docs/tutorial/connect-with-ibis-setup.md | 75 ++++++++++++ 2 files changed, 156 insertions(+), 68 deletions(-) create mode 100644 docs/tutorial/connect-with-ibis-setup.md diff --git a/catalog/database.go b/catalog/database.go index 2c6f14e1..6839e260 100644 --- a/catalog/database.go +++ b/catalog/database.go @@ -23,6 +23,7 @@ var _ sql.TableRenamer = (*Database)(nil) var _ sql.ViewDatabase = (*Database)(nil) var _ sql.TriggerDatabase = (*Database)(nil) var _ sql.CollatedDatabase = (*Database)(nil) +var _ sql.TemporaryTableCreator = (*Database)(nil) func NewDatabase(name string, catalogName string) *Database { return &Database{ @@ -109,75 +110,14 @@ func (d *Database) Name() string { func (d *Database) CreateTable(ctx *sql.Context, name string, schema sql.PrimaryKeySchema, collation sql.CollationID, comment string) error { d.mu.Lock() defer d.mu.Unlock() + return d.CreateAllTable(ctx, name, schema, collation, comment) +} - var columns []string - var columnCommentSQLs []string - for _, col := range schema.Schema { - typ, err := DuckdbDataType(col.Type) - if err != nil { - return err - } - colDef := fmt.Sprintf(`"%s" %s`, col.Name, typ.name) - if col.Nullable { - colDef += " NULL" - } else { - colDef += " NOT NULL" - } - - if col.Default != nil { - columnDefault, err := typ.mysql.withDefault(col.Default.String()) - if err != nil { - return err - } - colDef += " DEFAULT " + columnDefault - } - - columns = append(columns, colDef) - - if col.Comment != "" || typ.mysql.Name != "" || col.Default != nil { - columnCommentSQLs = append(columnCommentSQLs, - fmt.Sprintf(`COMMENT ON COLUMN %s IS '%s'`, FullColumnName(d.catalog, d.name, name, col.Name), - NewCommentWithMeta[MySQLType](col.Comment, typ.mysql).Encode())) - } - } - - var sqlsBuild strings.Builder - - sqlsBuild.WriteString(fmt.Sprintf(`CREATE TABLE %s (%s`, FullTableName(d.catalog, d.name, name), strings.Join(columns, ", "))) - - var primaryKeys []string - for _, pkord := range schema.PkOrdinals { - primaryKeys = append(primaryKeys, schema.Schema[pkord].Name) - } - - if len(primaryKeys) > 0 { - sqlsBuild.WriteString(fmt.Sprintf(", PRIMARY KEY (%s)", strings.Join(primaryKeys, ", "))) - } - - sqlsBuild.WriteString(")") - - // Add comment to the table - if comment != "" { - sqlsBuild.WriteString(fmt.Sprintf("; COMMENT ON TABLE %s IS '%s'", FullTableName(d.catalog, d.name, name), NewComment[any](comment).Encode())) - } - - // Add column comments - for _, s := range columnCommentSQLs { - sqlsBuild.WriteString(";") - sqlsBuild.WriteString(s) - } - - _, err := adapter.Exec(ctx, sqlsBuild.String()) - if err != nil { - if IsDuckDBTableAlreadyExistsError(err) { - return sql.ErrTableAlreadyExists.New(name) - } - return ErrDuckDB.New(err) - } - - // TODO: support collation - - return nil +// CreateTemporaryTable implements sql.CreateTemporaryTable. +func (d *Database) CreateTemporaryTable(ctx *sql.Context, name string, schema sql.PrimaryKeySchema, collation sql.CollationID) error { + d.mu.Lock() + defer d.mu.Unlock() + return d.CreateAllTable(ctx, name, schema, collation, "") } // DropTable implements sql.TableDropper. @@ -309,6 +249,79 @@ func (d *Database) DropView(ctx *sql.Context, name string) error { return nil } +// CreateTable implements sql.TableCreator. +func (d *Database) CreateAllTable(ctx *sql.Context, name string, schema sql.PrimaryKeySchema, collation sql.CollationID, comment string) error { + + var columns []string + var columnCommentSQLs []string + for _, col := range schema.Schema { + typ, err := DuckdbDataType(col.Type) + if err != nil { + return err + } + colDef := fmt.Sprintf(`"%s" %s`, col.Name, typ.name) + if col.Nullable { + colDef += " NULL" + } else { + colDef += " NOT NULL" + } + + if col.Default != nil { + columnDefault, err := typ.mysql.withDefault(col.Default.String()) + if err != nil { + return err + } + colDef += " DEFAULT " + columnDefault + } + + columns = append(columns, colDef) + + if col.Comment != "" || typ.mysql.Name != "" || col.Default != nil { + columnCommentSQLs = append(columnCommentSQLs, + fmt.Sprintf(`COMMENT ON COLUMN %s IS '%s'`, FullColumnName(d.catalog, d.name, name, col.Name), + NewCommentWithMeta[MySQLType](col.Comment, typ.mysql).Encode())) + } + } + + var sqlsBuild strings.Builder + + sqlsBuild.WriteString(fmt.Sprintf(`CREATE TABLE %s (%s`, FullTableName(d.catalog, d.name, name), strings.Join(columns, ", "))) + + var primaryKeys []string + for _, pkord := range schema.PkOrdinals { + primaryKeys = append(primaryKeys, schema.Schema[pkord].Name) + } + + if len(primaryKeys) > 0 { + sqlsBuild.WriteString(fmt.Sprintf(", PRIMARY KEY (%s)", strings.Join(primaryKeys, ", "))) + } + + sqlsBuild.WriteString(")") + + // Add comment to the table + if comment != "" { + sqlsBuild.WriteString(fmt.Sprintf("; COMMENT ON TABLE %s IS '%s'", FullTableName(d.catalog, d.name, name), NewComment[any](comment).Encode())) + } + + // Add column comments + for _, s := range columnCommentSQLs { + sqlsBuild.WriteString(";") + sqlsBuild.WriteString(s) + } + + _, err := adapter.Exec(ctx, sqlsBuild.String()) + if err != nil { + if IsDuckDBTableAlreadyExistsError(err) { + return sql.ErrTableAlreadyExists.New(name) + } + return ErrDuckDB.New(err) + } + + // TODO: support collation + + return nil +} + // CreateTrigger implements sql.TriggerDatabase. func (d *Database) CreateTrigger(ctx *sql.Context, definition sql.TriggerDefinition) error { return sql.ErrTriggersNotSupported.New(d.name) diff --git a/docs/tutorial/connect-with-ibis-setup.md b/docs/tutorial/connect-with-ibis-setup.md new file mode 100644 index 00000000..1828777b --- /dev/null +++ b/docs/tutorial/connect-with-ibis-setup.md @@ -0,0 +1,75 @@ +# **Connecting to MyDuckServer using Ibis** + +[ibis](https://ibis-project.org/) offers an efficient way to handle data analysis tasks without loading the entire dataset into memory.This tutorial will guide you through setting up a connection using Ibis and performing basic operations with myduckserver. + +### Steps + +1. **Installing ibis** + + ``` + //use conda + conda install -c conda-forge ibis-mysql + //use pip + pip install 'ibis-framework[mysql]' + ``` + +2. **Run MyDuck Server:** + + ``` + docker run -p 13306:3306 -p 15432:5432 apecloud/myduckserver:latest + ``` + +3. **Connecting to the Myduck Server** + + ``` + import ibis + host = '127.0.0.1' + port = 13306 + user = 'root' + password = '' + database = 'mydb' #should first create the database mydb. + con = ibis.mysql.connect( + host=host, + port=port, + user=user, + password=password, + database=database + ) + ``` + +4. **Executing Queries** + + ``` + import ibis + + table_name = 'persistent_temp_table' + schema = ibis.schema([('id', 'int32'), ('value', 'double')]) + + if table_name not in con.list_tables(): + con.create_table(table_name, schema=schema) + + con.insert(table_name, [{'id': 1, 'value': 10.5}]) + + table = con.table(table_name) + result = table.execute() + print(result) + ``` + + + + + + + + + + + + + + + + + + +