Sophie

Sophie

distrib > Fedora > 18 > i386 > by-pkgid > ab4fdf14325ac74f1f8dab792ae625b3 > files > 56

python-fdb-doc-1.1-1.fc18.noarch.rpm


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
    <title>Usage Guide &mdash; FDB 1.1 documentation</title>
    
    <link rel="stylesheet" href="_static/fdbtheme.css" type="text/css" />
    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
    
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    '',
        VERSION:     '1.1',
        COLLAPSE_INDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true
      };
    </script>
    <script type="text/javascript" src="_static/jquery.js"></script>
    <script type="text/javascript" src="_static/underscore.js"></script>
    <script type="text/javascript" src="_static/doctools.js"></script>
    <link rel="top" title="FDB 1.1 documentation" href="index.html" />
    <link rel="next" title="Compliance to Python Database API 2.0" href="python-db-api-compliance.html" />
    <link rel="prev" title="Getting Started with FDB" href="getting-started.html" />
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Neuton&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Nobile:regular,italic,bold,bolditalic&amp;subset=latin" type="text/css" media="screen" charset="utf-8" />
<!--[if lte IE 6]>
<link rel="stylesheet" href="_static/ie6.css" type="text/css" media="screen" charset="utf-8" />
<![endif]-->

  </head>
  <body>

    <div class="related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="genindex.html" title="General Index"
             accesskey="I">index</a></li>
        <li class="right" >
          <a href="py-modindex.html" title="Python Module Index"
             >modules</a> |</li>
        <li class="right" >
          <a href="python-db-api-compliance.html" title="Compliance to Python Database API 2.0"
             accesskey="N">next</a> |</li>
        <li class="right" >
          <a href="getting-started.html" title="Getting Started with FDB"
             accesskey="P">previous</a> |</li>
        <li><a href="index.html">FDB 1.1 documentation</a> &raquo;</li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body">
            
  <div class="section" id="usage-guide">
<h1>Usage Guide<a class="headerlink" href="#usage-guide" title="Permalink to this headline">¶</a></h1>
<div class="section" id="driver-structure">
<h2>Driver structure<a class="headerlink" href="#driver-structure" title="Permalink to this headline">¶</a></h2>
<p>Source code is currently divided into next submodules:</p>
<ul class="simple">
<li><a class="reference internal" href="reference.html#module-fdb.ibase" title="fdb.ibase: Python ctypes interface to Firebird client library"><tt class="xref py py-mod docutils literal"><span class="pre">ibase</span></tt></a> - Python <a class="reference external" href="http://docs.python.org/whatsnew/2.5.html#module-ctypes" title="(in Python v2.7)"><em class="xref std std-ref">ctypes</em></a> interface to Firebird client library.</li>
<li><a class="reference internal" href="reference.html#module-fdb.fbcore" title="fdb.fbcore: Implementation of Firebird driver"><tt class="xref py py-mod docutils literal"><span class="pre">fbcore</span></tt></a> - Main driver source code.</li>
<li><a class="reference internal" href="reference.html#module-fdb.services" title="fdb.services: Submodule for work with Firebird Services"><tt class="xref py py-mod docutils literal"><span class="pre">services</span></tt></a> - Driver code to work with Firebird Services.</li>
</ul>
<p>All important data, functions, classes and constants are available directly in fdb namespace,
so there is not need to import or use <a class="reference internal" href="reference.html#module-fdb.fbcore" title="fdb.fbcore: Implementation of Firebird driver"><tt class="xref py py-mod docutils literal"><span class="pre">fbcore</span></tt></a> and <a class="reference internal" href="reference.html#module-fdb.ibase" title="fdb.ibase: Python ctypes interface to Firebird client library"><tt class="xref py py-mod docutils literal"><span class="pre">ibase</span></tt></a> submodules directly.
Exception is the <a class="reference internal" href="reference.html#module-fdb.services" title="fdb.services: Submodule for work with Firebird Services"><tt class="xref py py-mod docutils literal"><span class="pre">fdb.services</span></tt></a> submodule that contains functions and classes for work with
Firebird Services. Because Services are optional, not so frequently used Firebird facility, all
service-related code was isolated in separate submodule rather than exposed directly through
main module namespace. Because <a class="reference internal" href="reference.html#module-fdb.services" title="fdb.services: Submodule for work with Firebird Services"><tt class="xref py py-mod docutils literal"><span class="pre">services</span></tt></a> submodule contains names also used by main
driver (<a class="reference internal" href="reference.html#fdb.services.connect" title="fdb.services.connect"><tt class="xref py py-func docutils literal"><span class="pre">connect()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.services.Connection" title="fdb.services.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a>), it&#8217;s advised to use
fully qualified names when refering to them instead importing them via <cite>from fdb.services import ...</cite>.</p>
</div>
<div class="section" id="databases">
<span id="index-0"></span><h2>Databases<a class="headerlink" href="#databases" title="Permalink to this headline">¶</a></h2>
<p>Access to the database is made available through <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> objects. FDB provides two
constructors for these:</p>
<ul class="simple">
<li><a class="reference internal" href="reference.html#fdb.connect" title="fdb.connect"><tt class="xref py py-func docutils literal"><span class="pre">connect()</span></tt></a> - Returns <cite>Connection</cite> to database that already exists.</li>
<li><a class="reference internal" href="reference.html#fdb.create_database" title="fdb.create_database"><tt class="xref py py-func docutils literal"><span class="pre">create_database()</span></tt></a> - Returns <cite>Connection</cite> to newly created database.</li>
</ul>
<div class="section" id="using-connect">
<span id="index-1"></span><h3>Using <cite>connect</cite><a class="headerlink" href="#using-connect" title="Permalink to this headline">¶</a></h3>
<p>This constructor has number of keyword parameters that could be divided into several groups:</p>
<ul class="simple">
<li>Database specification (parameters <cite>dsn</cite>, <cite>host</cite>, <cite>database</cite> and <cite>port</cite>)</li>
<li>User specification (parameters <cite>user</cite>, <cite>password</cite> and <cite>role</cite>)</li>
<li>Connection options (parameters <cite>sql_dialect</cite>, <cite>charset</cite>, <cite>isolation_level</cite>, <cite>buffers</cite>,
<cite>force_writes</cite>, <cite>no_reserve</cite> and <cite>db_key_scope</cite>)</li>
</ul>
<p>To establish a connection to database, you always must specify the database, either as <cite>connection
string</cite> parameter <cite>dsn</cite>, or as required combination of parameters <cite>host</cite>, <cite>database</cite> and <cite>port</cite>.</p>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p class="last">Current driver version ignores the value of <cite>port</cite> parameter. If you need to specify the port
number, you have to use <cite>dsn</cite> parameter instead.</p>
</div>
<p>Although specification of <cite>user</cite> and <cite>password</cite> parameters is optional (if environment variables
<cite>ISC_USER</cite> and <cite>ISC_PASSWORD</cite> are set, their values are used if these parameters are ommited),
it&#8217;s recommended practice to use them. Parameter <cite>role</cite> is needed only when you use Firebird roles.</p>
<p>Connection options are optional (see <a class="reference external" href="http://www.firebirdsql.org/en/reference-manuals/">Firebird Documentation</a> for details). However you may often
want to specify <cite>charset</cite>, as it directs automatic conversions of string data between client and
server, and automatic conversions from/to unicode performed by FDB driver (see <a class="reference internal" href="#data-handling-and-conversions">Data handling
and conversions</a> for details).</p>
<p><strong>Examples:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># Connecting via &#39;dsn&#39;</span>
<span class="c">#</span>
<span class="c"># Local database (local protocol, if supported)</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;/path/database.fdb&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="c"># Local database (TCP/IP)</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:/path/database.fdb&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="c"># Local database (TCP/IP with port specification)</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost/3050:/path/database.fdb&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="c"># Remote database</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;host:/path/database.db&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="c"># Remote database with port specification</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;host/3050:/path/database.db&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="c">#</span>
<span class="c"># Connecting via &#39;database&#39;, &#39;host&#39; and &#39;port&#39;</span>
<span class="c">#</span>
<span class="c"># Local database (local protocol, if supported)</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">database</span><span class="o">=</span><span class="s">&#39;/path/database.db&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="c"># Local database (TCP/IP)</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">database</span><span class="o">=</span><span class="s">&#39;/path/database.db&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="c"># Local database (TCP/IP with port specification)</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">3050</span><span class="p">,</span> <span class="n">database</span><span class="o">=</span><span class="s">&#39;/path/database.db&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="c"># Remote database</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;myhost&#39;</span><span class="p">,</span> <span class="n">database</span><span class="o">=</span><span class="s">&#39;/path/database.db&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="using-create-database">
<span id="index-2"></span><h3>Using <cite>create_database</cite><a class="headerlink" href="#using-create-database" title="Permalink to this headline">¶</a></h3>
<p>The Firebird engine supports dynamic database creation via the SQL statement <cite>CREATE DATABASE</cite>.
FDB wraps it into <a class="reference internal" href="reference.html#fdb.create_database" title="fdb.create_database"><tt class="xref py py-func docutils literal"><span class="pre">create_database()</span></tt></a>, that returns <cite>Connection</cite> instance attached to newly
created database.</p>
<p><strong>Example:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">create_database</span><span class="p">(</span><span class="s">&quot;create database &#39;host:/temp/db.db&#39; user &#39;sysdba&#39; password &#39;pass&#39;&quot;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="deleting-databases">
<span id="index-3"></span><h3>Deleting databases<a class="headerlink" href="#deleting-databases" title="Permalink to this headline">¶</a></h3>
<p>The Firebird engine also supports dropping (deleting) databases dynamically, but dropping is a more
complicated operation than creating, for several reasons: an existing database may be in use by users
other than the one who requests the deletion, it may have supporting objects such as temporary sort
files, and it may even have dependent shadow databases. Although the database engine recognizes a
<cite>DROP DATABASE</cite> SQL statement, support for that statement is limited to the <cite>isql</cite> command-line
administration utility. However, the engine supports the deletion of databases via an API call, which
FDB exposes as <a class="reference internal" href="reference.html#fdb.Connection.drop_database" title="fdb.Connection.drop_database"><tt class="xref py py-meth docutils literal"><span class="pre">drop_database()</span></tt></a> method in <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> class. So, to drop
a database you need to connect to it first.</p>
<p><strong>Examples:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">create_database</span><span class="p">(</span><span class="s">&quot;create database &#39;/temp/db.db&#39; user &#39;sysdba&#39; password &#39;pass&#39;&quot;</span><span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">drop_database</span><span class="p">()</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;/path/database.fdb&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">drop_database</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="section" id="connection-object">
<span id="index-4"></span><h3>Connection object<a class="headerlink" href="#connection-object" title="Permalink to this headline">¶</a></h3>
<p><a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> object represents a direct link to database, and works as gateway for next operations
with it:</p>
<ul class="simple">
<li><a class="reference internal" href="#executing-sql-statements">Executing SQL Statements</a>: methods <a class="reference internal" href="reference.html#fdb.Connection.execute_immediate" title="fdb.Connection.execute_immediate"><tt class="xref py py-meth docutils literal"><span class="pre">execute_immediate()</span></tt></a> and <a class="reference internal" href="reference.html#fdb.Connection.cursor" title="fdb.Connection.cursor"><tt class="xref py py-meth docutils literal"><span class="pre">cursor()</span></tt></a>.</li>
<li>Dropping database: method <a class="reference internal" href="reference.html#fdb.Connection.drop_database" title="fdb.Connection.drop_database"><tt class="xref py py-meth docutils literal"><span class="pre">drop_database()</span></tt></a>.</li>
<li><a class="reference internal" href="#trasanction-management">Trasanction management</a>: methods <a class="reference internal" href="reference.html#fdb.Connection.begin" title="fdb.Connection.begin"><tt class="xref py py-meth docutils literal"><span class="pre">begin()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Connection.commit" title="fdb.Connection.commit"><tt class="xref py py-meth docutils literal"><span class="pre">commit()</span></tt></a>,
<a class="reference internal" href="reference.html#fdb.Connection.rollback" title="fdb.Connection.rollback"><tt class="xref py py-meth docutils literal"><span class="pre">rollback()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Connection.savepoint" title="fdb.Connection.savepoint"><tt class="xref py py-meth docutils literal"><span class="pre">savepoint()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Connection.trans" title="fdb.Connection.trans"><tt class="xref py py-meth docutils literal"><span class="pre">trans()</span></tt></a>,
<a class="reference internal" href="reference.html#fdb.Connection.trans_info" title="fdb.Connection.trans_info"><tt class="xref py py-meth docutils literal"><span class="pre">trans_info()</span></tt></a> and <a class="reference internal" href="reference.html#fdb.Connection.transaction_info" title="fdb.Connection.transaction_info"><tt class="xref py py-meth docutils literal"><span class="pre">transaction_info()</span></tt></a>, and attributes
<a class="reference internal" href="reference.html#fdb.Connection.main_transaction" title="fdb.Connection.main_transaction"><tt class="xref py py-attr docutils literal"><span class="pre">main_transaction</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Connection.transactions" title="fdb.Connection.transactions"><tt class="xref py py-attr docutils literal"><span class="pre">transactions</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Connection.default_tpb" title="fdb.Connection.default_tpb"><tt class="xref py py-attr docutils literal"><span class="pre">default_tpb</span></tt></a>
and <a class="reference internal" href="reference.html#fdb.Connection.group" title="fdb.Connection.group"><tt class="xref py py-attr docutils literal"><span class="pre">group</span></tt></a>.</li>
<li>Work with <a class="reference internal" href="#database-events">Database Events</a>: method <a class="reference internal" href="reference.html#fdb.Connection.event_conduit" title="fdb.Connection.event_conduit"><tt class="xref py py-meth docutils literal"><span class="pre">event_conduit()</span></tt></a>.</li>
<li>Getting information about database: methods <a class="reference internal" href="reference.html#fdb.Connection.db_info" title="fdb.Connection.db_info"><tt class="xref py py-meth docutils literal"><span class="pre">db_info()</span></tt></a> and
<a class="reference internal" href="reference.html#fdb.Connection.database_info" title="fdb.Connection.database_info"><tt class="xref py py-meth docutils literal"><span class="pre">database_info()</span></tt></a>.</li>
<li>Getting information about Firebird version: attribute <a class="reference internal" href="reference.html#fdb.Connection.server_version" title="fdb.Connection.server_version"><tt class="xref py py-attr docutils literal"><span class="pre">server_version</span></tt></a>.</li>
</ul>
</div>
<div class="section" id="getting-information-about-database">
<span id="index-5"></span><h3>Getting information about database<a class="headerlink" href="#getting-information-about-database" title="Permalink to this headline">¶</a></h3>
<p>Firebird provides various informations about server and connected database via <cite>database_info</cite> API call.
FDB surfaces this API through methods <a class="reference internal" href="reference.html#fdb.Connection.db_info" title="fdb.Connection.db_info"><tt class="xref py py-meth docutils literal"><span class="pre">db_info()</span></tt></a> and <a class="reference internal" href="reference.html#fdb.Connection.database_info" title="fdb.Connection.database_info"><tt class="xref py py-meth docutils literal"><span class="pre">database_info()</span></tt></a>
on Connection object.</p>
<p><a class="reference internal" href="reference.html#fdb.Connection.database_info" title="fdb.Connection.database_info"><tt class="xref py py-meth docutils literal"><span class="pre">Connection.database_info()</span></tt></a> is a <cite>very thin</cite> wrapper around function <cite>isc_database_info()</cite>.
This method does not attempt to interpret its results except with regard to whether they are a string
or an integer. For example, requesting <cite>isc_info_user_names</cite> with the call:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">con</span><span class="o">.</span><span class="n">database_info</span><span class="p">(</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_user_names</span><span class="p">,</span> <span class="s">&#39;s&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>will return a binary string containing a raw succession of length-name pairs.</p>
<p><strong>Example program:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:/temp/test.db&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>

<span class="c"># Retrieving an integer info item is quite simple.</span>
<span class="n">bytesInUse</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">database_info</span><span class="p">(</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_current_memory</span><span class="p">,</span> <span class="s">&#39;i&#39;</span><span class="p">)</span>

<span class="k">print</span> <span class="s">&#39;The server is currently using </span><span class="si">%d</span><span class="s"> bytes of memory.&#39;</span> <span class="o">%</span> <span class="n">bytesInUse</span>

<span class="c"># Retrieving a string info item is somewhat more involved, because the</span>
<span class="c"># information is returned in a raw binary buffer that must be parsed</span>
<span class="c"># according to the rules defined in the Interbase® 6 API Guide section</span>
<span class="c"># entitled &quot;Requesting buffer items and result buffer values&quot; (page 51).</span>
<span class="c">#</span>
<span class="c"># Often, the buffer contains a succession of length-string pairs</span>
<span class="c"># (one byte telling the length of s, followed by s itself).</span>
<span class="c"># Function fdb.ibase.ord2 is provided to convert a raw</span>
<span class="c"># byte to a Python integer (see examples below).</span>
<span class="n">buf</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">database_info</span><span class="p">(</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_db_id</span><span class="p">,</span> <span class="s">&#39;s&#39;</span><span class="p">)</span>

<span class="c"># Parse the filename from the buffer.</span>
<span class="n">beginningOfFilename</span> <span class="o">=</span> <span class="mi">2</span>
<span class="c"># The second byte in the buffer contains the size of the database filename</span>
<span class="c"># in bytes.</span>
<span class="n">lengthOfFilename</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">ibase</span><span class="o">.</span><span class="n">ord2</span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">buf</span><span class="p">[</span><span class="n">beginningOfFilename</span><span class="p">:</span><span class="n">beginningOfFilename</span> <span class="o">+</span> <span class="n">lengthOfFilename</span><span class="p">]</span>

<span class="c"># Parse the host name from the buffer.</span>
<span class="n">beginningOfHostName</span> <span class="o">=</span> <span class="p">(</span><span class="n">beginningOfFilename</span> <span class="o">+</span> <span class="n">lengthOfFilename</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
<span class="c"># The first byte after the end of the database filename contains the size</span>
<span class="c"># of the host name in bytes.</span>
<span class="n">lengthOfHostName</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">ibase</span><span class="o">.</span><span class="n">ord2</span><span class="p">(</span><span class="n">buf</span><span class="p">[</span><span class="n">beginningOfHostName</span> <span class="o">-</span> <span class="mi">1</span><span class="p">])</span>
<span class="n">host</span> <span class="o">=</span> <span class="n">buf</span><span class="p">[</span><span class="n">beginningOfHostName</span><span class="p">:</span><span class="n">beginningOfHostName</span> <span class="o">+</span> <span class="n">lengthOfHostName</span><span class="p">]</span>

<span class="k">print</span> <span class="s">&#39;We are connected to the database at </span><span class="si">%s</span><span class="s"> on host </span><span class="si">%s</span><span class="s">.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">host</span><span class="p">)</span>
</pre></div>
</div>
<p>Sample output:</p>
<div class="highlight-python"><pre>The server is currently using 8931328 bytes of memory.
We are connected to the database at C:\TEMP\TEST.DB on host WEASEL.</pre>
</div>
<p>A more convenient way to access the same functionality is via the <a class="reference internal" href="reference.html#fdb.Connection.db_info" title="fdb.Connection.db_info"><tt class="xref py py-meth docutils literal"><span class="pre">db_info()</span></tt></a> method,
which is high-level convenience wrapper around the <cite>database_info()</cite> method that parses the output of
database_info into Python-friendly objects instead of returning raw binary buffers in the case of complex
result types. For example, requesting <cite>isc_info_user_names</cite> with the call:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">con</span><span class="o">.</span><span class="n">db_info</span><span class="p">(</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_user_names</span><span class="p">)</span>
</pre></div>
</div>
<p>returns a dictionary that maps (username -&gt; number of open connections). If SYSDBA has one open connection
to the database to which <cite>con</cite> is connected, and TEST_USER_1 has three open connections to that same database,
the return value would be:</p>
<div class="highlight-python"><pre>{‘SYSDBA’: 1, ‘TEST_USER_1’: 3}</pre>
</div>
<p><strong>Example program:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>
<span class="kn">import</span> <span class="nn">os.path</span>

<span class="c">###############################################################################</span>
<span class="c"># Querying an isc_info_* item that has a complex result:</span>
<span class="c">###############################################################################</span>
<span class="c"># Establish three connections to the test database as TEST_USER_1, and one</span>
<span class="c"># connection as SYSDBA.  Then use the Connection.db_info method to query the</span>
<span class="c"># number of attachments by each user to the test database.</span>
<span class="n">testUserCons</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">):</span>
  <span class="n">tcon</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:/temp/test.db&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;TEST_USER_1&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
  <span class="n">testUserCons</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">tcon</span><span class="p">)</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:/temp/test.db&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>

<span class="k">print</span> <span class="s">&#39;Open connections to this database:&#39;</span>
<span class="k">print</span> <span class="n">con</span><span class="o">.</span><span class="n">db_info</span><span class="p">(</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_user_names</span><span class="p">)</span>

<span class="c">###############################################################################</span>
<span class="c"># Querying multiple isc_info_* items at once:</span>
<span class="c">###############################################################################</span>
<span class="c"># Request multiple db_info items at once, specifically the page size of the</span>
<span class="c"># database and the number of pages currently allocated.  Compare the size</span>
<span class="c"># computed by that method with the size reported by the file system.</span>
<span class="c"># The advantages of using db_info instead of the file system to compute</span>
<span class="c"># database size are:</span>
<span class="c">#   - db_info works seamlessly on connections to remote databases that reside</span>
<span class="c">#     in file systems to which the client program lacks access.</span>
<span class="c">#   - If the database is split across multiple files, db_info includes all of</span>
<span class="c">#     them.</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">db_info</span><span class="p">([</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_page_size</span><span class="p">,</span> <span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_allocation</span><span class="p">])</span>
<span class="n">pagesAllocated</span> <span class="o">=</span> <span class="n">res</span><span class="p">[</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_allocation</span><span class="p">]</span>
<span class="n">pageSize</span> <span class="o">=</span> <span class="n">res</span><span class="p">[</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_page_size</span><span class="p">]</span>
<span class="k">print</span> <span class="s">&#39;</span><span class="se">\n</span><span class="s">db_info indicates database size is&#39;</span><span class="p">,</span> <span class="n">pageSize</span> <span class="o">*</span> <span class="n">pagesAllocated</span><span class="p">,</span> <span class="s">&#39;bytes&#39;</span>
<span class="k">print</span> <span class="s">&#39;os.path.getsize indicates size is &#39;</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">getsize</span><span class="p">(</span><span class="n">DB_FILENAME</span><span class="p">),</span> <span class="s">&#39;bytes&#39;</span>
</pre></div>
</div>
<p>Sample output:</p>
<div class="highlight-python"><pre>Open connections to this database:
{'SYSDBA': 1, 'TEST_USER_1': 3}

db_info indicates database size is 20684800 bytes
os.path.getsize indicates size is  20684800 bytes</pre>
</div>
</div>
</div>
<div class="section" id="executing-sql-statements">
<span id="index-6"></span><h2>Executing SQL Statements<a class="headerlink" href="#executing-sql-statements" title="Permalink to this headline">¶</a></h2>
<p>FDB implements two ways for execution of SQL commands against connected database:</p>
<ul class="simple">
<li><a class="reference internal" href="reference.html#fdb.Connection.execute_immediate" title="fdb.Connection.execute_immediate"><tt class="xref py py-meth docutils literal"><span class="pre">execute_immediate()</span></tt></a> - for execution of SQL commands that don&#8217;t
return any result.</li>
<li><a class="reference internal" href="reference.html#fdb.Cursor" title="fdb.Cursor"><tt class="xref py py-class docutils literal"><span class="pre">Cursor</span></tt></a> objects that offer rich interface for execution of SQL commands and
fetching their results.</li>
</ul>
<div class="section" id="cursor-object">
<span id="index-7"></span><h3>Cursor object<a class="headerlink" href="#cursor-object" title="Permalink to this headline">¶</a></h3>
<p>Because <cite>Cursor</cite> objects always operate in context of single <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> (and <a class="reference internal" href="reference.html#fdb.Transaction" title="fdb.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a>),
<cite>Cursor</cite> instances are not created directly, but by constructor method. Python DB API 2.0 assume that
if database engine supports transactions, it supports only one transaction per connection, hence it
defines constructor method <a class="reference internal" href="reference.html#fdb.Connection.cursor" title="fdb.Connection.cursor"><tt class="xref py py-meth docutils literal"><span class="pre">cursor()</span></tt></a> (and other transaction-related methods) as part
of <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> interface. However, Firebird supports multiple independent transactions per
connection. To conform to Python DB API, FDB uses concept of internal <a class="reference internal" href="reference.html#fdb.Connection.main_transaction" title="fdb.Connection.main_transaction"><tt class="xref py py-attr docutils literal"><span class="pre">main_transaction</span></tt></a>
and secondary <a class="reference internal" href="reference.html#fdb.Connection.transactions" title="fdb.Connection.transactions"><tt class="xref py py-attr docutils literal"><span class="pre">transactions</span></tt></a>. Cursor constructor is primarily defined by
<a class="reference internal" href="reference.html#fdb.Transaction" title="fdb.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a>, and Cursor constructor on <cite>Connection</cite> is therefore a shortcut for <cite>main_transaction.cursor()</cite>.</p>
<p><cite>Cursor</cite> objects are used for next operations:</p>
<ul class="simple">
<li>Execution of SQL Statemets: methods <a class="reference internal" href="reference.html#fdb.Cursor.execute" title="fdb.Cursor.execute"><tt class="xref py py-meth docutils literal"><span class="pre">execute()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Cursor.executemany" title="fdb.Cursor.executemany"><tt class="xref py py-meth docutils literal"><span class="pre">executemany()</span></tt></a> and
<a class="reference internal" href="reference.html#fdb.Cursor.callproc" title="fdb.Cursor.callproc"><tt class="xref py py-meth docutils literal"><span class="pre">callproc()</span></tt></a>.</li>
<li>Creating <a class="reference internal" href="reference.html#fdb.PreparedStatement" title="fdb.PreparedStatement"><tt class="xref py py-class docutils literal"><span class="pre">PreparedStatement</span></tt></a> objects for efficient repeated execution of SQL statements, and
to obtain additional information about SQL statements (like execution <a class="reference internal" href="reference.html#fdb.PreparedStatement.plan" title="fdb.PreparedStatement.plan"><tt class="xref py py-attr docutils literal"><span class="pre">plan</span></tt></a>):
method <a class="reference internal" href="reference.html#fdb.Cursor.prep" title="fdb.Cursor.prep"><tt class="xref py py-meth docutils literal"><span class="pre">prep()</span></tt></a>.</li>
<li><a class="reference external" href="Fetchingdatafromserver">Fetching results</a>: methods <a class="reference internal" href="reference.html#fdb.Cursor.fetchone" title="fdb.Cursor.fetchone"><tt class="xref py py-meth docutils literal"><span class="pre">fetchone()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Cursor.fetchmany" title="fdb.Cursor.fetchmany"><tt class="xref py py-meth docutils literal"><span class="pre">fetchmany()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Cursor.fetchall" title="fdb.Cursor.fetchall"><tt class="xref py py-meth docutils literal"><span class="pre">fetchall()</span></tt></a>,
<a class="reference internal" href="reference.html#fdb.Cursor.fetchonemap" title="fdb.Cursor.fetchonemap"><tt class="xref py py-meth docutils literal"><span class="pre">fetchonemap()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Cursor.fetchmanymap" title="fdb.Cursor.fetchmanymap"><tt class="xref py py-meth docutils literal"><span class="pre">fetchmanymap()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Cursor.fetchallmap" title="fdb.Cursor.fetchallmap"><tt class="xref py py-meth docutils literal"><span class="pre">fetchallmap()</span></tt></a>,
<a class="reference internal" href="reference.html#fdb.Cursor.iter" title="fdb.Cursor.iter"><tt class="xref py py-meth docutils literal"><span class="pre">iter()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Cursor.itermap" title="fdb.Cursor.itermap"><tt class="xref py py-meth docutils literal"><span class="pre">itermap()</span></tt></a> and <a class="reference internal" href="reference.html#fdb.Cursor.next" title="fdb.Cursor.next"><tt class="xref py py-meth docutils literal"><span class="pre">next()</span></tt></a>.</li>
</ul>
</div>
<div class="section" id="sql-execution-basics">
<span id="index-8"></span><h3>SQL Execution Basics<a class="headerlink" href="#sql-execution-basics" title="Permalink to this headline">¶</a></h3>
<p>There are three methods how to execute SQL commands:</p>
<ul>
<li><p class="first"><a class="reference internal" href="reference.html#fdb.Connection.execute_immediate" title="fdb.Connection.execute_immediate"><tt class="xref py py-meth docutils literal"><span class="pre">Connection.execute_immediate()</span></tt></a> or <a class="reference internal" href="reference.html#fdb.Transaction.execute_immediate" title="fdb.Transaction.execute_immediate"><tt class="xref py py-meth docutils literal"><span class="pre">Transaction.execute_immediate()</span></tt></a> for SQL commands that
don&#8217;t return any result, and are not executed frequently. This method also <strong>doesn&#8217;t</strong> support either
<a class="reference internal" href="#id1">parametrized statements</a> or <a class="reference internal" href="#id2">prepared statements</a>.</p>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">This method is efficient for <cite>administrative</cite> and <a class="reference external" href="http://en.wikipedia.org/wiki/Data_Definition_Language">DDL</a> SQL commands, like <cite>DROP</cite>, <cite>CREATE</cite> or <cite>ALTER</cite>
commands, <cite>SET STATISTICS</cite> etc.</p>
</div>
</li>
<li><p class="first"><a class="reference internal" href="reference.html#fdb.Cursor.execute" title="fdb.Cursor.execute"><tt class="xref py py-meth docutils literal"><span class="pre">Cursor.execute()</span></tt></a> or <a class="reference internal" href="reference.html#fdb.Cursor.executemany" title="fdb.Cursor.executemany"><tt class="xref py py-meth docutils literal"><span class="pre">Cursor.executemany()</span></tt></a> for commands that return result sets, i.e. sequence
of <cite>rows</cite> of the same structure, and sequence has unknown number of <cite>rows</cite> (including zero).</p>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">This method is preferred for all <cite>SELECT</cite> and other <a class="reference external" href="http://en.wikipedia.org/wiki/Data_Manipulation_Language">DML</a> statements, or any statement that is executed
frequently, either <cite>as is</cite> or in <cite>parametrized</cite> form.</p>
</div>
</li>
<li><p class="first"><a class="reference internal" href="reference.html#fdb.Cursor.callproc" title="fdb.Cursor.callproc"><tt class="xref py py-meth docutils literal"><span class="pre">Cursor.callproc()</span></tt></a> for execution of <cite>Stored procedures</cite> that always return exactly one set of values.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">This method of SP invocation is equivalent to <cite>&#8220;EXECUTE PROCEDURE ...&#8221;</cite> SQL statement.</p>
</div>
</li>
</ul>
</div>
<div class="section" id="parametrized-statements">
<span id="index-9"></span><span id="id1"></span><h3>Parametrized statements<a class="headerlink" href="#parametrized-statements" title="Permalink to this headline">¶</a></h3>
<p>When SQL command you want to execute contains data <cite>values</cite>, you can either:</p>
<ul>
<li><p class="first">Embed them <cite>directly</cite> or via <cite>string formatting</cite> into command <cite>string</cite>, e.g.:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into the_table (a,b,c) values (&#39;aardvark&#39;, 1, 0.1)&quot;</span><span class="p">)</span>
<span class="c"># or</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from the_table where col == &#39;aardvark&#39;&quot;</span><span class="p">)</span>
<span class="c"># or</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into the_table (a,b,c) values (&#39;</span><span class="si">%s</span><span class="s">&#39;, </span><span class="si">%i</span><span class="s">, </span><span class="si">%f</span><span class="s">)&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="s">&#39;aardvark&#39;</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mf">0.1</span><span class="p">))</span>
<span class="c"># or</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from the_table where col == &#39;</span><span class="si">%s</span><span class="s">&#39;&quot;</span> <span class="o">%</span> <span class="s">&#39;aardvark&#39;</span><span class="p">)</span>
</pre></div>
</div>
</li>
<li><p class="first">Use parameter marker (<cite>?</cite>) in command <cite>string</cite> in the slots where values are expected, then supply
those values as Python list or tuple:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into the_table (a,b,c) values (?,?,?)&quot;</span><span class="p">,</span> <span class="p">(</span><span class="s">&#39;aardvark&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">))</span>
<span class="c"># or</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from the_table where col == ?&quot;</span><span class="p">,(</span><span class="s">&#39;aardvark&#39;</span><span class="p">,))</span>
</pre></div>
</div>
</li>
</ul>
<p>While both methods have the same results, the second one (called <cite>parametrized</cite>) has several important
advantages:</p>
<ul class="simple">
<li>You don&#8217;t need to handle conversions from Python data types to strings.</li>
<li>FDB will handle all data type conversions (if necessary) from Python data types to Firebird ones,
including <cite>None/NULL</cite> conversion and conversion from <cite>unicode</cite> to <cite>byte strings</cite> in encoding expected
by server.</li>
<li>You may pass BLOB values as open <cite>file-like</cite> objects, and FDB will handle the transfer of BLOB value.</li>
<li>If you&#8217;ll pass exactly the same command <cite>string</cite> again to particular <a class="reference internal" href="reference.html#fdb.Cursor" title="fdb.Cursor"><tt class="xref py py-class docutils literal"><span class="pre">Cursor</span></tt></a> instance,
it will be executed more efficiently (see section about <a class="reference internal" href="#id2">Prepared Statements</a> for details).</li>
</ul>
<p>Parametrized statemets also have some limitations. Currently:</p>
<ul class="simple">
<li><cite>DATE</cite>, <cite>TIME</cite> and <cite>DATETIME</cite> values must be relevant <a class="reference external" href="http://docs.python.org/library/datetime.html#datetime" title="(in Python v2.7)"><tt class="xref py py-mod docutils literal"><span class="pre">datetime</span></tt></a> objects.</li>
<li><cite>NUMERIC</cite> and <cite>DECIMAL</cite> values must be <a class="reference external" href="http://docs.python.org/library/decimal.html#decimal" title="(in Python v2.7)"><tt class="xref py py-mod docutils literal"><span class="pre">decimal</span></tt></a> objects.</li>
</ul>
</div>
<div class="section" id="fetching-data-from-server">
<span id="index-10"></span><h3>Fetching data from server<a class="headerlink" href="#fetching-data-from-server" title="Permalink to this headline">¶</a></h3>
<p>Result of SQL statement execution consists from sequence of zero to unknown number of <cite>rows</cite>, where each
<cite>row</cite> is a set of exactly the same number of values. <a class="reference internal" href="reference.html#fdb.Cursor" title="fdb.Cursor"><tt class="xref py py-class docutils literal"><span class="pre">Cursor</span></tt></a> object offer number of different
methods for fetching these <cite>rows</cite>, that should satisfy all your specific needs:</p>
<ul>
<li><p class="first"><a class="reference internal" href="reference.html#fdb.Cursor.fetchone" title="fdb.Cursor.fetchone"><tt class="xref py py-meth docutils literal"><span class="pre">fetchone()</span></tt></a> - Returns the next row of a query result set, or <cite>None</cite> when no more data is
available.</p>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">Cursor supports the <a class="reference external" href="http://docs.python.org/library/stdtypes.html#typeiter" title="(in Python v2.7)"><em class="xref std std-ref">iterator protocol</em></a>, yielding tuples of values like
<a class="reference internal" href="reference.html#fdb.Cursor.fetchone" title="fdb.Cursor.fetchone"><tt class="xref py py-meth docutils literal"><span class="pre">fetchone()</span></tt></a>.</p>
</div>
</li>
<li><p class="first"><a class="reference internal" href="reference.html#fdb.Cursor.fetchmany" title="fdb.Cursor.fetchmany"><tt class="xref py py-meth docutils literal"><span class="pre">fetchmany()</span></tt></a> - Returns the next set of rows of a query result, returning a sequence of
sequences (e.g. a list of tuples). An empty sequence is returned when no more rows are available.</p>
<p>The number of rows to fetch per call is specified by the parameter. If it is not given, the cursor’s
<a class="reference internal" href="reference.html#fdb.Cursor.arraysize" title="fdb.Cursor.arraysize"><tt class="xref py py-attr docutils literal"><span class="pre">arraysize</span></tt></a> determines the number of rows to be fetched. The method does try to fetch
as many rows as indicated by the size parameter. If this is not possible due to the specified number
of rows not being available, fewer rows may be returned.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">The default value of <a class="reference internal" href="reference.html#fdb.Cursor.arraysize" title="fdb.Cursor.arraysize"><tt class="xref py py-attr docutils literal"><span class="pre">arraysize</span></tt></a> is <cite>1</cite>, so without paremeter it&#8217;s equivalent to
<a class="reference internal" href="reference.html#fdb.Cursor.fetchone" title="fdb.Cursor.fetchone"><tt class="xref py py-meth docutils literal"><span class="pre">fetchone()</span></tt></a>, but returns list of <cite>rows</cite>, instead actual <cite>row</cite> directly.</p>
</div>
</li>
<li><p class="first"><a class="reference internal" href="reference.html#fdb.Cursor.fetchall" title="fdb.Cursor.fetchall"><tt class="xref py py-meth docutils literal"><span class="pre">fetchall()</span></tt></a> -  Returns all (remaining) rows of a query result as list of tuples, where
each tuple is one row of returned values.</p>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">This method can potentially return huge amount of data, that may exhaust available memory.
If you need just <cite>iteration</cite> over potentially big result set, use loops with <a class="reference internal" href="reference.html#fdb.Cursor.fetchone" title="fdb.Cursor.fetchone"><tt class="xref py py-meth docutils literal"><span class="pre">fetchone()</span></tt></a>,
Cursor&#8217;s built-in support for <a class="reference external" href="http://docs.python.org/library/stdtypes.html#typeiter" title="(in Python v2.7)"><em class="xref std std-ref">iterator protocol</em></a> or call to <a class="reference internal" href="reference.html#fdb.Cursor.iter" title="fdb.Cursor.iter"><tt class="xref py py-meth docutils literal"><span class="pre">iter()</span></tt></a>
instead this method.</p>
</div>
</li>
<li><p class="first"><a class="reference internal" href="reference.html#fdb.Cursor.fetchonemap" title="fdb.Cursor.fetchonemap"><tt class="xref py py-meth docutils literal"><span class="pre">fetchonemap()</span></tt></a> - Returns the next row like <a class="reference internal" href="reference.html#fdb.Cursor.fetchone" title="fdb.Cursor.fetchone"><tt class="xref py py-meth docutils literal"><span class="pre">fetchone()</span></tt></a>, but returns a mapping
of <cite>field name</cite> to <cite>field value</cite>, rather than a tuple.</p>
</li>
<li><p class="first"><a class="reference internal" href="reference.html#fdb.Cursor.fetchmanymap" title="fdb.Cursor.fetchmanymap"><tt class="xref py py-meth docutils literal"><span class="pre">fetchmanymap()</span></tt></a> - Returns the next set of rows of a query result like <a class="reference internal" href="reference.html#fdb.Cursor.fetchmany" title="fdb.Cursor.fetchmany"><tt class="xref py py-meth docutils literal"><span class="pre">fetchmany()</span></tt></a>,
but returns a list of mapping of <cite>field name</cite> to <cite>field value</cite>, rather than a tuple.</p>
</li>
<li><p class="first"><a class="reference internal" href="reference.html#fdb.Cursor.fetchallmap" title="fdb.Cursor.fetchallmap"><tt class="xref py py-meth docutils literal"><span class="pre">fetchallmap()</span></tt></a> - Returns all (remaining) rows of a query result like <a class="reference internal" href="reference.html#fdb.Cursor.fetchall" title="fdb.Cursor.fetchall"><tt class="xref py py-meth docutils literal"><span class="pre">fetchall()</span></tt></a>,
returns a list of mappings of <cite>field name</cite> to <cite>field value</cite>, rather than a tuple.</p>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">This method can potentially return huge amount of data, that may exhaust available memory.
If you need just <cite>iteration</cite> over potentially big result set with mapping support, use
<a class="reference internal" href="reference.html#fdb.Cursor.itermap" title="fdb.Cursor.itermap"><tt class="xref py py-meth docutils literal"><span class="pre">itermap()</span></tt></a> instead this method.</p>
</div>
</li>
<li><p class="first"><a class="reference internal" href="reference.html#fdb.Cursor.iter" title="fdb.Cursor.iter"><tt class="xref py py-meth docutils literal"><span class="pre">iter()</span></tt></a> - Equivalent to the <a class="reference internal" href="reference.html#fdb.Cursor.fetchall" title="fdb.Cursor.fetchall"><tt class="xref py py-meth docutils literal"><span class="pre">fetchall()</span></tt></a>, except that it returns <a class="reference external" href="http://docs.python.org/library/stdtypes.html#typeiter" title="(in Python v2.7)"><em class="xref std std-ref">iterator</em></a> rather than materialized list.</p>
</li>
<li><p class="first"><a class="reference internal" href="reference.html#fdb.Cursor.itermap" title="fdb.Cursor.itermap"><tt class="xref py py-meth docutils literal"><span class="pre">itermap()</span></tt></a> - Equivalent to the <a class="reference internal" href="reference.html#fdb.Cursor.fetchallmap" title="fdb.Cursor.fetchallmap"><tt class="xref py py-meth docutils literal"><span class="pre">fetchallmap()</span></tt></a>, except that it returns
<a class="reference external" href="http://docs.python.org/library/stdtypes.html#typeiter" title="(in Python v2.7)"><em class="xref std std-ref">iterator</em></a> rather than materialized list.</p>
</li>
<li><p class="first">Call to <a class="reference internal" href="reference.html#fdb.Cursor.execute" title="fdb.Cursor.execute"><tt class="xref py py-meth docutils literal"><span class="pre">execute()</span></tt></a> returns self (Cursor instance) that itself supports
the <a class="reference external" href="http://docs.python.org/library/stdtypes.html#typeiter" title="(in Python v2.7)"><em class="xref std std-ref">iterator protocol</em></a>, yielding tuples of values like <a class="reference internal" href="reference.html#fdb.Cursor.fetchone" title="fdb.Cursor.fetchone"><tt class="xref py py-meth docutils literal"><span class="pre">fetchone()</span></tt></a>.</p>
</li>
</ul>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p class="last">FDB makes absolutely no guarantees about the return value of the <cite>fetchone</cite> / <cite>fetchmany</cite> / <cite>fetchall</cite>
methods except that it is a sequence indexed by field position. FDB makes absolutely no guarantees about
the return value of the <cite>fetchonemap</cite> / <cite>fetchmanymap</cite> / <cite>fetchallmap</cite> methods except that it is a mapping
of field name to field value. Therefore, client programmers should not rely on the return value being
an instance of a particular class or type.</p>
</div>
<p><strong>Examples:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;/temp/test.db&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>

<span class="n">cur</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
<span class="n">SELECT</span> <span class="o">=</span> <span class="s">&quot;select name, year_released from languages order by year_released&quot;</span>

<span class="c"># 1. Using built-in support for iteration protocol to iterate over the rows available from the cursor,</span>
<span class="c"># unpacking the resulting sequences to yield their elements (name, year_released):</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">SELECT</span><span class="p">)</span>
<span class="k">for</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">year_released</span><span class="p">)</span> <span class="ow">in</span> <span class="n">cur</span><span class="p">:</span>
    <span class="k">print</span> <span class="s">&#39;</span><span class="si">%s</span><span class="s"> has been publicly available since </span><span class="si">%d</span><span class="s">.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">year_released</span><span class="p">)</span>

<span class="c"># 2. Equivalently using fetchall():</span>
<span class="c"># This is potentially dangerous if result set is huge, as the whole result set is first materialized</span>
<span class="c"># as list and then used for iteration.</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">SELECT</span><span class="p">)</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">():</span>
    <span class="k">print</span> <span class="s">&#39;</span><span class="si">%s</span><span class="s"> has been publicly available since </span><span class="si">%d</span><span class="s">.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>

<span class="c"># 3. Using mapping-iteration rather than sequence-iteration:</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">SELECT</span><span class="p">)</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">cur</span><span class="o">.</span><span class="n">itermap</span><span class="p">():</span>
    <span class="k">print</span> <span class="s">&#39;</span><span class="si">%(name)s</span><span class="s"> has been publicly available since </span><span class="si">%(year_released)d</span><span class="s">.&#39;</span> <span class="o">%</span> <span class="n">row</span>
</pre></div>
</div>
</div>
<div class="section" id="prepared-statements">
<span id="index-11"></span><span id="id2"></span><h3>Prepared Statements<a class="headerlink" href="#prepared-statements" title="Permalink to this headline">¶</a></h3>
<p>Execution of any SQL statement has three phases:</p>
<ul class="simple">
<li><em>Preparation</em>: command is analyzed, validated, execution plan is determined by optimizer and all
necessary data structures (for example for input and output parameters) are initialized.</li>
<li><em>Execution</em>: input parameters (if any) are passed to server and previously prepared statement is
actually executed by database engine.</li>
<li><em>Fetching</em>: result of execution and data (if any) are transfered from server to client, and
allocated resources are then released.</li>
</ul>
<p>The preparation phase consumes some amount of server resources (memory and CPU). Although preparation
and release of resources typically takes only small amount of CPU time, it builds up as number
of executed statements grows. Firebird (like most database engines) allows to spare this time for
subsequent execution if particular statement should be executed repeatedly - by reusing once prepared
statement for repeated execution. This may save significant amount of server processing time, and better
overall performance.</p>
<p>FDB builds on this by encapsulating all statement-related code into separate <a class="reference internal" href="reference.html#fdb.PreparedStatement" title="fdb.PreparedStatement"><tt class="xref py py-class docutils literal"><span class="pre">PreparedStatement</span></tt></a>
class, and implementing <a class="reference internal" href="reference.html#fdb.Cursor" title="fdb.Cursor"><tt class="xref py py-class docutils literal"><span class="pre">Cursor</span></tt></a> class as a wrapper around it. Once executed statement has to
be disposed in favour of new one, the <cite>PreparedStatement</cite> instance is stored into <cite>Cursor&#8217;s</cite> internal cache.
Whenever SQL statement execution is requested, <cite>Cursor</cite> checks whether appropriate <cite>PreparedStatement</cite>
isn&#8217;t in this cache, and if it is, uses it instead creating new one. Because <cite>identity</cite> of SQL statement
is defined by its <cite>command string</cite>, this mechanism works best for SQL commands that either are <cite>static</cite>
or <a class="reference external" href="Parametrizedstatements">parametrized</a>.</p>
<p><strong>Example:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">insertStatement</span> <span class="o">=</span> <span class="s">&quot;insert into the_table (a,b,c) values (?,?,?)&quot;</span>

<span class="c"># First execution initializes the PreparedStatement</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">insertStatement</span><span class="p">,</span> <span class="p">(</span><span class="s">&#39;aardvark&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">))</span>

<span class="c"># This execution reuses PreparedStatement from cache</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">insertStatement</span><span class="p">,</span> <span class="p">(</span><span class="s">&#39;zymurgy&#39;</span><span class="p">,</span> <span class="mi">2147483647</span><span class="p">,</span> <span class="mf">99999.999</span><span class="p">))</span>

<span class="c"># And this one too</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into the_table (a,b,c) values (?,?,?)&quot;</span><span class="p">,</span> <span class="p">(</span><span class="s">&#39;foobar&#39;</span><span class="p">,</span> <span class="mi">2000</span><span class="p">,</span> <span class="mf">9.9</span><span class="p">))</span>
</pre></div>
</div>
<p>Additionally to automatic, implicit reuse of prepared statements, <cite>Cursor</cite> also allows to aquire and use
<cite>PreparedStatement</cite> instances explicitly. <cite>PreparedStatement</cite> aquired by calling <a class="reference internal" href="reference.html#fdb.Cursor.prep" title="fdb.Cursor.prep"><tt class="xref py py-meth docutils literal"><span class="pre">prep()</span></tt></a>
method could be then passed to <a class="reference internal" href="reference.html#fdb.Cursor.execute" title="fdb.Cursor.execute"><tt class="xref py py-meth docutils literal"><span class="pre">execute()</span></tt></a> or <a class="reference internal" href="reference.html#fdb.Cursor.executemany" title="fdb.Cursor.executemany"><tt class="xref py py-meth docutils literal"><span class="pre">executemany()</span></tt></a> instead <cite>command
string</cite>.</p>
<p><strong>Example:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">insertStatement</span> <span class="o">=</span> <span class="n">cur</span><span class="o">.</span><span class="n">prep</span><span class="p">(</span><span class="s">&quot;insert into the_table (a,b,c) values (?,?,?)&quot;</span><span class="p">)</span>

<span class="n">inputRows</span> <span class="o">=</span> <span class="p">[</span>
    <span class="p">(</span><span class="s">&#39;aardvark&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">),</span>
    <span class="p">(</span><span class="s">&#39;zymurgy&#39;</span><span class="p">,</span> <span class="mi">2147483647</span><span class="p">,</span> <span class="mf">99999.999</span><span class="p">),</span>
    <span class="p">(</span><span class="s">&#39;foobar&#39;</span><span class="p">,</span> <span class="mi">2000</span><span class="p">,</span> <span class="mf">9.9</span><span class="p">)</span>
  <span class="p">]</span>

<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">inputRows</span><span class="p">:</span>
   <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">insertStatement</span><span class="p">,</span><span class="n">row</span><span class="p">)</span>
<span class="c">#</span>
<span class="c"># or you can use executemany</span>
<span class="c">#</span>
<span class="n">cur</span><span class="o">.</span><span class="n">executemany</span><span class="p">(</span><span class="n">insertStatement</span><span class="p">,</span> <span class="n">inputRows</span><span class="p">)</span>
</pre></div>
</div>
<p>While both implicit and explicit prepared statements could be used to the same effect, there are
significant differences between both methods:</p>
<ul>
<li><p class="first"><strong>Implicit</strong> prepared statements remain in the cache until <cite>Cursor</cite> instance is disposed,
preventing server-side resources allocated for the statement to be fully released. If it may
become a problem, it&#8217;s necessary to release the <cite>Cursor</cite> instance, or call its <a class="reference internal" href="reference.html#fdb.Cursor.clear_cache" title="fdb.Cursor.clear_cache"><tt class="xref py py-meth docutils literal"><span class="pre">clear_cache()</span></tt></a>
method.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Because <cite>Cursor</cite> is just a wrapper around <a class="reference internal" href="reference.html#fdb.PreparedStatement" title="fdb.PreparedStatement"><tt class="xref py py-class docutils literal"><span class="pre">PreparedStatement</span></tt></a> instance(s), calling
<a class="reference internal" href="reference.html#fdb.Cursor.close" title="fdb.Cursor.close"><tt class="xref py py-meth docutils literal"><span class="pre">close()</span></tt></a> doesn&#8217;t render the <cite>Cursor</cite> instance unusable (unlike other objects like
<a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> or <a class="reference internal" href="reference.html#fdb.Transaction" title="fdb.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a>). It just closes the current prepared statement, but
all prepared statements (current and all in internal cache) are still available for use, and <cite>Cursor</cite>
itself is still bound to <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> and <a class="reference internal" href="reference.html#fdb.Transaction" title="fdb.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a>, and could be still used
to execute SQL statements.</p>
</div>
<div class="admonition warning">
<p class="first admonition-title">Warning</p>
<p>FDB&#8217;s implementation of Cursor somewhat violates the Python DB API 2.0, which requires that cursor
will be unusable after call to <cite>close</cite>; and an Error (or subclass) exception should be raised if
any operation is attempted with the cursor.</p>
<p class="last">If you&#8217;ll take advantage of this <cite>anomaly</cite>, your code would be less portable to other Python DB
API 2.0 compliant drivers.</p>
</div>
</li>
<li><p class="first"><strong>Explicit</strong> prepared statements are never stored in <cite>Cursor&#8217;s</cite> cache, but they are still bound to
<cite>Cursor</cite> instance that created them, and can&#8217;t be used with any other <cite>Cursor</cite> instance. Beside
repeated execution they are also useful to get information about statement (like its output
<a class="reference internal" href="reference.html#fdb.PreparedStatement.description" title="fdb.PreparedStatement.description"><tt class="xref py py-attr docutils literal"><span class="pre">description</span></tt></a>, execution <a class="reference internal" href="reference.html#fdb.PreparedStatement.plan" title="fdb.PreparedStatement.plan"><tt class="xref py py-attr docutils literal"><span class="pre">plan</span></tt></a> or
<a class="reference internal" href="reference.html#fdb.PreparedStatement.statement_type" title="fdb.PreparedStatement.statement_type"><tt class="xref py py-attr docutils literal"><span class="pre">statement_type</span></tt></a>) before its execution.</p>
</li>
</ul>
<p><strong>Example Program:</strong></p>
<p>The following program demonstrates the explicit use of <cite>PreparedStatements</cite>. It also benchmarks explicit
<cite>PreparedStatement</cite> reuse against FDB’s automatic <cite>PreparedStatement</cite> reuse, and against an input strategy
that prevents <cite>PreparedStatement</cite> reuse.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:employee&#39;</span><span class="p">,</span>
    <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span>
  <span class="p">)</span>

<span class="n">cur</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

<span class="c"># Create supporting database entities:</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;recreate table t (a int, b varchar(50))&quot;</span><span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;create unique index unique_t_a on t(a)&quot;</span><span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="c"># Explicitly prepare the insert statement:</span>
<span class="n">psIns</span> <span class="o">=</span> <span class="n">cur</span><span class="o">.</span><span class="n">prep</span><span class="p">(</span><span class="s">&quot;insert into t (a,b) values (?,?)&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;psIns.sql: &quot;</span><span class="si">%s</span><span class="s">&quot;&#39;</span> <span class="o">%</span> <span class="n">psIns</span><span class="o">.</span><span class="n">sql</span>
<span class="k">print</span> <span class="s">&#39;psIns.statement_type == fdb.isc_info_sql_stmt_insert:&#39;</span><span class="p">,</span> <span class="p">(</span>
    <span class="n">psIns</span><span class="o">.</span><span class="n">statement_type</span> <span class="o">==</span> <span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_sql_stmt_insert</span>
  <span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;psIns.n_input_params: </span><span class="si">%d</span><span class="s">&#39;</span> <span class="o">%</span> <span class="n">psIns</span><span class="o">.</span><span class="n">n_input_params</span>
<span class="k">print</span> <span class="s">&#39;psIns.n_output_params: </span><span class="si">%d</span><span class="s">&#39;</span> <span class="o">%</span> <span class="n">psIns</span><span class="o">.</span><span class="n">n_output_params</span>
<span class="k">print</span> <span class="s">&#39;psIns.plan: </span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="n">psIns</span><span class="o">.</span><span class="n">plan</span>

<span class="k">print</span>

<span class="n">N</span> <span class="o">=</span> <span class="mi">50000</span>
<span class="n">iStart</span> <span class="o">=</span> <span class="mi">0</span>

<span class="c"># The client programmer uses a PreparedStatement explicitly:</span>
<span class="n">startTime</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="n">iStart</span><span class="p">,</span> <span class="n">iStart</span> <span class="o">+</span> <span class="n">N</span><span class="p">):</span>
    <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">psIns</span><span class="p">,</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">)))</span>
<span class="k">print</span> <span class="p">(</span>
    <span class="s">&#39;With explicit prepared statement, performed&#39;</span>
    <span class="s">&#39;</span><span class="se">\n</span><span class="s">  </span><span class="si">%0.2f</span><span class="s"> insertions per second.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">N</span> <span class="o">/</span> <span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">startTime</span><span class="p">))</span>
  <span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="n">iStart</span> <span class="o">+=</span> <span class="n">N</span>

<span class="c"># FDB automatically uses a PreparedStatement &quot;under the hood&quot;:</span>
<span class="n">startTime</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="n">iStart</span><span class="p">,</span> <span class="n">iStart</span> <span class="o">+</span> <span class="n">N</span><span class="p">):</span>
    <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into t (a,b) values (?,?)&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">)))</span>
<span class="k">print</span> <span class="p">(</span>
    <span class="s">&#39;With implicit prepared statement, performed&#39;</span>
    <span class="s">&#39;</span><span class="se">\n</span><span class="s">  </span><span class="si">%0.2f</span><span class="s"> insertions per second.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">N</span> <span class="o">/</span> <span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">startTime</span><span class="p">))</span>
  <span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="n">iStart</span> <span class="o">+=</span> <span class="n">N</span>

<span class="c"># A new SQL string containing the inputs is submitted every time, so</span>
<span class="c"># FDB is not able to implicitly reuse a PreparedStatement.  Also, in a</span>
<span class="c"># more complicated scenario where the end user supplied the string input</span>
<span class="c"># values, the program would risk SQL injection attacks:</span>
<span class="n">startTime</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="n">iStart</span><span class="p">,</span> <span class="n">iStart</span> <span class="o">+</span> <span class="n">N</span><span class="p">):</span>
    <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into t (a,b) values (</span><span class="si">%d</span><span class="s">,&#39;</span><span class="si">%s</span><span class="s">&#39;)&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">)))</span>
<span class="k">print</span> <span class="p">(</span>
    <span class="s">&#39;When unable to reuse prepared statement, performed&#39;</span>
    <span class="s">&#39;</span><span class="se">\n</span><span class="s">  </span><span class="si">%0.2f</span><span class="s"> insertions per second.&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">N</span> <span class="o">/</span> <span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">startTime</span><span class="p">))</span>
  <span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="c"># Prepare a SELECT statement and examine its properties.  The optimizer&#39;s plan</span>
<span class="c"># should use the unique index that we created at the beginning of this program.</span>
<span class="k">print</span>
<span class="n">psSel</span> <span class="o">=</span> <span class="n">cur</span><span class="o">.</span><span class="n">prep</span><span class="p">(</span><span class="s">&quot;select * from t where a = ?&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;psSel.sql: &quot;</span><span class="si">%s</span><span class="s">&quot;&#39;</span> <span class="o">%</span> <span class="n">psSel</span><span class="o">.</span><span class="n">sql</span>
<span class="k">print</span> <span class="s">&#39;psSel.statement_type == fdb.isc_info_sql_stmt_select:&#39;</span><span class="p">,</span> <span class="p">(</span>
    <span class="n">psSel</span><span class="o">.</span><span class="n">statement_type</span> <span class="o">==</span> <span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_sql_stmt_select</span>
  <span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;psSel.n_input_params: </span><span class="si">%d</span><span class="s">&#39;</span> <span class="o">%</span> <span class="n">psSel</span><span class="o">.</span><span class="n">n_input_params</span>
<span class="k">print</span> <span class="s">&#39;psSel.n_output_params: </span><span class="si">%d</span><span class="s">&#39;</span> <span class="o">%</span> <span class="n">psSel</span><span class="o">.</span><span class="n">n_output_params</span>
<span class="k">print</span> <span class="s">&#39;psSel.plan: </span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="n">psSel</span><span class="o">.</span><span class="n">plan</span>

<span class="c"># The current implementation does not allow PreparedStatements to be prepared</span>
<span class="c"># on one Cursor and executed on another:</span>
<span class="k">print</span>
<span class="k">print</span> <span class="s">&#39;Note that PreparedStatements are not transferrable from one cursor to another:&#39;</span>
<span class="n">cur2</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
<span class="n">cur2</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">psSel</span><span class="p">)</span>
</pre></div>
</div>
<p>Sample output:</p>
<div class="highlight-python"><pre>psIns.sql: "insert into t (a,b) values (?,?)"
psIns.statement_type == fdb.isc_info_sql_stmt_insert: True
psIns.n_input_params: 2
psIns.n_output_params: 0
psIns.plan: None

With explicit prepared statement, performed
  4276.00 insertions per second.
With implicit prepared statement, performed
  4185.09 insertions per second.
When unable to reuse prepared statement, performed
  2037.70 insertions per second.

psSel.sql: "select * from t where a = ?"
psSel.statement_type == fdb.isc_info_sql_stmt_select: True
psSel.n_input_params: 1
psSel.n_output_params: 2
psSel.plan: PLAN (T INDEX (UNIQUE_T_A))

Note that PreparedStatements are not transferrable from one cursor to another:
Traceback (most recent call last):
  File "pstest.py", line 85, in &lt;module&gt;
    cur2.execute(psSel)
     File "/home/job/python/envs/pyfirebird/fdb/fdb/fbcore.py", line 2623, in execute
    raise ValueError("PreparedStatement was created by different Cursor.")
ValueError: PreparedStatement was created by different Cursor.</pre>
</div>
<p>As you can see, the version that prevents the reuse of prepared statements is about two times slower
– <em>for a trivial statement</em>. In a real application, SQL statements are likely to be far more complicated,
so the speed advantage of using prepared statements would only increase.</p>
<p>As the timings indicate, FDB does a good job of reusing prepared statements even if the client program
is written in a style strictly compatible with the Python DB API 2.0 (which accepts only <cite>strings</cite> –
not <a class="reference internal" href="reference.html#fdb.PreparedStatement" title="fdb.PreparedStatement"><tt class="xref py py-class docutils literal"><span class="pre">PreparedStatement</span></tt></a> objects – to the <a class="reference internal" href="reference.html#fdb.Cursor.execute" title="fdb.Cursor.execute"><tt class="xref py py-meth docutils literal"><span class="pre">Cursor.execute()</span></tt></a> method). The performance loss
in this case is about one percent.</p>
</div>
<div class="section" id="named-cursors">
<span id="index-12"></span><h3>Named Cursors<a class="headerlink" href="#named-cursors" title="Permalink to this headline">¶</a></h3>
<p>To allow the Python programmer to perform scrolling <cite>UPDATE</cite> or <cite>DELETE</cite> via the <cite>“SELECT ... FOR UPDATE”</cite>
syntax, FDB provides the read/write property <a class="reference internal" href="reference.html#fdb.Cursor.name" title="fdb.Cursor.name"><tt class="xref py py-attr docutils literal"><span class="pre">Cursor.name</span></tt></a>.</p>
<p><strong>Example Program:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:/temp/test.db&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="n">curScroll</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
<span class="n">curUpdate</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

<span class="n">curScroll</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select city from addresses for update&quot;</span><span class="p">)</span>
<span class="n">curScroll</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="s">&#39;city_scroller&#39;</span>
<span class="n">update</span> <span class="o">=</span> <span class="s">&quot;update addresses set city=? where current of &quot;</span> <span class="o">+</span> <span class="n">curScroll</span><span class="o">.</span><span class="n">name</span>

<span class="k">for</span> <span class="p">(</span><span class="n">city</span><span class="p">,)</span> <span class="ow">in</span> <span class="n">curScroll</span><span class="p">:</span>
    <span class="n">city</span> <span class="o">=</span> <span class="o">...</span> <span class="c"># make some changes to city</span>
    <span class="n">curUpdate</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span> <span class="n">update</span><span class="p">,</span> <span class="p">(</span><span class="n">city</span><span class="p">,)</span> <span class="p">)</span>

<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="section" id="working-with-stored-procedures">
<span id="index-13"></span><h3>Working with stored procedures<a class="headerlink" href="#working-with-stored-procedures" title="Permalink to this headline">¶</a></h3>
<p>Firebird stored procedures can have <cite>input</cite> parameters and/or <cite>output</cite> parameters. Some databases support
<cite>input/output</cite> parameters, where the same parameter is used for both input and output; Firebird does not
support this.</p>
<p>It is important to distinguish between procedures that <cite>return a result set</cite> and procedures that <cite>populate
and return their output parameters</cite> exactly once. Conceptually, the latter “return their output parameters”
like a Python function, whereas the former “yield result rows” like a Python generator.</p>
<p>Firebird’s <cite>server-side</cite> procedural SQL syntax makes no such distinction, but client-side SQL code (and C
API code) must. A result set is retrieved from a stored procedure by <cite>SELECT&#8217;ing from the procedure,
whereas output parameters are retrieved with an &#8216;EXECUTE PROCEDURE&#8217; statement</cite>.</p>
<p>To <strong>retrieve a result set</strong> from a stored procedure with FDB, use code such as this:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select output1, output2 from the_proc(?, ?)&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">input1</span><span class="p">,</span> <span class="n">input2</span><span class="p">))</span>

<span class="c"># Ordinary fetch code here, such as:</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">cur</span><span class="p">:</span>
   <span class="o">...</span> <span class="c"># process row</span>

<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span> <span class="c"># If the procedure had any side effects, commit them.</span>
</pre></div>
</div>
<p>To <strong>execute</strong> a stored procedure and <strong>access its output parameters</strong>, use code such as this:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">cur</span><span class="o">.</span><span class="n">callproc</span><span class="p">(</span><span class="s">&quot;the_proc&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">input1</span><span class="p">,</span> <span class="n">input2</span><span class="p">))</span>

<span class="c"># If there are output parameters, retrieve them as though they were the</span>
<span class="c"># first row of a result set.  For example:</span>
<span class="n">outputParams</span> <span class="o">=</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>

<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span> <span class="c"># If the procedure had any side effects, commit them.</span>
</pre></div>
</div>
<p>This latter is not very elegant; it would be preferable to access the procedure’s output parameters as
the return value of <a class="reference internal" href="reference.html#fdb.Cursor.callproc" title="fdb.Cursor.callproc"><tt class="xref py py-meth docutils literal"><span class="pre">Cursor.callproc()</span></tt></a>. The Python DB API specification requires the current behavior,
however.</p>
</div>
</div>
<div class="section" id="data-handling-and-conversions">
<span id="index-14"></span><h2>Data handling and conversions<a class="headerlink" href="#data-handling-and-conversions" title="Permalink to this headline">¶</a></h2>
<div class="section" id="implicit-conversion-of-input-parameters-from-strings">
<span id="index-15"></span><h3>Implicit Conversion of Input Parameters from Strings<a class="headerlink" href="#implicit-conversion-of-input-parameters-from-strings" title="Permalink to this headline">¶</a></h3>
<p>The database engine treats most SQL data types in a weakly typed fashion: the engine may attempt to convert
the raw value to a different type, as appropriate for the current context. For instance, the SQL expressions
<cite>123</cite> (integer) and <cite>‘123’</cite> (string) are treated equivalently when the value is to be inserted into
an <cite>integer</cite> field; the same applies when <cite>‘123’</cite> and <cite>123</cite> are to be inserted into a <cite>varchar</cite> field.</p>
<p>This weak typing model is quite unlike Python’s dynamic yet strong typing. Although weak typing is regarded
with suspicion by most experienced Python programmers, the database engine is in certain situations so
aggressive about its typing model that KInterbasDB must compromise in order to remain an elegant means
of programming the database engine.</p>
<p>An example is the handling of “magic values” for date and time fields. The database engine interprets certain
string values such as <cite>‘yesterday’</cite> and <cite>‘now’</cite> as having special meaning in a date/time context. If FDB did
not accept strings as the values of parameters destined for storage in date/time fields, the resulting code
would be awkward. Consider the difference between the two Python snippets below, which insert a row containing
an integer and a timestamp into a table defined with the following DDL statement:</p>
<div class="highlight-sql"><div class="highlight"><pre><span class="k">create</span> <span class="k">table</span> <span class="n">test_table</span> <span class="p">(</span><span class="n">i</span> <span class="nb">integer</span><span class="p">,</span> <span class="n">t</span> <span class="k">timestamp</span><span class="p">)</span>
</pre></div>
</div>
<div class="highlight-python"><div class="highlight"><pre><span class="n">i</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">t</span> <span class="o">=</span> <span class="s">&#39;now&#39;</span>
<span class="n">sqlWithMagicValues</span> <span class="o">=</span> <span class="s">&quot;insert into test_table (i, t) values (?, &#39;</span><span class="si">%s</span><span class="s">&#39;)&quot;</span> <span class="o">%</span> <span class="n">t</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span> <span class="n">sqlWithMagicValues</span><span class="p">,</span> <span class="p">(</span><span class="n">i</span><span class="p">,)</span> <span class="p">)</span>
</pre></div>
</div>
<div class="highlight-python"><div class="highlight"><pre><span class="n">i</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">t</span> <span class="o">=</span> <span class="s">&#39;now&#39;</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span> <span class="s">&quot;insert into test_table (i, t) values (?, ?)&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">t</span><span class="p">)</span> <span class="p">)</span>
</pre></div>
</div>
<p>If FDB did not support weak parameter typing, string parameters that the database engine is to interpret
as “magic values” would have to be rolled into the SQL statement in a separate operation from the binding
of the rest of the parameters, as in the first Python snippet above. Implicit conversion of parameter values
from strings allows the consistency evident in the second snippet, which is both more readable and more
general.</p>
<p>It should be noted that FDB does not perform the conversion from string itself. Instead, it passes that
responsibility to the database engine by changing the parameter metadata structure dynamically at the last
moment, then restoring the original state of the metadata structure after the database engine has performed
the conversion.</p>
<p>A secondary benefit is that when one uses FDB to import large amounts of data from flat files into
the database, the incoming values need not necessarily be converted to their proper Python types before
being passed to the database engine. Eliminating this intermediate step may accelerate the import process
considerably, although other factors such as the chosen connection protocol and the deactivation of indexes
during the import are more consequential. For bulk import tasks, the database engine’s external tables also
deserve consideration. External tables can be used to suck semi-structured data from flat files directly
into the relational database without the intervention of an ad hoc conversion program.</p>
</div>
<div class="section" id="automatic-conversion-from-to-unicode">
<span id="index-16"></span><h3>Automatic conversion from/to unicode<a class="headerlink" href="#automatic-conversion-from-to-unicode" title="Permalink to this headline">¶</a></h3>
<p>In Firebird, every <cite>CHAR</cite>, <cite>VARCHAR</cite> or textual <cite>BLOB</cite> field can (or, better: must) have a <cite>character set</cite>
assigned. While it&#8217;s possible to define single character set for whole database, it&#8217;s also possible to
define different character set for each textual field. This information is used to correctly store the bytes
that make up the character string, and together with collation information (that defines the sort ordering
and uppercase conversions for a string) is vital for correct data manupulation, including automatic
transliteration between character sets when necessary.</p>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p>Because data also flow between server and client application, it&#8217;s vital that client will send data
encoded only in character set(s) that server expects. While it&#8217;s possible to leave this responsibility
completely on client application, it&#8217;s better when client and server settle on single character set
they would use for communication, especially when database operates with multiple character sets, or
uses character set that is not <cite>native</cite> for client application.</p>
<p>Character set for communication is specified using <cite>charset</cite> parameter in <a class="reference internal" href="reference.html#fdb.connect" title="fdb.connect"><tt class="xref py py-func docutils literal"><span class="pre">connection</span></tt></a> call.</p>
<p class="last">When <cite>connection charset</cite> is defined, all textual data returned from server are encoded in this charset,
and client application must ensure that all textual data sent to server are encoded only in this charset
as well.</p>
</div>
<p>FDB helps with client side of this character set bargain by automatically converting <cite>unicode</cite> strings into
<cite>bytes/strings</cite> encoded in connection character set, and vice versa. However, developers are still
responsible that <cite>non-unicode</cite> strings passed to server are in correct encoding (because FDB makes no
assuption about encoding of non-unicode strings, so it can&#8217;t recode them to connection charset).</p>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p class="last">In case that <cite>connection charset</cite> is NOT defined at all, or <cite>NONE</cite> charset is specified, FDB uses
<a class="reference external" href="http://docs.python.org/library/locale.html#locale.getpreferredencoding" title="(in Python v2.7)"><tt class="xref py py-func docutils literal"><span class="pre">locale.getpreferredencoding()</span></tt></a> to determine encoding for conversions from/to <cite>unicode</cite>.</p>
</div>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p class="last">There is one exception to automatic conversion: when character set OCTETS is defined for data column.
Values assigned to OCTETS columns are always passed <cite>as is</cite>, because they&#8217;re basically binary streams.
This has specific implications regarding Python version you use. Python 2.x <cite>native strings</cite> are <cite>bytes</cite>,
suitable for such binary streams, but Python 3 native strings are <cite>unicode</cite>, and you would probably
want to use <cite>bytes</cite> type instead. However, FDB in this case doesn&#8217;t check the value type at all, so
you&#8217;ll not be warned if you&#8217;ll make a mistake and pass <cite>unicode</cite> to OCTETS column (unless you&#8217;ll pass
more bytes than column may hold, or you intend to store unicode that way).</p>
</div>
<p>Rules for automatic conversion depend on Python version you use:</p>
<ul class="simple">
<li>Native Python 2.x <cite>strings</cite> are passed to server as is, and developers must explicitly use <cite>unicode</cite>
strings to take advantage of automatic conversion. String values coming from server are converted to
<cite>unicode</cite> <strong>only</strong>:<ul>
<li>for data stored in database (i.e. not for string values returned by Firebird Service  and <cite>info</cite>
calls etc.).</li>
<li>when <cite>connection charset</cite> is specified.</li>
</ul>
</li>
<li>Native Python 3 strings are <cite>unicode</cite>, so conversion is fully automatic in both directions for all
textual data, i.e. including for string values returned by Firebird Service  and <cite>info</cite> calls etc.
When <cite>connection charset</cite> is not specified, FDB uses <a class="reference external" href="http://docs.python.org/library/locale.html#locale.getpreferredencoding" title="(in Python v2.7)"><tt class="xref py py-func docutils literal"><span class="pre">locale.getpreferredencoding()</span></tt></a> to determine
encoding for conversions from/to <cite>unicode</cite>.</li>
</ul>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">Except for legacy databases that doesn&#8217;t have <cite>character set</cite> defined, <strong>always</strong> define character
set for your databases and specify <cite>connection charset</cite>. It will make your life much easier.</p>
</div>
</div>
<div class="section" id="working-with-blobs">
<span id="index-17"></span><span id="id3"></span><h3>Working with BLOBs<a class="headerlink" href="#working-with-blobs" title="Permalink to this headline">¶</a></h3>
<p>FDB uses two types of BLOB values:</p>
<ul class="simple">
<li><strong>Materialized</strong> BLOB values are Python strings. This is the <strong>default</strong> type.</li>
<li><strong>Streamed</strong> BLOB values are <cite>file-like</cite> objects.</li>
</ul>
<p>Materialized BLOBs are easy to work with, but are not suitable for:</p>
<ul class="simple">
<li><strong>deferred loading</strong> of BLOBs. They&#8217;re called <cite>materialized</cite> because they&#8217;re always fetched from server
as part of row fetch. Fetching BLOB value means separate API calls (and network roundtrips), which may
slow down you application considerably.</li>
<li><strong>large values</strong>, as they are always stored in memory in full size.</li>
</ul>
<p>These drawbacks are addressed by <cite>stream</cite> BLOBs. Using BLOBs in <cite>stream</cite> mode is easy:</p>
<ul class="simple">
<li>For <strong>input</strong> values, simply use <a class="reference internal" href="#parametrized-statements"><em>parametrized statement</em></a> and pass any
<cite>file-like</cite> object in place of BLOB parameter. The <cite>file-like</cite> object must implement only the
<a class="reference external" href="http://docs.python.org/library/stdtypes.html#file.read" title="(in Python v2.7)"><tt class="xref py py-meth docutils literal"><span class="pre">read()</span></tt></a> method, as no other metod is used.</li>
<li>For <strong>output</strong> values, you have to call <a class="reference internal" href="reference.html#fdb.Cursor.set_stream_blob" title="fdb.Cursor.set_stream_blob"><tt class="xref py py-meth docutils literal"><span class="pre">Cursor.set_stream_blob()</span></tt></a> (or <a class="reference internal" href="reference.html#fdb.PreparedStatement.set_stream_blob" title="fdb.PreparedStatement.set_stream_blob"><tt class="xref py py-meth docutils literal"><span class="pre">PreparedStatement.set_stream_blob()</span></tt></a>)
method with specification of column name(s) that should be returned as <cite>file-like</cite> objects. FDB then
returns <a class="reference internal" href="reference.html#fdb.BlobReader" title="fdb.BlobReader"><tt class="xref py py-class docutils literal"><span class="pre">BlobReader</span></tt></a> instance instead string in place of returned BLOB value for these column(s).</li>
</ul>
<p>The <a class="reference internal" href="reference.html#fdb.BlobReader" title="fdb.BlobReader"><tt class="xref py py-class docutils literal"><span class="pre">BlobReader</span></tt></a> instance is bound to particular BLOB value returned by server, so its life time
is limited. The actual BLOB value is not opened initially, so no additonal API calls to server are made
if you&#8217;ll decide to ignore the value completely. You also don&#8217;t need to open the BLOB value explicitly,
as BLOB is opened automatically on first call to <a class="reference internal" href="reference.html#fdb.BlobReader.next" title="fdb.BlobReader.next"><tt class="xref py py-meth docutils literal"><span class="pre">next()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.BlobReader.read" title="fdb.BlobReader.read"><tt class="xref py py-meth docutils literal"><span class="pre">read()</span></tt></a>,
<a class="reference internal" href="reference.html#fdb.BlobReader.readline" title="fdb.BlobReader.readline"><tt class="xref py py-meth docutils literal"><span class="pre">readline()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.BlobReader.readlines" title="fdb.BlobReader.readlines"><tt class="xref py py-meth docutils literal"><span class="pre">readlines()</span></tt></a> or <a class="reference internal" href="reference.html#fdb.BlobReader.seek" title="fdb.BlobReader.seek"><tt class="xref py py-meth docutils literal"><span class="pre">seek()</span></tt></a>. However, it&#8217;s
good practice to <a class="reference internal" href="reference.html#fdb.BlobReader.close" title="fdb.BlobReader.close"><tt class="xref py py-meth docutils literal"><span class="pre">close()</span></tt></a> the reader once you&#8217;re finished reading, as it&#8217;s likely that
Python&#8217;s garbage collector would call the <cite>__del__</cite> method too late, when fetch context is already gone,
and closing the reader would cause an error.</p>
<div class="admonition warning">
<p class="first admonition-title">Warning</p>
<p class="last">If BLOB was NOT CREATED as <cite>stream</cite> BLOB, calling <a class="reference internal" href="reference.html#fdb.BlobReader.seek" title="fdb.BlobReader.seek"><tt class="xref py py-meth docutils literal"><span class="pre">BlobReader.seek()</span></tt></a> method will raise
<a class="reference internal" href="reference.html#fdb.DatabaseError" title="fdb.DatabaseError"><tt class="xref py py-exc docutils literal"><span class="pre">DatabaseError</span></tt></a> exception. <strong>This constraint is set by Firebird.</strong></p>
</div>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p class="last">When working with BLOB values, always have memory efficiency in mind, especially when you&#8217;re
processing huge quantity of rows with BLOB values at once. Materialized BLOB values may exhaust
your memory quickly, but using stream BLOBs may have inpact on performance too, as new <cite>BlobReader</cite>
instance is created for each value fetched.</p>
</div>
<p><strong>Example program:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">os.path</span>
<span class="kn">from</span> <span class="nn">cStringIO</span> <span class="kn">import</span> <span class="n">StringIO</span>

<span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>

<span class="n">cur</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;recreate table blob_test (a blob)&quot;</span><span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="c"># --- Materialized mode (str objects for both input and output) ---</span>
<span class="c"># Insertion:</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into blob_test values (?)&quot;</span><span class="p">,</span> <span class="p">(</span><span class="s">&#39;abcdef&#39;</span><span class="p">,))</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into blob_test values (?)&quot;</span><span class="p">,</span> <span class="p">(</span><span class="s">&#39;ghijklmnop&#39;</span><span class="p">,))</span>
<span class="c"># Retrieval:</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from blob_test&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;Materialized retrieval (as str):&#39;</span>
<span class="k">print</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;delete from blob_test&quot;</span><span class="p">)</span>

<span class="c"># --- Streaming mode (file-like objects for input; fdb.BlobReader objects for output) ---</span>

<span class="c"># Insertion:</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into blob_test values (?)&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">StringIO</span><span class="p">(</span><span class="s">&#39;abcdef&#39;</span><span class="p">),))</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into blob_test values (?)&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">StringIO</span><span class="p">(</span><span class="s">&#39;ghijklmnop&#39;</span><span class="p">),))</span>

<span class="n">f</span> <span class="o">=</span> <span class="nb">file</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">),</span> <span class="s">&#39;rb&#39;</span><span class="p">)</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into blob_test values (?)&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">f</span><span class="p">,))</span>
<span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

<span class="c"># Retrieval using the &quot;file-like&quot; methods of BlobReader:</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from blob_test&quot;</span><span class="p">)</span>
<span class="n">cur</span><span class="o">.</span><span class="n">set_stream_blob</span><span class="p">(</span><span class="s">&#39;A&#39;</span><span class="p">)</span> <span class="c"># Note the capital letter</span>

<span class="n">readerA</span> <span class="o">=</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>

<span class="k">print</span> <span class="s">&#39;</span><span class="se">\n</span><span class="s">Streaming retrieval (via fdb.BlobReader):&#39;</span>

<span class="c"># Python &quot;file-like&quot; interface:</span>
<span class="k">print</span> <span class="s">&#39;readerA.mode:    &quot;</span><span class="si">%s</span><span class="s">&quot;&#39;</span> <span class="o">%</span> <span class="n">readerA</span><span class="o">.</span><span class="n">mode</span>
<span class="k">print</span> <span class="s">&#39;readerA.closed:   </span><span class="si">%s</span><span class="s">&#39;</span>  <span class="o">%</span> <span class="n">readerA</span><span class="o">.</span><span class="n">closed</span>
<span class="k">print</span> <span class="s">&#39;readerA.tell():   </span><span class="si">%d</span><span class="s">&#39;</span>  <span class="o">%</span> <span class="n">readerA</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span>
<span class="k">print</span> <span class="s">&#39;readerA.read(2): &quot;</span><span class="si">%s</span><span class="s">&quot;&#39;</span> <span class="o">%</span> <span class="n">readerA</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;readerA.tell():   </span><span class="si">%d</span><span class="s">&#39;</span>  <span class="o">%</span> <span class="n">readerA</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span>
<span class="k">print</span> <span class="s">&#39;readerA.read():  &quot;</span><span class="si">%s</span><span class="s">&quot;&#39;</span> <span class="o">%</span> <span class="n">readerA</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="k">print</span> <span class="s">&#39;readerA.tell():   </span><span class="si">%d</span><span class="s">&#39;</span>  <span class="o">%</span> <span class="n">readerA</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span>
<span class="k">print</span> <span class="s">&#39;readerA.read():  &quot;</span><span class="si">%s</span><span class="s">&quot;&#39;</span> <span class="o">%</span> <span class="n">readerA</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">readerA</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">print</span> <span class="s">&#39;readerA.closed:   </span><span class="si">%s</span><span class="s">&#39;</span>  <span class="o">%</span> <span class="n">readerA</span><span class="o">.</span><span class="n">closed</span>
</pre></div>
</div>
<p>Output:</p>
<div class="highlight-python"><pre>Materialized retrieval (as str):
[('abcdef',), ('ghijklmnop',)]

Streaming retrieval (via fdb.BlobReader):
readerA.mode:    "rb"
readerA.closed:   False
readerA.tell():   0
readerA.read(2): "ab"
readerA.tell():   2
readerA.read():  "cdef"
readerA.tell():   6
readerA.read():  ""
readerA.closed:   True</pre>
</div>
</div>
<div class="section" id="firebird-array-type">
<span id="index-18"></span><h3>Firebird ARRAY type<a class="headerlink" href="#firebird-array-type" title="Permalink to this headline">¶</a></h3>
<p>FDB supports Firebird ARRAY data type. ARRAY values are represented as Python lists. On input, the Python
sequence (list or tuple) must be nested appropriately if the array field is multi-dimensional, and
the incoming sequence must not fall short of its maximum possible length (it will not be “padded”
implicitly–see below). On output, the lists will be nested if the database array has multiple dimensions.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p>Database arrays have no place in a purely relational data model, which requires that data values be
atomized (that is, every value stored in the database must be reduced to elementary, non-decomposable
parts). The Firebird implementation of database arrays, like that of most relational database engines
that support this data type, is fraught with limitations.</p>
<p>Database arrays are of fixed size, with a predeclared number of dimensions (max. 16) and number of elements
per dimension. Individual array elements cannot be set to NULL / None, so the mapping between Python lists
(which have dynamic length and are therefore not normally “padded” with dummy values) and non-trivial
database arrays is clumsy.</p>
<p>Stored procedures cannot have array parameters.</p>
<p>Finally, many interface libraries, GUIs, and even the isql command line utility do not support database
arrays.</p>
<p class="last">In general, it is preferable to avoid using database arrays unless you have a compelling reason.</p>
</div>
<p><strong>Example:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">fdb</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">cur</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select LANGUAGE_REQ from job where job_code=&#39;Eng&#39; and job_grade=3 and job_country=&#39;Japan&#39;&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">cur</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
<span class="go">([&#39;Japanese\n&#39;, &#39;Mandarin\n&#39;, &#39;English\n&#39;, &#39;\n&#39;, &#39;\n&#39;],)</span>
</pre></div>
</div>
<p><strong>Example program:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:/temp/test.db&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">execute_immediate</span><span class="p">(</span><span class="s">&quot;recreate table array_table (a int[3,4])&quot;</span><span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="n">cur</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

<span class="n">arrayIn</span> <span class="o">=</span> <span class="p">[</span>
    <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">],</span>
    <span class="p">[</span><span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">],</span>
    <span class="p">[</span><span class="mi">9</span><span class="p">,</span><span class="mi">10</span><span class="p">,</span><span class="mi">11</span><span class="p">,</span><span class="mi">12</span><span class="p">]</span>
  <span class="p">]</span>

<span class="k">print</span> <span class="s">&#39;arrayIn:  </span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="n">arrayIn</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into array_table values (?)&quot;</span><span class="p">,</span> <span class="p">(</span><span class="n">arrayIn</span><span class="p">,))</span>

<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select a from array_table&quot;</span><span class="p">)</span>
<span class="n">arrayOut</span> <span class="o">=</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">print</span> <span class="s">&#39;arrayOut: </span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="n">arrayOut</span>

<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
</pre></div>
</div>
<p>Output:</p>
<div class="highlight-python"><pre>arrayIn:  [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
arrayOut: [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]</pre>
</div>
</div>
</div>
<div class="section" id="trasanction-management">
<span id="index-19"></span><h2>Trasanction management<a class="headerlink" href="#trasanction-management" title="Permalink to this headline">¶</a></h2>
<p>For the sake of simplicity, FDB lets the Python programmer ignore transaction management to the greatest
extent allowed by the Python Database API Specification 2.0. The specification says, “if the database
supports an auto-commit feature, this must be initially off”. At a minimum, therefore, it is necessary to
call the commit method of the connection in order to persist any changes made to the database.</p>
<p>Remember that because of ACID, every data manipulation operation in the Firebird database engine takes
place in the context of a transaction, including operations that are conceptually “read-only”, such as
a typical SELECT. The client programmer of FDB establishes a transaction implicitly by using any SQL
execution method, such as <a class="reference internal" href="reference.html#fdb.Connection.execute_immediate" title="fdb.Connection.execute_immediate"><tt class="xref py py-meth docutils literal"><span class="pre">execute_immediate()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Cursor.execute" title="fdb.Cursor.execute"><tt class="xref py py-meth docutils literal"><span class="pre">Cursor.execute()</span></tt></a>, or
<a class="reference internal" href="reference.html#fdb.Cursor.callproc" title="fdb.Cursor.callproc"><tt class="xref py py-meth docutils literal"><span class="pre">Cursor.callproc()</span></tt></a>.</p>
<p>Although FDB allows the programmer to pay little attention to transactions, it also exposes the full
complement of the database engine’s advanced transaction control features: <a class="reference internal" href="#transaction-parameters">transaction parameters</a>,
<a class="reference internal" href="#retaining-transactions">retaining transactions</a>, <a class="reference internal" href="#savepoints">savepoints</a>, and <a class="reference internal" href="#id4">distributed transactions</a>.</p>
<div class="section" id="basics">
<h3>Basics<a class="headerlink" href="#basics" title="Permalink to this headline">¶</a></h3>
<p>When it comes to transactions, Python Database API 2.0 specify that <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> object has to
respond to the following methods:</p>
<p><a class="reference internal" href="reference.html#fdb.Connection.commit" title="fdb.Connection.commit"><tt class="xref py py-meth docutils literal"><span class="pre">Connection.commit()</span></tt></a></p>
<blockquote>
<div>Commit any pending transaction to the database. Note that if the database supports an auto-commit
feature, this must be initially off. An interface method may be provided to turn it back on. Database
modules that do not support transactions should implement this method with void functionality.</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.Connection.rollback" title="fdb.Connection.rollback"><tt class="xref py py-meth docutils literal"><span class="pre">Connection.rollback()</span></tt></a></p>
<blockquote>
<div>(optional) In case a database does provide transactions this method causes the the database to roll
back to the start of any pending transaction. <strong>Closing a connection without committing the changes
first will cause an implicit rollback to be performed.</strong></div></blockquote>
<p>In addition to the implicit transaction initiation required by Python Database API, FDB allows the programmer
to start transactions explicitly via the <a class="reference internal" href="reference.html#fdb.Connection.begin" title="fdb.Connection.begin"><tt class="xref py py-meth docutils literal"><span class="pre">Connection.begin()</span></tt></a> method. Also <a class="reference internal" href="reference.html#fdb.Connection.savepoint" title="fdb.Connection.savepoint"><tt class="xref py py-meth docutils literal"><span class="pre">Connection.savepoint()</span></tt></a>
method was added to provide support for <a class="reference external" href="http://www.firebirdsql.org/refdocs/langrefupd15-savepoint.html">Firebird SAVEPOINTs</a>.</p>
<p>But Python Database API 2.0 was created with assumption that connection can support only one transactions
per single connection. However, Firebird can support multiple independent transactions that can run
simultaneously within single connection / attachment to the database. This feature is very important,
as applications may require multiple transaction openned simultaneously to perform various tasks,
which would require to open multiple connections and thus consume more resources than necessary.</p>
<p>FDB surfaces this Firebird feature by separating transaction management out from <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> into
separate <a class="reference internal" href="reference.html#fdb.Transaction" title="fdb.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a> objects. To comply with Python DB API 2.0 requirements, <cite>Connection</cite> object
uses one <cite>Transaction</cite> instance as <a class="reference internal" href="reference.html#fdb.Connection.main_transaction" title="fdb.Connection.main_transaction"><tt class="xref py py-attr docutils literal"><span class="pre">main</span> <span class="pre">transaction</span></tt></a>, and delegates
<a class="reference internal" href="reference.html#fdb.Connection.begin" title="fdb.Connection.begin"><tt class="xref py py-meth docutils literal"><span class="pre">begin()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Connection.savepoint" title="fdb.Connection.savepoint"><tt class="xref py py-meth docutils literal"><span class="pre">savepoint()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Connection.commit" title="fdb.Connection.commit"><tt class="xref py py-meth docutils literal"><span class="pre">commit()</span></tt></a>,
<a class="reference internal" href="reference.html#fdb.Connection.rollback" title="fdb.Connection.rollback"><tt class="xref py py-meth docutils literal"><span class="pre">rollback()</span></tt></a>, <a class="reference internal" href="reference.html#fdb.Connection.trans_info" title="fdb.Connection.trans_info"><tt class="xref py py-meth docutils literal"><span class="pre">trans_info()</span></tt></a> and <a class="reference internal" href="reference.html#fdb.Connection.transaction_info" title="fdb.Connection.transaction_info"><tt class="xref py py-meth docutils literal"><span class="pre">transaction_info()</span></tt></a>
calls to it.</p>
<div class="admonition-see-also admonition seealso">
<p class="first admonition-title">See also</p>
<p class="last">More about using multiple transactions with the same connection in separate
<a class="reference internal" href="#multiple-transactions"><em>section</em></a>.</p>
</div>
<p><strong>Example:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>

<span class="n">cur</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

<span class="c"># Most minimalistic transaction management -&gt; implicit start, only commit() and rollback()</span>
<span class="c"># ========================================================================================</span>
<span class="c">#</span>
<span class="c"># Transaction is started implicitly</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into country values (&#39;</span><span class="n">Oz</span><span class="s">&#39;,&#39;</span><span class="n">Crowns</span><span class="s">&#39;)</span>
<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span> <span class="c"># commits active transaction</span>
<span class="c"># Again, transaction is started implicitly</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into country values (&#39;</span><span class="n">Barsoom</span><span class="s">&#39;,&#39;</span><span class="n">XXX</span><span class="s">&#39;)</span>
<span class="n">con</span><span class="o">.</span><span class="n">rollback</span><span class="p">()</span> <span class="c"># rolls back active transaction</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into country values (&#39;</span><span class="n">Pellucidar</span><span class="s">&#39;,&#39;</span><span class="n">Shells</span><span class="s">&#39;)</span>

<span class="c"># This will roll back the transaction</span>
<span class="c"># because Python DB API 2.0 requires that closing connection</span>
<span class="c"># with pending transaction must cause an implicit rollback</span>
<span class="n">con</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="section" id="auto-commit">
<span id="index-20"></span><h3>Auto-commit<a class="headerlink" href="#auto-commit" title="Permalink to this headline">¶</a></h3>
<p>FDB doesn&#8217;t support <cite>auto-commit</cite> feature directly, but developers may achieve the similar result
using <cite>explicit</cite> transaction start, taking advantage of <a class="reference internal" href="reference.html#fdb.Transaction.default_action" title="fdb.Transaction.default_action"><tt class="xref py py-attr docutils literal"><span class="pre">default_action</span></tt></a> and its
default value (<cite>commit</cite>).</p>
<p><strong>Example:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>

<span class="n">cur</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

<span class="n">con</span><span class="o">.</span><span class="n">begin</span><span class="p">()</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into country values (&#39;</span><span class="n">Oz</span><span class="s">&#39;,&#39;</span><span class="n">Crowns</span><span class="s">&#39;)</span>
<span class="n">con</span><span class="o">.</span><span class="n">begin</span><span class="p">()</span> <span class="c"># commits active transaction and starts new one</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into country values (&#39;</span><span class="n">Barsoom</span><span class="s">&#39;,&#39;</span><span class="n">XXX</span><span class="s">&#39;)</span>
<span class="n">con</span><span class="o">.</span><span class="n">begin</span><span class="p">()</span> <span class="c"># commits active transaction and starts new one</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into country values (&#39;</span><span class="n">Pellucidar</span><span class="s">&#39;,&#39;</span><span class="n">Shells</span><span class="s">&#39;)</span>

<span class="c"># However, commit is required before connection is closed,</span>
<span class="c"># because Python DB API 2.0 requires that closing connection</span>
<span class="c"># with pending transaction must cause an implicit rollback</span>
<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">con</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="section" id="transaction-parameters">
<span id="index-21"></span><h3>Transaction parameters<a class="headerlink" href="#transaction-parameters" title="Permalink to this headline">¶</a></h3>
<p>The database engine offers the client programmer an optional facility called <cite>transaction parameter
buffers</cite> (TPBs) for tweaking the operating characteristics of the transactions he initiates. These
include characteristics such as whether the transaction has read and write access to tables, or
read-only access, and whether or not other simultaneously active transactions can share table access
with the transaction.</p>
<p>Connections have a <a class="reference internal" href="reference.html#fdb.Connection.default_tpb" title="fdb.Connection.default_tpb"><tt class="xref py py-attr docutils literal"><span class="pre">default_tpb</span></tt></a> attribute that can be changed to set the default
TPB for all transactions subsequently started on the connection. Alternatively, if the programmer
only wants to set the TPB for a single transaction, he can start a transaction explicitly via the
<a class="reference internal" href="reference.html#fdb.Connection.begin" title="fdb.Connection.begin"><tt class="xref py py-meth docutils literal"><span class="pre">begin()</span></tt></a> method and pass a TPB for that single transaction.</p>
<p>For details about TPB construction, see the <a class="reference external" href="http://www.ibphoenix.com/files/60ApiGuide.zip">Firebird API documentation</a>. In particular, the <cite>ibase.h</cite>
supplied with Firebird contains all possible TPB elements – single bytes that the C API defines as
constants whose names begin with <cite>isc_tpb_</cite>. FDB makes all of those TPB constants available (under
the same names) as module-level constants. A transaction parameter buffer is handled in C as a character
array; FDB requires that TPBs be constructed as Python <cite>strings</cite> (or <cite>bytes</cite> for Python 3). Since
the constants in the <cite>fdb.isc_tpb_*</cite> family are numbers, they can&#8217;t be simply concatenated to create
a TPB, but you may use utility function <strong>fdb.bs(byte_array)</strong> that accepts sequence of numbers and
returns <cite>string</cite> (P2) or <cite>bytes</cite> (P3).</p>
<p>For example next call returns TPB for typical <cite>READ COMMITED</cite> transaction:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">TPB</span> <span class="o">=</span> <span class="n">bs</span><span class="p">([</span><span class="n">isc_tpb_version3</span><span class="p">,</span>
          <span class="n">isc_tpb_write</span><span class="p">,</span>
          <span class="n">isc_tpb_wait</span><span class="p">,</span>
          <span class="n">isc_tpb_read_committed</span><span class="p">,</span>
          <span class="n">isc_tpb_rec_version</span><span class="p">])</span>
</pre></div>
</div>
<div class="admonition warning">
<p class="first admonition-title">Warning</p>
<p class="last">This method requires good knowledge of <cite>tpc_block</cite> structure and proper order of various parameters,
as Firebird engine will raise an error when badly structured block would be used. Also definition of
<cite>table reservation</cite> parameters is uncomfortable as you’ll need to mix binary codes with table names
passed as Pascal strings (characters preceded by string length).</p>
</div>
<p>FDB provides several predefined TPB&#8217;s for convenience:</p>
<ul>
<li><dl class="first docutils">
<dt><strong>ISOLATION_LEVEL_READ_COMMITED</strong></dt>
<dd><p class="first last">Read/Write READ COMMITED with <cite>record version</cite> and WAIT option. Isolation level with greatest
concurrent throughput. This is <strong>Default</strong> TPB.</p>
</dd>
</dl>
<div class="admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">This isolation level is optimal for transactions that write data and doesn&#8217;t require stable
snapshot of database for their operations (i.e. most operations are limited to individual rows).</p>
</div>
</li>
<li><dl class="first docutils">
<dt><strong>ISOLATION_LEVEL_READ_COMMITED_LEGACY</strong></dt>
<dd><p class="first">Read/Write READ COMMITED with <cite>NO record version</cite> and WAIT option.</p>
<div class="last admonition warning">
<p class="first admonition-title">Warning</p>
<p class="last">This isolation level emulates RDBMS that use locks instead multiversion control (MVC).
It&#8217;s not recommended to use it at all, except for legacy applications lazily ported from such
RDBMS to Firebird.</p>
</div>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>ISOLATION_LEVEL_READ_COMMITED_RO</strong></dt>
<dd><p class="first">Like <cite>ISOLATION_LEVEL_READ_COMMITED</cite>, but <strong>Read Only</strong>.</p>
<div class="last admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">Firebird threats these transactions as <cite>pre-committed</cite>, so they are best option <strong>for long
running transactions that only read data</strong>.</p>
</div>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>ISOLATION_LEVEL_REPEATABLE_READ</strong> or <strong>ISOLATION_LEVEL_SNAPSHOT</strong></dt>
<dd><p class="first">Read/Write SNAPSHOT (concurrency) with WAIT option.</p>
<div class="last admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">This isolation level is necessary for transactions that process data in bulk, like reporting,
recalculations etc.</p>
</div>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>ISOLATION_LEVEL_SERIALIZABLE</strong> or <strong>ISOLATION_LEVEL_SNAPSHOT_TABLE_STABILITY</strong></dt>
<dd><p class="first">Read/Write SNAPSHOT TABLE STABILITY (consistency) with WAIT option. Like REPEATABLE_READ/SNAPSHOT,
but locks whole tables for writes from other transactions. Isolation level with lowest concurrent
throughput.</p>
<div class="admonition warning">
<p class="first admonition-title">Warning</p>
<p class="last">Because tables are locked for <cite>protected write</cite> (i.e. no other transaction can write until lock
is released) <strong>at time of first access</strong>, there is a great risk of <cite>deadlock</cite> between transactions.</p>
</div>
<div class="last admonition tip">
<p class="first admonition-title">Tip</p>
<p class="last">To prevent deadlocks and increase concurrent throughput it&#8217;s recommended to use custom TPB&#8217;s with
<cite>fine-grained table access reservation</cite>.</p>
</div>
</dd>
</dl>
</li>
</ul>
<p><strong>Example:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>

<span class="n">cur</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

<span class="c"># Start transaction with default_tpb (ISOLATION_LEVEL_READ_COMMITED)</span>
<span class="n">con</span><span class="o">.</span><span class="n">begin</span><span class="p">()</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;select * from JOB&#39;</span><span class="p">)</span>
<span class="n">com</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="c"># Start using transactions in REPEATABLE READ (SNAPSHOT) isolation</span>
<span class="n">con</span><span class="o">.</span><span class="n">default_tpb</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">ISOLATION_LEVEL_REPEATABLE_READ</span>
<span class="n">con</span><span class="o">.</span><span class="n">begin</span><span class="p">()</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;select * from JOB&#39;</span><span class="p">)</span>
<span class="n">com</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="c"># Start THIS transaction as R/O READ COMMITTED</span>
<span class="n">con</span><span class="o">.</span><span class="n">begin</span><span class="p">(</span><span class="n">fdb</span><span class="o">.</span><span class="n">ISOLATION_LEVEL_READ_COMMITED_RO</span><span class="p">)</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;select * from JOB&#39;</span><span class="p">)</span>
<span class="n">com</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
</pre></div>
</div>
<p>For cases when predefined transaction parameter blocks are not suitable for your needs, FDB offers utility
class <a class="reference internal" href="reference.html#fdb.TPB" title="fdb.TPB"><tt class="xref py py-class docutils literal"><span class="pre">TPB</span></tt></a> for convenient and safe construction of custom <cite>tpb blocks</cite>. Simply create instance
of this class, set member attributes to required values and use either <a class="reference internal" href="reference.html#fdb.TPB.render" title="fdb.TPB.render"><tt class="xref py py-meth docutils literal"><span class="pre">rendered</span></tt></a> binary
tpb block or <cite>TPB</cite> instance itself to set <cite>default_tpb</cite> or as paraneter to <cite>begin()</cite>.</p>
<p><strong>Example:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>

<span class="c"># Use TPB to construct valid transaction parameter block</span>
<span class="c"># from the fdb.isc_tpb_* family.</span>
<span class="n">customTPB</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">TPB</span><span class="p">()</span>
<span class="n">customTPB</span><span class="o">.</span><span class="n">isolation_level</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">isc_tpb_consistency</span> <span class="c"># SERIALIZABLE</span>
<span class="n">customTPB</span><span class="o">.</span><span class="n">table_reservation</span><span class="p">[</span><span class="s">&quot;MY_TABLE&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_tpb_protected</span><span class="p">,</span> <span class="n">fdb</span><span class="o">.</span><span class="n">isc_tpb_lock_write</span><span class="p">)</span>

<span class="c"># Explicitly start a transaction with the custom TPB:</span>
<span class="n">con</span><span class="o">.</span><span class="n">begin</span><span class="p">(</span><span class="n">tpb</span><span class="o">=</span><span class="n">customTPB</span><span class="p">)</span>

<span class="c"># For frequent use, it&#39;s better to use already assembled version of TPB</span>
<span class="n">customTPB</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">TPB</span><span class="p">()</span>
<span class="n">customTPB</span><span class="o">.</span><span class="n">access_mode</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">isc_tpb_read</span>  <span class="c"># read only</span>
<span class="n">customTPB</span><span class="o">.</span><span class="n">isolation_level</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">isc_tpb_concurrency</span> <span class="c"># SNAPSHOT</span>
<span class="n">customTPB</span> <span class="o">=</span> <span class="n">customTPB</span><span class="o">.</span><span class="n">render</span><span class="p">()</span> <span class="c"># Create valid block according to current values of member attributes.</span>

<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1000</span><span class="p">):</span>
   <span class="n">con</span><span class="o">.</span><span class="n">begin</span><span class="p">(</span><span class="n">tpb</span><span class="o">=</span><span class="n">customTPB</span><span class="p">)</span>
</pre></div>
</div>
<p>If you want to build only <cite>table reservation</cite> part of <cite>tpb</cite> (for example to add to various custom built
parameter blocks), you can use class <a class="reference internal" href="reference.html#fdb.TableReservation" title="fdb.TableReservation"><tt class="xref py py-class docutils literal"><span class="pre">TableReservation</span></tt></a> instead <cite>TPB</cite>.</p>
</div>
<div class="section" id="getting-information-about-transaction">
<span id="index-22"></span><h3>Getting information about transaction<a class="headerlink" href="#getting-information-about-transaction" title="Permalink to this headline">¶</a></h3>
<p><a class="reference internal" href="reference.html#fdb.Transaction" title="fdb.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a> object exposes two methods that return infromation about currently managed
active transaction (the same methods are exposed also by <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> object for
<a class="reference internal" href="reference.html#fdb.Connection.main_transaction" title="fdb.Connection.main_transaction"><tt class="xref py py-attr docutils literal"><span class="pre">main_transaction</span></tt></a>):</p>
<p><a class="reference internal" href="reference.html#fdb.Transaction.transaction_info" title="fdb.Transaction.transaction_info"><tt class="xref py py-meth docutils literal"><span class="pre">transaction_info()</span></tt></a> is a very thin wrapper around function <cite>isc_transaction_info()</cite>.
This method does not attempt to interpret its results except with regard to whether they are a string
or an integer.</p>
<p>A more convenient way to access the same functionality is via the <a class="reference internal" href="reference.html#fdb.Transaction.trans_info" title="fdb.Transaction.trans_info"><tt class="xref py py-meth docutils literal"><span class="pre">trans_info()</span></tt></a> method,
which is high-level convenience wrapper around the <cite>transaction_info</cite> method that parses the output
of <cite>transaction_info</cite> into Python-friendly objects instead of returning raw binary buffers in the case
of complex result types.</p>
<p><strong>Example program:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;localhost:employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>

<span class="c"># Start transaction, so we can get information about it</span>
<span class="n">con</span><span class="o">.</span><span class="n">begin</span><span class="p">()</span>

<span class="n">info</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">trans_info</span><span class="p">([</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_id</span><span class="p">,</span> <span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_oldest_interesting</span><span class="p">,</span>
                       <span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_oldest_snapshot</span><span class="p">,</span> <span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_oldest_active</span><span class="p">,</span>
                       <span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_isolation</span><span class="p">,</span> <span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_access</span><span class="p">,</span>
                       <span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_lock_timeout</span><span class="p">])</span>

<span class="k">print</span> <span class="n">info</span>
<span class="k">print</span> <span class="s">&quot;TransactionID:&quot;</span><span class="p">,</span> <span class="n">info</span><span class="p">[</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_id</span><span class="p">]</span>
<span class="k">print</span> <span class="s">&quot;Oldest Interesting (OIT):&quot;</span><span class="p">,</span><span class="n">info</span><span class="p">[</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_oldest_interesting</span><span class="p">]</span>
<span class="k">print</span> <span class="s">&quot;Oldest Snapshot:&quot;</span><span class="p">,</span><span class="n">info</span><span class="p">[</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_oldest_snapshot</span><span class="p">]</span>
<span class="k">print</span> <span class="s">&quot;Oldest Active (OAT):&quot;</span><span class="p">,</span><span class="n">info</span><span class="p">[</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_oldest_active</span><span class="p">]</span>
<span class="k">print</span> <span class="s">&quot;Isolation Level:&quot;</span><span class="p">,</span><span class="n">info</span><span class="p">[</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_isolation</span><span class="p">]</span>
<span class="k">print</span> <span class="s">&quot;Access Mode:&quot;</span><span class="p">,</span><span class="n">info</span><span class="p">[</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_access</span><span class="p">]</span>
<span class="k">print</span> <span class="s">&quot;Lock Timeout:&quot;</span><span class="p">,</span><span class="n">info</span><span class="p">[</span><span class="n">fdb</span><span class="o">.</span><span class="n">isc_info_tra_lock_timeout</span><span class="p">]</span>
</pre></div>
</div>
<p>Output:</p>
<div class="highlight-python"><pre>{4: 459, 5: 430, 6: 459, 7: 459, 8: (3, 1), 9: 1, 10: -1}
TransactionID: 459
Oldest Interesting (OIT): 430
Oldest Snapshot: 459
Oldest Active (OAT): 459
Isolation Level: (3, 1)
Access Mode: 1
Lock Timeout: -1</pre>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p>Isolation level info values are available as FDB constants <cite>isc_info_tra_consistency</cite>,
<cite>isc_info_tra_concurrency</cite> and <cite>isc_info_tra_read_committed</cite>. For <cite>read committed</cite>, a tuple
of two values is returned instead single value, where the second value is record version flag
<cite>isc_info_tra_no_rec_version</cite> or <cite>isc_info_tra_rec_version</cite>.</p>
<p class="last">Access mode values are available as FDB constants <cite>isc_info_tra_readonly</cite> and <cite>isc_info_tra_readwrite</cite>.</p>
</div>
</div>
<div class="section" id="retaining-transactions">
<span id="index-23"></span><h3>Retaining transactions<a class="headerlink" href="#retaining-transactions" title="Permalink to this headline">¶</a></h3>
<p>The <a class="reference internal" href="reference.html#fdb.Transaction.commit" title="fdb.Transaction.commit"><tt class="xref py py-meth docutils literal"><span class="pre">commit()</span></tt></a> and <a class="reference internal" href="reference.html#fdb.Transaction.rollback" title="fdb.Transaction.rollback"><tt class="xref py py-meth docutils literal"><span class="pre">rollback()</span></tt></a> methods accept an optional boolean
parameter <cite>retaining</cite> (<strong>default False</strong>) to indicate whether to recycle the transactional context of
the transaction being resolved by the method call.</p>
<p>If retaining is <cite>True</cite>, the infrastructural support for the transaction active at the time of the method
call will be “retained” (efficiently and transparently recycled) after the database server has committed
or rolled back the conceptual transaction.</p>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p class="last">In code that commits or rolls back frequently, “retaining” the transaction yields considerably better
performance. However, retaining transactions must be used cautiously because they can interfere with
the server’s ability to garbage collect old record versions. For details about this issue, read the
“Garbage” section of <a class="reference external" href="http://www.ibphoenix.com/resources/documents/search/doc_21">this document</a>
by Ann Harrison.</p>
</div>
<p>For more information about retaining transactions, see <cite>Firebird documentation</cite>.</p>
</div>
<div class="section" id="savepoints">
<span id="index-24"></span><h3>Savepoints<a class="headerlink" href="#savepoints" title="Permalink to this headline">¶</a></h3>
<p>Savepoints are named, intermediate control points within an open transaction that can later be rolled
back to, without affecting the preceding work. Multiple savepoints can exist within a single unresolved
transaction, providing “multi-level undo” functionality.</p>
<p>Although Firebird savepoints are fully supported from SQL alone via the <cite>SAVEPOINT ‘name’</cite> and
<cite>ROLLBACK TO ‘name’</cite> statements, FDB also exposes savepoints at the Python API level for the sake
of convenience.</p>
<p>Call to method <a class="reference internal" href="reference.html#fdb.Transaction.savepoint" title="fdb.Transaction.savepoint"><tt class="xref py py-meth docutils literal"><span class="pre">savepoint()</span></tt></a> establishes a savepoint with the specified <cite>name</cite>. To roll back
to a specific savepoint, call the <a class="reference internal" href="reference.html#fdb.Transaction.rollback" title="fdb.Transaction.rollback"><tt class="xref py py-meth docutils literal"><span class="pre">rollback()</span></tt></a> method and provide a value (the name of the
savepoint) for the optional <cite>savepoint</cite> parameter. If the savepoint parameter of <cite>rollback()</cite> is not
specified, the active transaction is cancelled in its entirety, as required by the Python Database API
Specification.</p>
<p>The following program demonstrates savepoint manipulation via the FDB API, rather than raw SQL.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;employee&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="n">cur</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;recreate table test_savepoints (a integer)&quot;</span><span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="k">print</span> <span class="s">&#39;Before the first savepoint, the contents of the table are:&#39;</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from test_savepoints&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39; &#39;</span><span class="p">,</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into test_savepoints values (?)&quot;</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="n">con</span><span class="o">.</span><span class="n">savepoint</span><span class="p">(</span><span class="s">&#39;A&#39;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;After savepoint A, the contents of the table are:&#39;</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from test_savepoints&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39; &#39;</span><span class="p">,</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into test_savepoints values (?)&quot;</span><span class="p">,</span> <span class="p">[</span><span class="mi">2</span><span class="p">])</span>
<span class="n">con</span><span class="o">.</span><span class="n">savepoint</span><span class="p">(</span><span class="s">&#39;B&#39;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;After savepoint B, the contents of the table are:&#39;</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from test_savepoints&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39; &#39;</span><span class="p">,</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into test_savepoints values (?)&quot;</span><span class="p">,</span> <span class="p">[</span><span class="mi">3</span><span class="p">])</span>
<span class="n">con</span><span class="o">.</span><span class="n">savepoint</span><span class="p">(</span><span class="s">&#39;C&#39;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;After savepoint C, the contents of the table are:&#39;</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from test_savepoints&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39; &#39;</span><span class="p">,</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

<span class="n">con</span><span class="o">.</span><span class="n">rollback</span><span class="p">(</span><span class="n">savepoint</span><span class="o">=</span><span class="s">&#39;A&#39;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;After rolling back to savepoint A, the contents of the table are:&#39;</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from test_savepoints&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39; &#39;</span><span class="p">,</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

<span class="n">con</span><span class="o">.</span><span class="n">rollback</span><span class="p">()</span>
<span class="k">print</span> <span class="s">&#39;After rolling back entirely, the contents of the table are:&#39;</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from test_savepoints&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39; &#39;</span><span class="p">,</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
</pre></div>
</div>
<p>The output of the example program is shown below:</p>
<div class="highlight-python"><pre>Before the first savepoint, the contents of the table are:
  []
After savepoint A, the contents of the table are:
  [(1,)]
After savepoint B, the contents of the table are:
  [(1,), (2,)]
After savepoint C, the contents of the table are:
  [(1,), (2,), (3,)]
After rolling back to savepoint A, the contents of the table are:
  [(1,)]
After rolling back entirely, the contents of the table are:
  []</pre>
</div>
</div>
<div class="section" id="using-multiple-transactions-with-the-same-connection">
<span id="multiple-transactions"></span><span id="index-25"></span><h3>Using multiple transactions with the same connection<a class="headerlink" href="#using-multiple-transactions-with-the-same-connection" title="Permalink to this headline">¶</a></h3>
<p>To use additional transactions that could run simultaneously with
<a class="reference internal" href="reference.html#fdb.Connection.main_transaction" title="fdb.Connection.main_transaction"><tt class="xref py py-attr docutils literal"><span class="pre">main</span> <span class="pre">transaction</span></tt></a> managed by <cite>Connection</cite>, create new
<a class="reference internal" href="reference.html#fdb.Transaction" title="fdb.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a> object calling <a class="reference internal" href="reference.html#fdb.Connection.trans" title="fdb.Connection.trans"><tt class="xref py py-meth docutils literal"><span class="pre">Connection.trans()</span></tt></a> method. If you don&#8217;t specify the optional
<cite>default_tpb</cite> parameter, this new <cite>Transaction</cite> inherits the <a class="reference internal" href="reference.html#fdb.Connection.default_tpb" title="fdb.Connection.default_tpb"><tt class="xref py py-attr docutils literal"><span class="pre">default_tpb</span></tt></a> from
<cite>Connection</cite>. Physical transaction is not started when <cite>Transaction</cite> instance is created, but implicitly
when first SQL statement is executed, or explicitly via <a class="reference internal" href="reference.html#fdb.Transaction.begin" title="fdb.Transaction.begin"><tt class="xref py py-meth docutils literal"><span class="pre">Transaction.begin()</span></tt></a> call.</p>
<p>To execute statements in context of this additional transaction you have to use <cite>cursors</cite> obtained directly
from this <cite>Transaction</cite> instance calling its <a class="reference internal" href="reference.html#fdb.Transaction.cursor" title="fdb.Transaction.cursor"><tt class="xref py py-meth docutils literal"><span class="pre">cursor()</span></tt></a> method, or call
<a class="reference internal" href="reference.html#fdb.Transaction.execute_immediate" title="fdb.Transaction.execute_immediate"><tt class="xref py py-meth docutils literal"><span class="pre">Transaction.execute_immediate()</span></tt></a> method.</p>
<p><strong>Example:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;employee&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;pass&#39;</span><span class="p">)</span>
<span class="c"># Cursor for main_transaction context</span>
<span class="n">cur</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

<span class="c"># Create new READ ONLY READ COMMITTED transaction</span>
<span class="n">ro_transaction</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">trans</span><span class="p">(</span><span class="n">fdb</span><span class="o">.</span><span class="n">ISOLATION_LEVEL_READ_COMMITED_RO</span><span class="p">)</span>
<span class="c"># and cursor</span>
<span class="n">ro_cur</span> <span class="o">=</span> <span class="n">ro_transaction</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into country values (&#39;</span><span class="n">Oz</span><span class="s">&#39;,&#39;</span><span class="n">Crowns</span><span class="s">&#39;)</span>
<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span> <span class="c"># commits main transaction</span>

<span class="c"># Read data created by main transaction from second one</span>
<span class="n">ro_cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from COUNTRY where COUNTRY = `Oz`&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="n">ro_cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

<span class="c"># Insert more data, but don&#39;t commit</span>
<span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into country values (&#39;</span><span class="n">Barsoom</span><span class="s">&#39;,&#39;</span><span class="n">XXX</span><span class="s">&#39;)</span>

<span class="c"># Read data created by main transaction from second one</span>
<span class="n">ro_cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;select * from COUNTRY where COUNTRY = `Barsoom`&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="n">ro_cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
</pre></div>
</div>
</div>
<div class="section" id="distributed-transactions">
<span id="index-26"></span><span id="id4"></span><h3>Distributed Transactions<a class="headerlink" href="#distributed-transactions" title="Permalink to this headline">¶</a></h3>
<p>Distributed transactions are transactions that span multiple databases. FDB provides this Firebird feature
through <a class="reference internal" href="reference.html#fdb.ConnectionGroup" title="fdb.ConnectionGroup"><tt class="xref py py-class docutils literal"><span class="pre">ConnectionGroup</span></tt></a> class. Instances of this class act as managers for <a class="reference internal" href="reference.html#fdb.Transaction" title="fdb.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a>
object that is bound to multiple connections, and to <a class="reference internal" href="reference.html#fdb.Cursor" title="fdb.Cursor"><tt class="xref py py-class docutils literal"><span class="pre">cursors</span></tt></a> bound to it and connections
participated in group. That&#8217;s it, distributed transaction is fully independent from all other transactions,
main or secondary, of member connections.</p>
<p>To assemble a group of connections, you can either pass the sequence of <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> instances to
<a class="reference internal" href="reference.html#fdb.ConnectionGroup" title="fdb.ConnectionGroup"><tt class="xref py py-class docutils literal"><span class="pre">ConnectionGroup</span></tt></a> constructor, or add connections latter calling <a class="reference internal" href="reference.html#fdb.ConnectionGroup.add" title="fdb.ConnectionGroup.add"><tt class="xref py py-meth docutils literal"><span class="pre">ConnectionGroup.add()</span></tt></a> method.</p>
<p>Any <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> could be a member of only one group, and attempt to add it to another one would
raise an exception. Also, <cite>Connection</cite> participating in group cannot be <a class="reference internal" href="reference.html#fdb.Connection.close" title="fdb.Connection.close"><tt class="xref py py-meth docutils literal"><span class="pre">closed</span></tt></a>
before it&#8217;s <a class="reference internal" href="reference.html#fdb.ConnectionGroup.remove" title="fdb.ConnectionGroup.remove"><tt class="xref py py-meth docutils literal"><span class="pre">removed</span></tt></a>  or whole group is
<a class="reference internal" href="reference.html#fdb.ConnectionGroup.disband" title="fdb.ConnectionGroup.disband"><tt class="xref py py-meth docutils literal"><span class="pre">disbanded</span></tt></a>.</p>
<div class="admonition warning">
<p class="first admonition-title">Warning</p>
<p class="last">Never add more than one connection to the same database to the same <cite>ConnectionGroup</cite>!</p>
</div>
<p>Similarly to <a class="reference internal" href="reference.html#fdb.Transaction" title="fdb.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a>, distributed transactions are managed through <a class="reference internal" href="reference.html#fdb.ConnectionGroup.begin" title="fdb.ConnectionGroup.begin"><tt class="xref py py-meth docutils literal"><span class="pre">ConnectionGroup.begin()</span></tt></a>,
<a class="reference internal" href="reference.html#fdb.ConnectionGroup.savepoint" title="fdb.ConnectionGroup.savepoint"><tt class="xref py py-meth docutils literal"><span class="pre">ConnectionGroup.savepoint()</span></tt></a>. <a class="reference internal" href="reference.html#fdb.ConnectionGroup.commit" title="fdb.ConnectionGroup.commit"><tt class="xref py py-meth docutils literal"><span class="pre">ConnectionGroup.commit()</span></tt></a> and <a class="reference internal" href="reference.html#fdb.ConnectionGroup.rollback" title="fdb.ConnectionGroup.rollback"><tt class="xref py py-meth docutils literal"><span class="pre">ConnectionGroup.rollback()</span></tt></a> methods.
Additionally, <cite>ConnectionGroup</cite> exposes method <a class="reference internal" href="reference.html#fdb.ConnectionGroup.prepare" title="fdb.ConnectionGroup.prepare"><tt class="xref py py-meth docutils literal"><span class="pre">prepare()</span></tt></a> that explicitly initiates
the first phase of <cite>Two-Phase Commit Protocol</cite>. Transaction parameters are defined similarly to
<a class="reference internal" href="reference.html#fdb.Transaction" title="fdb.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a> using <a class="reference internal" href="reference.html#fdb.ConnectionGroup.default_tpb" title="fdb.ConnectionGroup.default_tpb"><tt class="xref py py-attr docutils literal"><span class="pre">ConnectionGroup.default_tpb</span></tt></a> or as optional parameter to
<a class="reference internal" href="reference.html#fdb.ConnectionGroup.begin" title="fdb.ConnectionGroup.begin"><tt class="xref py py-meth docutils literal"><span class="pre">begin()</span></tt></a> call.</p>
<p>SQL statements that should belong to context of distributed transaction are executed via <a class="reference internal" href="reference.html#fdb.Cursor" title="fdb.Cursor"><tt class="xref py py-class docutils literal"><span class="pre">Cursor</span></tt></a>
instances aquired through <a class="reference internal" href="reference.html#fdb.ConnectionGroup.cursor" title="fdb.ConnectionGroup.cursor"><tt class="xref py py-meth docutils literal"><span class="pre">ConnectionGroup.cursor()</span></tt></a> method, or calling
<a class="reference internal" href="reference.html#fdb.ConnectionGroup.execute_immediate" title="fdb.ConnectionGroup.execute_immediate"><tt class="xref py py-meth docutils literal"><span class="pre">ConnectionGroup.execute_immediate()</span></tt></a> method.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Because <a class="reference internal" href="reference.html#fdb.Cursor" title="fdb.Cursor"><tt class="xref py py-class docutils literal"><span class="pre">Cursor</span></tt></a> instances can belong to only one <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a>, the <a class="reference internal" href="reference.html#fdb.ConnectionGroup.cursor" title="fdb.ConnectionGroup.cursor"><tt class="xref py py-meth docutils literal"><span class="pre">cursor()</span></tt></a>
method has manadory parameter <cite>connection</cite>, to specify to which member connection cursor should belong.</p>
</div>
<p><strong>Example program:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="c"># First database</span>
<span class="n">con1</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">create_database</span><span class="p">(</span><span class="s">&quot;CREATE DATABASE &#39;testdb-1.fdb&#39; USER &#39;SYSDBA&#39; PASSWORD &#39;masterkey&#39;&quot;</span><span class="p">)</span>
<span class="n">con1</span><span class="o">.</span><span class="n">execute_immediate</span><span class="p">(</span><span class="s">&quot;recreate table T (PK integer, C1 integer)&quot;</span><span class="p">)</span>
<span class="n">con1</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="c"># Second database</span>
<span class="n">con2</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">create_database</span><span class="p">(</span><span class="s">&quot;CREATE DATABASE &#39;testdb-2,fdb&#39; USER &#39;SYSDBA&#39; PASSWORD &#39;masterkey&#39;&quot;</span><span class="p">)</span>
<span class="n">con2</span><span class="o">.</span><span class="n">execute_immediate</span><span class="p">(</span><span class="s">&quot;recreate table T (PK integer, C1 integer)&quot;</span><span class="p">)</span>
<span class="n">con2</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="c"># Create connection group</span>
<span class="n">cg</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">ConnectionGroup</span><span class="p">((</span><span class="n">con1</span><span class="p">,</span><span class="n">con2</span><span class="p">))</span>

<span class="c"># Prepare Group cursors for each connection</span>
<span class="n">gc1</span> <span class="o">=</span> <span class="n">cg</span><span class="o">.</span><span class="n">cursor</span><span class="p">(</span><span class="n">con1</span><span class="p">)</span>
<span class="n">gc2</span> <span class="o">=</span> <span class="n">cg</span><span class="o">.</span><span class="n">cursor</span><span class="p">(</span><span class="n">con2</span><span class="p">)</span>

<span class="c"># Connection cursors to check content of databases</span>
<span class="n">q</span> <span class="o">=</span> <span class="s">&#39;select * from T order by pk&#39;</span>

<span class="n">cc1</span> <span class="o">=</span> <span class="n">con1</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
<span class="n">p1</span> <span class="o">=</span> <span class="n">cc1</span><span class="o">.</span><span class="n">prep</span><span class="p">(</span><span class="n">q</span><span class="p">)</span>

<span class="n">cc2</span> <span class="o">=</span> <span class="n">con2</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
<span class="n">p2</span> <span class="o">=</span> <span class="n">cc2</span><span class="o">.</span><span class="n">prep</span><span class="p">(</span><span class="n">q</span><span class="p">)</span>

<span class="k">print</span> <span class="s">&quot;Distributed transaction: COMMIT&quot;</span>
<span class="c">#      ===============================</span>
<span class="n">gc1</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into t (pk) values (1)&#39;</span><span class="p">)</span>
<span class="n">gc2</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into t (pk) values (1)&#39;</span><span class="p">)</span>
<span class="n">cg</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="c"># check it</span>
<span class="n">con1</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">cc1</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">p1</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;db1:&#39;</span><span class="p">,</span><span class="n">cc1</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
<span class="n">con2</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">cc2</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">p2</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;db2:&#39;</span><span class="p">,</span><span class="n">cc2</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

<span class="k">print</span> <span class="s">&quot;Distributed transaction: PREPARE + COMMIT&quot;</span>
<span class="c">#      =========================================</span>
<span class="n">gc1</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into t (pk) values (2)&#39;</span><span class="p">)</span>
<span class="n">gc2</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into t (pk) values (2)&#39;</span><span class="p">)</span>
<span class="n">cg</span><span class="o">.</span><span class="n">prepare</span><span class="p">()</span>
<span class="n">cg</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="c"># check it</span>
<span class="n">con1</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">cc1</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">p1</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;db1:&#39;</span><span class="p">,</span><span class="n">cc1</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
<span class="n">con2</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">cc2</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">p2</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;db2:&#39;</span><span class="p">,</span><span class="n">cc2</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

<span class="k">print</span> <span class="s">&quot;Distributed transaction: SAVEPOINT + ROLLBACK to it&quot;</span>
<span class="c">#      ===================================================</span>
<span class="n">gc1</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into t (pk) values (3)&#39;</span><span class="p">)</span>
<span class="n">cg</span><span class="o">.</span><span class="n">savepoint</span><span class="p">(</span><span class="s">&#39;CG_SAVEPOINT&#39;</span><span class="p">)</span>
<span class="n">gc2</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&#39;insert into t (pk) values (3)&#39;</span><span class="p">)</span>
<span class="n">cg</span><span class="o">.</span><span class="n">rollback</span><span class="p">(</span><span class="n">savepoint</span><span class="o">=</span><span class="s">&#39;CG_SAVEPOINT&#39;</span><span class="p">)</span>

<span class="c"># check it - via group cursors, as transaction is still active</span>
<span class="n">gc1</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">q</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;db1:&#39;</span><span class="p">,</span><span class="n">gc1</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
<span class="n">gc2</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">q</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;db2:&#39;</span><span class="p">,</span><span class="n">gc2</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

<span class="k">print</span> <span class="s">&quot;Distributed transaction: ROLLBACK&quot;</span>
<span class="c">#      =================================</span>
<span class="n">cg</span><span class="o">.</span><span class="n">rollback</span><span class="p">()</span>

<span class="c"># check it</span>
<span class="n">con1</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">cc1</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">p1</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;db1:&#39;</span><span class="p">,</span><span class="n">cc1</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
<span class="n">con2</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">cc2</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">p2</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;db2:&#39;</span><span class="p">,</span><span class="n">cc2</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

<span class="k">print</span> <span class="s">&quot;Distributed transaction: EXECUTE_IMMEDIATE&quot;</span>
<span class="c">#      ==========================================</span>
<span class="n">cg</span><span class="o">.</span><span class="n">execute_immediate</span><span class="p">(</span><span class="s">&#39;insert into t (pk) values (3)&#39;</span><span class="p">)</span>
<span class="n">cg</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="c"># check it</span>
<span class="n">con1</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">cc1</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">p1</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;db1:&#39;</span><span class="p">,</span><span class="n">cc1</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
<span class="n">con2</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">cc2</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">p2</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;db2:&#39;</span><span class="p">,</span><span class="n">cc2</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>

<span class="c"># Finalize</span>
<span class="n">con1</span><span class="o">.</span><span class="n">drop_database</span><span class="p">()</span>
<span class="n">con1</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">con2</span><span class="o">.</span><span class="n">drop_database</span><span class="p">()</span>
<span class="n">con2</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</pre></div>
</div>
<p>Output:</p>
<div class="highlight-python"><pre>Distributed transaction: COMMIT
db1: [(1, None)]
db2: [(1, None)]
Distributed transaction: PREPARE + COMMIT
db1: [(1, None), (2, None)]
db2: [(1, None), (2, None)]
Distributed transaction: SAVEPOINT + ROLLBACK to it
db1: [(1, None), (2, None), (3, None)]
db2: [(1, None), (2, None)]
Distributed transaction: ROLLBACK
db1: [(1, None), (2, None)]
db2: [(1, None), (2, None)]
Distributed transaction: EXECUTE_IMMEDIATE
db1: [(1, None), (2, None), (3, None)]
db2: [(1, None), (2, None), (3, None)]</pre>
</div>
</div>
<div class="section" id="transaction-context-manager">
<span id="id5"></span><h3>Transaction Context Manager<a class="headerlink" href="#transaction-context-manager" title="Permalink to this headline">¶</a></h3>
<p>FDB provides context manager <a class="reference internal" href="reference.html#fdb.TransactionContext" title="fdb.TransactionContext"><tt class="xref py py-class docutils literal"><span class="pre">TransactionContext</span></tt></a> that allows automatic transaction
management using <a class="reference external" href="http://docs.python.org/reference/compound_stmts.html#with" title="(in Python v2.7)"><em>The with statement</em></a>. It can work with any object that supports <cite>begin()</cite>, <cite>commit()</cite> and
<cite>rollback()</cite> methods, i.e. <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a>, <a class="reference internal" href="reference.html#fdb.ConnectionGroup" title="fdb.ConnectionGroup"><tt class="xref py py-class docutils literal"><span class="pre">ConnectionGroup</span></tt></a> or <a class="reference internal" href="reference.html#fdb.Transaction" title="fdb.Transaction"><tt class="xref py py-class docutils literal"><span class="pre">Transaction</span></tt></a>.</p>
<p>It starts transaction when WITH block is entered and commits it if no exception occurst within it, or
calls <cite>rollback()</cite> otherwise. Exceptions raised in WITH block are never suppressed.</p>
<p>Examples:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span><span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>

<span class="c"># Uses default main transaction</span>
<span class="k">with</span> <span class="n">TransactionContext</span><span class="p">(</span><span class="n">con</span><span class="p">):</span>
   <span class="n">cur</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
   <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into T (PK,C1) values (1,&#39;TXT&#39;)&quot;</span><span class="p">)</span>

<span class="c"># Uses separate transaction</span>
<span class="k">with</span> <span class="n">TransactionContext</span><span class="p">(</span><span class="n">con</span><span class="o">.</span><span class="n">trans</span><span class="p">())</span> <span class="k">as</span> <span class="n">tr</span><span class="p">:</span>
   <span class="n">cur</span> <span class="o">=</span> <span class="n">tr</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
   <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into T (PK,C1) values (2,&#39;AAA&#39;)&quot;</span><span class="p">)</span>

<span class="c"># Uses connection group (distributed transaction)</span>
<span class="n">con2</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;remote:employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span><span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="n">cg</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">ConnectionGroup</span><span class="p">((</span><span class="n">con</span><span class="p">,</span><span class="n">con2</span><span class="p">))</span>
<span class="k">with</span> <span class="n">TransactionContext</span><span class="p">(</span><span class="n">cg</span><span class="p">):</span>
   <span class="n">cur1</span> <span class="o">=</span> <span class="n">cg</span><span class="o">.</span><span class="n">cursor</span><span class="p">(</span><span class="n">con</span><span class="p">)</span>
   <span class="n">cur2</span> <span class="o">=</span> <span class="n">cg</span><span class="o">.</span><span class="n">cursor</span><span class="p">(</span><span class="n">con2</span><span class="p">)</span>
   <span class="n">cur1</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into T (PK,C1) values (3,&#39;Local&#39;)&quot;</span><span class="p">)</span>
   <span class="n">cur2</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">&quot;insert into T (PK,C1) values (3,&#39;Remote&#39;)&quot;</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="database-events">
<span id="index-27"></span><h2>Database Events<a class="headerlink" href="#database-events" title="Permalink to this headline">¶</a></h2>
<div class="section" id="what-they-are">
<h3>What they are<a class="headerlink" href="#what-they-are" title="Permalink to this headline">¶</a></h3>
<p>The Firebird engine features a distributed, interprocess communication mechanism based on messages
called <cite>database events</cite>. A database event is a message passed from a trigger or stored procedure
to an application to announce the occurrence of a specified condition or action, usually a database
change such as an insertion, modification, or deletion of a record. The Firebird event mechanism enables
applications to respond to actions and database changes made by other, concurrently running applications
without the need for those applications to communicate directly with one another, and without incurring
the expense of CPU time required for periodic polling to determine if an event has occurred.</p>
</div>
<div class="section" id="why-use-them">
<h3>Why use them<a class="headerlink" href="#why-use-them" title="Permalink to this headline">¶</a></h3>
<p>Anything that can be accomplished with database events can also be implemented using other techniques,
so why bother with events? Since you’ve chosen to write database-centric programs in Python rather than
assembly language, you probably already know the answer to this question, but let’s illustrate.</p>
<p>A typical application for database events is the handling of administrative messages. Suppose you have
an administrative message database with a <cite>message&#8217;s</cite> table, into which various applications insert
timestamped status reports. It may be desirable to react to these messages in diverse ways, depending
on the status they indicate: to ignore them, to initiate the update of dependent databases upon their
arrival, to forward them by e-mail to a remote administrator, or even to set off an alarm so that on-site
administrators will know a problem has occurred.</p>
<p>It is undesirable to tightly couple the program whose status is being reported (the <cite>message producer</cite>) to
the program that handles the status reports (the <cite>message handler</cite>). There are obvious losses of flexibility
in doing so. For example, the message producer may run on a separate machine from the administrative
message database and may lack access rights to the downstream reporting facilities (e.g., network access
to the SMTP server, in the case of forwarded e-mail notifications). Additionally, the actions required
to handle status reports may themselves be time-consuming and error-prone, as in accessing a remote network
to transmit e-mail.</p>
<p>In the absence of database event support, the message handler would probably be implemented via <cite>polling</cite>.
Polling is simply the repetition of a check for a condition at a specified interval. In this case,
the message handler would check in an infinite loop to see whether the most recent record in the <cite>messages</cite>
table was more recent than the last message it had handled. If so, it would handle the fresh message(s);
if not, it would go to sleep for a specified interval, then loop.</p>
<p>The <cite>polling-based</cite> implementation of the message handler is fundamentally flawed. Polling is a form
of <a class="reference external" href="http://www.catb.org/jargon/html/B/busy-wait.html">busy-wait</a>; the check for new messages is performed at the specified interval, regardless of the actual
activity level of the message producers. If the polling interval is lengthy, messages might not be handled
within a reasonable time period after their arrival; if the polling interval is brief, the message handler
program (and there may be many such programs) will waste a large amount of CPU time on unnecessary checks.</p>
<p>The database server is necessarily aware of the exact moment when a new message arrives. Why not let
the message handler program request that the database server send it a notification when a new message
arrives? The message handler can then efficiently sleep until the moment its services are needed. Under
this <cite>event-based</cite> scheme, the message handler becomes aware of new messages at the instant they arrive,
yet it does not waste CPU time checking in vain for new messages when there are none available.</p>
</div>
<div class="section" id="how-events-are-exposed">
<h3>How events are exposed<a class="headerlink" href="#how-events-are-exposed" title="Permalink to this headline">¶</a></h3>
<ol class="arabic">
<li><p class="first">Server Process (&#8220;An event just occurred!&#8221;)</p>
<p>To notify any interested listeners that a specific event has
occurred, issue the <cite>POST_EVENT</cite> statement from Stored Procedure
or Trigger. The <cite>POST_EVENT</cite> statement has one parameter: the name
of the event to post. In the preceding example of the administrative
message database, <cite>POST_EVENT</cite> might be used from an <cite>after insert</cite>
trigger on the <cite>messages</cite> table, like this:</p>
<div class="highlight-s"><div class="highlight"><pre>create trigger trig_messages_handle_insert
  for messages
    after insert
as
begin
  POST_EVENT <span class="s">&#39;new_message&#39;</span><span class="p">;</span>
end
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">The physical notification of the client process does not
occur until the transaction in which the <cite>POST_EVENT</cite> took place is
actually committed. Therefore, multiple events may <em>conceptually</em>
occur before the client process is <em>physically</em> informed of even one
occurrence. Furthermore, the database engine makes no guarantee that
clients will be informed of events in the same groupings in which they
conceptually occurred. If, within a single transaction, an event named
<cite>event_a</cite> is posted once and an event named <cite>event_b</cite> is posted once,
the client may receive those posts in separate &#8220;batches&#8221;, despite the
fact that they occurred in the same conceptual unit (a single
transaction). This also applies to multiple occurrences of <em>the same</em>
event within a single conceptual unit: the physical notifications may
arrive at the client separately.</p>
</div>
</li>
<li><p class="first">Client Process (&#8220;Send me a message when an event occurs.&#8221;)</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">If you don&#8217;t care about the gory details of event notification,
skip to the section that describes FDB&#8217;s Python-level event handling
API.</p>
</div>
<p>The Firebird C client library offers two forms of event notification.
The first form is <em>synchronous</em> notification, by way of the function
<tt class="xref c c-func docutils literal"><span class="pre">isc_wait_for_event()</span></tt>. This form is admirably simple for a C programmer
to use, but is inappropriate as a basis for FDB&#8217;s event support,
chiefly because it&#8217;s not sophisticated enough to serve as the basis for
a comfortable Python-level API. The other form of event notification
offered by the database client library is <em>asynchronous</em>, by way of the
functions <tt class="xref c c-func docutils literal"><span class="pre">isc_que_events()</span></tt> (note that the name of that function
is misspelled), <tt class="xref c c-func docutils literal"><span class="pre">isc_cancel_events()</span></tt>, and others. The details are
as nasty as they are numerous, but the essence of using asynchronous
notification from C is as follows:</p>
<blockquote>
<div><ol class="arabic simple">
<li>Call <tt class="xref c c-func docutils literal"><span class="pre">isc_event_block()</span></tt> to create a formatted binary buffer that
will tell the server which events the client wants to listen for.</li>
<li>Call <tt class="xref c c-func docutils literal"><span class="pre">isc_que_events()</span></tt> (passing the buffer created in the previous
step) to inform the server that the client is ready to receive event
notifications, and provide a callback that will be asynchronously
invoked when one or more of the registered events occurs.</li>
<li>[The thread that called <tt class="xref c c-func docutils literal"><span class="pre">isc_que_events()</span></tt> to initiate event
listening must now do something else.]</li>
<li>When the callback is invoked (the database client library starts a
thread dedicated to this purpose), it can use the <tt class="xref c c-func docutils literal"><span class="pre">isc_event_counts()</span></tt>
function to determine how many times each of the registered events has
occurred since the last call to <tt class="xref c c-func docutils literal"><span class="pre">isc_event_counts()</span></tt> (if any).</li>
<li>[The callback thread should now &#8220;do its thing&#8221;, which may include
communicating with the thread that called <tt class="xref c c-func docutils literal"><span class="pre">isc_que_events()</span></tt>.]</li>
<li>When the callback thread is finished handling an event
notification, it must call <tt class="xref c c-func docutils literal"><span class="pre">isc_que_events()</span></tt> again in order to receive
future notifications. Future notifications will invoke the callback
again, effectively &#8220;looping&#8221; the callback thread back to Step 4.</li>
</ol>
</div></blockquote>
</li>
</ol>
</div>
<div class="section" id="api-for-python-developers">
<h3>API for Python developers<a class="headerlink" href="#api-for-python-developers" title="Permalink to this headline">¶</a></h3>
<p>The FDB database event API is comprised of the following: the method <a class="reference internal" href="reference.html#fdb.Connection.event_conduit" title="fdb.Connection.event_conduit"><tt class="xref py py-meth docutils literal"><span class="pre">Connection.event_conduit()</span></tt></a>
and the class <a class="reference internal" href="reference.html#fdb.EventConduit" title="fdb.EventConduit"><tt class="xref py py-class docutils literal"><span class="pre">EventConduit</span></tt></a>.</p>
<p>The <a class="reference internal" href="reference.html#fdb.EventConduit" title="fdb.EventConduit"><tt class="xref py py-class docutils literal"><span class="pre">EventConduit</span></tt></a> class serve as &#8220;conduit&#8221; through which database event notifications will flow
into the Python program. It&#8217;s not designed to be instantiated directly by the Python programmer. Instead,
use the <a class="reference internal" href="reference.html#fdb.Connection.event_conduit" title="fdb.Connection.event_conduit"><tt class="xref py py-meth docutils literal"><span class="pre">Connection.event_conduit()</span></tt></a> method to create <cite>EventConduit</cite> instances. <cite>event_conduit</cite> is
a method of <cite>Connection</cite> rather than a module-level function or a class constructor because the database
engine deals with events in the context of a particular database (after all, <cite>POST_EVENT</cite> must be issued
by a stored procedure or a trigger).</p>
<p><a class="reference internal" href="reference.html#fdb.Connection.event_conduit" title="fdb.Connection.event_conduit"><tt class="xref py py-meth docutils literal"><span class="pre">Connection.event_conduit()</span></tt></a> takes a sequence of string event names as parameter, and returns
<a class="reference internal" href="reference.html#fdb.EventConduit" title="fdb.EventConduit"><tt class="xref py py-class docutils literal"><span class="pre">EventConduit</span></tt></a> instance that immediately starts to accumulate notifications of any events that occur
within the conduit’s internal queue until the conduit is closed either explicitly (via the
<a class="reference internal" href="reference.html#fdb.EventConduit.close" title="fdb.EventConduit.close"><tt class="xref py py-meth docutils literal"><span class="pre">close()</span></tt></a> method) or implicitly (via garbage collection).</p>
<p>Notifications about events are aquired through call to <a class="reference internal" href="reference.html#fdb.EventConduit.wait" title="fdb.EventConduit.wait"><tt class="xref py py-meth docutils literal"><span class="pre">EventConduit.wait()</span></tt></a> method, that blocks
the calling thread until at least one of the events occurs, or the specified <cite>timeout</cite> (if any) expires,
and returns <cite>None</cite> if the wait timed out, or a dictionary that maps <cite>event_name -&gt; event_occurrence_count</cite>.</p>
<p><strong>Example:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">conduit</span> <span class="o">=</span> <span class="n">connection</span><span class="o">.</span><span class="n">event_conduit</span><span class="p">(</span> <span class="p">(</span><span class="s">&#39;event_a&#39;</span><span class="p">,</span> <span class="s">&#39;event_b&#39;</span><span class="p">)</span> <span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">conduit</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
<span class="go">{</span>
<span class="go"> &#39;event_a&#39;: 1,</span>
<span class="go"> &#39;event_b&#39;: 0</span>
<span class="go">}</span>
</pre></div>
</div>
<p>If you want to drop notifications accumulated so far by conduit, call <a class="reference internal" href="reference.html#fdb.EventConduit.flush" title="fdb.EventConduit.flush"><tt class="xref py py-meth docutils literal"><span class="pre">EventConduit.flush()</span></tt></a> method.</p>
<p><strong>Example program:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>
<span class="kn">import</span> <span class="nn">threading</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="c"># Prepare database</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">create_database</span><span class="p">(</span><span class="s">&quot;CREATE DATABASE &#39;event_test.fdb&#39; USER &#39;SYSDBA&#39; PASSWORD &#39;masterkey&#39;&quot;</span><span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">execute_immediate</span><span class="p">(</span><span class="s">&quot;CREATE TABLE T (PK Integer, C1 Integer)&quot;</span><span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">execute_immediate</span><span class="p">(</span><span class="s">&quot;&quot;&quot;CREATE TRIGGER EVENTS_AU FOR T ACTIVE</span>
<span class="s">BEFORE UPDATE POSITION 0</span>
<span class="s">AS</span>
<span class="s">BEGIN</span>
<span class="s">   if (old.C1 &lt;&gt; new.C1) then</span>
<span class="s">      post_event &#39;c1_updated&#39; ;</span>
<span class="s">END&quot;&quot;&quot;</span><span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">execute_immediate</span><span class="p">(</span><span class="s">&quot;&quot;&quot;CREATE TRIGGER EVENTS_AI FOR T ACTIVE</span>
<span class="s">AFTER INSERT POSITION 0</span>
<span class="s">AS</span>
<span class="s">BEGIN</span>
<span class="s">   if (new.c1 = 1) then</span>
<span class="s">     post_event &#39;insert_1&#39; ;</span>
<span class="s">   else if (new.c1 = 2) then</span>
<span class="s">     post_event &#39;insert_2&#39; ;</span>
<span class="s">   else if (new.c1 = 3) then</span>
<span class="s">     post_event &#39;insert_3&#39; ;</span>
<span class="s">   else</span>
<span class="s">     post_event &#39;insert_other&#39; ;</span>
<span class="s">END&quot;&quot;&quot;</span><span class="p">)</span>
<span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="n">cur</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>

<span class="c"># Utility function</span>
<span class="k">def</span> <span class="nf">send_events</span><span class="p">(</span><span class="n">command_list</span><span class="p">):</span>
   <span class="k">for</span> <span class="n">cmd</span> <span class="ow">in</span> <span class="n">command_list</span><span class="p">:</span>
      <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span>
   <span class="n">con</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>

<span class="k">print</span> <span class="s">&quot;One event&quot;</span>
<span class="c">#      =========</span>
<span class="n">timed_event</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Timer</span><span class="p">(</span><span class="mf">3.0</span><span class="p">,</span><span class="n">send_events</span><span class="p">,</span><span class="n">args</span><span class="o">=</span><span class="p">[[</span><span class="s">&quot;insert into T (PK,C1) values (1,1)&quot;</span><span class="p">,]])</span>
<span class="n">events</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">event_conduit</span><span class="p">([</span><span class="s">&#39;insert_1&#39;</span><span class="p">])</span>
<span class="n">timed_event</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="n">e</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
<span class="n">events</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">print</span> <span class="n">e</span>

<span class="k">print</span> <span class="s">&quot;Multiple events&quot;</span>
<span class="c">#      ===============</span>
<span class="n">cmds</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;insert into T (PK,C1) values (1,1)&quot;</span><span class="p">,</span>
        <span class="s">&quot;insert into T (PK,C1) values (1,2)&quot;</span><span class="p">,</span>
        <span class="s">&quot;insert into T (PK,C1) values (1,3)&quot;</span><span class="p">,</span>
        <span class="s">&quot;insert into T (PK,C1) values (1,1)&quot;</span><span class="p">,</span>
        <span class="s">&quot;insert into T (PK,C1) values (1,2)&quot;</span><span class="p">,]</span>
<span class="n">timed_event</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Timer</span><span class="p">(</span><span class="mf">3.0</span><span class="p">,</span><span class="n">send_events</span><span class="p">,</span><span class="n">args</span><span class="o">=</span><span class="p">[</span><span class="n">cmds</span><span class="p">])</span>
<span class="n">events</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">con</span><span class="o">.</span><span class="n">event_conduit</span><span class="p">([</span><span class="s">&#39;insert_1&#39;</span><span class="p">,</span><span class="s">&#39;insert_3&#39;</span><span class="p">])</span>
<span class="n">timed_event</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="n">e</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
<span class="n">events</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">print</span> <span class="n">e</span>

<span class="k">print</span> <span class="s">&quot;20 events&quot;</span>
<span class="c">#      =========</span>
<span class="n">cmds</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;insert into T (PK,C1) values (1,1)&quot;</span><span class="p">,</span>
        <span class="s">&quot;insert into T (PK,C1) values (1,2)&quot;</span><span class="p">,</span>
        <span class="s">&quot;insert into T (PK,C1) values (1,3)&quot;</span><span class="p">,</span>
        <span class="s">&quot;insert into T (PK,C1) values (1,1)&quot;</span><span class="p">,</span>
        <span class="s">&quot;insert into T (PK,C1) values (1,2)&quot;</span><span class="p">,]</span>
<span class="n">timed_event</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Timer</span><span class="p">(</span><span class="mf">1.0</span><span class="p">,</span><span class="n">send_events</span><span class="p">,</span><span class="n">args</span><span class="o">=</span><span class="p">[</span><span class="n">cmds</span><span class="p">])</span>
<span class="n">events</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">event_conduit</span><span class="p">([</span><span class="s">&#39;insert_1&#39;</span><span class="p">,</span><span class="s">&#39;A&#39;</span><span class="p">,</span><span class="s">&#39;B&#39;</span><span class="p">,</span><span class="s">&#39;C&#39;</span><span class="p">,</span><span class="s">&#39;D&#39;</span><span class="p">,</span>
                            <span class="s">&#39;E&#39;</span><span class="p">,</span><span class="s">&#39;F&#39;</span><span class="p">,</span><span class="s">&#39;G&#39;</span><span class="p">,</span><span class="s">&#39;H&#39;</span><span class="p">,</span><span class="s">&#39;I&#39;</span><span class="p">,</span><span class="s">&#39;J&#39;</span><span class="p">,</span><span class="s">&#39;K&#39;</span><span class="p">,</span><span class="s">&#39;L&#39;</span><span class="p">,</span><span class="s">&#39;M&#39;</span><span class="p">,</span>
                            <span class="s">&#39;N&#39;</span><span class="p">,</span><span class="s">&#39;O&#39;</span><span class="p">,</span><span class="s">&#39;P&#39;</span><span class="p">,</span><span class="s">&#39;Q&#39;</span><span class="p">,</span><span class="s">&#39;R&#39;</span><span class="p">,</span><span class="s">&#39;insert_3&#39;</span><span class="p">])</span>
<span class="n">timed_event</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">e</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
<span class="n">events</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">print</span> <span class="n">e</span>

<span class="k">print</span> <span class="s">&quot;Flush events&quot;</span>
<span class="c">#      ============</span>
<span class="n">timed_event</span> <span class="o">=</span> <span class="n">threading</span><span class="o">.</span><span class="n">Timer</span><span class="p">(</span><span class="mf">3.0</span><span class="p">,</span><span class="n">send_events</span><span class="p">,</span><span class="n">args</span><span class="o">=</span><span class="p">[[</span><span class="s">&quot;insert into T (PK,C1) values (1,1)&quot;</span><span class="p">,]])</span>
<span class="n">events</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">event_conduit</span><span class="p">([</span><span class="s">&#39;insert_1&#39;</span><span class="p">])</span>
<span class="n">send_events</span><span class="p">([</span><span class="s">&quot;insert into T (PK,C1) values (1,1)&quot;</span><span class="p">,</span>
             <span class="s">&quot;insert into T (PK,C1) values (1,1)&quot;</span><span class="p">])</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">events</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<span class="n">timed_event</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="n">e</span> <span class="o">=</span> <span class="n">events</span><span class="o">.</span><span class="n">wait</span><span class="p">()</span>
<span class="n">events</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">print</span> <span class="n">e</span>

<span class="c"># Finalize</span>
<span class="n">con</span><span class="o">.</span><span class="n">drop_database</span><span class="p">()</span>
<span class="n">con</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</pre></div>
</div>
<p>Output:</p>
<div class="highlight-python"><pre>One event
{'insert_1': 1}
Multiple events
{'insert_3': 1, 'insert_1': 2}
20 events
{'A': 0, 'C': 0, 'B': 0, 'E': 0, 'D': 0, 'G': 0, 'insert_1': 2, 'I': 0, 'H': 0, 'K': 0, 'J': 0, 'M': 0,
 'L': 0, 'O': 0, 'N': 0, 'Q': 0, 'P': 0, 'R': 0, 'insert_3': 1, 'F': 0}
Flush events
{'insert_1': 1}</pre>
</div>
</div>
</div>
<div class="section" id="working-with-services">
<span id="index-28"></span><span id="id6"></span><h2>Working with Services<a class="headerlink" href="#working-with-services" title="Permalink to this headline">¶</a></h2>
<p>Database server maintenance tasks such as user management, load monitoring, and database backup have
traditionally been automated by scripting the command-line tools <strong class="program">gbak</strong>, <strong class="program">gfix</strong>,
<strong class="program">gsec</strong>, and <strong class="program">gstat</strong>.</p>
<p>The API presented to the client programmer by these utilities is inelegant because they are, after all,
command-line tools rather than native components of the client language. To address this problem, Firebird
has a facility called the <cite>Services API</cite>, which exposes a uniform interface to the administrative
functionality of the traditional command-line tools.</p>
<p>The native Services API, though consistent, is much lower-level than a Pythonic API. If the native version
were exposed directly, accomplishing a given task would probably require more Python code than scripting
the traditional command-line tools. For this reason, FDB presents its own abstraction over the native API
via the <a class="reference internal" href="reference.html#module-fdb.services" title="fdb.services: Submodule for work with Firebird Services"><tt class="xref py py-mod docutils literal"><span class="pre">fdb.services</span></tt></a> module.</p>
<div class="section" id="services-api-connections">
<h3>Services API Connections<a class="headerlink" href="#services-api-connections" title="Permalink to this headline">¶</a></h3>
<p>All Services API operations are performed in the context of a <cite>connection</cite> to a specific database server,
represented by the <a class="reference internal" href="reference.html#fdb.services.Connection" title="fdb.services.Connection"><tt class="xref py py-class docutils literal"><span class="pre">fdb.services.Connection</span></tt></a> class. Similarly to database connections, FDB provides
<a class="reference internal" href="reference.html#fdb.services.connect" title="fdb.services.connect"><tt class="xref py py-func docutils literal"><span class="pre">connect()</span></tt></a> constructor function to create such connections.</p>
<p>This constructor has three keyword parameters:</p>
<blockquote>
<div><table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">host:</th><td class="field-body">The network name of the computer on which the database server is running.</td>
</tr>
<tr class="field-even field"><th class="field-name">user:</th><td class="field-body">The name of the database user under whose authority the maintenance tasks are to be performed.</td>
</tr>
<tr class="field-odd field"><th class="field-name">password:</th><td class="field-body">User’s password.</td>
</tr>
</tbody>
</table>
</div></blockquote>
<p>Since maintenance operations are most often initiated by an administrative user on the same computer as
the database server, <cite>host</cite> defaults to the local computer, and <cite>user</cite> defaults to <cite>SYSDBA</cite>.</p>
<p>The three calls to <a class="reference internal" href="reference.html#fdb.services.connect" title="fdb.services.connect"><tt class="xref py py-func docutils literal"><span class="pre">fdb.services.connect()</span></tt></a> in the following program are equivalent:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>

<span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Like database connections, it&#8217;s good practice to <a class="reference internal" href="reference.html#fdb.services.Connection.close" title="fdb.services.Connection.close"><tt class="xref py py-meth docutils literal"><span class="pre">close()</span></tt></a> them when you don&#8217;t need them
anymore.</p>
</div>
<p><a class="reference internal" href="reference.html#fdb.services.Connection" title="fdb.services.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> object provides number of methods that could be divided into several groups:</p>
<ul class="simple">
<li><a class="reference internal" href="#server-configuration-and-state">Server Configuration and State</a>: To get information about server configuration, active attachments or
users, or to get content of server log.</li>
<li><a class="reference internal" href="#database-options">Database options</a>: To set various database parameters like size of page cache, access mode or SQL dialect.</li>
<li><a class="reference internal" href="#database-maintenance">Database maintenance</a>: To perform backup, restore, validation or other database maintenance tasks.</li>
<li><a class="reference internal" href="#user-maintanance">User maintanance</a>: To get or change information about users defined in security database, to create new
or remove users.</li>
<li><a class="reference internal" href="#trace-service">Trace service</a>: To start, stop, pause/resume or list Firebird <cite>trace sessions</cite>.</li>
<li><a class="reference internal" href="#text-ouput-from-services">Text ouput from Services</a>: Some services like <cite>backup</cite> or <cite>trace</cite> may return significant amount of text.
This output is not returned directly by method that starts the service, but through separate methods that
emulate read from text file, or provide <a class="reference external" href="http://docs.python.org/library/stdtypes.html#typeiter" title="(in Python v2.7)"><em class="xref std std-ref">iterator protocol</em></a> support on <cite>Connection</cite>.</li>
</ul>
</div>
<div class="section" id="server-configuration-and-state">
<h3>Server Configuration and State<a class="headerlink" href="#server-configuration-and-state" title="Permalink to this headline">¶</a></h3>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_service_manager_version" title="fdb.services.Connection.get_service_manager_version"><tt class="xref py py-meth docutils literal"><span class="pre">get_service_manager_version()</span></tt></a></p>
<blockquote>
<div><p>To help client programs adapt to version changes, the service manager exposes its version number as
an integer.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">print</span> <span class="n">con</span><span class="o">.</span><span class="n">get_service_manager_version</span><span class="p">()</span>
<span class="mi">2</span>
</pre></div>
</div>
<p><cite>fdb.services</cite> is a thick wrapper of the Services API that can shield its users from changes in
the underlying C API, so this method is unlikely to be useful to the typical Python client programmer.</p>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_server_version" title="fdb.services.Connection.get_server_version"><tt class="xref py py-meth docutils literal"><span class="pre">get_server_version()</span></tt></a></p>
<blockquote>
<div><p>Returns the server’s version string</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">print</span> <span class="n">con</span><span class="o">.</span><span class="n">get_server_version</span><span class="p">()</span>
<span class="n">LI</span><span class="o">-</span><span class="n">V2</span><span class="o">.</span><span class="mf">5.2</span><span class="o">.</span><span class="mi">26536</span> <span class="n">Firebird</span> <span class="mf">2.5</span>
</pre></div>
</div>
<p>At first glance, this method appears to duplicate the functionality of the
<a class="reference internal" href="reference.html#fdb.Connection.server_version" title="fdb.Connection.server_version"><tt class="xref py py-attr docutils literal"><span class="pre">fdb.Connection.server_version</span></tt></a> property, but when working with Firebird, there is a difference.
<a class="reference internal" href="reference.html#fdb.Connection.server_version" title="fdb.Connection.server_version"><tt class="xref py py-attr docutils literal"><span class="pre">fdb.Connection.server_version</span></tt></a> is based on a C API call (<cite>isc_database_info()</cite>) that existed long
before the introduction of the Services API. Some programs written before the advent of Firebird test
the version number in the return value of <cite>isc_database_info()</cite>, and refuse to work if it indicates that
the server is too old. Since the first stable version of Firebird was labeled 1.0, this pre-Firebird
version testing scheme incorrectly concludes that (e.g.) Firebird 1.0 is older than Interbase 5.0.</p>
<p>Firebird addresses this problem by making <cite>isc_database_info()</cite> return a “pseudo-InterBase” version
number, whereas the Services API returns the true Firebird version, as shown:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="kn">import</span> <span class="nn">fdb</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;employee&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;Interbase-compatible version string:&#39;</span><span class="p">,</span> <span class="n">con</span><span class="o">.</span><span class="n">server_version</span>
<span class="n">svcCon</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&#39;Actual Firebird version string:     &#39;</span><span class="p">,</span> <span class="n">svcCon</span><span class="o">.</span><span class="n">get_server_version</span><span class="p">()</span>
</pre></div>
</div>
<p>Output (on Firebird 2.5.1/Linux64):</p>
<div class="highlight-python"><pre>Interbase-compatible version string: LI-V6.3.1.26351 Firebird 2.5
Actual Firebird version string:      LI-V2.5.1.26351 Firebird 2.5</pre>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_architecture" title="fdb.services.Connection.get_architecture"><tt class="xref py py-meth docutils literal"><span class="pre">get_architecture()</span></tt></a></p>
<blockquote>
<div><p>Returns platform information for the server, including hardware architecture and operating system family.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">print</span> <span class="n">con</span><span class="o">.</span><span class="n">get_architecture</span><span class="p">()</span>
<span class="n">Firebird</span><span class="o">/</span><span class="n">linux</span> <span class="n">AMD64</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_home_directory" title="fdb.services.Connection.get_home_directory"><tt class="xref py py-meth docutils literal"><span class="pre">get_home_directory()</span></tt></a></p>
<blockquote>
<div><p>Returns the equivalent of the RootDirectory setting from <tt class="file docutils literal"><span class="pre">firebird.conf</span></tt>.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">print</span> <span class="n">con</span><span class="o">.</span><span class="n">get_home_directory</span><span class="p">()</span>
<span class="o">/</span><span class="n">opt</span><span class="o">/</span><span class="n">firebird</span><span class="o">/</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_security_database_path" title="fdb.services.Connection.get_security_database_path"><tt class="xref py py-meth docutils literal"><span class="pre">get_security_database_path()</span></tt></a></p>
<blockquote>
<div><p>Returns the location of the server’s core security database, which contains user definitions and such.
Name of this database is <tt class="file docutils literal"><span class="pre">security2.fdb</span></tt> (Firebird 2.0 and later) or <tt class="file docutils literal"><span class="pre">security.fdb</span></tt>
(Firebird 1.5).</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">print</span> <span class="n">con</span><span class="o">.</span><span class="n">get_security_database_path</span><span class="p">()</span>
<span class="o">/</span><span class="n">opt</span><span class="o">/</span><span class="n">firebird</span><span class="o">/</span><span class="n">security2</span><span class="o">.</span><span class="n">fdb</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_lock_file_directory" title="fdb.services.Connection.get_lock_file_directory"><tt class="xref py py-meth docutils literal"><span class="pre">get_lock_file_directory()</span></tt></a></p>
<blockquote>
<div><p>Returns the directory location for Firebird lock files.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">print</span> <span class="n">con</span><span class="o">.</span><span class="n">get_lock_file_directory</span><span class="p">()</span>
<span class="o">/</span><span class="n">tmp</span><span class="o">/</span><span class="n">firebird</span><span class="o">/</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_server_capabilities" title="fdb.services.Connection.get_server_capabilities"><tt class="xref py py-meth docutils literal"><span class="pre">get_server_capabilities()</span></tt></a></p>
<blockquote>
<div><p>Returns tuple of capability info codes for each capability reported by Firebird server. Following
constants are defined in <a class="reference internal" href="reference.html#module-fdb.services" title="fdb.services: Submodule for work with Firebird Services"><tt class="xref py py-mod docutils literal"><span class="pre">fdb.services</span></tt></a> for convenience:</p>
<blockquote>
<div><ul class="simple">
<li><a class="reference internal" href="reference.html#fdb.services.CAPABILITY_MULTI_CLIENT" title="fdb.services.CAPABILITY_MULTI_CLIENT"><tt class="xref py py-data docutils literal"><span class="pre">CAPABILITY_MULTI_CLIENT</span></tt></a></li>
<li><a class="reference internal" href="reference.html#fdb.services.CAPABILITY_REMOTE_HOP" title="fdb.services.CAPABILITY_REMOTE_HOP"><tt class="xref py py-data docutils literal"><span class="pre">CAPABILITY_REMOTE_HOP</span></tt></a></li>
<li><a class="reference internal" href="reference.html#fdb.services.CAPABILITY_SERVER_CONFIG" title="fdb.services.CAPABILITY_SERVER_CONFIG"><tt class="xref py py-data docutils literal"><span class="pre">CAPABILITY_SERVER_CONFIG</span></tt></a></li>
<li><a class="reference internal" href="reference.html#fdb.services.CAPABILITY_QUOTED_FILENAME" title="fdb.services.CAPABILITY_QUOTED_FILENAME"><tt class="xref py py-data docutils literal"><span class="pre">CAPABILITY_QUOTED_FILENAME</span></tt></a></li>
<li><a class="reference internal" href="reference.html#fdb.services.CAPABILITY_NO_SERVER_SHUTDOWN" title="fdb.services.CAPABILITY_NO_SERVER_SHUTDOWN"><tt class="xref py py-data docutils literal"><span class="pre">CAPABILITY_NO_SERVER_SHUTDOWN</span></tt></a></li>
</ul>
</div></blockquote>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">print</span> <span class="n">con</span><span class="o">.</span><span class="n">get_server_capabilities</span><span class="p">()</span>
<span class="p">(</span><span class="il">2L</span><span class="p">,</span> <span class="il">4L</span><span class="p">,</span> <span class="il">512L</span><span class="p">,</span> <span class="il">256L</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">fdb</span><span class="o">.</span><span class="n">services</span><span class="o">.</span><span class="n">CAPABILITY_MULTI_CLIENT</span> <span class="ow">in</span> <span class="n">con</span><span class="o">.</span><span class="n">get_server_capabilities</span><span class="p">()</span>
<span class="bp">True</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">fdb</span><span class="o">.</span><span class="n">services</span><span class="o">.</span><span class="n">CAPABILITY_QUOTED_FILENAME</span> <span class="ow">in</span> <span class="n">con</span><span class="o">.</span><span class="n">get_server_capabilities</span><span class="p">()</span>
<span class="bp">False</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_message_file_directory" title="fdb.services.Connection.get_message_file_directory"><tt class="xref py py-meth docutils literal"><span class="pre">get_message_file_directory()</span></tt></a></p>
<blockquote>
<div><p>To support internationalized error messages/prompts, the database engine stores its messages in a file
named <tt class="file docutils literal"><span class="pre">firebird.msg</span></tt>. The directory in which this file resides can be determined with this method.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">print</span> <span class="n">con</span><span class="o">.</span><span class="n">get_message_file_directory</span><span class="p">()</span>
<span class="o">/</span><span class="n">opt</span><span class="o">/</span><span class="n">firebird</span><span class="o">/</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_connection_count" title="fdb.services.Connection.get_connection_count"><tt class="xref py py-meth docutils literal"><span class="pre">get_connection_count()</span></tt></a></p>
<blockquote>
<div><p>Returns the number of active connections to databases managed by the server. This count only includes
database connections (such as open instances of <a class="reference internal" href="reference.html#fdb.Connection" title="fdb.Connection"><tt class="xref py py-class docutils literal"><span class="pre">fdb.Connection</span></tt></a>), not services manager connections
(such as open instances of <a class="reference internal" href="reference.html#fdb.services.Connection" title="fdb.services.Connection"><tt class="xref py py-class docutils literal"><span class="pre">fdb.services.Connection</span></tt></a>).</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">db1</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span><span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">db2</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span><span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">print</span> <span class="n">con</span><span class="o">.</span><span class="n">get_connection_count</span><span class="p">()</span>
<span class="mi">2</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_attached_database_names" title="fdb.services.Connection.get_attached_database_names"><tt class="xref py py-meth docutils literal"><span class="pre">get_attached_database_names()</span></tt></a></p>
<blockquote>
<div><p>Returns a list of the names of all databases to which the server is maintaining at least one connection.
The database names are not guaranteed to be in any particular order.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">db1</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span><span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">db2</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">dsn</span><span class="o">=</span><span class="s">&#39;employee&#39;</span><span class="p">,</span><span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span><span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="k">print</span> <span class="n">con</span><span class="o">.</span><span class="n">get_attached_database_names</span><span class="p">()</span>
<span class="p">[</span><span class="s">&#39;/opt/firebird/examples/empbuild/employee.fdb&#39;</span><span class="p">]</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_log" title="fdb.services.Connection.get_log"><tt class="xref py py-meth docutils literal"><span class="pre">get_log()</span></tt></a></p>
<blockquote>
<div><p>Request the contents of the server’s log file (<tt class="file docutils literal"><span class="pre">firebird.log</span></tt>).</p>
<p>This method is so-called <cite>Async method</cite> that only initiates log transfer. Actual log content could be
read by one from many methods for <a class="reference internal" href="#text-ouput-from-services">text ouput from Services</a> that <cite>Connection</cite> provides .</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span><span class="o">.</span><span class="n">get_log</span><span class="p">()</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">log</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
</pre></div>
</div>
</div></blockquote>
</div>
<div class="section" id="database-options">
<h3>Database options<a class="headerlink" href="#database-options" title="Permalink to this headline">¶</a></h3>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.set_default_page_buffers" title="fdb.services.Connection.set_default_page_buffers"><tt class="xref py py-meth docutils literal"><span class="pre">set_default_page_buffers()</span></tt></a></p>
<blockquote>
<div><p>Sets individual page cache size for Database.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">set_default_page_buffers</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">,</span><span class="mi">100</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.set_sweep_interval" title="fdb.services.Connection.set_sweep_interval"><tt class="xref py py-meth docutils literal"><span class="pre">set_sweep_interval()</span></tt></a></p>
<blockquote>
<div><p>Sets treshold for automatic sweep.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">set_sweep_interval</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">,</span><span class="mi">100000</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.set_reserve_page_space" title="fdb.services.Connection.set_reserve_page_space"><tt class="xref py py-meth docutils literal"><span class="pre">set_reserve_page_space()</span></tt></a></p>
<blockquote>
<div><p>Sets data page space reservation policy.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="go"># Use all space</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">set_reserve_page_space</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">,</span><span class="bp">False</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.set_write_mode" title="fdb.services.Connection.set_write_mode"><tt class="xref py py-meth docutils literal"><span class="pre">set_write_mode()</span></tt></a></p>
<blockquote>
<div><p>Sets Disk Write Mode: Sync (forced writes) or Async (buffered). Following constants are defined
in <a class="reference internal" href="reference.html#module-fdb.services" title="fdb.services: Submodule for work with Firebird Services"><tt class="xref py py-mod docutils literal"><span class="pre">fdb.services</span></tt></a> for convenience:</p>
<ul class="simple">
<li><a class="reference internal" href="reference.html#fdb.services.WRITE_FORCED" title="fdb.services.WRITE_FORCED"><tt class="xref py py-data docutils literal"><span class="pre">WRITE_FORCED</span></tt></a></li>
<li><a class="reference internal" href="reference.html#fdb.services.WRITE_BUFFERED" title="fdb.services.WRITE_BUFFERED"><tt class="xref py py-data docutils literal"><span class="pre">WRITE_BUFFERED</span></tt></a></li>
</ul>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="go"># Disable Forced Writes</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">set_write_mode</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">,</span><span class="n">services</span><span class="o">.</span><span class="n">WRITE_BUFFERED</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.set_access_mode" title="fdb.services.Connection.set_access_mode"><tt class="xref py py-meth docutils literal"><span class="pre">set_access_mode()</span></tt></a></p>
<blockquote>
<div><p>Sets Database Access mode: Read Only or Read/Write. Following constants are defined
in <a class="reference internal" href="reference.html#module-fdb.services" title="fdb.services: Submodule for work with Firebird Services"><tt class="xref py py-mod docutils literal"><span class="pre">fdb.services</span></tt></a> for convenience:</p>
<ul class="simple">
<li><a class="reference internal" href="reference.html#fdb.services.ACCESS_READ_WRITE" title="fdb.services.ACCESS_READ_WRITE"><tt class="xref py py-data docutils literal"><span class="pre">ACCESS_READ_WRITE</span></tt></a></li>
<li><a class="reference internal" href="reference.html#fdb.services.ACCESS_READ_ONLY" title="fdb.services.ACCESS_READ_ONLY"><tt class="xref py py-data docutils literal"><span class="pre">ACCESS_READ_ONLY</span></tt></a></li>
</ul>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="go"># Set database to R/O mode</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">set_access_mode</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">,</span><span class="n">services</span><span class="o">.</span><span class="n">ACCESS_READ_ONLY</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.set_sql_dialect" title="fdb.services.Connection.set_sql_dialect"><tt class="xref py py-meth docutils literal"><span class="pre">set_sql_dialect()</span></tt></a></p>
<blockquote>
<div><p>Sets SQL Dialect for Database.</p>
<div class="admonition warning">
<p class="first admonition-title">Warning</p>
<p class="last">Changing SQL dialect on existing database is not recommended. Only newly created database
objects would respect new dialect setting, while objects created with previous dialect remain
unchanged. That may have dire consequences.</p>
</div>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="go"># Use SQL dialect 1</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">set_sql_dialect</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
</div>
<div class="section" id="database-maintenance">
<h3>Database maintenance<a class="headerlink" href="#database-maintenance" title="Permalink to this headline">¶</a></h3>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_limbo_transaction_ids" title="fdb.services.Connection.get_limbo_transaction_ids"><tt class="xref py py-meth docutils literal"><span class="pre">get_limbo_transaction_ids()</span></tt></a></p>
<blockquote>
<div>Returns list of transactions in limbo.</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.commit_limbo_transaction" title="fdb.services.Connection.commit_limbo_transaction"><tt class="xref py py-meth docutils literal"><span class="pre">commit_limbo_transaction()</span></tt></a></p>
<blockquote>
<div>Resolves limbo transaction with commit.</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.rollback_limbo_transaction" title="fdb.services.Connection.rollback_limbo_transaction"><tt class="xref py py-meth docutils literal"><span class="pre">rollback_limbo_transaction()</span></tt></a></p>
<blockquote>
<div>Resolves limbo transaction with rollback.</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_statistics" title="fdb.services.Connection.get_statistics"><tt class="xref py py-meth docutils literal"><span class="pre">get_statistics()</span></tt></a></p>
<blockquote>
<div><p>Request database statisctics. Report is in the same format as the output of the gstat command-line
utility. This method has one required parameter, the location of the database on which to compute
statistics, and six optional boolean parameters for controlling the domain of the statistics.</p>
<p>This method is so-called <cite>Async method</cite> that only initiates report processing. Actual report could be
read by one from many methods for <a class="reference internal" href="#text-ouput-from-services">text ouput from Services</a> that <cite>Connection</cite> provides .</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Until statistical report is not fully fetched from service (or ignored via
<a class="reference internal" href="reference.html#fdb.services.Connection.wait" title="fdb.services.Connection.wait"><tt class="xref py py-meth docutils literal"><span class="pre">wait()</span></tt></a>), any attempt to start another asynchronous service will
fail with exception.</p>
</div>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">get_statistics</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">stat_report</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.backup" title="fdb.services.Connection.backup"><tt class="xref py py-meth docutils literal"><span class="pre">backup()</span></tt></a></p>
<blockquote>
<div><p>Request logical (GBAK) database backup. Produces report about backup process.</p>
<p>This method is so-called <cite>Async method</cite> that only initiates backup process. Actual report could be
read by one from many methods for <a class="reference internal" href="#text-ouput-from-services">text ouput from Services</a> that <cite>Connection</cite> provides .</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Until backup report is not fully fetched from service (or ignored via
<a class="reference internal" href="reference.html#fdb.services.Connection.wait" title="fdb.services.Connection.wait"><tt class="xref py py-meth docutils literal"><span class="pre">wait()</span></tt></a>), any attempt to start another asynchronous service will
fail with exception.</p>
</div>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span><span class="o">.</span><span class="n">backup</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">,</span> <span class="s">&#39;/home/data/employee.fbk&#39;</span><span class="p">,</span> <span class="n">metadata_only</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">collect_garbage</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">backup_report</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.restore" title="fdb.services.Connection.restore"><tt class="xref py py-meth docutils literal"><span class="pre">restore()</span></tt></a></p>
<blockquote>
<div><p>Request database restore from logical (GBAK) backup. Produces report about restore process.</p>
<p>This method is so-called <cite>Async method</cite> that only initiates restore process. Actual report could be
read by one from many methods for <a class="reference internal" href="#text-ouput-from-services">text ouput from Services</a> that <cite>Connection</cite> provides .</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Until restore report is not fully fetched from service (or ignored via
<a class="reference internal" href="reference.html#fdb.services.Connection.wait" title="fdb.services.Connection.wait"><tt class="xref py py-meth docutils literal"><span class="pre">wait()</span></tt></a>), any attempt to start another asynchronous service will
fail with exception.</p>
</div>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span><span class="o">.</span><span class="n">restore</span><span class="p">(</span><span class="s">&#39;/home/data/employee.fbk&#39;</span><span class="p">,</span> <span class="s">&#39;/home/data/empcopy.fdb&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">restore_report</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.nbackup" title="fdb.services.Connection.nbackup"><tt class="xref py py-meth docutils literal"><span class="pre">nbackup()</span></tt></a></p>
<blockquote>
<div><p>Perform physical (NBACKUP) database backup.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Method call will not return until sweep is finished.</p>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.nrestore" title="fdb.services.Connection.nrestore"><tt class="xref py py-meth docutils literal"><span class="pre">nrestore()</span></tt></a></p>
<blockquote>
<div><p>Perform restore from physical (NBACKUP) database backup.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Method call will not return until sweep is finished.</p>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.shutdown" title="fdb.services.Connection.shutdown"><tt class="xref py py-meth docutils literal"><span class="pre">shutdown()</span></tt></a></p>
<blockquote>
<div><p>Database shutdown. Following constants are defined in <a class="reference internal" href="reference.html#module-fdb.services" title="fdb.services: Submodule for work with Firebird Services"><tt class="xref py py-mod docutils literal"><span class="pre">fdb.services</span></tt></a> for convenience:</p>
<p>For shutdow mode:</p>
<ul class="simple">
<li><a class="reference internal" href="reference.html#fdb.services.SHUT_SINGLE" title="fdb.services.SHUT_SINGLE"><tt class="xref py py-data docutils literal"><span class="pre">SHUT_SINGLE</span></tt></a></li>
<li><a class="reference internal" href="reference.html#fdb.services.SHUT_MULTI" title="fdb.services.SHUT_MULTI"><tt class="xref py py-data docutils literal"><span class="pre">SHUT_MULTI</span></tt></a></li>
<li><a class="reference internal" href="reference.html#fdb.services.SHUT_FULL" title="fdb.services.SHUT_FULL"><tt class="xref py py-data docutils literal"><span class="pre">SHUT_FULL</span></tt></a></li>
</ul>
<p>For shutdown method:</p>
<ul class="simple">
<li><a class="reference internal" href="reference.html#fdb.services.SHUT_FORCE" title="fdb.services.SHUT_FORCE"><tt class="xref py py-data docutils literal"><span class="pre">SHUT_FORCE</span></tt></a></li>
<li><a class="reference internal" href="reference.html#fdb.services.SHUT_DENY_NEW_TRANSACTIONS" title="fdb.services.SHUT_DENY_NEW_TRANSACTIONS"><tt class="xref py py-data docutils literal"><span class="pre">SHUT_DENY_NEW_TRANSACTIONS</span></tt></a></li>
<li><a class="reference internal" href="reference.html#fdb.services.SHUT_DENY_NEW_ATTACHMENTS" title="fdb.services.SHUT_DENY_NEW_ATTACHMENTS"><tt class="xref py py-data docutils literal"><span class="pre">SHUT_DENY_NEW_ATTACHMENTS</span></tt></a></li>
</ul>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="c"># Shutdown database to single-user maintenance mode</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span><span class="o">.</span><span class="n">shutdown</span><span class="p">(</span><span class="s">&#39;empoyee&#39;</span><span class="p">,</span> <span class="n">services</span><span class="o">.</span><span class="n">SHUT_SINGLE</span><span class="p">,</span> <span class="n">services</span><span class="o">.</span><span class="n">SHUT_FORCE</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="c"># Go to full shutdown mode, disabling new attachments during 5 seconds</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span><span class="o">.</span><span class="n">shutdown</span><span class="p">(</span><span class="s">&#39;empoyee&#39;</span><span class="p">,</span> <span class="n">services</span><span class="o">.</span><span class="n">SHUT_FULL</span><span class="p">,</span> <span class="n">services</span><span class="o">.</span><span class="n">SHUT_DENY_NEW_ATTACHMENTS</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.bring_online" title="fdb.services.Connection.bring_online"><tt class="xref py py-meth docutils literal"><span class="pre">bring_online()</span></tt></a></p>
<blockquote>
<div><p>Bring previously shut down database back online. Following constants are defined in
<a class="reference internal" href="reference.html#module-fdb.services" title="fdb.services: Submodule for work with Firebird Services"><tt class="xref py py-mod docutils literal"><span class="pre">fdb.services</span></tt></a> for convenience:</p>
<p>For on-line mode:</p>
<ul class="simple">
<li><a class="reference internal" href="reference.html#fdb.services.SHUT_NORMAL" title="fdb.services.SHUT_NORMAL"><tt class="xref py py-data docutils literal"><span class="pre">SHUT_NORMAL</span></tt></a></li>
<li><a class="reference internal" href="reference.html#fdb.services.SHUT_SINGLE" title="fdb.services.SHUT_SINGLE"><tt class="xref py py-data docutils literal"><span class="pre">SHUT_SINGLE</span></tt></a></li>
<li><a class="reference internal" href="reference.html#fdb.services.SHUT_MULTI" title="fdb.services.SHUT_MULTI"><tt class="xref py py-data docutils literal"><span class="pre">SHUT_MULTI</span></tt></a></li>
</ul>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># 64-bit Linux Firebird 2.5.1 SuperServer</span>
<span class="o">&gt;&gt;&gt;</span> <span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="c"># Enable multi-user maintenance</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span><span class="o">.</span><span class="n">bring_online</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">,</span> <span class="n">services</span><span class="o">.</span><span class="n">SHUT_MULTI</span><span class="p">)</span>
<span class="c"># Enable single-user maintenance</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span><span class="o">.</span><span class="n">bring_online</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">,</span> <span class="n">services</span><span class="o">.</span><span class="n">SHUT_SINGLE</span><span class="p">)</span>
<span class="c"># Return to normal state</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">con</span><span class="o">.</span><span class="n">bring_online</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.activate_shadow" title="fdb.services.Connection.activate_shadow"><tt class="xref py py-meth docutils literal"><span class="pre">activate_shadow()</span></tt></a></p>
<blockquote>
<div>Activates Database Shadow(s).</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.sweep" title="fdb.services.Connection.sweep"><tt class="xref py py-meth docutils literal"><span class="pre">sweep()</span></tt></a></p>
<blockquote>
<div><p>Performs Database Sweep.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Method call will not return until sweep is finished.</p>
</div>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">sweep</span><span class="p">(</span><span class="s">&#39;empoyee&#39;</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.repair" title="fdb.services.Connection.repair"><tt class="xref py py-meth docutils literal"><span class="pre">repair()</span></tt></a></p>
<blockquote>
<div><p>Database Validation and Repair.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Method call will not return until action is finished.</p>
</div>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="go"># Just validate</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">repair</span><span class="p">(</span><span class="s">&#39;empoyee&#39;</span><span class="p">,</span> <span class="n">ignore_checksums</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">read_only_validation</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="go"># Mend the database</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">repair</span><span class="p">(</span><span class="s">&#39;empoyee&#39;</span><span class="p">,</span> <span class="n">ignore_checksums</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">mend_database</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
</div>
<div class="section" id="user-maintanance">
<h3>User maintanance<a class="headerlink" href="#user-maintanance" title="Permalink to this headline">¶</a></h3>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.get_users" title="fdb.services.Connection.get_users"><tt class="xref py py-meth docutils literal"><span class="pre">get_users()</span></tt></a></p>
<blockquote>
<div><p>Returns information about specified user or all users as a list of <a class="reference internal" href="reference.html#fdb.services.User" title="fdb.services.User"><tt class="xref py py-class docutils literal"><span class="pre">User</span></tt></a> instances.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">users</span> <span class="o">=</span> <span class="n">con</span><span class="o">.</span><span class="n">get_users</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">users</span><span class="p">:</span>
<span class="gp">... </span>   <span class="k">print</span> <span class="n">user</span><span class="o">.</span><span class="n">name</span>
<span class="gp">... </span>   <span class="k">print</span> <span class="n">user</span><span class="o">.</span><span class="n">first_name</span><span class="p">,</span> <span class="n">user</span><span class="o">.</span><span class="n">middle_name</span><span class="p">,</span> <span class="n">user</span><span class="o">.</span><span class="n">last_name</span>
<span class="gp">... </span>   <span class="k">print</span> <span class="n">user</span><span class="o">.</span><span class="n">user_id</span><span class="p">,</span> <span class="n">user</span><span class="o">.</span><span class="n">group_id</span>
<span class="go">SYSDBA</span>
<span class="go">Sql Server Administrator</span>
<span class="go">0 0</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.add_user" title="fdb.services.Connection.add_user"><tt class="xref py py-meth docutils literal"><span class="pre">add_user()</span></tt></a></p>
<blockquote>
<div><p>Adds new user. Requires instance of <a class="reference internal" href="reference.html#fdb.services.User" title="fdb.services.User"><tt class="xref py py-class docutils literal"><span class="pre">User</span></tt></a> with <strong>at least</strong> its <a class="reference internal" href="reference.html#fdb.services.User.name" title="fdb.services.User.name"><tt class="xref py py-attr docutils literal"><span class="pre">name</span></tt></a>
and <a class="reference internal" href="reference.html#fdb.services.User.password" title="fdb.services.User.password"><tt class="xref py py-attr docutils literal"><span class="pre">password</span></tt></a> attributes specified as non-empty values. All other attributes
are optional.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">user</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">User</span><span class="p">(</span><span class="s">&#39;NewUser&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">user</span><span class="o">.</span><span class="n">password</span> <span class="o">=</span> <span class="s">&#39;secret&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">user</span><span class="o">.</span><span class="n">first_name</span> <span class="o">=</span> <span class="s">&#39;John&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">user</span><span class="o">.</span><span class="n">last_name</span> <span class="o">=</span> <span class="s">&#39;Doe&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">add_users</span><span class="p">(</span><span class="n">User</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.modify_user" title="fdb.services.Connection.modify_user"><tt class="xref py py-meth docutils literal"><span class="pre">modify_user()</span></tt></a></p>
<blockquote>
<div><p>Modifycation of user information. Requires instance of <a class="reference internal" href="reference.html#fdb.services.User" title="fdb.services.User"><tt class="xref py py-class docutils literal"><span class="pre">User</span></tt></a> with <strong>at least</strong> its
<a class="reference internal" href="reference.html#fdb.services.User.name" title="fdb.services.User.name"><tt class="xref py py-attr docutils literal"><span class="pre">name</span></tt></a> attribute specified as non-empty value.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Sets <a class="reference internal" href="reference.html#fdb.services.User.first_name" title="fdb.services.User.first_name"><tt class="xref py py-attr docutils literal"><span class="pre">first_name</span></tt></a>, <a class="reference internal" href="reference.html#fdb.services.User.middle_name" title="fdb.services.User.middle_name"><tt class="xref py py-attr docutils literal"><span class="pre">middle_name</span></tt></a> and <a class="reference internal" href="reference.html#fdb.services.User.last_name" title="fdb.services.User.last_name"><tt class="xref py py-attr docutils literal"><span class="pre">last_name</span></tt></a> to
their actual values, and ignores the <a class="reference internal" href="reference.html#fdb.services.User.user_id" title="fdb.services.User.user_id"><tt class="xref py py-attr docutils literal"><span class="pre">user_id</span></tt></a> and <a class="reference internal" href="reference.html#fdb.services.User.group_id" title="fdb.services.User.group_id"><tt class="xref py py-attr docutils literal"><span class="pre">group_id</span></tt></a> attributes
regardless of their values. <a class="reference internal" href="reference.html#fdb.services.User.password" title="fdb.services.User.password"><tt class="xref py py-attr docutils literal"><span class="pre">password</span></tt></a> is set <strong>only</strong> when it has value.</p>
</div>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">user</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">User</span><span class="p">(</span><span class="s">&#39;SYSDBA&#39;</span><span class="p">)</span>
<span class="go"># Change pasword</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">user</span><span class="o">.</span><span class="n">password</span> <span class="o">=</span> <span class="s">&#39;Pa$$w0rd&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">modify_user</span><span class="p">(</span><span class="n">User</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.remove_user" title="fdb.services.Connection.remove_user"><tt class="xref py py-meth docutils literal"><span class="pre">remove_user()</span></tt></a></p>
<blockquote>
<div><p>Removes user. Requires User name or instance of <a class="reference internal" href="reference.html#fdb.services.User" title="fdb.services.User"><tt class="xref py py-class docutils literal"><span class="pre">User</span></tt></a> with <strong>at least</strong> its
<a class="reference internal" href="reference.html#fdb.services.User.name" title="fdb.services.User.name"><tt class="xref py py-attr docutils literal"><span class="pre">name</span></tt></a> attribute specified as non-empty value.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">remove_user</span><span class="p">(</span><span class="s">&#39;NewUser&#39;</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.user_exists" title="fdb.services.Connection.user_exists"><tt class="xref py py-meth docutils literal"><span class="pre">user_exists()</span></tt></a></p>
<blockquote>
<div><p>Checks for user&#8217;s existence. Requires User name or instance of <a class="reference internal" href="reference.html#fdb.services.User" title="fdb.services.User"><tt class="xref py py-class docutils literal"><span class="pre">User</span></tt></a> with <strong>at least</strong> its
<a class="reference internal" href="reference.html#fdb.services.User.name" title="fdb.services.User.name"><tt class="xref py py-attr docutils literal"><span class="pre">name</span></tt></a> attribute specified as non-empty value.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">user_exists</span><span class="p">(</span><span class="s">&#39;NewUser&#39;</span><span class="p">)</span>
<span class="go">False</span>
</pre></div>
</div>
</div></blockquote>
</div>
<div class="section" id="trace-service">
<h3>Trace service<a class="headerlink" href="#trace-service" title="Permalink to this headline">¶</a></h3>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.trace_start" title="fdb.services.Connection.trace_start"><tt class="xref py py-meth docutils literal"><span class="pre">trace_start()</span></tt></a></p>
<blockquote>
<div><p>Starts new trace session. Requires trace <cite>configuration</cite> and returns <cite>Session ID</cite>.</p>
<p>Trace session output could be retrieved through <a class="reference internal" href="reference.html#fdb.services.Connection.readline" title="fdb.services.Connection.readline"><tt class="xref py py-meth docutils literal"><span class="pre">readline()</span></tt></a>,
<a class="reference internal" href="reference.html#fdb.services.Connection.readlines" title="fdb.services.Connection.readlines"><tt class="xref py py-meth docutils literal"><span class="pre">readlines()</span></tt></a>, iteration over <cite>Connection</cite> or ignored via call to
<a class="reference internal" href="reference.html#fdb.services.Connection.wait" title="fdb.services.Connection.wait"><tt class="xref py py-meth docutils literal"><span class="pre">wait()</span></tt></a>.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Until session output is not fully fetched from service (or ignored via <a class="reference internal" href="reference.html#fdb.services.Connection.wait" title="fdb.services.Connection.wait"><tt class="xref py py-meth docutils literal"><span class="pre">wait()</span></tt></a>),
any attempt to start another asynchronous service including call to any <cite>trace_</cite> method will fail
with exception.</p>
</div>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>

<span class="n">svc</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="c"># Because trace session blocks the connection, we need another one to stop trace session!</span>
<span class="n">svc_aux</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>

<span class="n">trace_config</span> <span class="o">=</span> <span class="s">&quot;&quot;&quot;&lt;database &#39;employee&#39;&gt;</span>
<span class="s">    enabled true</span>
<span class="s">    log_statement_finish true</span>
<span class="s">    print_plan true</span>
<span class="s">    include_filter </span><span class="si">%%</span><span class="s">SELECT</span><span class="si">%%</span><span class="s"></span>
<span class="s">    exclude_filter </span><span class="si">%%</span><span class="s">RDB$</span><span class="si">%%</span><span class="s"></span>
<span class="s">    time_threshold 0</span>
<span class="s">    max_sql_length 2048</span>
<span class="s">&lt;/database&gt;</span>
<span class="s">&quot;&quot;&quot;</span>
<span class="n">trace_id</span> <span class="o">=</span> <span class="n">svc</span><span class="o">.</span><span class="n">trace_start</span><span class="p">(</span><span class="n">trace_config</span><span class="p">,</span><span class="s">&#39;test_trace_1&#39;</span><span class="p">)</span>
<span class="n">trace_log</span> <span class="o">=</span> <span class="p">[]</span>
<span class="c"># Get first 10 lines of trace output</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
   <span class="n">trace_log</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">svc</span><span class="o">.</span><span class="n">readline</span><span class="p">())</span>
<span class="c"># Stop trace session</span>
<span class="n">svc_aux</span><span class="o">.</span><span class="n">stop_trace</span><span class="p">(</span><span class="n">trace_id</span><span class="p">)</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.trace_stop" title="fdb.services.Connection.trace_stop"><tt class="xref py py-meth docutils literal"><span class="pre">trace_stop()</span></tt></a></p>
<blockquote>
<div><p>Stops trace session specified by ID.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">trace_stop</span><span class="p">(</span><span class="mi">15</span><span class="p">)</span>
<span class="go">Trace session ID 15 stopped</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.trace_suspend" title="fdb.services.Connection.trace_suspend"><tt class="xref py py-meth docutils literal"><span class="pre">trace_suspend()</span></tt></a></p>
<blockquote>
<div><p>Suspends trace session specified by ID.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">trace_suspend</span><span class="p">(</span><span class="mi">15</span><span class="p">)</span>
<span class="go">Trace session ID 15 paused</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.trace_resume" title="fdb.services.Connection.trace_resume"><tt class="xref py py-meth docutils literal"><span class="pre">trace_resume()</span></tt></a></p>
<blockquote>
<div><p>resumes trace session specified by ID.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">trace_resume</span><span class="p">(</span><span class="mi">15</span><span class="p">)</span>
<span class="go">Trace session ID 15 resumed</span>
</pre></div>
</div>
</div></blockquote>
<p><a class="reference internal" href="reference.html#fdb.services.Connection.trace_list" title="fdb.services.Connection.trace_list"><tt class="xref py py-meth docutils literal"><span class="pre">trace_list()</span></tt></a></p>
<blockquote>
<div><p>Returns information about existing trace sessions as dictionary mapping <cite>SESSION_ID -&gt; SESSION_PARAMS</cite>.
Session parameters is another dictionary with next keys:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">name:</th><td class="field-body">(string) (optional) Session name if specified.</td>
</tr>
<tr class="field-even field"><th class="field-name">date:</th><td class="field-body">(datetime.datetime) Session start date and time.</td>
</tr>
<tr class="field-odd field"><th class="field-name">user:</th><td class="field-body">(string) Trace user name.</td>
</tr>
<tr class="field-even field"><th class="field-name">flags:</th><td class="field-body">(list of strings) Session flags.</td>
</tr>
</tbody>
</table>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">fdb</span> <span class="kn">import</span> <span class="n">services</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span> <span class="o">=</span> <span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="s">&#39;sysdba&#39;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">con</span><span class="o">.</span><span class="n">trace_list</span><span class="p">()</span>
<span class="go">{53: {&#39;date&#39;: datetime.datetime(2012, 10, 5, 10, 45, 4),</span>
<span class="go">      &#39;flags&#39;: [&#39;active&#39;, &#39; admin&#39;, &#39; trace&#39;],</span>
<span class="go">      &#39;user&#39;: &#39;SYSDBA&#39;}}</span>
</pre></div>
</div>
</div></blockquote>
</div>
<div class="section" id="text-ouput-from-services">
<h3>Text ouput from Services<a class="headerlink" href="#text-ouput-from-services" title="Permalink to this headline">¶</a></h3>
<p>Some services like <cite>backup</cite> or <cite>trace</cite> may return significant amount of text. Rather than return the whole
text as single string value by methods that provide access to these services, FDB isolated the transfer
process to separate methods:</p>
<ul class="simple">
<li><a class="reference internal" href="reference.html#fdb.services.Connection.readline" title="fdb.services.Connection.readline"><tt class="xref py py-meth docutils literal"><span class="pre">readline()</span></tt></a> - Similar to <a class="reference external" href="http://docs.python.org/library/stdtypes.html#file.readline" title="(in Python v2.7)"><tt class="xref py py-meth docutils literal"><span class="pre">file.readline()</span></tt></a>, returns next line of output from Service.</li>
<li><a class="reference internal" href="reference.html#fdb.services.Connection.readlines" title="fdb.services.Connection.readlines"><tt class="xref py py-meth docutils literal"><span class="pre">readlines()</span></tt></a> - Like <a class="reference external" href="http://docs.python.org/library/stdtypes.html#file.readlines" title="(in Python v2.7)"><tt class="xref py py-meth docutils literal"><span class="pre">file.readlines()</span></tt></a>, returns list of output lines.</li>
<li>Iteration over <cite>Connection</cite> object, because <a class="reference internal" href="reference.html#fdb.services.Connection" title="fdb.services.Connection"><tt class="xref py py-class docutils literal"><span class="pre">Connection</span></tt></a> has built-in support for <a class="reference external" href="http://docs.python.org/library/stdtypes.html#typeiter" title="(in Python v2.7)"><em class="xref std std-ref">iterator
protocol</em></a>.</li>
<li>Using <cite>callback</cite> method provided by developer. Each <cite>Connection</cite> method that returns its result
asynchronously accepts an optional parameter <cite>callback</cite>, which must be a function that accepts one string
parameter. This method is then called with each output line coming from service.</li>
<li><a class="reference internal" href="reference.html#fdb.services.Connection.wait" title="fdb.services.Connection.wait"><tt class="xref py py-meth docutils literal"><span class="pre">wait()</span></tt></a> - Waits for Sevice to finish, ignoring rest of the output it may produce.</li>
</ul>
<div class="admonition warning">
<p class="first admonition-title">Warning</p>
<p>Until output is not fully fetched from service, any attempt to start another asynchronous service will
fail with exception! This constraint is set by Firebird Service API.</p>
<p>You may check the status of asynchronous Services using <a class="reference internal" href="reference.html#fdb.services.Connection.fetching" title="fdb.services.Connection.fetching"><tt class="xref py py-attr docutils literal"><span class="pre">Connection.fetching</span></tt></a> attribute or
<a class="reference internal" href="reference.html#fdb.services.Connection.isrunning" title="fdb.services.Connection.isrunning"><tt class="xref py py-meth docutils literal"><span class="pre">Connection.isrunning()</span></tt></a> method.</p>
<p class="last">In cases when you&#8217;re not interested in output produced by Service, call <a class="reference internal" href="reference.html#fdb.services.Connection.wait" title="fdb.services.Connection.wait"><tt class="xref py py-meth docutils literal"><span class="pre">wait()</span></tt></a> to
wait for service to complete.</p>
</div>
<p><strong>Examples:</strong></p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">fdb</span>
<span class="n">svc</span> <span class="o">=</span> <span class="n">fdb</span><span class="o">.</span><span class="n">services</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">password</span><span class="o">=</span><span class="s">&#39;masterkey&#39;</span><span class="p">)</span>

<span class="k">print</span> <span class="s">&quot;Fetch materialized&quot;</span>
<span class="k">print</span> <span class="s">&quot;==================&quot;</span>
<span class="k">print</span> <span class="s">&quot;Start backup&quot;</span>
<span class="n">svc</span><span class="o">.</span><span class="n">backup</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">,</span> <span class="s">&#39;employee.fbk&#39;</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&quot;svc.fetching is&quot;</span><span class="p">,</span> <span class="n">svc</span><span class="o">.</span><span class="n">fetching</span>
<span class="k">print</span> <span class="s">&quot;svc.running is&quot;</span><span class="p">,</span> <span class="n">svc</span><span class="o">.</span><span class="n">isrunning</span><span class="p">()</span>
<span class="n">report</span> <span class="o">=</span> <span class="n">svc</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="k">print</span> <span class="s">&quot;</span><span class="si">%i</span><span class="s"> lines returned&quot;</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">report</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&quot;First 5 lines from output:&quot;</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
   <span class="k">print</span> <span class="n">i</span><span class="p">,</span><span class="n">report</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
<span class="k">print</span> <span class="s">&quot;svc.fetching is&quot;</span><span class="p">,</span> <span class="n">svc</span><span class="o">.</span><span class="n">fetching</span>
<span class="k">print</span> <span class="s">&quot;svc.running is&quot;</span><span class="p">,</span> <span class="n">svc</span><span class="o">.</span><span class="n">isrunning</span><span class="p">()</span>
<span class="k">print</span>
<span class="k">print</span> <span class="s">&quot;Iterate over result&quot;</span>
<span class="k">print</span> <span class="s">&quot;===================&quot;</span>
<span class="n">svc</span><span class="o">.</span><span class="n">backup</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">,</span> <span class="s">&#39;employee.fbk&#39;</span><span class="p">)</span>
<span class="n">output</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">svc</span><span class="p">:</span>
   <span class="n">output</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&quot;</span><span class="si">%i</span><span class="s"> lines returned&quot;</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&quot;Last 5 lines from output:&quot;</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">output</span><span class="p">[</span><span class="o">-</span><span class="mi">5</span><span class="p">:]:</span>
   <span class="k">print</span> <span class="n">line</span>
<span class="k">print</span>
<span class="k">print</span> <span class="s">&quot;Callback&quot;</span>
<span class="k">print</span> <span class="s">&quot;========&quot;</span>

<span class="n">output</span> <span class="o">=</span> <span class="p">[]</span>

<span class="c"># Callback function</span>
<span class="k">def</span> <span class="nf">fetchline</span><span class="p">(</span><span class="n">line</span><span class="p">):</span>
   <span class="n">output</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>

<span class="n">svc</span><span class="o">.</span><span class="n">backup</span><span class="p">(</span><span class="s">&#39;employee&#39;</span><span class="p">,</span> <span class="s">&#39;employee.fbk&#39;</span><span class="p">,</span> <span class="n">callback</span><span class="o">=</span><span class="n">fetchline</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&quot;</span><span class="si">%i</span><span class="s"> lines returned&quot;</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
<span class="k">print</span> <span class="s">&quot;Last 5 lines from output:&quot;</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">output</span><span class="p">[</span><span class="o">-</span><span class="mi">5</span><span class="p">:]:</span>
   <span class="k">print</span> <span class="n">line</span>
</pre></div>
</div>
<p>Output:</p>
<div class="highlight-python"><pre>Fetch materialized
==================
Start backup
svc.fetching is True
svc.running is True
558 lines returned
First 5 lines from output:
0 gbak:readied database employee for backup
1 gbak:creating file employee.fbk
2 gbak:starting transaction
3 gbak:database employee has a page size of 4096 bytes.
4 gbak:writing domains
svc.fetching is False
svc.running is False

Iterate over result
===================
558 lines returned
Last 5 lines from output:
gbak:writing referential constraints
gbak:writing check constraints
gbak:writing SQL roles
gbak:writing names mapping
gbak:closing file, committing, and finishing. 74752 bytes written

Callback
========
558 lines returned
Last 5 lines from output:
gbak:writing referential constraints
gbak:writing check constraints
gbak:writing SQL roles
gbak:writing names mapping
gbak:closing file, committing, and finishing. 74752 bytes written</pre>
</div>
</div>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="sphinxsidebar">
        <div class="sphinxsidebarwrapper">
  <h3><a href="index.html">Table Of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">Usage Guide</a><ul>
<li><a class="reference internal" href="#driver-structure">Driver structure</a></li>
<li><a class="reference internal" href="#databases">Databases</a><ul>
<li><a class="reference internal" href="#using-connect">Using <cite>connect</cite></a></li>
<li><a class="reference internal" href="#using-create-database">Using <cite>create_database</cite></a></li>
<li><a class="reference internal" href="#deleting-databases">Deleting databases</a></li>
<li><a class="reference internal" href="#connection-object">Connection object</a></li>
<li><a class="reference internal" href="#getting-information-about-database">Getting information about database</a></li>
</ul>
</li>
<li><a class="reference internal" href="#executing-sql-statements">Executing SQL Statements</a><ul>
<li><a class="reference internal" href="#cursor-object">Cursor object</a></li>
<li><a class="reference internal" href="#sql-execution-basics">SQL Execution Basics</a></li>
<li><a class="reference internal" href="#parametrized-statements">Parametrized statements</a></li>
<li><a class="reference internal" href="#fetching-data-from-server">Fetching data from server</a></li>
<li><a class="reference internal" href="#prepared-statements">Prepared Statements</a></li>
<li><a class="reference internal" href="#named-cursors">Named Cursors</a></li>
<li><a class="reference internal" href="#working-with-stored-procedures">Working with stored procedures</a></li>
</ul>
</li>
<li><a class="reference internal" href="#data-handling-and-conversions">Data handling and conversions</a><ul>
<li><a class="reference internal" href="#implicit-conversion-of-input-parameters-from-strings">Implicit Conversion of Input Parameters from Strings</a></li>
<li><a class="reference internal" href="#automatic-conversion-from-to-unicode">Automatic conversion from/to unicode</a></li>
<li><a class="reference internal" href="#working-with-blobs">Working with BLOBs</a></li>
<li><a class="reference internal" href="#firebird-array-type">Firebird ARRAY type</a></li>
</ul>
</li>
<li><a class="reference internal" href="#trasanction-management">Trasanction management</a><ul>
<li><a class="reference internal" href="#basics">Basics</a></li>
<li><a class="reference internal" href="#auto-commit">Auto-commit</a></li>
<li><a class="reference internal" href="#transaction-parameters">Transaction parameters</a></li>
<li><a class="reference internal" href="#getting-information-about-transaction">Getting information about transaction</a></li>
<li><a class="reference internal" href="#retaining-transactions">Retaining transactions</a></li>
<li><a class="reference internal" href="#savepoints">Savepoints</a></li>
<li><a class="reference internal" href="#using-multiple-transactions-with-the-same-connection">Using multiple transactions with the same connection</a></li>
<li><a class="reference internal" href="#distributed-transactions">Distributed Transactions</a></li>
<li><a class="reference internal" href="#transaction-context-manager">Transaction Context Manager</a></li>
</ul>
</li>
<li><a class="reference internal" href="#database-events">Database Events</a><ul>
<li><a class="reference internal" href="#what-they-are">What they are</a></li>
<li><a class="reference internal" href="#why-use-them">Why use them</a></li>
<li><a class="reference internal" href="#how-events-are-exposed">How events are exposed</a></li>
<li><a class="reference internal" href="#api-for-python-developers">API for Python developers</a></li>
</ul>
</li>
<li><a class="reference internal" href="#working-with-services">Working with Services</a><ul>
<li><a class="reference internal" href="#services-api-connections">Services API Connections</a></li>
<li><a class="reference internal" href="#server-configuration-and-state">Server Configuration and State</a></li>
<li><a class="reference internal" href="#database-options">Database options</a></li>
<li><a class="reference internal" href="#database-maintenance">Database maintenance</a></li>
<li><a class="reference internal" href="#user-maintanance">User maintanance</a></li>
<li><a class="reference internal" href="#trace-service">Trace service</a></li>
<li><a class="reference internal" href="#text-ouput-from-services">Text ouput from Services</a></li>
</ul>
</li>
</ul>
</li>
</ul>

  <h4>Previous topic</h4>
  <p class="topless"><a href="getting-started.html"
                        title="previous chapter">Getting Started with FDB</a></p>
  <h4>Next topic</h4>
  <p class="topless"><a href="python-db-api-compliance.html"
                        title="next chapter">Compliance to Python Database API 2.0</a></p>
<div id="searchbox" style="display: none">
  <h3>Quick search</h3>
    <form class="search" action="search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="Go" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    <p class="searchtip" style="font-size: 90%">
    Enter search terms or a module, class or function name.
    </p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="genindex.html" title="General Index"
             >index</a></li>
        <li class="right" >
          <a href="py-modindex.html" title="Python Module Index"
             >modules</a> |</li>
        <li class="right" >
          <a href="python-db-api-compliance.html" title="Compliance to Python Database API 2.0"
             >next</a> |</li>
        <li class="right" >
          <a href="getting-started.html" title="Getting Started with FDB"
             >previous</a> |</li>
        <li><a href="index.html">FDB 1.1 documentation</a> &raquo;</li> 
      </ul>
    </div>
    <div class="footer">
        &copy; Copyright 2009-2012, David Rushby, Pavel Cisar.
      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
    </div>
  </body>
</html>