title: How to avoid nested transactions
body: <p>I'm currently implementing some functionality relying on an SQLite database. While doing so, I'm being confronted with a limitation that I did not anticipate. It made me wonder whether I'm tackling my problem the right way. I'm hoping someone can suggest a different approach that takes into account the requirements.</p>
  
  <p><strong>Goal</strong></p>
  
  <p>The goal is to store a large collection of objects into a database as fast as possible. However, if at any point, it is determined that the storage of these objects should not take place, the operation should not have any effect on the database. The exact storage queries (the 'inserts') depend on previous inserts.</p>
  
  <p><strong>Use Case</strong></p>
  
  <p>Consider a very large collection of 'instance information packages', each package represents part of the knowledge of some corresponding abstract instance. The total collection thus represents the complete knowledge of one or more abstract instances. The information of each package consists of:</p>
  
  <ol>
  <li>an instance_id; used to uniquely identify the abstract instance to which this information relates.</li>
  <li>an attributes map; (attribute_uri, attribute_value)-pairs where attribute_uri uniquely identifies an attribute and attribute_value is a corresponding text value. </li>
  </ol>
  
  <p>Both instance_id and attribute_id are found in a table, respectively TBL_INSTANCES and TBL_ATTRIBUTES. The database model used here is an EAV-model.</p>
  
  <p>After insertion, a table TBL_ENTRIES should contain entries in the form:</p>
  
  <pre><code>[ entry_id | instance_id | attribute_id | attribute_value ]
  </code></pre>
  
  <p><strong>Issue</strong></p>
  
  <p>The implementation seemed to be straightforward:</p>
  
  <ol>
  <li>Set a savepoint</li>
  <li>Begin the transaction</li>
  <li>Prepare statement for many inserts in TBL_ENTRIES</li>
  <li>For each instance in the collection:
  <ul>
  <li>4.1. Lookup instance_id in TBL_INSTANCES. If not present, add it to TBL_INSTANCES</li>
  <li>4.2. For each attribute in the instance's attribute map:
  <ul>
  <li>4.2.1. Lookup attribute_id in TBL_ATTRIBUTES. If not present, add it to TBL_ATTRIBUTES.</li>
  <li>4.2.2. Add entry to TBL_ENTRIES</li>
  </ul></li>
  </ul></li>
  <li>If at any point an error occured, rollback to the savepoint, otherwise commit.</li>
  </ol>
  
  <p>Unfortunately, in the lookup steps (4.1 and 4.2.1), SQLite reports a "cannot start a transaction within a transaction" error. Reading the documentation, it seems to lie in the fact the lookups call the sqlite3_exec routines, which (unless I am mistaken) seems to setup a transaction internally.</p>
  
  <p><strong>Question</strong></p>
  
  <p>If nested transactions are not allowed, how am I supposed to perform the lookup steps (which are basically "INSERT OR REPLACE" expressions followed by a "SELECT" query)? Is there some way to avoid them or to use sqlite3_exec within the current transaction? If not, am I approaching my problem the wrong way? Perhaps I should not use separate integer as keys, e.g. use attribute_uri directly as key instead of looking up the corresponding attribute_id.</p>
  
  <p>In any case, I still need to do something equivalent during the transaction as the real speed gain lies in preparing the statements over the collection of instances, not the collection of attributes: an instance might have just one or two attributes whereas the number of instances in the instance collection will always be very large.</p>
  
  <p>I'm using C/C++, SQLite 3.7.</p>
  
  <p>Any suggestions or remarks on my approach are much appreciated!</p>