{"action":"created","comment":{"url":"https://api.github.com/repos/druid-io/druid/pulls/comments/125143875","pull_request_review_id":47511040,"id":125143875,"diff_hunk":"@@ -1,77 +1,328 @@\n ---\n layout: doc_page\n ---\n-# SQL Support for Druid\n-\n-## Built-in SQL\n+# SQL\n \n <div class=\"note caution\">\n Built-in SQL is an <a href=\"../development/experimental.html\">experimental</a> feature. The API described here is\n subject to change.\n </div>\n \n-Druid includes a native SQL layer with an [Apache Calcite](https://calcite.apache.org/)-based parser and planner. All\n-parsing and planning takes place on the Broker, where SQL is converted to native Druid queries. Those native Druid\n-queries are then passed down to data nodes. Each Druid datasource appears as a table in the \"druid\" schema. Datasource\n-and column names are both case-sensitive and can optionally be quoted using double quotes. Literal strings should be\n-quoted with single quotes, like `'foo'`. Literal strings with Unicode escapes can be written like `U&'fo\\00F6'`, where\n-character codes in hex are prefixed by a backslash.\n+Druid SQL is a built-in SQL layer and an alternative to Druid's native JSON-based query language, and is powered by a\n+parser and planner based on [Apache Calcite](https://calcite.apache.org/). Druid SQL translates SQL into native Druid\n+queries on the query broker (the first node you query), which are then passed down to data nodes as native Druid\n+queries. Other than the (slight) overhead of translating SQL on the broker, there isn't an additional performance\n+penalty versus native queries.\n \n-Add \"EXPLAIN PLAN FOR\" to the beginning of any query to see how Druid will plan that query.\n+To enable Druid SQL, make sure you have set `druid.sql.enable = true` either in your common.runtime.properties or your\n+broker's runtime.properties.\n \n-### Querying with JDBC\n+## Query syntax\n \n-You can make Druid SQL queries using the [Avatica JDBC driver](https://calcite.apache.org/avatica/downloads/). Once\n-you've downloaded the Avatica client jar, add it to your classpath and use the connect string:\n+Each Druid datasource appears as a table in the \"druid\" schema. This is also the default schema, so Druid datasources\n+can be referenced as either `druid.dataSourceName` or simply `dataSourceName`.\n+\n+Identifiers like datasource and column names can optionally be quoted using double quotes. To escape a double quote\n+inside an identifier, use another double quote, like `\"My \"\"very own\"\" identifier\"`. All identifiers are case-sensitive\n+and no implicit case conversions are performed.\n+\n+Literal strings should be quoted with single quotes, like `'foo'`. Literal strings with Unicode escapes can be written\n+like `U&'fo\\00F6'`, where character codes in hex are prefixed by a backslash. Literal numbers can be written in forms\n+like `100` (denoting an integer), `100.0` (denoting a floating point value), or `1.0e5` (scientific notation). Literal\n+timestamps can be written like `TIMESTAMP '2000-01-01 00:00:00'`. Literal intervals, used for time arithmetic, can be\n+written like `INTERVAL '1' HOUR`, `INTERVAL '1 02:03' DAY TO MINUTE`, `INTERVAL '1-2' YEAR TO MONTH`, and so on.\n+\n+Druid SQL supports SELECT queries with the following structure:\n \n ```\n-jdbc:avatica:remote:url=http://BROKER:8082/druid/v2/sql/avatica/\n+[ EXPLAIN PLAN FOR ]\n+[ WITH tableName [ ( column1, column2, ... ) ] AS ( query ) ]\n+SELECT [ ALL | DISTINCT ] { * | exprs }\n+FROM table\n+[ WHERE expr ]\n+[ GROUP BY exprs ]\n+[ HAVING expr ]\n+[ ORDER BY expr [ ASC | DESC ], expr [ ASC | DESC ], ... ]\n+[ LIMIT limit ]\n ```\n \n-Example code:\n+The FROM clause refers to either a Druid datasource, like `druid.foo`, an [INFORMATION_SCHEMA table](#retrieving-metadata), a\n+subquery, or a common-table-expression provided in the WITH clause. If the FROM clause references a subquery or a\n+common-table-expression, and both levels of queries are aggregations and they cannot be combined into a single level of\n+aggregation, the overall query will be executed as a [nested GroupBy](groupbyquery.html#nested-groupbys).\n+\n+The WHERE clause refers to columns in the FROM table, and will be translated to [native filters](filters.html). The\n+WHERE clause can also reference a subquery, like `WHERE col1 IN (SELECT foo FROM ...)`. Queries like this are executed\n+as [semi-joins](#query-execution), described below.\n+\n+The GROUP BY clause refers to columns in the FROM table. Using GROUP BY, DISTINCT, or any aggregation functions will\n+trigger an aggregation query using one of Druid's [three native aggregation query types](#query-execution).\n+\n+The HAVING clause refers to columns that are present after execution of GROUP BY. It can be used to filter on either\n+grouping expressions or aggregated values. It can only be used together with GROUP BY.\n+\n+The ORDER BY clause refers to columns that are present after execution of GROUP BY. It can be used to order the results\n+based on either grouping expressions or aggregated values. It can only be used together with GROUP BY.\n+\n+The LIMIT clause can be used to limit the number of rows returned. It can be used with any query type. It is pushed down\n+to data nodes for queries that run with the native TopN query type, but not the native GroupBy query type. Future\n+versions of Druid will support pushing down limits using the native GroupBy query type as well. If you notice that\n+adding a limit doesn't change performance very much, then it's likely that Druid didn't push down the limit for your\n+query.\n+\n+Add \"EXPLAIN PLAN FOR\" to the beginning of any query to see how it would be run as a native Druid query. In this case,\n+the query will not actually be executed.\n+\n+### Aggregation functions\n+\n+Aggregation functions can appear in the SELECT clause of any query. Any aggregator can be filtered using syntax like\n+`AGG(expr) FILTER(WHERE whereExpr)`. Filtered aggregators will only aggregate rows that match their filter. It's\n+possible for two aggregators in the same SQL query to have different filters.\n+\n+Only the COUNT aggregation can accept DISTINCT.\n+\n+|Function|Notes|\n+|--------|-----|\n+|`COUNT(*)`|Counts the number of rows.|\n+|`COUNT(DISTINCT expr)`|Counts distinct values of expr, which can be string, numeric, or hyperUnique. By default this is approximate, using a variant of [HyperLogLog](http://algo.inria.fr/flajolet/Publications/FlFuGaMe07.pdf). To get exact counts set \"useApproximateCountDistinct\" to \"false\". If you do this, expr must be string or numeric, since exact counts are not possible using hyperUnique columns. See also `APPROX_COUNT_DISTINCT(expr)`. In exact mode, only one distinct count per query is permitted.|\n+|`SUM(expr)`|Sums numbers.|\n+|`MIN(expr)`|Takes the minimum of numbers.|\n+|`MAX(expr)`|Takes the maximum of numbers.|\n+|`AVG(expr)`|Averages numbers.|\n+|`APPROX_COUNT_DISTINCT(expr)`|Counts distinct values of expr, which can be a regular column or a hyperUnique column. This is always approximate, regardless of the value of \"useApproximateCountDistinct\". See also `COUNT(DISTINCT expr)`.|\n+|`APPROX_QUANTILE(expr, probability, [resolution])`|Computes approximate quantiles on numeric or approxHistogram exprs. The \"probability\" should be between 0 and 1 (exclusive). The \"resolution\" is the number of centroids to use for the computation. Higher resolutions will give more precise results but also have higher overhead. If not provided, the default resolution is 50. The [approximate histogram extension](../development/extensions-core/approximate-histograms.html) must be loaded to use this function.|\n+\n+### Numeric functions\n+\n+Numeric functions will return 64 bit integers or 64 bit floats, depending on their inputs.\n+\n+|Function|Notes|\n+|--------|-----|\n+|`ABS(expr)`|Absolute value.|\n+|`CEIL(expr)`|Ceiling.|\n+|`EXP(expr)`|e to the power of expr.|\n+|`FLOOR(expr)`|Floor.|\n+|`LN(expr)`|Logarithm (base e).|\n+|`LOG10(expr)`|Logarithm (base 10).|\n+|`POW(expr, power)`|expr to a power.|\n+|`SQRT(expr)`|Square root.|\n+|`x + y`|Addition.|\n+|`x - y`|Subtraction.|\n+|`x * y`|Multiplication.|\n+|`x / y`|Division.|\n+|`x % y`|Mod.|\n+\n+### String functions\n+\n+String functions accept strings, and return a type appropriate to the function.\n+\n+|Function|Notes|\n+|--------|-----|\n+|`x \\|\\| y`|Concat strings x and y.|\n+|`CHARACTER_LENGTH(expr)`|Length of expr in UTF-16 code units.|\n+|`LOOKUP(expr, lookupName)`|Look up expr in a registered [query-time lookup table](lookups.html).|\n+|`LOWER(expr)`|Returns expr in all lowercase.|\n+|`REGEXP_EXTRACT(expr, pattern, [index])`|Apply regular expression pattern and extract a capture group, or null if there is no match. If index is unspecified or zero, returns the substring that matched the pattern.|\n+|`REPLACE(expr, pattern, replacement)`|Replaces pattern with replacement in expr, and returns the result.|\n+|`SUBSTRING(expr, index, [length])`|Returns a substring of expr starting at index, with a max length, both measured in UTF-16 code units.|\n+|`TRIM(expr)`|Returns expr with leading and trailing whitespace removed.|\n+|`UPPER(expr)`|Returns expr in all uppercase.|\n \n-```java\n-// Connect to /druid/v2/sql/avatica/ on your broker.\n-String url = \"jdbc:avatica:remote:url=http://localhost:8082/druid/v2/sql/avatica/\";\n+### Time functions\n \n-// Set any connection context parameters you need here (see \"Connection context\" below).\n-// Or leave empty for default behavior.\n-Properties connectionProperties = new Properties();\n+Time functions can be used with Druid's `__time` column, with any column storing millisecond timestamps through use\n+of the `MILLIS_TO_TIMESTAMP` function, or with any column storing string timestamps through use of the `TIME_PARSE`\n+function. By default, time operations use the UTC time zone. You can change the time zone by setting the connection\n+context parameter \"sqlTimeZone\" to the name of another time zone, like \"America/Los_Angeles\", or to an offset like\n+\"-08:00\". If you need to mix multiple time zones in the same query, or if you need to use a time zone other than\n+the connection time zone, some functions also accept time zones as parameters. These parameters always take precedence\n+over the connection time zone.\n+\n+|Function|Notes|\n+|--------|-----|\n+|`CURRENT_TIMESTAMP`|Current timestamp in the connection's time zone.|\n+|`CURRENT_DATE`|Current date in the connection's time zone.|\n+|`TIME_FLOOR(<timestamp_expr>, <period>, [<origin>, [<timezone>]])`|Rounds down a timestamp, returning it as a new timestamp. Period can be any ISO8601 period, like P3M (quarters) or PT12H (half-days). The time zone, if provided, should be a time zone name like \"America/Los_Angeles\" or offset like \"-08:00\". This function is similar to `FLOOR` but is more flexible.|\n+|`TIME_SHIFT(<timestamp_expr>, <period>, <step>, [<timezone>])`|Shifts a timestamp by a period (step times), returning it as a new timestamp. Period can be any ISO8601 period. Step may be negative. The time zone, if provided, should be a time zone name like \"America/Los_Angeles\" or offset like \"-08:00\".|\n+|`TIME_EXTRACT(<timestamp_expr>, [<unit>, [<timezone>]])`|Extracts a time part from expr, returning it as a number. Unit can be EPOCH, SECOND, MINUTE, HOUR, DAY (day of month), DOW (day of week), DOY (day of year), WEEK (week of [week year](https://en.wikipedia.org/wiki/ISO_week_date)), MONTH (1 through 12), QUARTER (1 through 4), or YEAR. The time zone, if provided, should be a time zone name like \"America/Los_Angeles\" or offset like \"-08:00\". This function is similar to `EXTRACT` but is more flexible. Unit and time zone must be literals, and must be provided quoted, like `TIME_EXTRACT(__time, 'HOUR')` or `TIME_EXTRACT(__time, 'HOUR', 'America/Los_Angeles')`.|\n+|`TIME_PARSE(<string_expr>, [<pattern>, [<timezone>]])`|Parses a string into a timestamp using a given [Joda DateTimeFormat pattern](http://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat.html), or ISO8601 (e.g. `2000-01-02T03:04:05Z`) if the pattern is not provided. The time zone, if provided, should be a time zone name like \"America/Los_Angeles\" or offset like \"-08:00\", and will be used as the time zone for strings that do not include a time zone offset. Pattern and time zone must be literals. Strings that cannot be parsed as timestamps will be returned as NULL.|\n+|`TIME_FORMAT(<timestamp_expr>, [<pattern>, [<timezone>]])`|Formats a timestamp as a string with a given [Joda DateTimeFormat pattern](http://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat.html), or ISO8601 (e.g. `2000-01-02T03:04:05Z`) if the pattern is not provided. The time zone, if provided, should be a time zone name like \"America/Los_Angeles\" or offset like \"-08:00\". Pattern and time zone must be literals.|\n+|`MILLIS_TO_TIMESTAMP(millis_expr)`|Converts a number of milliseconds since the epoch into a timestamp.|\n+|`TIMESTAMP_TO_MILLIS(timestamp_expr)`|Converts a timestamp into a number of milliseconds since the epoch.|\n+|`EXTRACT(<unit> FROM timestamp_expr)`|Extracts a time part from expr, returning it as a number. Unit can be EPOCH, SECOND, MINUTE, HOUR, DAY (day of month), DOW (day of week), DOY (day of year), WEEK (week of year), MONTH, QUARTER, or YEAR. Units must be provided unquoted, like `EXTRACT(HOUR FROM __time)`.|\n+|`FLOOR(timestamp_expr TO <unit>)`|Rounds down a timestamp, returning it as a new timestamp. Unit can be SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, or YEAR.|\n+|`CEIL(timestamp_expr TO <unit>)`|Rounds up a timestamp, returning it as a new timestamp. Unit can be SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, or YEAR.|\n+|`timestamp_expr { + \\| - } <interval_expr>`|Add or subtract an amount of time from a timestamp. interval_expr can include interval literals like `INTERVAL '2' HOUR`, and may include interval arithmetic as well. This operator treats days as uniformly 86400 seconds long, and does not take into account daylight savings time. To account for daylight savings time, use TIME_PLUS or TIME_MINUS instead.|\n+\n+### Comparison operators\n+\n+|Function|Notes|\n+|--------|-----|\n+|`x = y`|Equals.|\n+|`x <> y`|Not-equals.|\n+|`x > y`|Greater than.|\n+|`x >= y`|Greater than or equal to.|\n+|`x < y`|Less than.|\n+|`x <= y`|Less than or equal to.|\n+|`x LIKE pattern [ESCAPE esc]`|True if x matches a SQL LIKE pattern (with an optional escape).|\n+|`x NOT LIKE pattern [ESCAPE esc]`|True if x does not match a SQL LIKE pattern (with an optional escape).|\n+|`x IS NULL`|True if x is NULL or empty string.|\n+|`x IS NOT NULL`|True if x is neither NULL nor empty string.|\n+|`x IS TRUE`|True if x is true.|\n+|`x IS NOT TRUE`|True if x is not true.|\n+|`x IS FALSE`|True if x is false.|\n+|`x IS NOT FALSE`|True if x is not false.|\n+|`x IN (values)`|True if x is one of the listed values.|\n+|`x NOT IN (values)`|True if x is not one of the listed values.|\n+|`x IN (subquery)`|True if x is returned by the subquery. See [Syntax and execution](#syntax-and-execution) above for details about how Druid SQL handles `IN (subquery)`.|\n+|`x NOT IN (subquery)`|True if x is not returned by the subquery. See [Syntax and execution](#syntax-and-execution) for details about how Druid SQL handles `IN (subquery)`.|\n+|`x AND y`|Boolean AND.|\n+|`x OR y`|Boolean OR.|\n+|`NOT x`|Boolean NOT.|\n+\n+### Other functions\n+\n+|Function|Notes|\n+|--------|-----|\n+|`CAST(value AS TYPE)`|Cast value to another type. See [Data types and casts](#data-types-and-casts) for details about how Druid SQL handles CAST.|\n+|`CASE expr WHEN value1 THEN result1 \\[ WHEN value2 THEN result2 ... \\] \\[ ELSE resultN \\] END`|Simple CASE.|\n+|`CASE WHEN boolean_expr1 THEN result1 \\[ WHEN boolean_expr2 THEN result2 ... \\] \\[ ELSE resultN \\] END`|Searched CASE.|\n+|`NULLIF(value1, value2)`|Returns NULL if value1 and value2 match, else returns value1.|\n+|`COALESCE(value1, value2, ...)`|Returns the first value that is neither NULL nor empty string.|\n \n-try (Connection connection = DriverManager.getConnection(url, connectionProperties)) {\n-  try (ResultSet resultSet = connection.createStatement().executeQuery(\"SELECT COUNT(*) AS cnt FROM data_source\")) {\n-    while (resultSet.next()) {\n-      // Do something\n-    }\n-  }\n-}\n-```\n+### Unsupported features\n \n-Table metadata is available over JDBC using `connection.getMetaData()` or by querying the \"INFORMATION_SCHEMA\" tables\n-(see below).\n+Druid does not support all SQL features, including:\n \n-Parameterized queries don't work properly, so avoid those.\n+- OVER clauses, and analytic functions such as `LAG` and `LEAD`.\n+- JOIN clauses, other than semi-joins as described above.\n+- OFFSET clauses.\n+- DDL and DML.\n \n-### Querying with JSON over HTTP\n+Additionally, some Druid features are not supported by the SQL language. Some unsupported Druid features include:\n \n-You can make Druid SQL queries using JSON over HTTP by POSTing to the endpoint `/druid/v2/sql/`. The request format\n-is:\n+- [Multi-value dimensions](multi-value-dimensions.html).\n+- [DataSketches aggregators](../development/extensions-core/datasketches-aggregators.html).\n+\n+## Data types and casts\n+\n+Druid natively supports four main column types: \"long\" (64 bit signed int), \"float\" (32 bit float), \"string\" (UTF-8\n+encoded strings), and \"complex\" (catch-all for more exotic data types like hyperUnique and approxHistogram columns).\n+Timestamps (including the `__time` column) are stored as longs, with the value being the number of milliseconds since 1\n+January 1970 UTC.\n+\n+At runtime, Druid will widen floats to \"double\" (64 bit float) for certain features, like `SUM` aggregators. But this\n+widening is not universal; some floating point operations retain 32 bit precision.\n+\n+Druid generally treats NULLs and empty strings interchangeably, rather than according to the SQL standard. As such,\n+Druid SQL only has partial support for NULLs. For example, the expressions `col IS NULL` and `col = ''` are equivalent,\n+and both will evaluate to true if `col` contains an empty string. Similarly, the expression `COALESCE(col1, col2)` will\n+return `col2` if `col1` is an empty string. While the `COUNT(*)` aggregator counts all rows, the `COUNT(expr)`\n+aggregator will count the number of rows where expr is neither null nor the empty string. String columns in Druid are\n+NULLable. Numeric columns are NOT NULL; if you query a numeric column that is not present in all segments of your Druid","path":"docs/content/querying/sql.md","position":257,"original_position":257,"commit_id":"7ffbbc0055534ccb85850437cf65e0fdd7fd7ba0","original_commit_id":"7ffbbc0055534ccb85850437cf65e0fdd7fd7ba0","user":{"login":"gianm","id":1214075,"avatar_url":"https://avatars0.githubusercontent.com/u/1214075?v=3","gravatar_id":"","url":"https://api.github.com/users/gianm","html_url":"https://github.com/gianm","followers_url":"https://api.github.com/users/gianm/followers","following_url":"https://api.github.com/users/gianm/following{/other_user}","gists_url":"https://api.github.com/users/gianm/gists{/gist_id}","starred_url":"https://api.github.com/users/gianm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gianm/subscriptions","organizations_url":"https://api.github.com/users/gianm/orgs","repos_url":"https://api.github.com/users/gianm/repos","events_url":"https://api.github.com/users/gianm/events{/privacy}","received_events_url":"https://api.github.com/users/gianm/received_events","type":"User","site_admin":false},"body":"I guess it's a matter of how you want to think about it.\r\n\r\nWhat is really happening in the Druid runtime is that for columns that the SQL layer believes are numeric, a LongColumnSelector or FloatColumnSelector will get created. If the column doesn't actually exist in a particular segment, the StorageAdapter will generate a selector that returns all zeroes.\r\n\r\nMaybe you could think of that as \"casting null to zero\". I'm not sure if that's the right way to think about it or not.","created_at":"2017-06-30T22:56:22Z","updated_at":"2017-06-30T22:56:22Z","html_url":"https://github.com/druid-io/druid/pull/4360#discussion_r125143875","pull_request_url":"https://api.github.com/repos/druid-io/druid/pulls/4360","_links":{"self":{"href":"https://api.github.com/repos/druid-io/druid/pulls/comments/125143875"},"html":{"href":"https://github.com/druid-io/druid/pull/4360#discussion_r125143875"},"pull_request":{"href":"https://api.github.com/repos/druid-io/druid/pulls/4360"}}},"pull_request":{"url":"https://api.github.com/repos/druid-io/druid/pulls/4360","id":123793140,"html_url":"https://github.com/druid-io/druid/pull/4360","diff_url":"https://github.com/druid-io/druid/pull/4360.diff","patch_url":"https://github.com/druid-io/druid/pull/4360.patch","issue_url":"https://api.github.com/repos/druid-io/druid/issues/4360","number":4360,"state":"open","locked":false,"title":"SQL + Expressions = Best friends forever.","user":{"login":"gianm","id":1214075,"avatar_url":"https://avatars0.githubusercontent.com/u/1214075?v=3","gravatar_id":"","url":"https://api.github.com/users/gianm","html_url":"https://github.com/gianm","followers_url":"https://api.github.com/users/gianm/followers","following_url":"https://api.github.com/users/gianm/following{/other_user}","gists_url":"https://api.github.com/users/gianm/gists{/gist_id}","starred_url":"https://api.github.com/users/gianm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gianm/subscriptions","organizations_url":"https://api.github.com/users/gianm/orgs","repos_url":"https://api.github.com/users/gianm/repos","events_url":"https://api.github.com/users/gianm/events{/privacy}","received_events_url":"https://api.github.com/users/gianm/received_events","type":"User","site_admin":false},"body":"This is a follow-up to #4207, but taking a different approach. The line count is higher but that's mostly because this patch also adds important functionality (in particular, post-aggregation projections, and a lot of new functions) that the other patch didn't have.\r\n\r\nThe motivation is to make more kinds of queries possible. With the changes in this patch, these are all possible in both native queries and Druid SQL queries:\r\n\r\n- Grouping by functions of multiple columns (e.g. group by `concat(lastName, \", \", firstName)`)\r\n- Filtering on functions of multiple columns (e.g. filter where `x > y`)\r\n- Post-aggregation projections on dimensions (e.g. group by `mydim` but include `strlen(mydim)` as a post-aggregation)\r\n- Ordering by post-aggregation projections (e.g. group by `mydim` but order by `lower(mydim)`)\r\n\r\nMain changes:\r\n\r\n- Use expressions as a projection layer for anything that can't be\r\n  expressed using traditional Druid extractionFns. Sometimes they're\r\n  embedded directly (like \"expression\" filters, builtin aggregators,\r\n  or \"expression\" post-aggregators). Sometimes they're referenced\r\n  through virtual columns (like dimensionSpecs, which can't innately\r\n  reference functions of more than one column without the virtual\r\n  column layer).\r\n- Add many new functions and operators, taking advantage of the\r\n  expression capability (see the querying/sql.md doc).\r\n- Improve consistency of constant reduction and of casting by\r\n  using Druid expressions for this instead of Calcite's RexExecutor.","created_at":"2017-06-02T20:20:10Z","updated_at":"2017-06-30T22:56:22Z","closed_at":null,"merged_at":null,"merge_commit_sha":"43ffbef0ac02879b1a654298b2dce950dddc66ad","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":{"url":"https://api.github.com/repos/druid-io/druid/milestones/23","html_url":"https://github.com/druid-io/druid/milestone/23","labels_url":"https://api.github.com/repos/druid-io/druid/milestones/23/labels","id":2338417,"number":23,"title":"0.11.0","description":"","creator":{"login":"gianm","id":1214075,"avatar_url":"https://avatars0.githubusercontent.com/u/1214075?v=3","gravatar_id":"","url":"https://api.github.com/users/gianm","html_url":"https://github.com/gianm","followers_url":"https://api.github.com/users/gianm/followers","following_url":"https://api.github.com/users/gianm/following{/other_user}","gists_url":"https://api.github.com/users/gianm/gists{/gist_id}","starred_url":"https://api.github.com/users/gianm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gianm/subscriptions","organizations_url":"https://api.github.com/users/gianm/orgs","repos_url":"https://api.github.com/users/gianm/repos","events_url":"https://api.github.com/users/gianm/events{/privacy}","received_events_url":"https://api.github.com/users/gianm/received_events","type":"User","site_admin":false},"open_issues":28,"closed_issues":16,"state":"open","created_at":"2017-02-21T17:48:27Z","updated_at":"2017-06-30T17:38:40Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/druid-io/druid/pulls/4360/commits","review_comments_url":"https://api.github.com/repos/druid-io/druid/pulls/4360/comments","review_comment_url":"https://api.github.com/repos/druid-io/druid/pulls/comments{/number}","comments_url":"https://api.github.com/repos/druid-io/druid/issues/4360/comments","statuses_url":"https://api.github.com/repos/druid-io/druid/statuses/7ffbbc0055534ccb85850437cf65e0fdd7fd7ba0","head":{"label":"gianm:sql-expression","ref":"sql-expression","sha":"7ffbbc0055534ccb85850437cf65e0fdd7fd7ba0","user":{"login":"gianm","id":1214075,"avatar_url":"https://avatars0.githubusercontent.com/u/1214075?v=3","gravatar_id":"","url":"https://api.github.com/users/gianm","html_url":"https://github.com/gianm","followers_url":"https://api.github.com/users/gianm/followers","following_url":"https://api.github.com/users/gianm/following{/other_user}","gists_url":"https://api.github.com/users/gianm/gists{/gist_id}","starred_url":"https://api.github.com/users/gianm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gianm/subscriptions","organizations_url":"https://api.github.com/users/gianm/orgs","repos_url":"https://api.github.com/users/gianm/repos","events_url":"https://api.github.com/users/gianm/events{/privacy}","received_events_url":"https://api.github.com/users/gianm/received_events","type":"User","site_admin":false},"repo":{"id":28350072,"name":"druid","full_name":"gianm/druid","owner":{"login":"gianm","id":1214075,"avatar_url":"https://avatars0.githubusercontent.com/u/1214075?v=3","gravatar_id":"","url":"https://api.github.com/users/gianm","html_url":"https://github.com/gianm","followers_url":"https://api.github.com/users/gianm/followers","following_url":"https://api.github.com/users/gianm/following{/other_user}","gists_url":"https://api.github.com/users/gianm/gists{/gist_id}","starred_url":"https://api.github.com/users/gianm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gianm/subscriptions","organizations_url":"https://api.github.com/users/gianm/orgs","repos_url":"https://api.github.com/users/gianm/repos","events_url":"https://api.github.com/users/gianm/events{/privacy}","received_events_url":"https://api.github.com/users/gianm/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/gianm/druid","description":"Real²time Exploratory Analytics on Large Datasets","fork":true,"url":"https://api.github.com/repos/gianm/druid","forks_url":"https://api.github.com/repos/gianm/druid/forks","keys_url":"https://api.github.com/repos/gianm/druid/keys{/key_id}","collaborators_url":"https://api.github.com/repos/gianm/druid/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/gianm/druid/teams","hooks_url":"https://api.github.com/repos/gianm/druid/hooks","issue_events_url":"https://api.github.com/repos/gianm/druid/issues/events{/number}","events_url":"https://api.github.com/repos/gianm/druid/events","assignees_url":"https://api.github.com/repos/gianm/druid/assignees{/user}","branches_url":"https://api.github.com/repos/gianm/druid/branches{/branch}","tags_url":"https://api.github.com/repos/gianm/druid/tags","blobs_url":"https://api.github.com/repos/gianm/druid/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/gianm/druid/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/gianm/druid/git/refs{/sha}","trees_url":"https://api.github.com/repos/gianm/druid/git/trees{/sha}","statuses_url":"https://api.github.com/repos/gianm/druid/statuses/{sha}","languages_url":"https://api.github.com/repos/gianm/druid/languages","stargazers_url":"https://api.github.com/repos/gianm/druid/stargazers","contributors_url":"https://api.github.com/repos/gianm/druid/contributors","subscribers_url":"https://api.github.com/repos/gianm/druid/subscribers","subscription_url":"https://api.github.com/repos/gianm/druid/subscription","commits_url":"https://api.github.com/repos/gianm/druid/commits{/sha}","git_commits_url":"https://api.github.com/repos/gianm/druid/git/commits{/sha}","comments_url":"https://api.github.com/repos/gianm/druid/comments{/number}","issue_comment_url":"https://api.github.com/repos/gianm/druid/issues/comments{/number}","contents_url":"https://api.github.com/repos/gianm/druid/contents/{+path}","compare_url":"https://api.github.com/repos/gianm/druid/compare/{base}...{head}","merges_url":"https://api.github.com/repos/gianm/druid/merges","archive_url":"https://api.github.com/repos/gianm/druid/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/gianm/druid/downloads","issues_url":"https://api.github.com/repos/gianm/druid/issues{/number}","pulls_url":"https://api.github.com/repos/gianm/druid/pulls{/number}","milestones_url":"https://api.github.com/repos/gianm/druid/milestones{/number}","notifications_url":"https://api.github.com/repos/gianm/druid/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/gianm/druid/labels{/name}","releases_url":"https://api.github.com/repos/gianm/druid/releases{/id}","deployments_url":"https://api.github.com/repos/gianm/druid/deployments","created_at":"2014-12-22T17:32:01Z","updated_at":"2016-01-18T01:27:33Z","pushed_at":"2017-06-29T21:38:14Z","git_url":"git://github.com/gianm/druid.git","ssh_url":"git@github.com:gianm/druid.git","clone_url":"https://github.com/gianm/druid.git","svn_url":"https://github.com/gianm/druid","homepage":"http://druid.io","size":122614,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"druid-io:master","ref":"master","sha":"9ae457f7ad1a4771bc5aacab3005d91d881b365e","user":{"login":"druid-io","id":4203474,"avatar_url":"https://avatars3.githubusercontent.com/u/4203474?v=3","gravatar_id":"","url":"https://api.github.com/users/druid-io","html_url":"https://github.com/druid-io","followers_url":"https://api.github.com/users/druid-io/followers","following_url":"https://api.github.com/users/druid-io/following{/other_user}","gists_url":"https://api.github.com/users/druid-io/gists{/gist_id}","starred_url":"https://api.github.com/users/druid-io/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/druid-io/subscriptions","organizations_url":"https://api.github.com/users/druid-io/orgs","repos_url":"https://api.github.com/users/druid-io/repos","events_url":"https://api.github.com/users/druid-io/events{/privacy}","received_events_url":"https://api.github.com/users/druid-io/received_events","type":"Organization","site_admin":false},"repo":{"id":6358188,"name":"druid","full_name":"druid-io/druid","owner":{"login":"druid-io","id":4203474,"avatar_url":"https://avatars3.githubusercontent.com/u/4203474?v=3","gravatar_id":"","url":"https://api.github.com/users/druid-io","html_url":"https://github.com/druid-io","followers_url":"https://api.github.com/users/druid-io/followers","following_url":"https://api.github.com/users/druid-io/following{/other_user}","gists_url":"https://api.github.com/users/druid-io/gists{/gist_id}","starred_url":"https://api.github.com/users/druid-io/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/druid-io/subscriptions","organizations_url":"https://api.github.com/users/druid-io/orgs","repos_url":"https://api.github.com/users/druid-io/repos","events_url":"https://api.github.com/users/druid-io/events{/privacy}","received_events_url":"https://api.github.com/users/druid-io/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/druid-io/druid","description":"Column oriented distributed data store ideal for powering interactive applications","fork":false,"url":"https://api.github.com/repos/druid-io/druid","forks_url":"https://api.github.com/repos/druid-io/druid/forks","keys_url":"https://api.github.com/repos/druid-io/druid/keys{/key_id}","collaborators_url":"https://api.github.com/repos/druid-io/druid/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/druid-io/druid/teams","hooks_url":"https://api.github.com/repos/druid-io/druid/hooks","issue_events_url":"https://api.github.com/repos/druid-io/druid/issues/events{/number}","events_url":"https://api.github.com/repos/druid-io/druid/events","assignees_url":"https://api.github.com/repos/druid-io/druid/assignees{/user}","branches_url":"https://api.github.com/repos/druid-io/druid/branches{/branch}","tags_url":"https://api.github.com/repos/druid-io/druid/tags","blobs_url":"https://api.github.com/repos/druid-io/druid/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/druid-io/druid/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/druid-io/druid/git/refs{/sha}","trees_url":"https://api.github.com/repos/druid-io/druid/git/trees{/sha}","statuses_url":"https://api.github.com/repos/druid-io/druid/statuses/{sha}","languages_url":"https://api.github.com/repos/druid-io/druid/languages","stargazers_url":"https://api.github.com/repos/druid-io/druid/stargazers","contributors_url":"https://api.github.com/repos/druid-io/druid/contributors","subscribers_url":"https://api.github.com/repos/druid-io/druid/subscribers","subscription_url":"https://api.github.com/repos/druid-io/druid/subscription","commits_url":"https://api.github.com/repos/druid-io/druid/commits{/sha}","git_commits_url":"https://api.github.com/repos/druid-io/druid/git/commits{/sha}","comments_url":"https://api.github.com/repos/druid-io/druid/comments{/number}","issue_comment_url":"https://api.github.com/repos/druid-io/druid/issues/comments{/number}","contents_url":"https://api.github.com/repos/druid-io/druid/contents/{+path}","compare_url":"https://api.github.com/repos/druid-io/druid/compare/{base}...{head}","merges_url":"https://api.github.com/repos/druid-io/druid/merges","archive_url":"https://api.github.com/repos/druid-io/druid/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/druid-io/druid/downloads","issues_url":"https://api.github.com/repos/druid-io/druid/issues{/number}","pulls_url":"https://api.github.com/repos/druid-io/druid/pulls{/number}","milestones_url":"https://api.github.com/repos/druid-io/druid/milestones{/number}","notifications_url":"https://api.github.com/repos/druid-io/druid/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/druid-io/druid/labels{/name}","releases_url":"https://api.github.com/repos/druid-io/druid/releases{/id}","deployments_url":"https://api.github.com/repos/druid-io/druid/deployments","created_at":"2012-10-23T19:08:07Z","updated_at":"2017-06-30T21:21:44Z","pushed_at":"2017-06-30T20:16:40Z","git_url":"git://github.com/druid-io/druid.git","ssh_url":"git@github.com:druid-io/druid.git","clone_url":"https://github.com/druid-io/druid.git","svn_url":"https://github.com/druid-io/druid","homepage":"http://druid.io","size":122572,"stargazers_count":5058,"watchers_count":5058,"language":"Java","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1228,"mirror_url":null,"open_issues_count":731,"forks":1228,"open_issues":731,"watchers":5058,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/druid-io/druid/pulls/4360"},"html":{"href":"https://github.com/druid-io/druid/pull/4360"},"issue":{"href":"https://api.github.com/repos/druid-io/druid/issues/4360"},"comments":{"href":"https://api.github.com/repos/druid-io/druid/issues/4360/comments"},"review_comments":{"href":"https://api.github.com/repos/druid-io/druid/pulls/4360/comments"},"review_comment":{"href":"https://api.github.com/repos/druid-io/druid/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/druid-io/druid/pulls/4360/commits"},"statuses":{"href":"https://api.github.com/repos/druid-io/druid/statuses/7ffbbc0055534ccb85850437cf65e0fdd7fd7ba0"}}}}
{"actor":{"display_login":"gianm"}}