Skip to content

Commit

Permalink
Merge pull request #205 from takapi327/feature/2024-04-Create-Callabl…
Browse files Browse the repository at this point in the history
…eStatement

Feature/2024 04 create callable statement
  • Loading branch information
takapi327 authored May 12, 2024
2 parents 10fb7cd + dccfeb4 commit 0ecd064
Show file tree
Hide file tree
Showing 13 changed files with 2,076 additions and 19 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ JVM, JS and Native platforms are all supported.

- [x] Statement
- [x] PreparedStatement
- [ ] CallableStatement
- [x] CallableStatement
- [ ] ResultSet Insert/Update/Delete

### Transaction function implementation
Expand All @@ -86,13 +86,13 @@ JVM, JS and Native platforms are all supported.

### Utility Commands

- [x] [COM_QUIT](https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_quit.html)
- [x] [COM_INIT_DB](https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_init_db.html)
- [x] [COM_STATISTICS](https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_statistics.html)
- [x] [COM_PING](https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_ping.html)
- [x] [COM_CHANGE_USER](https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_change_user.html)
- [x] [COM_RESET_CONNECTION](https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_reset_connection.html)
- [x] [COM_SET_OPTION](https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_set_option.html)
- [x] COM_QUIT
- [x] COM_INIT_DB
- [x] COM_STATISTICS
- [x] COM_PING
- [x] COM_CHANGE_USER
- [x] COM_RESET_CONNECTION
- [x] COM_SET_OPTION

### Connection pooling implementation

Expand Down
61 changes: 59 additions & 2 deletions database/connector_test.sql
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,35 @@ INSERT INTO `all_types` VALUES (

CREATE TABLE `transaction_test`(`c1` BIGINT NOT NULL);

delimiter //
CREATE TABLE `tax` (`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, `value` DOUBLE NOT NULL, `start_date` DATE NOT NULL);
INSERT INTO `tax` (`value`, `start_date`) VALUES (0.05, '2020-01-01'), (0.08, '2020-02-01'), (0.1, '2020-03-01');

DELIMITER //
CREATE PROCEDURE proc1()
BEGIN
SELECT VERSION();
END;
//

CREATE PROCEDURE proc2(IN param INT)
BEGIN
SELECT param;
END;
//

CREATE PROCEDURE proc3(IN param1 INT, IN param2 VARCHAR(8))
BEGIN
SELECT param1, param2;
END;
//

CREATE PROCEDURE proc4(OUT param1 INT, OUT param2 VARCHAR(8))
BEGIN
SET param1 = -1;
SET param2 = 'hello';
END;
//

CREATE PROCEDURE demoSp(IN inputParam VARCHAR(255), INOUT inOutParam INT)
BEGIN
DECLARE z INT;
Expand All @@ -187,7 +215,36 @@ SELECT inputParam;
SELECT CONCAT('zyxw', inputParam);
END
//
delimiter ;

CREATE FUNCTION func1()
RETURNS INT DETERMINISTIC
BEGIN
RETURN -1;
END;
//

CREATE FUNCTION func2()
RETURNS VARCHAR(12) DETERMINISTIC
BEGIN
RETURN 'hello, world';
END;
//

CREATE FUNCTION getPrice(price int)
RETURNS INT DETERMINISTIC
BEGIN
declare tax DOUBLE DEFAULT 0.1;

SELECT VALUE INTO tax
from tax
WHERE start_date <= current_date
ORDER BY start_date DESC
LIMIT 1;

RETURN TRUNCATE(price + (price * tax), 0);
END;
//
DELIMITER ;

CREATE TABLE `privileges_table` (
`c1` INT NOT NULL PRIMARY KEY,
Expand Down
63 changes: 62 additions & 1 deletion docs/src/main/mdoc/en/09-Connector.md
Original file line number Diff line number Diff line change
Expand Up @@ -776,12 +776,73 @@ connection.use { conn =>

This is because if you are using `PreparedStatement`, you can set multiple parameters for a single query by using the `addBatch` method after setting the query parameters.

## Stored Procedure Execution

LDBC provides an API for executing stored procedures.

To execute a stored procedure, use the `prepareCall` method of `Connection` to construct a `CallableStatement`.

※ The stored procedures used are those described in the [official](https://dev.mysql.com/doc/connector-j/en/connector-j-usagenotes-statements-callable.html) document.

```sql
CREATE PROCEDURE demoSp(IN inputParam VARCHAR(255), INOUT inOutParam INT)
BEGIN
DECLARE z INT;
SET z = inOutParam + 1;
SET inOutParam = z;

SELECT inputParam;

SELECT CONCAT('zyxw', inputParam);
END
```

To execute the above stored procedure, the following would be used

```scala
connection.use { conn =>
for
callableStatement <- conn.prepareCall("CALL demoSp(?, ?)")
_ <- callableStatement.setString(1, "abcdefg")
_ <- callableStatement.setInt(2, 1)
hasResult <- callableStatement.execute()
values <- Monad[IO].whileM[List, Option[String]](callableStatement.getMoreResults()) {
for
resultSet <- callableStatement.getResultSet().flatMap {
case Some(rs) => IO.pure(rs)
case None => IO.raiseError(new Exception("No result set"))
}
value <- resultSet.getString(1)
yield value
}
yield values // List(Some("abcdefg"), Some("zyxwabcdefg"))
}
```

To get the value of an output parameter (a parameter you specified as OUT or INOUT when you created the stored procedure), in JDBC you must use the various `registerOutputParameter()` methods of the CallableStatement interface to specify parameters before statement execution, while LDBC will also set parameters during query execution by simply setting them using the `setXXX` method.

However, LDBC also allows you to specify parameters using the `registerOutputParameter()` method.

```scala
connection.use { conn =>
for
callableStatement <- conn.prepareCall("CALL demoSp(?, ?)")
_ <- callableStatement.setString(1, "abcdefg")
_ <- callableStatement.setInt(2, 1)
_ <- callableStatement.registerOutParameter(2, ldbc.connector.data.Types.INTEGER)
hasResult <- callableStatement.execute()
value <- callableStatement.getInt(2)
yield value // 2
}
```

※ Note that if you specify an Out parameter with `registerOutParameter`, the value will be set at `Null` for the server if the parameter is not set with the `setXXX` method using the same index value.

## Unsupported Feature

The LDBC connector is currently an experimental feature. Therefore, the following features are not supported.
We plan to provide the features as they become available.

- Connection Pooling
- Failover measures
- Execution of SQL Stored Procedures
- etc...
63 changes: 62 additions & 1 deletion docs/src/main/mdoc/ja/09-Connector.md
Original file line number Diff line number Diff line change
Expand Up @@ -770,12 +770,73 @@ connection.use { conn =>

これは、`PreparedStatement`を使用している場合、クエリのパラメーターを設定した後に`addBatch`メソッドを使用することで、1つのクエリに複数のパラメーターを設定することができるためです。

## ストアドプロシージャの実行

LDBCではストアドプロシージャを実行するためのAPIを提供しています。

ストアドプロシージャを実行するには`Connection``prepareCall`メソッドを使用して`CallableStatement`を構築します。

※ 使用するストアドプロシージャは[公式](https://dev.mysql.com/doc/connector-j/en/connector-j-usagenotes-statements-callable.html)ドキュメント記載のものを使用しています。

```sql
CREATE PROCEDURE demoSp(IN inputParam VARCHAR(255), INOUT inOutParam INT)
BEGIN
DECLARE z INT;
SET z = inOutParam + 1;
SET inOutParam = z;

SELECT inputParam;

SELECT CONCAT('zyxw', inputParam);
END
```

上記のストアドプロシージャを実行する場合は以下のようになります。

```scala
connection.use { conn =>
for
callableStatement <- conn.prepareCall("CALL demoSp(?, ?)")
_ <- callableStatement.setString(1, "abcdefg")
_ <- callableStatement.setInt(2, 1)
hasResult <- callableStatement.execute()
values <- Monad[IO].whileM[List, Option[String]](callableStatement.getMoreResults()) {
for
resultSet <- callableStatement.getResultSet().flatMap {
case Some(rs) => IO.pure(rs)
case None => IO.raiseError(new Exception("No result set"))
}
value <- resultSet.getString(1)
yield value
}
yield values // List(Some("abcdefg"), Some("zyxwabcdefg"))
}
```

出力パラメータ(ストアド・プロシージャを作成したときにOUTまたはINOUTとして指定したパラメータ)の値を取得するには、JDBCでは、CallableStatementインターフェイスのさまざまな`registerOutputParameter()`メソッドを使用して、ステートメント実行前にパラメータを指定する必要がありますが、LDBCでは`setXXX`メソッドを使用してパラメータを設定することだけクエリ実行時にパラメーターの設定も行なってくれます。

ただし、LDBCでも`registerOutputParameter()`メソッドを使用してパラメータを指定することもできます。

```scala
connection.use { conn =>
for
callableStatement <- conn.prepareCall("CALL demoSp(?, ?)")
_ <- callableStatement.setString(1, "abcdefg")
_ <- callableStatement.setInt(2, 1)
_ <- callableStatement.registerOutParameter(2, ldbc.connector.data.Types.INTEGER)
hasResult <- callableStatement.execute()
value <- callableStatement.getInt(2)
yield value // 2
}
```

`registerOutParameter`でOutパラメータを指定する場合、同じindex値を使用して`setXXX`メソッドでパラメータを設定していない場合サーバーには`Null`で値が設定されることに注意してください。

## 未対応機能

LDBCコネクタは現在実験的な機能となります。そのため、以下の機能はサポートされていません。
機能提供は順次行っていく予定です。

- コネクションプーリング
- フェイルオーバー対策
- SQL ストアドプロシージャの実行
- etc...
Loading

0 comments on commit 0ecd064

Please sign in to comment.