This was totally user error, I was ignoring "fields" and "collation" of the RelRoot. Passing "collation" to planner.transform stopped it from removing the sort.
Gian On Wed, Dec 14, 2016 at 3:21 PM, Gian Merlino <g...@imply.io> wrote: > I don't think so, since my test query (SELECT dim1 FROM s.foo GROUP BY > dim1 ORDER BY dim1 DESC) is sorting on a column that is also projected. > > Gian > > On Wed, Dec 14, 2016 at 11:58 AM, Julian Hyde <jh...@apache.org> wrote: > >> Are you running into some variant of the problems that inspired >> https://issues.apache.org/jira/browse/CALCITE-819: < >> https://issues.apache.org/jira/browse/CALCITE-819:> at the root of the >> tree, columns that are not projected are removed, and if the desired sort >> order involves non-projected columns, the desired sort order is forgotten). >> >> > On Dec 14, 2016, at 11:19 AM, Gian Merlino <g...@imply.io> wrote: >> > >> > Ah, thanks. So if that sort of thing is not a smoking gun, do you have >> an >> > idea about where I should look next? If not I'll keep poking around. >> > >> > Gian >> > >> > On Wed, Dec 14, 2016 at 11:06 AM, Julian Hyde <jh...@apache.org> wrote: >> > >> >>> - But its "set" field points to a RelSet with "rels" that _don't_ have >> >>> _any_ collation traits. >> >> >> >> That’s OK. A “subset” (RelSubset) is a collection of RelNodes that are >> >> logically and physically equivalent (same results, same physical >> >> properties) whereas a “set” (RelSet) is a collection of RelNodes that >> are >> >> logically equivalent. >> >> >> >> A set can therefore be considered to be a collection of subsets, each >> of >> >> which contains RelNodes. And it used to be implemented that way, but in >> >> https://issues.apache.org/jira/browse/CALCITE-88 < >> >> https://issues.apache.org/jira/browse/CALCITE-88> we introduced >> collation >> >> as a trait, and that made subsets non-disjoint (a RelNode can be >> sorted on >> >> (x, y), and also on (x), and also on (), and also on (z)) so we made >> >> RelSubset just a view onto a RelSet, filtering the list of RelNodes >> >> according to the ones that have (“subsume”) the desired traits. >> >> >> >> Julian >> >> >> >> >> >>> On Dec 14, 2016, at 10:45 AM, Gian Merlino <g...@imply.io> wrote: >> >>> >> >>> I spent some more time looking into (3) and found that when I had >> things >> >>> going through the Planner rather than the JDBC driver, SortRemoveRule >> was >> >>> removing sorts when it shouldn't have been. This happens even for >> simple >> >>> queries like "SELECT dim1 FROM s.foo GROUP BY dim1 ORDER BY dim1 >> >>> DESC". Removing SortRemoveRule from the planner fixed the broken >> tests on >> >>> my end. >> >>> >> >>> I dug into that a bit and saw that the call to >> "convert(sort.getInput(), >> >>> traits)" in SortRemoveRule was returning a RelSubset that looked a bit >> >>> funny in the debugger: >> >>> >> >>> - The RelSubset's "traitSet" _does_ have the proper collation trait. >> >>> - But its "set" field points to a RelSet with "rels" that _don't_ have >> >>> _any_ collation traits. >> >>> >> >>> From what I understand that causes Calcite to treat the unsorted and >> >> sorted >> >>> rels as equivalent when they in fact aren't. I'm still not sure if >> this >> >> is >> >>> a Calcite bug or user error on my part… I'll keep looking into it >> unless >> >>> someone has any bright ideas. >> >>> >> >>> fwiw, my Planner construction looks like this: >> >>> >> >>> final FrameworkConfig frameworkConfig = Frameworks >> >>> .newConfigBuilder() >> >>> .parserConfig( >> >>> SqlParser.configBuilder() >> >>> .setCaseSensitive(true) >> >>> .setUnquotedCasing(Casing.UNCHANGED) >> >>> .build() >> >>> ) >> >>> .defaultSchema(rootSchema) >> >>> .traitDefs(ConventionTraitDef.INSTANCE, >> >>> RelCollationTraitDef.INSTANCE) >> >>> .programs(Programs.ofRules(myRules)) >> >>> .executor(new RexExecutorImpl(Schemas.createDataContext(null))) >> >>> .context(Contexts.EMPTY_CONTEXT) >> >>> .build(); >> >>> >> >>> return Frameworks.getPlanner(frameworkConfig); >> >>> >> >>> Gian >> >>> >> >>> On Sat, Dec 3, 2016 at 5:53 PM, Gian Merlino <g...@imply.io> wrote: >> >>> >> >>>> Sure, I added those first two to the ticket. >> >>>> >> >>>> I don't think those are happening with (3) but I'll double check next >> >> time >> >>>> I take a look at using the Planner. >> >>>> >> >>>> Gian >> >>>> >> >>>> On Fri, Dec 2, 2016 at 12:20 PM, Julian Hyde <jh...@apache.org> >> wrote: >> >>>> >> >>>>> Can you please add (1) and (2) to https://issues.apache.org/jira >> >>>>> /browse/CALCITE-1525 <https://issues.apache.org/jir >> >> a/browse/CALCITE-1525>, >> >>>>> which deals with the whole issue of using “Planner” within the JDBC >> >> driver, >> >>>>> so we can be consistent. >> >>>>> >> >>>>> (3) doesn’t look likely to be related. Do your queries have UNION or >> >>>>> other set-ops? Are you sorting on columns that do not appear in the >> >> final >> >>>>> result? >> >>>>> >> >>>>> Julian >> >>>>> >> >>>>> >> >>>>>> On Nov 28, 2016, at 10:45 AM, Gian Merlino <g...@imply.io> wrote: >> >>>>>> >> >>>>>> I traveled a bit down the Frameworks/Planner road and got most of >> my >> >>>>> tests >> >>>>>> passing, but ran into some problems getting them all to work: >> >>>>>> >> >>>>>> (1) "EXPLAIN PLAN FOR" throws NullPointerException during >> >>>>> Planner.validate. >> >>>>>> It looks like CalcitePrepareImpl has some special code to handle >> >>>>> validation >> >>>>>> of EXPLAIN, but PlannerImpl doesn't. I'm not sure if this is >> >> something I >> >>>>>> should be doing on my end, or if it's a bug in PlannerImpl. >> >>>>>> (2) I don't see a way to do ?-style prepared statements with bound >> >>>>>> variables, which _is_ possible with the JDBC driver route. >> >>>>>> (3) Not sure why this is happening, but for some reason ORDER BY / >> >> LIMIT >> >>>>>> clauses are getting ignored sometimes, even when they work with the >> >> JDBC >> >>>>>> driver route. This may be something messed up with my rules though >> and >> >>>>> may >> >>>>>> not be Calcite's fault. >> >>>>>> >> >>>>>> Julian, do any of these look like bugs that should be raised in >> jira, >> >> or >> >>>>>> are they just stuff I should be dealing with on my side? >> >>>>>> >> >>>>>> Btw, I do like that the Frameworks/Planner route gives me back the >> >>>>> RelNode >> >>>>>> itself, since that means I can make the Druid queries directly >> without >> >>>>>> needing to go through the extra layers of the JDBC driver. That >> part >> >> is >> >>>>>> nice. >> >>>>>> >> >>>>>> Gian >> >>>>>> >> >>>>>> On Wed, Nov 23, 2016 at 10:11 PM, Julian Hyde <jh...@apache.org> >> >> wrote: >> >>>>>> >> >>>>>>> I don’t know how it’s used outside Calcite. Maybe some others can >> >>>>> chime in. >> >>>>>>> >> >>>>>>> Thanks for the PR. I logged https://issues.apache.org/jira >> >>>>>>> /browse/CALCITE-1509 <https://issues.apache.org/jir >> >>>>> a/browse/CALCITE-1509> >> >>>>>>> for it, and will commit shortly. >> >>>>>>> >> >>>>>>> Julian >> >>>>>>> >> >>>>>>>> On Nov 23, 2016, at 12:32 PM, Gian Merlino <g...@imply.io> >> wrote: >> >>>>>>>> >> >>>>>>>> Do you know examples of projects that use Planner or PlannerImpl >> >>>>>>> currently >> >>>>>>>> (from "outside")? As far as I can tell, within Calcite itself >> it's >> >>>>> only >> >>>>>>>> used in test code. Maybe that'd be a better entry point. >> >>>>>>>> >> >>>>>>>> In the meantime I raised a PR here for allowing a convertlet >> table >> >>>>>>> override >> >>>>>>>> in a CalcitePrepareImpl: https://github.com/apache/calc >> ite/pull/330 >> >> . >> >>>>>>> That >> >>>>>>>> was enough to get the JDBC driver on my end to behave how I want >> it >> >>>>> to. >> >>>>>>>> >> >>>>>>>> Gian >> >>>>>>>> >> >>>>>>>> On Thu, Nov 17, 2016 at 5:23 PM, Julian Hyde <jh...@apache.org> >> >>>>> wrote: >> >>>>>>>> >> >>>>>>>>> I was wrong earlier… FrameworkConfig already has a >> >> getConvertletTable >> >>>>>>>>> method. But regarding using FrameworkConfig from within the JDBC >> >>>>> driver, >> >>>>>>>>> It’s complicated. FrameworkConfig only works if you are >> “outside” >> >>>>>>> Calcite, >> >>>>>>>>> whereas CalcitePrepare is when you are customizing from the >> inside, >> >>>>> and >> >>>>>>>>> sadly CalcitePrepare does not use a FrameworkConfig. >> >>>>>>>>> >> >>>>>>>>> Compare and contrast: >> >>>>>>>>> * CalcitePrepareImpl.getSqlToRelConverter [ >> >>>>> https://github.com/apache/ >> >>>>>>>>> calcite/blob/3f92157d5742dd10f3b828d22d7a753e0a2899cc/core/ >> >>>>>>> src/main/java/ >> >>>>>>>>> org/apache/calcite/prepare/CalcitePrepareImpl.java#L1114 < >> >>>>>>>>> https://github.com/apache/calcite/blob/3f92157d5742dd10f3b82 >> >>>>> 8d22d7a75 >> >>>>>>>>> 3e0a2899cc/core/src/main/java/org/apache/calcite/prepare/ >> >>>>>>>>> CalcitePrepareImpl.java#L1114> ] >> >>>>>>>>> * PlannerImpl.rel [ https://github.com/apache/calcite/blob/ >> >>>>>>>>> 105bba1f83cd9631e8e1211d262e4886a4a863b7/core/src/main/java/ >> >>>>>>>>> org/apache/calcite/prepare/PlannerImpl.java#L225 < >> >>>>>>>>> https://github.com/apache/calcite/blob/105bba1f83cd9631e8e12 >> >>>>> 11d262e48 >> >>>>>>>>> 86a4a863b7/core/src/main/java/org/apache/calcite/prepare/ >> >>>>>>>>> PlannerImpl.java#L225> ] >> >>>>>>>>> >> >>>>>>>>> The latter uses a convertletTable sourced from a >> FrameworkConfig. >> >>>>>>>>> >> >>>>>>>>> The ideal thing would be to get CalcitePrepareImpl to use a >> >>>>> PlannerImpl >> >>>>>>> to >> >>>>>>>>> do its dirty work. Then “inside” and “outside” would work the >> same. >> >>>>>>> Would >> >>>>>>>>> definitely appreciate that as a patch. >> >>>>>>>>> >> >>>>>>>>> If you choose to go the JDBC driver route, you could override >> >>>>>>>>> Driver.createPrepareFactory to produce a sub-class of >> >> CalcitePrepare >> >>>>>>> that >> >>>>>>>>> works for your environment, one with an explicit convertletTable >> >>>>> rather >> >>>>>>>>> than just using the default. >> >>>>>>>>> >> >>>>>>>>> Julian >> >>>>>>>>> >> >>>>>>>>> >> >>>>>>>>>> On Nov 17, 2016, at 5:01 PM, Gian Merlino <g...@imply.io> >> wrote: >> >>>>>>>>>> >> >>>>>>>>>> Hey Julian, >> >>>>>>>>>> >> >>>>>>>>>> If the convertlets were customizable with a FrameworkConfig, >> how >> >>>>> would >> >>>>>>> I >> >>>>>>>>>> use that configure the JDBC driver (given that I'm doing it >> with >> >> the >> >>>>>>> code >> >>>>>>>>>> upthread)? Or would that suggest using a different approach to >> >>>>>>> embedding >> >>>>>>>>>> Calcite? >> >>>>>>>>>> >> >>>>>>>>>> Gian >> >>>>>>>>>> >> >>>>>>>>>> On Thu, Nov 17, 2016 at 4:02 PM, Julian Hyde <jh...@apache.org >> > >> >>>>> wrote: >> >>>>>>>>>> >> >>>>>>>>>>> Convertlets have a similar effect to planner rules (albeit >> they >> >>>>> act on >> >>>>>>>>>>> scalar expressions, not relational expressions) so people >> should >> >> be >> >>>>>>>>> able to >> >>>>>>>>>>> change the set of active convertlets. >> >>>>>>>>>>> >> >>>>>>>>>>> Would you like to propose a change that makes the convertlet >> >> table >> >>>>>>>>>>> pluggable? Maybe as part of FrameworkConfig? Regardless, >> please >> >>>>> log a >> >>>>>>>>> JIRA >> >>>>>>>>>>> to track this. >> >>>>>>>>>>> >> >>>>>>>>>>> And by the way, RexImpTable, which defines how operators are >> >>>>>>> implemented >> >>>>>>>>>>> by generating java code, should also be pluggable. It’s been >> on >> >> my >> >>>>>>> mind >> >>>>>>>>> for >> >>>>>>>>>>> a long time to allow the “engine” — related to the data >> format, >> >> and >> >>>>>>> how >> >>>>>>>>>>> code is generated to access fields and evaluate expressions >> and >> >>>>>>>>> operators — >> >>>>>>>>>>> to be pluggable. >> >>>>>>>>>>> >> >>>>>>>>>>> Regarding whether the JDBC driver is the right way to embed >> >>>>> Calcite. >> >>>>>>>>>>> There’s no easy answer. You might want to embed Calcite as a >> >>>>> library >> >>>>>>> in >> >>>>>>>>>>> your own server (as Drill and Hive do). Or you might want to >> make >> >>>>>>>>> yourself >> >>>>>>>>>>> just an adapter that runs inside a Calcite JDBC server (as the >> >> CSV >> >>>>>>>>> adapter >> >>>>>>>>>>> does). Or something in the middle, like what Phoenix does: >> using >> >>>>>>> Calcite >> >>>>>>>>>>> for JDBC, SQL, planning, but with your own metadata and >> runtime >> >>>>>>> engine. >> >>>>>>>>>>> >> >>>>>>>>>>> As long as you build the valuable stuff into planner rules, >> new >> >>>>>>>>> relational >> >>>>>>>>>>> operators (if necessary) and use the schema SPI, you should be >> >>>>> able to >> >>>>>>>>>>> change packaging in the future. >> >>>>>>>>>>> >> >>>>>>>>>>> Julian >> >>>>>>>>>>> >> >>>>>>>>>>> >> >>>>>>>>>>> >> >>>>>>>>>>> >> >>>>>>>>>>>> On Nov 17, 2016, at 1:59 PM, Gian Merlino <g...@imply.io> >> >> wrote: >> >>>>>>>>>>>> >> >>>>>>>>>>>> Hey Calcites, >> >>>>>>>>>>>> >> >>>>>>>>>>>> I'm working on embedding Calcite into Druid ( >> http://druid.io/, >> >>>>>>>>>>>> https://github.com/druid-io/druid/pull/3682) and am running >> >> into >> >>>>> a >> >>>>>>>>>>> problem >> >>>>>>>>>>>> that is making me wonder if the approach I'm using makes >> sense. >> >>>>>>>>>>>> >> >>>>>>>>>>>> Consider the expression EXTRACT(YEAR FROM __time). Calcite >> has a >> >>>>>>>>> standard >> >>>>>>>>>>>> convertlet rule "convertExtract" that changes this into some >> >>>>>>> arithmetic >> >>>>>>>>>>> on >> >>>>>>>>>>>> __time casted to an int type. But Druid has some builtin >> >>>>> functions to >> >>>>>>>>> do >> >>>>>>>>>>>> this, and I'd rather use those than arithmetic (for a bunch >> of >> >>>>>>>>> reasons). >> >>>>>>>>>>>> Ideally, in my RelOptRules that convert Calcite rels to Druid >> >>>>>>> queries, >> >>>>>>>>>>> I'd >> >>>>>>>>>>>> see the EXTRACT as a normal RexCall with the time flag and an >> >>>>>>>>> expression >> >>>>>>>>>>> to >> >>>>>>>>>>>> apply it to. That's a lot easier to translate than the >> >> arithmetic >> >>>>>>>>> stuff, >> >>>>>>>>>>>> which I'd have to pattern match and undo first before >> >> translating. >> >>>>>>>>>>>> >> >>>>>>>>>>>> So the problem I have is that I want to disable >> convertExtract, >> >>>>> but I >> >>>>>>>>>>> don't >> >>>>>>>>>>>> see a way to do that or to swap out the convertlet table. >> >>>>>>>>>>>> >> >>>>>>>>>>>> The code I'm using to set up a connection is: >> >>>>>>>>>>>> >> >>>>>>>>>>>> public CalciteConnection createCalciteConnection( >> >>>>>>>>>>>> final DruidSchema druidSchema >> >>>>>>>>>>>> ) throws SQLException >> >>>>>>>>>>>> { >> >>>>>>>>>>>> final Properties props = new Properties(); >> >>>>>>>>>>>> props.setProperty("caseSensitive", "true"); >> >>>>>>>>>>>> props.setProperty("unquotedCasing", "UNCHANGED"); >> >>>>>>>>>>>> final Connection connection = >> >>>>>>>>>>>> DriverManager.getConnection("jdbc:calcite:", props); >> >>>>>>>>>>>> final CalciteConnection calciteConnection = >> >>>>>>>>>>>> connection.unwrap(CalciteConnection.class); >> >>>>>>>>>>>> calciteConnection.getRootSchema().setCacheEnabled(false); >> >>>>>>>>>>>> calciteConnection.getRootSchema().add(DRUID_SCHEMA_NAME, >> >>>>>>>>>>> druidSchema); >> >>>>>>>>>>>> return calciteConnection; >> >>>>>>>>>>>> } >> >>>>>>>>>>>> >> >>>>>>>>>>>> This CalciteConnection is then used by the Druid HTTP server >> to >> >>>>>>> offer a >> >>>>>>>>>>> SQL >> >>>>>>>>>>>> API. >> >>>>>>>>>>>> >> >>>>>>>>>>>> Is there some way to swap out the convertlet table that I'm >> >>>>> missing? >> >>>>>>>>>>>> >> >>>>>>>>>>>> Also, just in general, am I going about this the right way? >> Is >> >>>>> using >> >>>>>>>>> the >> >>>>>>>>>>>> JDBC driver the right way to embed Calcite? Or should I be >> >> calling >> >>>>>>> into >> >>>>>>>>>>> it >> >>>>>>>>>>>> at some lower level? >> >>>>>>>>>>>> >> >>>>>>>>>>>> Thanks! >> >>>>>>>>>>>> >> >>>>>>>>>>>> Gian >> >>>>>>>>>>> >> >>>>>>>>>>> >> >>>>>>>>> >> >>>>>>>>> >> >>>>>>> >> >>>>>>> >> >>>>> >> >>>>> >> >>>> >> >> >> >> >> >> >