== Vert.x Common SQL interface

The common SQL interface is used to interact with Vert.x SQL services.

You obtain a connection to the database via the service interface for the specific SQL service that
you are using (e.g. JDBC/MySQL/PostgreSQL).

To use this project, add the following dependency to the _dependencies_ section of your build descriptor:

* Maven (in your `pom.xml`):

[source,xml,subs="+attributes"]
----
<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-sql-common</artifactId>
  <version>3.4.2</version>
</dependency>
----

* Gradle (in your `build.gradle` file):

[source,groovy,subs="+attributes"]
----
compile 'io.vertx:vertx-sql-common:3.4.2'
----

== The SQL Connection

A connection to the database is represented by `link:../../yardoc/VertxSql/SQLConnection.html[SQLConnection]`.

=== Auto-commit

When you obtain a connection auto commit is set to `true`. This means that each operation you perform will effectively
execute in its own transaction.

If you wish to perform multiple operations in a single transaction you should set auto commit to false with
`link:../../yardoc/VertxSql/SQLConnection.html#set_auto_commit-instance_method[setAutoCommit]`.

When the operation is complete, the handler will be called:

[source,java]
----
connection.set_auto_commit(false) { |res_err,res|
  if (res_err == nil)
    # OK!
  else
    # Failed!
  end
}

----

=== Executing queries

To execute a query use `link:../../yardoc/VertxSql/SQLConnection.html#query-instance_method[query]`

The query string is raw SQL that is passed through without changes to the actual database.

The handler will be called with the results, represented by `link:../dataobjects.html#ResultSet[ResultSet]` when the query has
been run.

[source,java]
----
connection.query("SELECT ID, FNAME, LNAME, SHOE_SIZE from PEOPLE") { |res_err,res|
  if (res_err == nil)
    # Get the result set
    resultSet = res
  else
    # Failed!
  end
}

----

The `link:../dataobjects.html#ResultSet[ResultSet]` instance represents the results of a query.

The list of column names are available with `link:../dataobjects.html#ResultSet#get_column_names-instance_method[getColumnNames]`, and the actual results
available with `link:../dataobjects.html#ResultSet#get_results-instance_method[getResults]`

The results are a list of `link:unavailable[JsonArray]` instances, one for each row of the results.

[source,java]
----

columnNames = resultSet['columnNames']

results = resultSet['results']

results.each do |row|

  id = row[0]
  fName = row[1]
  lName = row[2]
  shoeSize = row[3]

end


----

You can also retrieve the rows as a list of Json object instances with `link:../dataobjects.html#ResultSet#get_rows-instance_method[getRows]` -
this can give you a somewhat simpler API to work with, but please be aware that SQL results can contain duplicate
column names - if that's the case you should use `link:../dataobjects.html#ResultSet#get_results-instance_method[getResults]` instead.

Here's an example of iterating through the results as Json object instances:

[source,java]
----

rows = resultSet['rows']

rows.each do |row|

  id = row['ID']
  fName = row['FNAME']
  lName = row['LNAME']
  shoeSize = row['SHOE_SIZE']

end


----

=== Prepared statement queries

To execute a prepared statement query you can use
`link:../../yardoc/VertxSql/SQLConnection.html#query_with_params-instance_method[queryWithParams]`.

This takes the query, containing the parameter place holders, and a `link:unavailable[JsonArray]` or parameter
values.

[source,java]
----

query = "SELECT ID, FNAME, LNAME, SHOE_SIZE from PEOPLE WHERE LNAME=? AND SHOE_SIZE > ?"
params = [
  "Fox",
  9
]

connection.query_with_params(query, params) { |res_err,res|

  if (res_err == nil)
    # Get the result set
    resultSet = res
  else
    # Failed!
  end
}


----

=== Executing INSERT, UPDATE or DELETE

To execute an operation which updates the database use `link:../../yardoc/VertxSql/SQLConnection.html#update-instance_method[update]`.

The update string is raw SQL that is passed through without changes to the actual database.

The handler will be called with the results, represented by `link:../dataobjects.html#UpdateResult[UpdateResult]` when the update has
been run.

The update result holds the number of rows updated with `link:../dataobjects.html#UpdateResult#get_updated-instance_method[getUpdated]`, and
if the update generated keys, they are available with `link:../dataobjects.html#UpdateResult#get_keys-instance_method[getKeys]`.

[source,java]
----

connection.update("INSERT INTO PEOPLE VALUES (null, 'john', 'smith', 9)") { |res_err,res|
  if (res_err == nil)

    result = res
    puts "Updated no. of rows: #{result['updated']}"
    puts "Generated keys: #{result['keys']}"

  else
    # Failed!
  end
}



----

=== Prepared statement updates

To execute a prepared statement update you can use
`link:../../yardoc/VertxSql/SQLConnection.html#update_with_params-instance_method[updateWithParams]`.

This takes the update, containing the parameter place holders, and a `link:unavailable[JsonArray]` or parameter
values.

[source,java]
----

update = "UPDATE PEOPLE SET SHOE_SIZE = 10 WHERE LNAME=?"
params = [
  "Fox"
]

connection.update_with_params(update, params) { |res_err,res|

  if (res_err == nil)

    updateResult = res

    puts "No. of rows updated: #{updateResult['updated']}"

  else

    # Failed!

  end
}


----

=== Callable statements

To execute a callable statement (either SQL functions or SQL procedures) you can use
`link:../../yardoc/VertxSql/SQLConnection.html#call_with_params-instance_method[callWithParams]`.

This takes the callable statement using the standard JDBC format `{ call func_proc_name() }`, optionally including
parameter place holders e.g.: `{ call func_proc_name(?, ?) }`, a `link:unavailable[JsonArray]` containing the
parameter values and finally a `link:unavailable[JsonArray]` containing the
output types e.g.: `[null, 'VARCHAR']`.

Note that the index of the output type is as important as the params array. If the return value is the second
argument then the output array must contain a null value as the first element.

A SQL function returns some output using the `return` keyword, and in this case one can call it like this:

[source,java]
----
# Assume that there is a SQL function like this:
#
# create function one_hour_ago() returns timestamp
#    return now() - 1 hour;

# note that you do not need to declare the output for functions
func = "{ call one_hour_ago() }"

connection.call(func) { |res_err,res|

  if (res_err == nil)
    result = res
  else
    # Failed!
  end
}

----

When working with Procedures you and still return values from your procedures via its arguments, in the case you do
not return anything the usage is as follows:

[source,java]
----
# Assume that there is a SQL procedure like this:
#
# create procedure new_customer(firstname varchar(50), lastname varchar(50))
#   modifies sql data
#   insert into customers values (default, firstname, lastname, current_timestamp);

func = "{ call new_customer(?, ?) }"

connection.call_with_params(func, [
  "John",
  "Doe"
], nil) { |res_err,res|

  if (res_err == nil)
    # Success!
  else
    # Failed!
  end
}

----

However you can also return values like this:

[source,java]
----
# Assume that there is a SQL procedure like this:
#
# create procedure customer_lastname(IN firstname varchar(50), OUT lastname varchar(50))
#   modifies sql data
#   select lastname into lastname from customers where firstname = firstname;

func = "{ call customer_lastname(?, ?) }"

connection.call_with_params(func, [
  "John"
], [
  nil,
  "VARCHAR"
]) { |res_err,res|

  if (res_err == nil)
    result = res
  else
    # Failed!
  end
}

----

Note that the index of the arguments matches the index of the `?` and that the output parameters expect to be a
String describing the type you want to receive.

To avoid ambiguation the implementations are expected to follow the following rules:

* When a place holder in the `IN` array is `NOT NULL` it will be taken
* When the `IN` value is NULL a check is performed on the OUT
  * When the `OUT` value is not null it will be registered as a output parameter
  * When the `OUT` is also null it is expected that the IN value is the `NULL` value.

The registered `OUT` parameters will be available as an array in the result set under the output property.

=== Batch operations

The SQL common interface also defines how to execute batch operations. There are 3 types of batch operations:

* Batched statements `link:../../yardoc/VertxSql/SQLConnection.html#batch-instance_method[batch]`
* Batched prepared statements `link:../../yardoc/VertxSql/SQLConnection.html#batch_with_params-instance_method[batchWithParams]`
* Batched callable statements `link:../../yardoc/VertxSql/SQLConnection.html#batch_callable_with_params-instance_method[batchCallableWithParams]`

A batches statement will exeucte a list of sql statements as for example:

[source,java]
----
# Batch values
batch = Array.new
batch.push("INSERT INTO emp (NAME) VALUES ('JOE')")
batch.push("INSERT INTO emp (NAME) VALUES ('JANE')")

connection.batch(batch) { |res_err,res|
  if (res_err == nil)
    result = res
  else
    # Failed!
  end
}

----

While a prepared or callable statement batch will reuse the sql statement and take an list of arguments as for example:

[source,java]
----
# Batch values
batch = Array.new
batch.push([
  "joe"
])
batch.push([
  "jane"
])

connection.batch_with_params("INSERT INTO emp (name) VALUES (?)", batch) { |res_err,res|
  if (res_err == nil)
    result = res
  else
    # Failed!
  end
}

----

=== Executing other operations

To execute any other database operation, e.g. a `CREATE TABLE` you can use
`link:../../yardoc/VertxSql/SQLConnection.html#execute-instance_method[execute]`.

The string is passed through without changes to the actual database. The handler is called when the operation
is complete

[source,java]
----

sql = "CREATE TABLE PEOPLE (ID int generated by default as identity (start with 1 increment by 1) not null,FNAME varchar(255), LNAME varchar(255), SHOE_SIZE int);"

connection.execute(sql) { |execute_err,execute|
  if (execute_err == nil)
    puts "Table created !"
  else
    # Failed!
  end
}


----

=== Multiple ResultSet responses

In some cases your query might return more than one result set, in this case and to preserve the compatibility when
the returned result set object is converted to pure json, the next result sets are chained to the current result set
under the property `next`. A simple walk of all result sets can be achieved like this:

[source,ruby]
----
# do something with the result set...

# next step
rs = rs['next']


----

=== Streaming

When dealing with large data sets, it is not advised to use API just described but to stream data since it avoids
inflating the whole response into memory and JSON and data is just processed on a row by row basis, for example:

[source,ruby]
----
connection.query_stream("SELECT * FROM large_table") { |stream_err,stream|
  if (stream_err == nil)
    stream.handler() { |row|
      # do something with the row...
    }
  end
}

----

You still have full control on when the stream is pauses, resumed and ended. For cases where your query returns
multiple result sets you should use the result set ended event to fetch the next one if available. If there is more
data the stream handler will receive the new data, otherwise the end handler is invoked.

[source,ruby]
----
connection.query_stream("SELECT * FROM large_table; SELECT * FROM other_table") { |stream_err,stream|
  if (stream_err == nil)
    sqlRowStream = stream

    sqlRowStream.result_set_closed_handler() { |v|
      # will ask to restart the stream with the new result set if any
      sqlRowStream.more_results()
    }.handler() { |row|
      # do something with the row...
    }.end_handler() { |v|
      # no more data available...
    }
  end
}

----

=== Using transactions

To use transactions first set auto-commit to false with `link:../../yardoc/VertxSql/SQLConnection.html#set_auto_commit-instance_method[setAutoCommit]`.

You then do your transactional operations and when you want to commit or rollback use
`link:../../yardoc/VertxSql/SQLConnection.html#commit-instance_method[commit]` or
`link:../../yardoc/VertxSql/SQLConnection.html#rollback-instance_method[rollback]`.

Once the commit/rollback is complete the handler will be called and the next transaction will be automatically started.

[source,java]
----

# Do stuff with connection - updates etc

# Now commit

connection.commit() { |res_err,res|
  if (res_err == nil)
    # Committed OK!
  else
    # Failed!
  end
}


----

=== Closing connections

When you've done with the connection you should return it to the pool with `link:../../yardoc/VertxSql/SQLConnection.html#close-instance_method[close]`.