---
slug: error-tracing-intro
title: Introducing General Purpose Error Tracing
author: CG/SQL Team
author_title: Maintainer of CG/SQL
author_url: https://github.com/facebookincubator
author_image_url: https://avatars2.githubusercontent.com/u/69631?s=200&v=4
tags: [facebook, cg-sql, errors]
---

Today we made a couple of minor changes in the code generation to take care of some lingering issues.

The first is that when you did a `throw` inside a `catch` to basically rethrow the error, you would lose
the error code if something had succeeded within the catch handler.

The old codegen looked something like this:

```c
  catch_start_1: {
    printf("error\n");
    cql_best_error(&_rc_)
    goto cql_cleanup;
  }
```

The problem being that while the `printf` above is fine and well, if you did any SQL operation then `_rc_` would be
clobbered and you'd end up throwing an unrelated error code.   `cql_best_error` would at least make sure it was
a failure code (`SQLITE_ERROR`) but the original error code was lost.

The new code looks like this:

```c
  catch_start_1: {
    _rc_thrown_ = _rc_;
    printf("error\n");
    _rc_ = cql_best_error(_rc_thrown_);
    goto cql_cleanup;
  }
```

So now if there are db operations, the original return code is still preserved.  Note:  you still lose `sqlite3_errmsg()` because
SQLite doesn't know that cleanup logic is running.

This brings us to the second new thing: general purpose error traces.

Error checking of result codes happens very consistently in CQL output.  The usual pattern looks something like this:

```c
  _rc_ = cql_exec(_db_,
    "SAVEPOINT base_proc_savepoint");
  if (_rc_ != SQLITE_OK) goto cql_cleanup;
```

or if it's inside a try block a little different... very little actually

```c
  // try
  {
    _rc_ = cql_exec(_db_,
      "RELEASE SAVEPOINT base_proc_savepoint");
    if (_rc_ != SQLITE_OK) goto catch_start_8;
    // ... the rest of the try block
  }
```

Basically if the local `_rc_` doersn't match the necessary condition we `goto` the appropriate error label... either the relevant
catch block or else the procedure's cleanup code.

We generalize this a bit now so that it looks like this:


```c
  if (_rc_ != SQLITE_OK) { cql_error_trace(); goto cql_cleanup; }

-- or, in a catch...

  if (_rc_ != SQLITE_OK) { cql_error_trace(); goto catch_start_8; }
```

Now the default implementation of `cql_error_trace()` is in `cqlrt.h` which you can and should customize. I'll be writing more
about that later but suffice to say you're supposed to replace `cqlrt.h` and `cqlrt.c` with suitable runtime helpers for your environment
while keeping `cqlrt_common.h` and `cqlrt_common.c` fixed.

So for instance, your `cqlrt.h` could look like this:


```c
#ifndef CQL_TRACING_ENABLED
#define cql_error_trace()
#else
// whatever tracing you want, for example this might help in test code.
#define cql_error_trace() \
  fprintf(stderr, "Error at %s:%d in %s: %d %s\n", __FILE__, __LINE__, _PROC_, _rc_, sqlite3_errmsg(_db_))
#endif
```

So then when you need to debug problems involving lots of error recovery you can watch the entire chain of events easily.

Note that there are some useful variables there:

In any procedure `_db_` is the current database and `_rc_` is the most recent return code from SQLite.  `__FILE__` and `__LINE__`
of course come from the preprocessor.  and `_PROC_` (one underscore) is now generated by the compiler.  Every procedure's
body now begins with:

```
#undef _PROC_
#define _PROC_ "the_current_procedure"
```

So by defining your own cql_error_trace macro you can cause whatever logging you need to happen.  Note this can be
very expensive indeed because this happens a lot and even the string literals needed are a significant cost. So generally
this should be off for production builds and enabled as needed for debug builds.

The default implementation is just an empty block

```
#define cql_error_trace()
```

But the hook is enough to light up whatever logging you might need, and you can use `sqlite3_errmsg()` before that message is gone.

Good hunting.
