try/catch and using statements [duplicate] - c#

This question already has answers here:
try/catch + using, right syntax
(9 answers)
Closed 8 years ago.
The following 2 sets of codes produce same results, but I'm wondering which of these is the correct way of wrapping with the try...catch block. What's the difference between the 2 of them?
Edited: Which of this will properly capture the error, and also to make sure the connection will be closed even if there is an exception.
1
try
{
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand("Drop Table sometable", conn);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
}
catch
{
//
}
2
using (SqlConnection conn = new SqlConnection(connString))
{
try
{
SqlCommand cmd = new SqlCommand("Drop Table sometable", conn);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
catch
{
//
}
}

The difference is that in the #2 SqlConnection conn object will be disposed after the catch block will be finished. In #1 your connection will be disposed and than you will end up in the catch block.

Both are fine, depended on if you want to catch an error when opening the connection, and then of course you need to close the connection when you are done with it. usually closing earlier is better.

the difference is:
if you use code 2, and your connString you use in your using statement is invalid, it will throw an exception, because it is not in the try catch block.
in code 1, it will just catch that exception. but you will not be able to use your SqlConnection in the catch block

I thik that you are aware of exception handling.
We write all of our codes inside the catch block that can arise suspicious/unknown behavior to our applications. In that case the catch block handles the suspicious behavior of our application.
In context to your above two block of codes ....
For the first one- any exception caused by any one statement of your codes will be handled by catch block.
But for second one- exception caused by "using (SqlConnection conn = new SqlConnection(connString))" statement cannot be handled by your catch block, because it is outside of the try block. To test this just place some false connection string in sqlconnection.
Hope this will gives you better understanding for your scenario.

The using statement is a syntactic shortcut to represent a try/catch/finally. You could right your code as below, and would have the same effect as your examples above.
SqlConnection conn
try
{
conn = new SqlConnection(connString)
SqlCommand cmd = new SqlCommand("Drop Table sometable", conn);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
catch
{
//
}
finally
{
if(conn != null)
{
conn.Dispose()
}
}

Related

How to check if a SqlCommand is within a transaction or not

I have a standard routine for executing SqlCommand with an exception handler. But if an exception is thrown within this routine then I can't make an rollback if this standard routine is called within a transaction. So how can I check that this standard routine is placed inside a transaction or not? What is the proper way? I have googled a lot so far...
Do I have to thrown a new exception in my exception handler for the standard routine for forcing the overall transaction to rollback?
My standard routine looks like:
try
using (SqlConnection con = new SqlConnection(dbCon))
{
using (SqlCommand cmd = new SqlCommand(SQL, con))
{
con.Open();
cmd.CommandTimeout = 600;
cmd.ExecuteScalar();
}
}
}
catch (Exception ex)
{
// do some stuff here
maybe check for existence in a transaction here
}
My overall transaction look like this:
using (SqlConnection con = new SqlConnection(dbCon))
{
con.Open();
string TransactionName = "TransactionName";
using (SqlTransaction sqlTransaction = con.BeginTransaction(TransactionName))
{
try
{
// do some stuff here and call the standard routine here several times...
}
catch (Exception vDBException)
{
DB.getInstance().RollbackTransaction(sqlTransaction, TransactionName);
}
}
}
I have tried to make use of select ##trancount with no success.
I have also tried to check sys.sysprocesses from SQL Server with no success.
I really hope that someone can show me the right direction.

Why must I use Dispose()?

Here is my code:
public void InsertData()
{
using (SqlConnection connection = new SqlConnection(DBHelper.ConnectionString))
{
using (SqlCommand command = new SqlCommand("Some Simple Insert Query", connection))
{
connection.Open();
command.ExecuteNonQuery();
}
}
}
But I found this code sample:
public void InsertData()
{
SqlConnection connection = new SqlConnection(DBHelper.ConnectionString);
connection.Open();
SqlCommand command = new SqlCommand("Some Simple Insert Query", connection);
command.ExecuteNonQuery();
command.Dispose();
connection.Close();
connection.Dispose();
}
why does the author use
command.Dispose()
and
connection.Dispose();
in their code?
using can only be used on objects that are disposable (which is when they implement the interface IDisposable). Doing so will automatically call Dispose on that instance. However in contrast to call it yourself the using-statement ensures that Dispose is also called when an exception whithin that block occurs. So it´s safer to use that approach.
Your first example is equivalent to this:
try
{
SqlConnection connection = new SqlConnection(DBHelper.ConnectionString);
connection.Open();
SqlCommand command = new SqlCommand("Some Simple Insert Query", connection);
try
{
command.ExecuteNonQuery();
}
finally
{
command.Dispose();
}
}
finally
{
connection.Dispose();
}
You'll have resource leak when exception has been thrown:
public void InsertData()
{
SqlConnection connection = new SqlConnection(DBHelper.ConnectionString);
connection.Open();
SqlCommand command = new SqlCommand("Some Simple Insert Query", connection);
command.ExecuteNonQuery(); // <- imagine that this throws exception
// and so these don't execute at all and you'll have two resources leaked:
// 1. Connection
// 2. Command
command.Dispose();
connection.Close();
connection.Dispose();
}
The reasons of the exception can vary:
1. Insert failed (e.g. invalid field value insertion)
2. User doesn't have privelege required
3. RDMBS Internal error
...
You can emulate using with try .. finally which is wordy:
public void InsertData()
{
SqlConnection connection = null;
try {
connection = new SqlConnection(DBHelper.ConnectionString);
connection.Open();
SqlCommand command = null;
try {
command = new SqlCommand("Some Simple Insert Query", connection);
command.ExecuteNonQuery();
}
finally { // rain or shine, dispose the resource (if it has been created)
if (command != null)
command.Dispose();
}
}
finally { // rain or shine, dispose the resource (if it has been created)
if (connection != null)
connection.Dispose();
}
You don't have to use dispose in your example, because the using block does that for you.
See here: using Statement (C# Reference)
He is using connection.Dispose(); because the person is inexperienced and is writing bad code that is not safe. If a exception is thrown the connection will never be disposed of causing it to remain open till the GC collects the connection maybe minutes or hours later.
The using block is just syntactic sugar for the try/finally Dispose() pattern. This is all explained in the documentation.
Note you can also reduce the indentation in your code:
using (SqlConnection connection = new SqlConnection(DBHelper.ConnectionString))
using (SqlCommand command = new SqlCommand("Some Simple Insert Query", connection))
{
connection.Open();
command.ExecuteNonQuery();
}
In .Net IDisposable and the Dispose method are used to clean up unmanaged resources.
.Net keeps track of managed resources so it can clean them up automatically, but it needs to have some help when dealing with unmanaged resources.
Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
https://msdn.microsoft.com/en-us/library/system.idisposable.dispose(v=vs.110).aspx
The using statement is a way to automatically call the Dispose method when you're done using it.
Provides a convenient syntax that ensures the correct use of IDisposable objects.
It'll even get called if an exception is called.
The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler.
https://msdn.microsoft.com/en-us/library/yh598w02.aspx
The code which isn't using the using statements is incorrect.
It'll work most of the time, but if an exception occurs the unmanaged resources in SqlConnection could be left uncleaned.
As a rule, when you use an IDisposable object, you should declare and instantiate it in a using statement.

An exception can lead to the closing of a SqlConnection?

I'm building the treatment of a connection and came this question in mind, but I could not find a satisfactory answer. Then I come here to ask more experienced programmers. Is there any possibility that an exception can lead to the closing of an already opened SqlConnection?
illustrative code:
SqlConnection con = new SqlConnection(connectionString);
con.Open();
try
{
// some code that can throw an exception here....
}
catch (Exception)
{
// is there any possibility of this error close the connection?
}
Is there any possibility of an exception lead to the closing of an
already open SqlConnection?
Exceptions will not voluntarily close an open SqlConnection. In all instances, you have to take care of its resources. You can do this by explicitly calling the Close() method (best in a finally block), or wrapping it in a using statement (this technique is often preferred).
Explicitly calling .Close()
SqlConnection con = new SqlConnection(connectionString);
con.Open();
try
{
//some code that can throw an exception here....
}
catch (Exception)
{
//is there any possibility of this error close the connection? no
}
finally
{
//call close here - finally block will always execute
con.Close();
}
Using statement
using (SqlConnection con = new SqlConnection(connectionString)) {
con.Open();
try
{
//some code that can throw an exception here....
}
catch (Exception)
{
//is there any possibility of this error close the connection? no
}
//Close() is taken care of by the using statement
}
Also, I'd recommend putting your Open() call inside your try-catch as it can throw an exception.
Edit:
In case you're unsure about what the using statement does:
Provides a convenient syntax that ensures the correct use of
IDisposable objects.
You can read more about it in MSDN's documentation

Performance comparison between using block and Dispose method

Think about these 2 snippets:
Approach 1: use using statement
using(var connection = new SqlConnection())
using(var command = new SqlCommand(cmdText, connection)){
try{
connection.Open();
using(var reader = command.ExecuteReader(
CommandBehavior.CloseConnection | CommandBehavior.SingleResult){
while(reader.Read())
// read values
}
} catch (Exception ex) {
// log(ex);
}
}
Approach 2: use try/finally
var connection = new SqlConnection();
var command = new SqlCommand(cmdText, connection);
SqlDataReader = null;
try{
var reader = command.ExecuteReader(
CommandBehavior.CloseConnection | CommandBehavior.SingleResult);
while(reader.Read())
// read values...
} catch (Exception ex) {
// log(ex);
} finally {
command.Dispose();
if (reader != null) {
if (!reader.IsClosed)
reader.Close();
reader.Dispose();
}
if (connection.State != ConnectionState.Closed)
connection.Close();
connection.Dispose();
}
We all know that the using statements would be compiled to try/finally blocks. So is it correct to say: when the app get compiled, there would be 4 try blocks?
try { // for using SqlConnection
try { // for using SqlCommand
try { // my own try block
try { // for using SqlDataReader
} finally {
// dispose SqlDataReader
}
} catch {
// my own catch. can be used for log etc.
}
} finally {
// dispose SqlCommand
}
} finally {
// dispose SqlConnection
}
And, if the answer is yes, wouldn't that be a performance issue? Generally, is there any, I mean any performance difference between using blocks and try/finally blocks?
UPDATE:
From comments, I've to say:
1- The important question is, having multiple try blocks inside each other: is there any performance issue?
2- I have to care of code, because I'm responsible to code, not to query. The query-side has its own developer which is doing his best. So, I have to do my best too. So, it's important to me to take care of milliseconds ;) Thanks in advance.
Usually when you hear about try/catch is slow, it's all about exception handling. So if exception occurs then it might be slow. But just entering in try method is not something you should worry about. Especially in your case when you warp SQL query call.
If you want to know more about exceptions and performance in .NET you can find a lot of articles to read. For example: MSDN article or great CodeProject article.
And of course using is preferable way because it makes code much cleaner.

C# using statement catch error

I am just looking at the using statement, I have always known what it does but until now not tried using it, I have come up with the below code:
using (SqlCommand cmd =
new SqlCommand(reportDataSource,
new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString)))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
cmd.Connection.Open();
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
This seems to work but is there any point in this since as far as I can tell I would still need to enclose this in a try catch block to catch unforseen errors e.g. sql server down. Am I missing something?
As far as I can currently see it just stops me closing and disposing of cmd but there will be more lines of code due to the try catch still being needed.
When doing IO work I code to expect an exception.
SqlConnection conn = null;
SqlCommand cmd = null;
try
{
conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString)
cmd = new SqlCommand(reportDataSource, conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
conn.Open(); //opens connection
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
catch(Exception ex)
{
Logger.Log(ex);
throw;
}
finally
{
if(conn != null)
conn.Dispose();
if(cmd != null)
cmd.Dispose();
}
Edit: To be explicit, I avoid the using block here because I believe it to be important to log in situations like this. Experience has taught me that you never know what kind of weird exception might pop up. Logging in this situation might help you detect a deadlock, or find where a schema change is impacting a little used and little tested part of you code base, or any number of other problems.
Edit 2: One can argue that a using block could wrap a try/catch in this situation, and this is completely valid and functionally equivalent. This really boils down to preference. Do you want to avoid the extra nesting at the cost of handling your own disposal? Or do you incur the extra nesting to have auto-disposal. I feel that the former is cleaner so I do it that way. However, I don't rewrite the latter if I find it in the code base in which I am working.
Edit 3: I really, really wish MS had created a more explicit version of using() that made it more intuitive what was really happening and given more flexibility in this case. Consider the following, imaginary code:
SqlConnection conn = null;
SqlCommand cmd = null;
using(conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString),
cmd = new SqlCommand(reportDataSource, conn)
{
conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString);
cmd = new SqlCommand(reportDataSource, conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
cmd.Open();
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
catch(Exception ex)
{
Logger.Log(ex);
throw;
}
A using statement just creates a try/finally with Dispose() calls in the finally. Why not give the developer a unified way of doing disposal and exception handling?
This code should be as follows to ensure timely closing of the connection. Closing just the command doesn't close the connection:
using (SqlConnection con = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString))
using (SqlCommand cmd = new SqlCommand(reportDataSource, con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
cmd.Connection.Open();
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
To answer your question, you can do the same in a finally block, but this scopes the code nicely and ensures that you remember to clean up.
There may be no advantage to using a using statement in this case if you're going to have a try/catch/finally block anyway. As you know, the using statement is syntactic sugar for a try/finally that disposes of the IDisposable object. If you're going to have your own try/finally anyway, you can certainly do the Dispose yourself.
This really mainly boils down to style - your team may be more comfortable with using statements or using statements may make the code look cleaner.
But, if the boilerplate the using statement would be hiding is there anyway, go ahead and handle things yourself if that's your preference.
If your code looks like this:
using (SqlCommand cmd = new SqlCommand(...))
{
try
{
/* call stored procedure */
}
catch (SqlException ex)
{
/* handles the exception. does not rethrow the exception */
}
}
Then I would refactor it to use try.. catch.. finally instead.
SqlCommand cmd = new SqlCommand(...)
try
{
/* call stored procedure */
}
catch (SqlException ex)
{
/* handles the exception and does not ignore it */
}
finally
{
if (cmd!=null) cmd.Dispose();
}
In this scenario, I would be handling the exception so I have no choice but to add in that try..catch, I might as well put in the finally clause and save myself another nesting level. Note that I must be doing something in the catch block and not just ignoring the exception.
Elaborating on what Chris Ballance said, the C# specification (ECMA-334 version 4) section 15.13 states "A using statement is translated into three parts: acquisition, usage, and disposal. Usage of the resource is implicitly enclosed in a try statement that includes a finally clause. This finally clause disposes of the resource. If a null resource is acquired, then no call to Dispose is made, and no exception is thrown."
The description is close to 2 pages - worth a read.
In my experience, SqlConnection/SqlCommand can generate errors in so many ways that you almost need to handle the exceptions thrown more than handle the expected behaviour. I'm not sure I'd want the using clause here, as I'd want to be able to handle the null resource case myself.
using isn't about catching exceptions. It's about properly disposing of resources that are outside the view of the garbage collector.
one issue with "using" is that it doesn't handles exceptions.
if the designers of "using" would add "catch" optionally to its syntax like below pseudocode, it would be much more useful:
using (...MyDisposableObj...)
{
... use MyDisposableObj ...
catch (exception)
... handle exception ...
}
it could even have an optional "finally" clause to cleanup anything other than the "MyDisposableObj" allocated at the beginning of the "using" statement... like:
using (...MyDisposableObj...)
{
... use MyDisposableObj ...
... open a file or db connection ...
catch (exception)
... handle exception ...
finally
... close the file or db connection ...
}
still there'll be no need to write code to dispose of MyDisposableObj b/c it'd be handled by using...
How do like that?
Yes you would still need to catch exceptions. The benefit of the using block is you are adding scope to your code. You are saying, "Within this block of code do some stuff and when it gets to the end, close and dispose of resources"
It's not completely necessary at all, but it does define your intentions to anyone else using your code, and it also helps not leaving connections etc open by mistake.
There are a lot of great answers here, but I don't think this has been said yet.
No matter what... the "Dispose" method WILL be called on the object in the "using" block. If you put a return statement, or throw an error, the "Dispose" will be called.
Example:
I made a class called "MyDisposable", and it implements IDisposable and simply does a Console.Write. It always writes to the console even in all these scenarios:
using (MyDisposable blah = new MyDisposable())
{
int.Parse("!"); // <- calls "Dispose" after the error.
return; // <-- calls Dispose before returning.
}
The using statement is actually changed into a try/finally block by the compiler in which the parameter of the using block is disposed of so long as it implements the IDisposable interface. Aside from ensuring the specified objects are properly disposed when they fall out of scope, there is really no error capturing gained by using this construct.
As is mentioned by TheSoftwareJedi above, you will want to make sure both the SqlConnection and SqlCommand objects are disposed of properly. Stacking both into a single using block is a bit messy, and might not do what you think it does.
Also, be mindful of using the try/catch block as logic. It's a code smell that my nose has a particular dislike for, and often used by newbies or those of us in a big hurry to meet a deadline.
FYI, in this specific example, because you're using an ADO.net connection and Command object, be aware that the using statement just executes the Command.Dispose, and the Connection.Dispose() which do not actually close the connection, but simply releases it back into the ADO.net Connection pool to be reused by the next connection.open ... which is good, and the absolutely correct thing to do, bc if you don't, the connection will remain unuseable until the garbage collector releases it back to the pool, which might not be until numerous other connection requests, which would otherwise be forced to create new connections even though there's an unused one waiting to be garbage collected.
I would make my decision on when to and when not to use the using statement dependant on the resource I am dealing with. In the case of a limited resource, such as an ODBC connection I would prefer to use T/C/F so I can log meaningful errors at the point they occurred. Letting database driver errors bubble back to the client and potentially be lost in the higher level exception wrapping is sub optimal.
T/C/F gives you peace of mind that the resource is being handled the way you want it to. As some have already mentioned, the using statement does not provide exception handling it just ensures the resource is destructed. Exception handling is an underuitilised and underestimated language structure that is often the difference between the success and failure of a solution.
If the caller of your function is responsible for dealing with any exceptions the using statement is a nice way of ensuring resources are cleaned up no matter the outcome.
It allows you to place exception handling code at layer/assembly boundaries and helps prevent other functions becoming too cluttered.
Of course, it really depends on the types of exceptions thrown by your code. Sometimes you should use try-catch-finally rather than a using statement. My habit is to always start with a using statement for IDisposables (or have classes that contain IDisposables also implement the interface) and add try-catch-finally as needed.
So, basically, "using" is the exact same as "Try/catch/finally" only much more flexible for error handling.
Minor correction to the example: SqlDataAdapter also needs to be instantiated in a using statement:
using (SqlConnection con = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString))
using (SqlCommand cmd = new SqlCommand(reportDataSource, con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
con.Open();
DataSet dset = new DataSet();
using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
{
adapter.Fill(dset);
}
this.gridDataSource.DataSource = dset.Tables[0];
}
First, your code example should be:
using (SqlConnection conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString))
using (SqlCommand cmd = new SqlCommand(reportDataSource, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
cmd.Connection.Open();
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
With the code in your question, an exception creating the command will result in the just-created connection not being disposed. With the above, the connection is properly disposed.
If you need to handle exceptions in construction of the connection and command (as well as when using them), yes, you have to wrap the entire thing in a try/catch:
try
{
using (SqlConnection conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString))
using (SqlCommand cmd = new SqlCommand(reportDataSource, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
cmd.Connection.Open();
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
}
catch (RelevantException ex)
{
// ...handling...
}
But you don't need to handle cleaning up conn or cmd; it's already been done for you.
Contrast with the same thing without using:
SqlConnection conn = null;
SqlCommand cmd = null;
try
{
conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString);
cmd = new SqlCommand(reportDataSource, conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
cmd.Connection.Open();
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
catch (RelevantException ex)
{
// ...handling...
}
finally
{
if (cmd != null)
{
try
{
cmd.Dispose();
}
catch { }
cmd = null;
}
if (conn != null)
{
try
{
conn.Dispose();
}
catch { }
conn = null;
}
}
// And note that `cmd` and `conn` are still in scope here, even though they're useless
I know which I'd rather write. :-)

Categories