-
Notifications
You must be signed in to change notification settings - Fork 157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add support for DDL and INSERT/DELETE/UPDATE operations #252
Conversation
Cleaned up git commit log (I spend most of my time fighting this linter!). |
@jacques-n and others, how does this version look? |
Hey @curino , this is on my list to review. Will try to get to it soon. One thing I still don't understand is the output item in writerel. Can you give a concrete example in pseudo code/description? |
Thanks @jacques-n! Most DBMS return information about how the insert/delete/update operation went. These takes few forms:
What I learned reading few doc pages from various systems is that this is to simplify the common case where apps want to be able to double check how an operation went (e.g., validate that roughly the right number of tuples were affected) and potentially abort/compensate if things were off. This would otherwise required temp tables and complex multi-table transactions, so it is a rather appreciated/used feature. Including an I considered to simplify this and hardcode the "# of affected tuples" semantics as a return value, but this does seem to miss what I read was a rather common use case. I hope this helps clarify the rationale (happy to chat in the community call if it is easier). Thanks, |
Per conversation in latest community meeting, I modified the I also realized that in the original docs there were references to a bunch of other things (rotations, etc.) that are not currently represented (or at least I am not clear on what they mean). I would propose we converge on this patch, and then do further iterations to reflects further/fancier things (e.g., we left constraints and indexes out of table definitions as well). |
@jacques-n ping... |
proto/substrait/algebra.proto
Outdated
DDL_OP_ALTER_TABLE = 3; | ||
|
||
DDL_OP_CREATE_VIEW = 4; | ||
DDL_OP_CREATE_OR_REPLACE = 5; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't feel like an operation. It fields like a subcategory of the other operation types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could have the DDL_OP being TABLE or VIEW and then have another field capturing CREATE, ALTER, DROP (where VIEW + ALTER is equivalent to the CREATE_OR_REPLACE we have now)
proto/substrait/algebra.proto
Outdated
// Definition of which type of write operation is to be performed | ||
oneof write_type { | ||
NamedTableWrite named_table = 1; | ||
ReadRel.LocalFiles local_files = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm inclined to just include named table and extension table right now. (With the latter being completely independent of the read type.)
Amongst other things, I'm not convinced that a read spec for files is the same as a write spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could include tables only for now, but eventually we want WriteRel
to write to file as well I think.
proto/substrait/algebra.proto
Outdated
// The columns that will be modified (representing after-image of a schema change) | ||
NamedStruct base_schema = 2; | ||
// The default values for the columns (representing after-image of a schema change) | ||
repeated Expression.Literal defaults = 3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like it doesn't belong here. It isn't really specific to a named table, right? Maybe it should be at the write rel level?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As noted, if we move ctas, this can also exist inside of writerel. Note that we should specifically declare patterns around the requirement of including this (or not) and the behavior of it. I'd also note that after-image isn't clear here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if we move CTAS we need schema (names+types) and defaults for CREATE_TABLE right?
proto/substrait/algebra.proto
Outdated
DDL_OP_UNSPECIFIED = 0; | ||
DDL_OP_CREATE_TABLE = 1; | ||
DDL_OP_DROP_TABLE = 2; | ||
DDL_OP_ALTER_TABLE = 3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest we move CTAS to WriteRel. This removes the write_type stuff entirely from this and keeps it only in WriteRel. (This may mean we need to come up with a different name than DDL since that generally includes CTAS.)
Separately, I think we should probably remove CREATE TABLE and ALTER TABLE since there isn't sufficient information here to actually do them. (We need schema, etc.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we keep the write_type
it contains a NamedTableWrite
, which includes all we need for CREATE or ALTER TABLE I think (table name, column names, column types, default values).
proto/substrait/algebra.proto
Outdated
// A base table for writing. The list of string is used to represent namespacing (e.g., mydb.mytable). | ||
// This assumes shared catalog between systems exchanging a message. | ||
// it also includes a base schema, and default values | ||
message NamedTableWrite { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned elsewhere, let's move this into WriteRel and keep it constrained to that location.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this prevents us to do all `CREATE' and 'ALTER' operators.
proto/substrait/algebra.proto
Outdated
message NamedTableWrite { | ||
repeated string names = 1; | ||
// The columns that will be modified (representing after-image of a schema change) | ||
NamedStruct base_schema = 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't figure out how to use names + base schema to map my partial input onto a broader schema. I also don't think this belongs in Named Table, feels like a generic/cross table concept. After moving properties to writerel, I think we need a better clarity around what this write is and how it maps to an underlying schema. One option:
final schema and a indexbased mapping mapping the input schema to the output. For example:
input: (a int, c int)
output: (a int, b int, c int, d int)
defaults: (1, 4, 7, 6) -- defined based on the output schema.
map: (0,2) maps: input[0] => output[0] and input[1] => output[3]
I can't see how to use a set of names to do this mapping since there could be dupes at various levels of schema. (It also seems anti-substrait-patterns to use some form of naming system to map two schemas).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also probably have an option around defaults: do we only apply for missing columns or do we also apply for null values. (The latter is a lot more expensive...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thinking is as follows:
names
is simply a qualified table name (like mydb.table). I am copying the pattern fromReadRel.NamedTable
. Maybe we should call itqualified_table_name
or something like that.base_schema
describes the entire schema we want in output (after an ALTER or as a result of CREATE or INSERt operation etc.)- The content is positionally (as usual) mapped to
input
. For example if you are doing UPDATE TABLE foo WHERE col1=3 WHERE cond, we would have in theinput
something like SELECT "3", col2, col3... FROM foo WHERE cond.
In hindsight we might be able to skip the defaults
field altogether and use the input
for that (using a set of constants if we are issuing a CREATE TABLE
for example).
Thanks @jacques-n for the live-chat. I have addressed all we discussed, and updated some of the docs accordingly. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One little leftover that should be cleaned but otherwise looking good. I'll fix and merge assuming tests pass.
Thanks @jacques-n and @jcamachor for the help shaping this. |
I'm a bit late to the party now (was on vacation, sorry), but I can't help but notice that |
…ubstrait-io#284 (relation references) - add new relation types to rel_type to make them usable - add constraints to prevent cyclic relation references - document how relation references work in the relation basics section - s/tuples/records/g for naming consistency - move ReferenceRel out of the AggregateFunction message scope BREAKING CHANGE: various messages and semantics that were not yet reachable from the Plan message were changed
In collaboration with Jesus Camacho Rodriguez