<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://ogobrecht.com/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>https:&#x2F;&#x2F;ogobrecht.com</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>This is a web feed, also known as an Atom feed. Subscribe by copying the URL from the address bar into your newsreader. Visit About Feeds to learn more and get started. It&#x27;s free.</tabi:about_feeds>
        <tabi:visit_the_site>Visit website</tabi:visit_the_site>
        <tabi:recent_posts>Recent posts</tabi:recent_posts>
        <tabi:last_updated_on>Updated on $DATE</tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>oddgen</tabi:current_section>
    </tabi:metadata><title>Ottmar’s Notes - oddgen</title>
        <subtitle>Mainly about Oracle APEX and PL&#x2F;SQL</subtitle>
    <link href="https://ogobrecht.com/tags/oddgen/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://ogobrecht.com/tags/oddgen/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2020-12-26T00:00:00+00:00</updated><id>https://ogobrecht.com/tags/oddgen/atom.xml</id><entry xml:lang="en">
        <title>New Version of Oracle Table API Generator Available</title>
        <published>2020-12-26T00:00:00+00:00</published>
        <updated>2020-12-26T00:00:00+00:00</updated>
        <author>
            <name>Ottmar Gobrecht</name>
        </author>
        <link rel="alternate" href="https://ogobrecht.com/blog/new-version-of-oracle-table-api-generator-available/" type="text/html"/>
        <id>https://ogobrecht.com/blog/new-version-of-oracle-table-api-generator-available/</id>
        
            <content type="html">&lt;p&gt;Short before Christmas André and I released version 0.6.0 of our &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;OraMUC&#x2F;table-api-generator&quot;&gt;table API generator&lt;&#x2F;a&gt;. The last release was exactly two years ago - time flies. This blog post highlights some of the changes - the &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;OraMUC&#x2F;table-api-generator&#x2F;blob&#x2F;master&#x2F;docs&#x2F;changelog.md#060-2020-12-20&quot;&gt;complete changelog is available on GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bulk-processing&quot;&gt;Bulk Processing&lt;&#x2F;h2&gt;
&lt;p&gt;When you split your app over multiple schemas for higher data security you might need at some point the possibility to bulk process your data. Imagine the following, common schema setup (also see this nice &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=OF7qR5lAmiw&quot;&gt;video by Connor McDonald&lt;&#x2F;a&gt;, 20 minutes):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Data Schema: Holds your tables and provides table APIs for the other schemas, which have only select rights on the tables (or views) and execute rights on the table APIs&lt;&#x2F;li&gt;
&lt;li&gt;API Schema: Holds your business logic and provides business APIs to the app parsing schema&lt;&#x2F;li&gt;
&lt;li&gt;UI Schema: Has no own objects, only connect rights and is used as the parsing schema to run the application&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This setup follows the principle of the least privilege. When you need to bulk process your data in the business logic (API schema), then you have a problem without bulk processing facilities in your table APIs. You need to implement business logic in the data schema or you grant update and&#x2F;or delete rights to the API schema. The first solution is against the separation of concerns and the second one lowers your data security and maybe prevents you from not having triggers (more about this later in the audit columns section).&lt;&#x2F;p&gt;
&lt;p&gt;That is why we have now also bulk processing in the core of our generated table APIs. Here is how you can use it in your business logic:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;* EXAMPLE INSERT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;To keep the memory usage low we break our inserts into&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;a bulk size of 1000 rows. You should adapt the bulk size&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment z-punctuation z-definition z-comment&quot;&gt;to your use case. *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;declare&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  l_rows_tab     data_schema.your_table_api.t_rows_tab;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  l_number_bulks &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 100&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  l_bulk_size    &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1000&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;begin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  l_rows_tab :&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; data_schema.your_table_api.t_rows_tab&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  l_rows_tab.extend(l_bulk_size);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;  &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;number_bulks&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; z &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; .. l_number_bulks &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;loop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;    &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;bulk_size&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; .. l_bulk_size &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;loop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      l_rows_tab(i).column_1 :&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; your_logic_here;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      l_rows_tab(i).column_2 :&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; your_logic_here;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    end loop&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bulk_size;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    data_schema.your_table_api.create_rows(l_rows_tab);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    commit&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end loop&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; number_bulks;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;* EXAMPLE UPDATE *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;declare&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  l_rows_tab   data_schema.your_table_api.t_rows_tab;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  l_ref_cursor data_schema.your_table_api.t_strong_ref_cursor;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;begin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  -- optionally set bulk limit, default is 1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  -- data_schema.your_table_api.set_bulk_limit(500);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  open&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; l_ref_cursor &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;for&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    select&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; app_users &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;where&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; your_conditions_here;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;  &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;outer_bulk&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  loop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    l_rows_tab :&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; data_schema.your_table_api.read_rows(l_ref_cursor);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;    &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;inner_data&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; .. l_rows_tab.count&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    loop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      --do your business logic here&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      l_rows_tab(i).column_1 :&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; your_logic_here;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    end loop&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; inner_data;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    data_schema.your_table_api.update_rows(l_rows_tab);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    commit&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    exit &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;when&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; data_schema.your_table_api.bulk_is_complete;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end loop&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; outer_bulk;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  close&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; l_ref_cursor;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The bulk deletion works the same way as the bulk update - the difference is that you do not modify your data before calling the &lt;code&gt;delete_rows&lt;&#x2F;code&gt; method.&lt;&#x2F;p&gt;
&lt;p&gt;For more examples see the docs:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;OraMUC&#x2F;table-api-generator&#x2F;blob&#x2F;master&#x2F;docs&#x2F;bulk-processing.md&quot;&gt;Basic usage&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;OraMUC&#x2F;table-api-generator&#x2F;blob&#x2F;master&#x2F;docs&#x2F;bulk-processing-performance.md&quot;&gt;Performance tests&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;support-for-audit-columns&quot;&gt;Support for Audit Columns&lt;&#x2F;h2&gt;
&lt;p&gt;Keeping the bulk processing in mind for performance reasons it is a bad idea to have triggers only to manage audit columns in a table. If you have your tables in an own schema and the business logic and the app cannot directly write to the tables then it is easy to prevent triggers. Therefore the table APIs need to support that and hides the audit columns for insert or update operations. This is what our generator now supports.&lt;&#x2F;p&gt;
&lt;p&gt;You can map your specific audit column names to the four often used names &lt;code&gt;created&lt;&#x2F;code&gt;, &lt;code&gt;created_by&lt;&#x2F;code&gt;, &lt;code&gt;updated&lt;&#x2F;code&gt; and &lt;code&gt;updated_by&lt;&#x2F;code&gt; by providing a mapping string to the new parameter &lt;code&gt;p_audit_column_mappings&lt;&#x2F;code&gt; - an example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;-- TABLE DEFINITION --&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;create table&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; app_users&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  au_id          &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;integer            generated always as identity&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  au_first_name  &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;varchar2&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; char&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)                         ,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  au_last_name   &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;varchar2&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; char&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)                         ,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  au_email       &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;varchar2&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;30&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; char&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)               &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;not null&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;  ,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  au_active_yn   &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;varchar2&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; char&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)   &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;Y&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;  not null&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;  ,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  -- This is only for demo purposes. In reality we expect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  -- more unified names and types for audit columns.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  au_created_on  &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;date                            not null&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;  ,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  au_created_by  &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;char&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; char&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)                   &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;not null&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;  ,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  au_updated_at  &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;timestamp                       not null&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;  ,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  au_updated_by  &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;varchar2&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; char&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)               &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;not null&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;  ,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;  --&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  primary key&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (au_id),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  unique&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (au_email),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  check&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (au_active_yn &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Y&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;N&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;begin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  om_tapigen.compile_api(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    p_table_name            &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;APP_USERS&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    p_audit_column_mappings &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;created=#PREFIX#_CREATED_ON, created_by=#PREFIX#_CREATED_BY, updated=#PREFIX#_UPDATED_AT, updated_by=#PREFIX#_UPDATED_BY&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;#PREFIX#&lt;&#x2F;code&gt; in our example is optional (determined automatically by the generator) and replaced with the found column_prefix &lt;code&gt;au&lt;&#x2F;code&gt;. Doing it this way you can provide always the same audit column mapping to all of your tables. I know some people hate column prefixes - but if you design your data models this way the generator can save you the work to align the mapping for each table.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;support-for-a-row-version-column&quot;&gt;Support for a Row Version Column&lt;&#x2F;h2&gt;
&lt;p&gt;The same reasons with triggers for the audit columns are valid for the support of a row version column. This can also be handled by our generator:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;begin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  om_tapigen.compile_api(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    p_table_name                 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;YOUR_TABLE&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    p_row_version_column_mapping &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;#PREFIX#_VERSION_ID=tag_global_version_sequence.nextval&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can also see here the before mentioned &lt;code&gt;#PREFIX#&lt;&#x2F;code&gt; substitution. The difference is that you define here only your column and for the column the SQL expression which should be used for the row version column - in this case, a sequence.&lt;&#x2F;p&gt;
&lt;p&gt;What we cannot do here is to add always 1 to the previous value like it is possible in a trigger - the table API has no idea what the previous value was. So, we are a little bit limited to a SQL expression but the point is, you can let the generated API manage the row version column without having a trigger.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tenant-support&quot;&gt;Tenant Support&lt;&#x2F;h2&gt;
&lt;p&gt;This is the third new column mapping definition. For all people who have not an enterprise version with the VPD (virtual private database) functionality you can define a tenant expression for one of your columns:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;begin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  om_tapigen.compile_api(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    p_table_name            &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;YOUR_TABLE&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    p_tenant_column_mapping &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;#PREFIX#_TENANT_ID=to_number(sys_context(&amp;#39;&amp;#39;my_sec_ctx&amp;#39;&amp;#39;,&amp;#39;&amp;#39;my_tenant_id&amp;#39;&amp;#39;))&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For more information see the &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;OraMUC&#x2F;table-api-generator&#x2F;blob&#x2F;master&#x2F;docs&#x2F;parameters.md#p_tenant_column_mapping-since-v060&quot;&gt;parameter docs for p_tenant_column_mapping&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;more&quot;&gt;More&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;A new optional 1:1 view can be generated (new parameter &lt;code&gt;p_enable_one_to_one_view&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;All generated object names can now be customized (new parameters &lt;code&gt;p_dml_view_name&lt;&#x2F;code&gt;, &lt;code&gt;p_dml_view_trigger_name&lt;&#x2F;code&gt; and &lt;code&gt;p_one_to_one_view_name&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Double quoting of table and column names in the generated code can now be configured (new parameter &lt;code&gt;p_double_quote_names&lt;&#x2F;code&gt;, default true)&lt;&#x2F;li&gt;
&lt;li&gt;A new helper function &lt;code&gt;get_default_row&lt;&#x2F;code&gt; will be generated, when parameter &lt;code&gt;p_enable_column_defaults&lt;&#x2F;code&gt; is set to true (to support the row based create_row function)&lt;&#x2F;li&gt;
&lt;li&gt;We have now unit tests driven by utPLSQL (it will be a permanent task to improve the tests with every new feature or bugfix)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking Changes&lt;&#x2F;h2&gt;
&lt;p&gt;Where there is light, there is also shadow.&lt;&#x2F;p&gt;
&lt;p&gt;All the new features like bulk processing and audit column support make it hard, if not impossible, to generate a generic change log during the row processing. Also the check, if we have a modification and omit an update if not necessary is hard to implement and not good for the performance with the evolved generator. So we skipped the mentioned functionality.&lt;&#x2F;p&gt;
&lt;p&gt;As far as we know not many people use the generic changelog. If you do, you have to stick with the previous generator version or you have to find an alternative way to do it in the future. A good way seems to be the use of the Flashback Data Archive as it is performant and available in all database editions for free - and you can load existing data into the archive (see Tims article below):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Blog post by Connor McDonald: &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blogs.oracle.com&#x2F;oraclemagazine&#x2F;a-fresh-look-at-auditing-row-changes&quot;&gt;Triggers can provide auditing information, but there’s a future in flashback&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Blog post by Tim Hall: &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;oracle-base.com&#x2F;articles&#x2F;12c&#x2F;flashback-data-archive-fda-enhancements-12cr1&quot;&gt;Flashback Data Archive (FDA) Enhancements in Oracle Database 12c Release 1 (12.1)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Video by Connor McDonald: &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=qIs2UPIodQg&quot;&gt;Flashback Data Archive&lt;&#x2F;a&gt; (14 minutes)&lt;&#x2F;li&gt;
&lt;li&gt;Video APEX Connect 2020 by Connor McDonald: &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=gqX91080r7A&quot;&gt;Flashback – so much more&lt;&#x2F;a&gt; (47 minutes)&lt;&#x2F;li&gt;
&lt;li&gt;Video AskTOM Office Hours by Chris Saxon: &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=q81_UDnEpIs&quot;&gt;The Incredible Flashback Data Archive&lt;&#x2F;a&gt; (53 minutes)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And the last Breaking change is, that you need at least Oracle DB 12.1 or higher. That should (hopefully) no problem for the most projects.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;A big THANK YOU to all contributors - the current version of the generator would not be possible without your feedback and help.&lt;&#x2F;p&gt;
&lt;p&gt;Be sure to test the new generator before migrating to it. We use it already in some projects and it should be pretty stable. Nevertheless, with so many changed things we cannot give you a guarantee for every edge case - by using it you accept the MIT license. Please check out the &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;OraMUC&#x2F;table-api-generator&quot;&gt;project page at GitHub&lt;&#x2F;a&gt; and &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;OraMUC&#x2F;table-api-generator&#x2F;issues&#x2F;new&#x2F;choose&quot;&gt;open an issue&lt;&#x2F;a&gt; if you encounter a problem.&lt;&#x2F;p&gt;
&lt;p&gt;A happy new year and happy coding :-)&lt;&#x2F;p&gt;
&lt;p&gt;Ottmar&lt;&#x2F;p&gt;
</content>
        <summary type="html">Bulk processing, support for audit and row version columns and more</summary>
        </entry><entry xml:lang="en">
        <title>Table API Generator v0.5.0 Available</title>
        <published>2018-12-26T00:00:00+00:00</published>
        <updated>2018-12-26T00:00:00+00:00</updated>
        <author>
            <name>Ottmar Gobrecht</name>
        </author>
        <link rel="alternate" href="https://ogobrecht.com/blog/table-api-generator-v0-5-0-available/" type="text/html"/>
        <id>https://ogobrecht.com/blog/table-api-generator-v0-5-0-available/</id>
        
            <content type="html">&lt;p&gt;Short before Christmas André and I released version 0.5.0 of our &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;OraMUC&#x2F;table-api-generator&quot;&gt;PL&#x2F;SQL table API generator&lt;&#x2F;a&gt;. It took a long time to come to this point. One of the reasons behind was the fact that we had to rework some internals to support feature wishes from the community. Here the most important features of the new version:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Support for multicolumn primary keys&lt;&#x2F;li&gt;
&lt;li&gt;Support for 12c long identifier names&lt;&#x2F;li&gt;
&lt;li&gt;More control over the API features and name (10 new parameters)&lt;&#x2F;li&gt;
&lt;li&gt;Insert methods:
&lt;ul&gt;
&lt;li&gt;Can have the dictionary column defaults&lt;&#x2F;li&gt;
&lt;li&gt;Can return the whole row instead of the primary key&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;You can exclude columns (e.g. audit columns) for inserts and updates&lt;&#x2F;li&gt;
&lt;li&gt;Improved template engine:
&lt;ul&gt;
&lt;li&gt;Generated code better readable because of formatted parameter lists&lt;&#x2F;li&gt;
&lt;li&gt;Tables with many columns no longer breaking character limits&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Special methods for testing and dummy data generation&lt;&#x2F;li&gt;
&lt;li&gt;Also see the &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;OraMUC&#x2F;table-api-generator&#x2F;blob&#x2F;master&#x2F;docs&#x2F;changelog.md#050-2018-12-23&quot;&gt;full changelog on the project site&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Happy new year and happy coding :-)&lt;&#x2F;p&gt;
&lt;p&gt;Ottmar&lt;&#x2F;p&gt;
</content>
        <summary type="html">Long changelog and took a long time </summary>
        </entry><entry xml:lang="en">
        <title>Table API Generator</title>
        <published>2016-06-10T00:00:00+00:00</published>
        <updated>2016-06-10T00:00:00+00:00</updated>
        <author>
            <name>Ottmar Gobrecht</name>
        </author>
        <link rel="alternate" href="https://ogobrecht.com/blog/table-api-generator/" type="text/html"/>
        <id>https://ogobrecht.com/blog/table-api-generator/</id>
        
            <content type="html">&lt;p&gt;Last year I needed for a project a simple table API, which is able to generate a generic change log - something like “show me for table xyz which column was changed when and what was the old value and what is the new one”. Only changed values should be stored and all tables should log into the same generic logging table. Sounds like we need a generator for this.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately there was no time in the project to create such a generator from the ground. Luckily André, a colleague of me, had started to implement such an API generator in his free time and I had only to implement the generic change log functionality - also in my free time. Our API generator open source project was born :-)&lt;&#x2F;p&gt;
&lt;p&gt;Later on I needed a function to get the id from an record by the unique columns - next feature for the API generator: generate a (overloaded) function for each unique constraint on a table. Now it is a simple function call to get the id:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;your_var :&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; your_table_name_api.get_pk_by_unique_cols(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    p_column_name_1 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;xyz&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    p_column_name_2 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 123&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    ...);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The API is also handling the case, when no data is found and everything without the need to look in the dictionary for the unique columns of that table or to write boilerplate code and possibly forget one column.&lt;&#x2F;p&gt;
&lt;p&gt;The next thing for APEX was “For tabular forms you can’t use APIs”. We came up with the idea to generate a view for each table with an instead of trigger for inserts, updates and deletions. The trigger is simply calling the API. Now you can use APEX own “automatic row processing” and the generic logging together.&lt;&#x2F;p&gt;
&lt;p&gt;In my holiday this spring I stumbled over a tweet from Phillip Salvisberg about his &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.oddgen.org&quot;&gt;oddgen project&lt;&#x2F;a&gt;, a SQL Developer extension to invoke dictionary-driven code generators. I was thrilled, we can have a SQL Developer integration by writing a small PL&#x2F;SQL wrapper for oddgen. I finished the integration in my holiday, I could not wait.&lt;&#x2F;p&gt;
&lt;p&gt;Over the time we found out, that the generation of the thin API wrappers for our tables saves us time and makes our code more stable and readable because of the saved boilerplate code.
Business logic packages becomes invalid after table changes and API regeneration. This is good, because you can see, which API calls are now invalid. If you have simple insert or update statements you might oversee some places, where the statement is still valid for example with an added table column, but in fact does the wrong insert or update.&lt;&#x2F;p&gt;
&lt;p&gt;And the last thing, what is now possible: Security - separate the data from the user interface. Simply grant execute rights on the API and business logic packages to the UI schema and disable the deletion of rows in your API packages when you don’t need it. No user will be able to drop or truncate your tables, because there are no tables in the UI schema.&lt;&#x2F;p&gt;
&lt;p&gt;The generated API packages are really thin - nothing special at all. Nevertheless they are powerful time savers.&lt;&#x2F;p&gt;
&lt;p&gt;You can find the sources and more informations on &lt;a class=&quot;external&quot; rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;OraMUC&#x2F;table-api-generator&quot;&gt;GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Happy coding :-)&lt;&#x2F;p&gt;
&lt;p&gt;Ottmar&lt;&#x2F;p&gt;
</content>
        <summary type="html">An Oracle PL&#x2F;SQL package with SQL Developer integration</summary>
        </entry>
</feed>
