Skip to content
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

Fix 4501 PostgreSql sequence #4528

Merged
merged 11 commits into from
Nov 30, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ class PostgreSqlTypeResolver(private val parentResolver: TypeResolver) : TypeRes
-> IntermediateType(TEXT)
"json_array_length", "jsonb_array_length" -> IntermediateType(INTEGER)
"jsonb_path_exists", "jsonb_path_match", "jsonb_path_exists_tz", "jsonb_path_match_tz" -> IntermediateType(BOOLEAN)
"currval", "lastval", "nextval", "setval" -> IntermediateType(BIG_INT)
"generate_series" -> encapsulatingType(exprList, INTEGER, BIG_INT, REAL, TIMESTAMP_TIMEZONE, TIMESTAMP)
else -> null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"static com.alecstrong.sql.psi.core.psi.SqlTypes.LIMIT"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.LP"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.MINUS"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.NO"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.NOT"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.NOTHING"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.NULL"
Expand All @@ -69,6 +70,8 @@
"static com.alecstrong.sql.psi.core.psi.SqlTypes.SELECT"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.SET"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.STRING"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.TEMP"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.TEMPORARY"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.TO"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.TRUE"
"static com.alecstrong.sql.psi.core.psi.SqlTypes.UNIQUE"
Expand Down Expand Up @@ -364,7 +367,7 @@ json_expression ::= {column_name} ( jsona_binary_operator | jsonb_binary_operato
jsona_binary_operator ::= '->' | '->>' | '#>'
jsonb_binary_operator ::= '@>' | '<@' | '?|' | '?&' | '?' | '#-'

extension_stmt ::= copy_stdin {
extension_stmt ::= create_sequence_stmt | copy_stdin {
extends = "com.alecstrong.sql.psi.core.psi.impl.SqlExtensionStmtImpl"
implements = "com.alecstrong.sql.psi.core.psi.SqlExtensionStmt"
override = true
Expand All @@ -374,6 +377,21 @@ copy_stdin ::= 'COPY' [ {database_name} DOT ] {table_name} [ AS {table_alias} ]
mixin = "app.cash.sqldelight.dialects.postgresql.grammar.mixins.CopyMixin"
}

sequence_name ::= id | string

sequence_data_type ::= ( small_int_data_type
| int_data_type
| big_int_data_type )

create_sequence_stmt ::= CREATE [ (TEMPORARY | TEMP) | 'UNLOGGED' ] 'SEQUENCE' [ IF NOT EXISTS ] sequence_name
[ AS sequence_data_type ]
[ 'INCREMENT' [ BY ] {signed_number} ]
[ 'MINVALUE' {signed_number} | NO 'MINVALUE' ] [ 'MAXVALUE' {signed_number} | NO 'MAXVALUE' ]
[ 'START' [ WITH ] {signed_number} ] [ 'CACHE' {signed_number} ] [ [ NO ] 'CYCLE' ]
[ 'OWNED' BY ( {table_name} DOT {column_name} ) | 'NONE' ] {
mixin = "app.cash.sqldelight.dialects.postgresql.grammar.mixins.CreateSequenceMixin"
}

copy_option ::= copy_option_format | copy_option_freeze | copy_option_delimiter | copy_option_null | copy_option_header | copy_option_quote | copy_option_escape | copy_option_force_not_null | copy_option_force_null | copy_option_encoding
copy_option_format ::= 'FORMAT' ('TEXT' | 'CSV' | 'BINARY')
copy_option_freeze ::= 'FREEZE' [ (boolean_literal) ]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package app.cash.sqldelight.dialects.postgresql.grammar.mixins

import app.cash.sqldelight.dialects.postgresql.grammar.psi.PostgreSqlCreateSequenceStmt
import com.alecstrong.sql.psi.core.psi.QueryElement
import com.alecstrong.sql.psi.core.psi.SqlCompositeElementImpl
import com.intellij.lang.ASTNode
import com.intellij.psi.PsiElement

internal abstract class CreateSequenceMixin(node: ASTNode) :
SqlCompositeElementImpl(node),
PostgreSqlCreateSequenceStmt {
// Query any owner tableName element to allow the columnName to be resolved
override fun queryAvailable(child: PsiElement): Collection<QueryElement.QueryResult> {
return tablesAvailable(child).map { it.query }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
CREATE TABLE abc (
id INTEGER PRIMARY KEY
);

CREATE SEQUENCE integers_01;

CREATE SEQUENCE integers_02 START 31
OWNED BY abc.id;

CREATE SEQUENCE integers_03 AS INTEGER
INCREMENT 10
MINVALUE 100
MAXVALUE 250000
START 101
CACHE 1
NO CYCLE;

CREATE TEMPORARY SEQUENCE IF NOT EXISTS integers_04 AS SMALLINT
INCREMENT BY 2
NO MINVALUE
NO MAXVALUE
START WITH 3
CYCLE;

SELECT nextval('integers_01');

SELECT nextval('integers_02');

SELECT nextval('integers_03');

SELECT nextval('integers_04');
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
CREATE SEQUENCE serial START 200;

CREATE TABLE sigma (
id INTEGER PRIMARY KEY
);

insertNextVal:
INSERT INTO sigma VALUES (nextval('serial'))
RETURNING id;

selectNextVal:
SELECT nextval('serial');

selectCurrentVal:
SELECT currval('serial');

selectLastVal:
SELECT lastval();

selectSetVal:
SELECT setval('serial', 200, TRUE);
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,19 @@ class PostgreSqlTest {
}
}

@Test fun sequenceFunctions() {
val nextVal = database.sequencesQueries.insertNextVal().executeAsOne()
val currVal = database.sequencesQueries.selectCurrentVal().executeAsOne()
assertThat(nextVal).isEqualTo(currVal)

val selectNextVal = database.sequencesQueries.selectNextVal().executeAsOne()
val lastVal = database.sequencesQueries.selectLastVal().executeAsOne()
assertThat(selectNextVal).isEqualTo(lastVal)

val selectSetVal = database.sequencesQueries.selectSetVal().executeAsOne()
assertThat(selectSetVal).isEqualTo(nextVal)
}

@Test
fun testGenerateSeries() {
val start = OffsetDateTime.of(2023, 9, 1, 0, 0, 0, 0, ZoneOffset.ofHours(0))
Expand Down