<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Abdul Yadi&#039;s Blog</title>
	<atom:link href="https://abdulyadi.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://abdulyadi.wordpress.com</link>
	<description>once upon a time in Batam</description>
	<lastBuildDate>Tue, 07 Apr 2020 11:16:34 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<site xmlns="com-wordpress:feed-additions:1">5629914</site><cloud domain='abdulyadi.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>https://s0.wp.com/i/buttonw-com.png</url>
		<title>Abdul Yadi&#039;s Blog</title>
		<link>https://abdulyadi.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="https://abdulyadi.wordpress.com/osd.xml" title="Abdul Yadi&#039;s Blog" />
	<atom:link rel='hub' href='https://abdulyadi.wordpress.com/?pushpress=hub'/>
	<item>
		<title>Parallel Query Inside Function</title>
		<link>https://abdulyadi.wordpress.com/2020/04/07/parallel-query-inside-function/</link>
					<comments>https://abdulyadi.wordpress.com/2020/04/07/parallel-query-inside-function/#comments</comments>
		
		<dc:creator><![CDATA[abdulyadi]]></dc:creator>
		<pubDate>Tue, 07 Apr 2020 09:36:47 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=706</guid>

					<description><![CDATA[Parallel query is a big help for large amount of data retrieval. On my project using PostgreSQL 12.2, I found that the feature is enabled in plain SQL but disabled inside PLPGSQL or even SQL function. For years, I rely on user defined function for some considerations. First, to hide sql structure details from front &#8230;<p><a href="https://abdulyadi.wordpress.com/2020/04/07/parallel-query-inside-function/" class="more-link">Read More</a></p>]]></description>
										<content:encoded><![CDATA[<p>Parallel query is a big help for large amount of data retrieval. On my project using PostgreSQL 12.2, I found that the feature is enabled in plain SQL but disabled inside PLPGSQL or even SQL function. For years, I rely on user defined function for some considerations. First, to hide sql structure details from front end logic so that (as long as function declaration does not change) the change in internal query statements does not require front-end code rewriting. Second, it is easier to grant execution of function to group or login role while keep tables private rather than assign specific access for any single tables involved in query. How to make parallel query enabled inside function?</p>
<p>I have PostgreSQL 12.2 in my CentOS-7 laptop and create a table with single column:<br />
<code>create table public.test (mark integer not null);</code></p>
<p>Populate with ten million random numbers:<br />
<code>insert into public.test select (random() * 100)::integer from generate_series(1,10000000);</code></p>
<p>Update statistics:<br />
<code>analyze public.test;</code></p>
<p>Parallel query configuration setting is default:<br />
<code>show max_parallel_workers_per_gather;<br />
2</code></p>
<h2>Play with Query</h2>
<p>Think of building histogram with 4 bins (25, 50, 75 and 100), let us check query performance using plain SQL versus PLPGSQL and SQL function (query structure here is just an example and you may have better one).</p>
<h4>Plain SQL</h4>
<p><code>select 25 as bin, count(*) as freq, avg(mark) from public.test where mark between 0 and 25<br />
union<br />
select 50, count(*), avg(mark) from public.test where mark between 26 and 50<br />
union<br />
select 75, count(*), avg(mark) from public.test where mark between 51 and 75<br />
union<br />
select 100, count(*), avg(mark) from public.test where mark between 76 and 100<br />
order by 1;<br />
 bin |  freq   |         avg<br />
-----+---------+---------------------<br />
  25 | 2548432 | 12.7408167061157606<br />
  50 | 2501760 | 37.9986689370683039<br />
  75 | 2496096 | 63.0057958508006102<br />
 100 | 2453712 | 87.7504262928982700<br />
(4 rows)</p>
<p>Time: 1917.847 ms (00:01.918)</code></p>
<p>Runs for 1.9 seconds. Explain the query plan in graphics and see that parallel query works:<br />
<img data-attachment-id="735" data-permalink="https://abdulyadi.wordpress.com/2020/04/07/parallel-query-inside-function/sqlplan/" data-orig-file="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlplan-2.png" data-orig-size="1034,360" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sqlplan" data-image-description="" data-image-caption="" data-medium-file="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlplan-2.png?w=300" data-large-file="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlplan-2.png?w=545" src="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlplan-2.png?w=545" alt="Query Plan"  class="aligncenter size-large wp-image-735" srcset="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlplan-2.png?w=400 400w, https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlplan-2.png?w=800 800w, https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlplan-2.png?w=150 150w, https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlplan-2.png?w=300 300w, https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlplan-2.png?w=768 768w" sizes="(max-width: 400px) 100vw, 400px" /></p>
<h4>PLPGSQL Function</h4>
<p><code>create or replace function public.markstat_plpgsql(OUT bin integer, OUT freq bigint, OUT avg numeric)<br />
  returns setof record as<br />
$body$<br />
begin<br />
return query<br />
select 25 as bin, count(*) as freq, avg(mark) from public.test where mark between 0 and 25<br />
union<br />
select 50, count(*), avg(mark) from public.test where mark between 26 and 50<br />
union<br />
select 75, count(*), avg(mark) from public.test where mark between 51 and 75<br />
union<br />
select 100, count(*), avg(mark) from public.test where mark between 76 and 100<br />
order by 1;<br />
end;<br />
$body$<br />
  language plpgsql stable;</code></p>
<p><code>select * from public.markstat_plpgsql();<br />
 bin |  freq   |         avg<br />
-----+---------+---------------------<br />
  25 | 2548432 | 12.7408167061157606<br />
  50 | 2501760 | 37.9986689370683039<br />
  75 | 2496096 | 63.0057958508006102<br />
 100 | 2453712 | 87.7504262928982700<br />
(4 rows)</p>
<p>Time: 3444.977 ms (00:03.445)</code></p>
<p><strong>The same result with longer run 3.4 seconds (1.8 times slower than plain SQL version).</strong></p>
<h4>SQL Function</h4>
<p><code>create or replace function public.markstat_sql(OUT bin integer, OUT freq bigint, OUT avg numeric)<br />
  returns setof record as<br />
$body$<br />
select 25 as bin, count(*) as freq, avg(mark) from public.test where mark between 0 and 25<br />
union<br />
select 50, count(*), avg(mark) from public.test where mark between 26 and 50<br />
union<br />
select 75, count(*), avg(mark) from public.test where mark between 51 and 75<br />
union<br />
select 100, count(*), avg(mark) from public.test where mark between 76 and 100<br />
order by 1;<br />
$body$<br />
  language sql stable;</code></p>
<p><code>select * from public.markstat_sql();<br />
 bin |  freq   |         avg<br />
-----+---------+---------------------<br />
  25 | 2548432 | 12.7408167061157606<br />
  50 | 2501760 | 37.9986689370683039<br />
  75 | 2496096 | 63.0057958508006102<br />
 100 | 2453712 | 87.7504262928982700<br />
(4 rows)</p>
<p>Time: 3448.760 ms (00:03.449)</code></p>
<p><strong>3.4 seconds, almost as slow as PLPGSQL version</strong>.</p>
<h2>Discussion</h2>
<p>Plain SQL: 1.9 seconds<br />
PLPGSQL function: 3.4 seconds<br />
SQL function: 3.4 seconds</p>
<p>Why query runs in function is slower? CPU usage graph below clears up the situation.<br />
<img data-attachment-id="766" data-permalink="https://abdulyadi.wordpress.com/2020/04/07/parallel-query-inside-function/sqlcpu/" data-orig-file="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu.png" data-orig-size="657,186" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sqlcpu" data-image-description="" data-image-caption="" data-medium-file="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu.png?w=300" data-large-file="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu.png?w=545" src="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu.png?w=545" alt="SQL CPU Usage"  class="aligncenter size-large wp-image-766" srcset="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu.png?w=400 400w, https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu.png?w=150 150w, https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu.png?w=300 300w, https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu.png 657w" sizes="(max-width: 400px) 100vw, 400px" /><br />
With plain SQL (1), all of the CPU works indicating parallel query. While PLPGSQL (2) and SQL (3) functions only run on single CPU, not a parallel query.</p>
<p>Not much I can do with SQL function since the query structure is already exactly the same as the plain one. It looks like I can do more with PLPGSQL function. How if instead of &#8216;RETURN QUERY&#8217; the heavy query directly, the result set is saved into temporary array in memory then export it out once finished.</p>
<p>Create composite type for temporary array:<br />
<code>create type public.stat AS (bin integer, freq bigint, avg numeric);</code></p>
<p>Create second PLPGSQL function version, call it public.markstat_plpgsql2.<br />
<code>create or replace function public.markstat_plpgsql2(OUT bin integer, OUT freq bigint, OUT avg numeric)<br />
  returns setof record as<br />
$body$<br />
declare<br />
	_stats public.stat[];<br />
begin<br />
select array_agg(t) into _stats from (<br />
select 25 as bin, count(*) as freq, avg(mark) from public.test where mark between 0 and 25<br />
union<br />
select 50, count(*), avg(mark) from public.test where mark between 26 and 50<br />
union<br />
select 75, count(*), avg(mark) from public.test where mark between 51 and 75<br />
union<br />
select 100, count(*), avg(mark) from public.test where mark between 76 and 100<br />
) t;<br />
return query select s.bin, s.freq, s.avg from unnest(_stats) s order by s.bin;<br />
end;<br />
$body$<br />
  language plpgsql stable;</code></p>
<p><code>select * from public.markstat_plpgsql2();<br />
 bin |  freq   |         avg<br />
-----+---------+---------------------<br />
  25 | 2548432 | 12.7408167061157606<br />
  50 | 2501760 | 37.9986689370683039<br />
  75 | 2496096 | 63.0057958508006102<br />
 100 | 2453712 | 87.7504262928982700<br />
(4 rows)</p>
<p>Time: 2063.029 ms (00:02.063)</code></p>
<p><strong>Now, it is about 2.1 seconds, close to the fastest plain SQL 1.9 seconds.</strong></p>
<p>Please take a look on CPU usage graph below:<br />
<img data-attachment-id="777" data-permalink="https://abdulyadi.wordpress.com/2020/04/07/parallel-query-inside-function/sqlcpu-2/" data-orig-file="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu-1.png" data-orig-size="655,189" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="sqlcpu" data-image-description="" data-image-caption="" data-medium-file="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu-1.png?w=300" data-large-file="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu-1.png?w=545" src="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu-1.png?w=545" alt="SQL CPU Usage"  class="aligncenter size-large wp-image-777" srcset="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu-1.png?w=400 400w, https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu-1.png?w=150 150w, https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu-1.png?w=300 300w, https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu-1.png 655w" sizes="(max-width: 400px) 100vw, 400px" /></p>
<p>Number 1, 2 and 3 are plain SQL, PLPGSQL function and SQL function, respectively. While number 4 is for my newly crafted PLPGSQL function called public.markstat_plpgsql2, runs on multiple CPU, parallel query is back.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://abdulyadi.wordpress.com/2020/04/07/parallel-query-inside-function/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">706</post-id>
		<media:content url="https://1.gravatar.com/avatar/da81f4cbd1a6974053ebad2a0d12754bc3e60f9f9a899d47b00020f827d0a59d?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>

		<media:content url="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlplan-2.png?w=400" medium="image">
			<media:title type="html">Query Plan</media:title>
		</media:content>

		<media:content url="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu.png?w=400" medium="image">
			<media:title type="html">SQL CPU Usage</media:title>
		</media:content>

		<media:content url="https://abdulyadi.wordpress.com/wp-content/uploads/2020/04/sqlcpu-1.png?w=400" medium="image">
			<media:title type="html">SQL CPU Usage</media:title>
		</media:content>
	</item>
		<item>
		<title>Extension for String Translation</title>
		<link>https://abdulyadi.wordpress.com/2020/02/01/extension-for-string-translation/</link>
					<comments>https://abdulyadi.wordpress.com/2020/02/01/extension-for-string-translation/#respond</comments>
		
		<dc:creator><![CDATA[abdulyadi]]></dc:creator>
		<pubDate>Sat, 01 Feb 2020 08:23:27 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=698</guid>

					<description><![CDATA[PostgreSQL provides a built-in function for character wise string replacement: select translate('abcdefghijkl', 'ace', '123'); translate -------------- 1b2d3fghijkl pgstrtranslate extends it with multi-character replacement. It takes 4 arguments and returning a text. CREATE OR REPLACE FUNCTION public.pgstrtranslate( &#160;&#160;&#160;&#160;fullsearch boolean, &#160;&#160;&#160;&#160;t text, &#160;&#160;&#160;&#160;search text[], &#160;&#160;&#160;&#160;replacement text[]) &#160;&#160;RETURNS text AS '$libdir/pgstrtranslate', 'pgstrtranslate' &#160;&#160;&#160;&#160;LANGUAGE c IMMUTABLE STRICT; How it &#8230;<p><a href="https://abdulyadi.wordpress.com/2020/02/01/extension-for-string-translation/" class="more-link">Read More</a></p>]]></description>
										<content:encoded><![CDATA[<p>PostgreSQL provides a built-in function for character wise string replacement:<br />
<code>select translate('abcdefghijkl', 'ace', '123');<br />
  translate<br />
--------------<br />
 1b2d3fghijkl</code></p>
<p><b>pgstrtranslate</b> extends it with multi-character replacement. It takes 4 arguments and returning a text.<br />
<code>CREATE OR REPLACE FUNCTION public.pgstrtranslate(<br />
&nbsp;&nbsp;&nbsp;&nbsp;fullsearch boolean,<br />
&nbsp;&nbsp;&nbsp;&nbsp;t text,<br />
&nbsp;&nbsp;&nbsp;&nbsp;search text[],<br />
&nbsp;&nbsp;&nbsp;&nbsp;replacement text[])<br />
&nbsp;&nbsp;RETURNS text AS<br />
'$libdir/pgstrtranslate', 'pgstrtranslate'<br />
&nbsp;&nbsp;&nbsp;&nbsp;LANGUAGE c IMMUTABLE STRICT;</code></p>
<h1>How it works</h1>
<h2>Non-fullsearch replacement:</h2>
<p><code>select pgstrtranslate(false, --non-fullsearch<br />
&nbsp;&nbsp;&nbsp;&nbsp;'abcdefghijkl', --original string<br />
&nbsp;&nbsp;&nbsp;&nbsp;array['ab', 'efg', '2cd']::text[], --array of searchs<br />
&nbsp;&nbsp;&nbsp;&nbsp;array['012', '3', '78']::text[]); --array of replacement<br />
  translate<br />
--------------<br />
 012cd3hijkl</code><br />
&#8216;<b>ab</b>cd<b>efg</b>hijkl&#8217; -&gt; &#8216;<b>012</b>cd<b>3</b>hijkl&#8217;<br />
Note that &#8216;2cd&#8217; does not match original string.</p>
<h2>Fullsearch replacement:</h2>
<p><code>select pgstrtranslate(true, --fullsearch<br />
&nbsp;&nbsp;&nbsp;&nbsp;'abcdefghijkl', --original string<br />
&nbsp;&nbsp;&nbsp;&nbsp;array['ab', 'efg', '2cd']::text[], --array of searchs<br />
&nbsp;&nbsp;&nbsp;&nbsp;array['012', '3', '78']::text[]); --array of replacement<br />
  translate<br />
--------------<br />
 01783hijkl</code><br />
Replace &#8216;ab&#8217; with &#8216;012&#8217;: &#8216;<b>ab</b>cdefghijkl&#8217; -&gt; &#8216;<b>012</b>cdefghijkl&#8217;<br />
Replace &#8216;efg&#8217; with &#8216;3&#8217;: &#8216;012cd<b>efg</b>hijkl&#8217; -&gt; &#8216;012cd<b>3</b>hijkl&#8217;<br />
Replace &#8216;2cd&#8217; with &#8217;78&#8217;: &#8217;01<b>2cd</b>3hijkl&#8217; -&gt; &#8217;01<b>78</b>3hijkl&#8217;</p>
<h1>How to install</h1>
<ol>
<li>Clone or download source code from <a href="https://github.com/AbdulYadi/pgstrtranslate.git" rel="nofollow">https://github.com/AbdulYadi/pgstrtranslate.git</a>. Extract it.</li>
<li>If necessary, modify PG_CONFIG path according to your specific PostgreSQL installation location.</li>
<li>Build as usual:</li>
<p><code>$ make<br />
$ make install</code></p>
<li>On successful compilation, install this extension in PostgreSQL environment:</li>
<p><code>$ create extension pgstrtranslate;</code>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>https://abdulyadi.wordpress.com/2020/02/01/extension-for-string-translation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">698</post-id>
		<media:content url="https://1.gravatar.com/avatar/da81f4cbd1a6974053ebad2a0d12754bc3e60f9f9a899d47b00020f827d0a59d?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>Reinforce Data Validation: Prevent Direct Table Modification</title>
		<link>https://abdulyadi.wordpress.com/2019/12/26/reinforce-data-validation-prevent-direct-table-modification/</link>
					<comments>https://abdulyadi.wordpress.com/2019/12/26/reinforce-data-validation-prevent-direct-table-modification/#respond</comments>
		
		<dc:creator><![CDATA[abdulyadi]]></dc:creator>
		<pubDate>Thu, 26 Dec 2019 12:16:52 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=668</guid>

					<description><![CDATA[Simple validation for tuple modification (insert/update/delete) is by applying constraints. More complex validation can be forced through trigger which is considered expensive by database experts. The more efficient approach is by implementing validation in user defined function. Superuser prevents regular users from issuing INSERT/UPDATE/DELETE directly to table by revoking their privileges. They must invoke provided &#8230;<p><a href="https://abdulyadi.wordpress.com/2019/12/26/reinforce-data-validation-prevent-direct-table-modification/" class="more-link">Read More</a></p>]]></description>
										<content:encoded><![CDATA[<p>Simple validation for tuple modification (insert/update/delete) is by applying constraints. More complex validation can be forced through trigger which is considered expensive by database experts.</p>
<p>The more efficient approach is by implementing validation in user defined function. Superuser prevents regular users from issuing INSERT/UPDATE/DELETE directly to table by revoking their privileges. They must invoke provided function to perform those tasks.</p>
<p>But, if you are the function programmer or superuser, the biggest enemy is yourself. You can easily bypass the function, modify table directly and break validation rule that you have set.</p>
<p>I have written additional functionality in PostgreSQL version 12.1 version backend to prevent regular user and even superuser from modifying directly table created with &#8220;private_modify&#8221; option. He or she should call SQL, PLPGSQL or other SPI-based function to do that.<br />
<code><br />
CREATE TABLE public.regular (id integer NOT NULL, label text NOT NULL);<br />
CREATE TABLE public.test (id integer NOT NULL, label text NOT NULL)<br />
&nbsp;&nbsp;WITH(private_modify=true);<br />
</code></p>
<p>Check table options in system table:<br />
<code><br />
SELECT n.nspname, relname, reloptions<br />
FROM pg_class c<br />
INNER JOIN pg_namespace n ON n.oid = c.relnamespace<br />
WHERE c.relname in('regular','test') AND n.nspname='public';</p>
<p>nspname | relname | reloptions<br />
---------+---------+-----------------------<br />
public | regular |<br />
public | test | {private_modify=true}<br />
</code></p>
<p>Insert into public.regular directly and it works as usual.<br />
<code><br />
INSERT INTO public.regular VALUES (1, 'abc');<br />
</code><br />
Now, insert into public.test directly and you will have error message.<br />
<code><br />
INSERT INTO public.test VALUES (1, 'abc');<br />
ERROR: do not modify table with "private modify" option outside SQL, PLPGSQL or other SPI-based function<br />
</code><br />
Anonymous block does not work too<br />
<code><br />
DO $$<br />
BEGIN<br />
&nbsp;&nbsp;&nbsp;&nbsp;INSERT INTO public.test VALUES (1, 'abc');<br />
END$$;<br />
ERROR:  do not modify table with "private modify" option outside SQL, PLPGSQL or other SPI-based function<br />
</code><br />
Update or delete will have the same error message.</p>
<p>So let us create function in SQL language and PLPGSQL language:<br />
<code><br />
CREATE OR REPLACE FUNCTION public.testinsert_sql(i_id integer, t_label text)<br />
RETURNS void AS<br />
$BODY$<br />
&nbsp;&nbsp;&nbsp;&nbsp;/*do necessary validation*/<br />
&nbsp;&nbsp;&nbsp;&nbsp;INSERT INTO public.test (id, "label") VALUES ($1, $2);<br />
$BODY$<br />
LANGUAGE sql VOLATILE SECURITY DEFINER;</p>
<p>CREATE OR REPLACE FUNCTION public.testinsert_plpgsql(i_id integer, t_label text)<br />
RETURNS void AS<br />
$BODY$<br />
BEGIN<br />
&nbsp;&nbsp;&nbsp;&nbsp;/*do necessary validation*/<br />
&nbsp;&nbsp;&nbsp;&nbsp;INSERT INTO public.test (id, "label") VALUES ($1, $2);<br />
RETURN;<br />
END;$BODY$<br />
LANGUAGE plpgsql VOLATILE SECURITY DEFINER;<br />
</code></p>
<p>And use those functions for table modifications without error:<br />
<code><br />
SELECT public.testinsert_sql(1, 'abc');<br />
SELECT public.testinsert_plpgsql(2, 'def');<br />
</code></p>
<p>Check the result:<br />
<code><br />
SELECT * FROM public.test;<br />
id | label<br />
----+-------<br />
1 | abc<br />
2 | def<br />
</code></p>
<p>But, to not interrupt replication agents which set session_replication_role to &#8216;replica&#8217; prior to table modifications (e.g. Slony and Bucardo), such restrictions should be relaxed:<br />
<code><br />
SET session_replication_role TO 'replica';<br />
INSERT INTO public.test VALUES (3, 'ghi');<br />
</code></p>
<h2>How to apply patch and build PostgreSQL</h2>
<ol>
<li>Clone or download patch from <a href="https://github.com/AbdulYadi/postgresql-private" rel="nofollow">https://github.com/AbdulYadi/postgresql-private</a>. Extract as necessary.</li>
<li>Download PostgreSQL version 12.1 from <a href="https://ftp.postgresql.org/pub/source/v12.1/postgresql-12.1.tar.bz2" rel="nofollow">https://ftp.postgresql.org/pub/source/v12.1/postgresql-12.1.tar.bz2</a> or <a href="https://ftp.postgresql.org/pub/source/v12.1/postgresql-12.1.tar.gz" rel="nofollow">https://ftp.postgresql.org/pub/source/v12.1/postgresql-12.1.tar.gz</a>. Extract to your preferred directory.</li>
<li>Apply patch: change directory to the extracted PostgreSQL source code root and run patch -p0 &lt; path-to-downloaded-patch-file.</li>
<li>Build as instructed in PostgreSQL&#8217;s INSTALL file.</li>
</ol>
<h2>Warning</h2>
<p>This patch is still an experiment so do not put into production server.</p>
<h2>Example</h2>
<p>A zoo can only breed maximum of 5 elephants (&#8216;e&#8217;) and 3 tigers (&#8216;t&#8217;).<br />
<code><br />
CREATE TABLE public.zoo<br />
(<br />
&nbsp;&nbsp;&nbsp;&nbsp;id serial NOT NULL,<br />
&nbsp;&nbsp;&nbsp;&nbsp;animal char NOT NULL,<br />
&nbsp;&nbsp;&nbsp;&nbsp;"name" text NOT NULL,<br />
&nbsp;&nbsp;&nbsp;&nbsp;CONSTRAINT zoo_pkey PRIMARY KEY (id),<br />
&nbsp;&nbsp;&nbsp;&nbsp;CONSTRAINT animal_kind CHECK (animal IN ('e','t'))<br />
)<br />
WITH (private_modify=true);<br />
</code></p>
<p>Animal kind can be simply validated by CHECK constraint. Other then &#8216;e&#8217; or &#8216;t&#8217; will be rejected. How about the maximum number constrained without additional book-keeping table. Option &#8220;private_modify&#8221; come to the rescue. Regular user and superuser can no longer directly INSERT/UPDATE/DELETE to public.zoo table. Following user defined function is needed:<br />
<code><br />
CREATE OR REPLACE FUNCTION public.zoo_insert(c_animal char, t_name text)<br />
&nbsp;&nbsp;RETURNS void AS<br />
$BODY$<br />
DECLARE<br />
&nbsp;&nbsp;&nbsp;&nbsp;_count integer;<br />
BEGIN<br />
&nbsp;&nbsp;&nbsp;&nbsp;PERFORM * FROM public.zoo WHERE animal = c_animal FOR UPDATE;--prevent race condition<br />
&nbsp;&nbsp;&nbsp;&nbsp;SELECT COUNT(*) INTO _count FROM public.zoo WHERE animal = c_animal;<br />
&nbsp;&nbsp;&nbsp;&nbsp;IF c_animal = 'e' AND _count &gt;= 5 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RAISE EXCEPTION '5 elephants maximum';<br />
&nbsp;&nbsp;&nbsp;&nbsp;ELSIF c_animal = 't' AND _count &gt;= 3 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RAISE EXCEPTION '3 tigers maximum';<br />
&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;INSERT INTO public.zoo (animal, "name") VALUES (c_animal, t_name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN;<br />
END;$BODY$<br />
&nbsp;&nbsp;LANGUAGE plpgsql VOLATILE SECURITY DEFINER;<br />
GRANT EXECUTE ON FUNCTION public.zoo_insert(char, text) TO public;<br />
</code></p>
<p>Run following command one row at a time to add elephant. Notice that &#8220;ERROR:  5 elephants maximum&#8221; reported on sixth row:<br />
<code><br />
SELECT public.zoo_insert('e', 'el-1');<br />
SELECT public.zoo_insert('e', 'el-2');<br />
SELECT public.zoo_insert('e', 'el-3');<br />
SELECT public.zoo_insert('e', 'el-4');<br />
SELECT public.zoo_insert('e', 'el-5');<br />
SELECT public.zoo_insert('e', 'el-6');/*failing row*/<br />
</code></p>
<p>The same thing for tiger. Fourth row will fail with &#8220;ERROR:  3 tigers maximum&#8221;:<br />
<code><br />
SELECT public.zoo_insert('t', 'ti-1');<br />
SELECT public.zoo_insert('t', 'ti-2');<br />
SELECT public.zoo_insert('t', 'ti-3');<br />
SELECT public.zoo_insert('t', 'ti-4');/*failing row*/<br />
</code></p>
]]></content:encoded>
					
					<wfw:commentRss>https://abdulyadi.wordpress.com/2019/12/26/reinforce-data-validation-prevent-direct-table-modification/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">668</post-id>
		<media:content url="https://1.gravatar.com/avatar/da81f4cbd1a6974053ebad2a0d12754bc3e60f9f9a899d47b00020f827d0a59d?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>pgAdmin3 for PostgreSQL 12.0</title>
		<link>https://abdulyadi.wordpress.com/2019/11/07/pgadmin3-for-postgresql-12-0/</link>
					<comments>https://abdulyadi.wordpress.com/2019/11/07/pgadmin3-for-postgresql-12-0/#comments</comments>
		
		<dc:creator><![CDATA[abdulyadi]]></dc:creator>
		<pubDate>Thu, 07 Nov 2019 04:27:59 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=660</guid>

					<description><![CDATA[Why do I still need pgAdmin3? As of now, pgAdmin4 does not show nested partition table in its object tree view. Since pgAdmin3 LTS repository in bitbucket by BigSQL Development Team is no longer available, I republish it in github: https://github.com/AbdulYadi/pgadmin3 with code fixes for PostgreSQL 12 internal relation field changes: No more relhasoids in &#8230;<p><a href="https://abdulyadi.wordpress.com/2019/11/07/pgadmin3-for-postgresql-12-0/" class="more-link">Read More</a></p>]]></description>
										<content:encoded><![CDATA[<p>Why do I still need pgAdmin3? As of now, pgAdmin4 does not show nested partition table in its object tree view. Since pgAdmin3 LTS repository in bitbucket by BigSQL Development Team is no longer available, I republish it in github: <a href="https://github.com/AbdulYadi/pgadmin3" rel="nofollow">https://github.com/AbdulYadi/pgadmin3</a> with code fixes for PostgreSQL 12 internal relation field changes:</p>
<ol>
<li>No more relhasoids in pg_class.</li>
<li>No more cache_value, is_cycled, is_called in sequence object (since PostgreSQL 11).</li>
<li>No more adsrc in pg_attrdef, it should be calculated as pg_catalog.pg_get_expr(adbin, adrelid) instead.</li>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>https://abdulyadi.wordpress.com/2019/11/07/pgadmin3-for-postgresql-12-0/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">660</post-id>
		<media:content url="https://1.gravatar.com/avatar/da81f4cbd1a6974053ebad2a0d12754bc3e60f9f9a899d47b00020f827d0a59d?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>pgqr: a QR Code Generator</title>
		<link>https://abdulyadi.wordpress.com/2019/01/12/pgqr-a-qr-code-generator/</link>
					<comments>https://abdulyadi.wordpress.com/2019/01/12/pgqr-a-qr-code-generator/#comments</comments>
		
		<dc:creator><![CDATA[abdulyadi]]></dc:creator>
		<pubDate>Sat, 12 Jan 2019 12:23:03 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=648</guid>

					<description><![CDATA[Related with my post: https://abdulyadi.wordpress.com/2015/11/14/extension-for-qr-code-bitmap/. I have repackage the module and available on github: https://github.com/AbdulYadi/pgqr. This project adds 2 functionality to QR code generator from repository https://github.com/swex/QR-Image-embedded: In-memory monochrome bitmap construction (1 bit per pixel). Wrap the whole package as PostgreSQL extension. This project has been compiled successfully in Linux against PostgreSQL version 11. $ make clean &#8230;<p><a href="https://abdulyadi.wordpress.com/2019/01/12/pgqr-a-qr-code-generator/" class="more-link">Read More</a></p>]]></description>
										<content:encoded><![CDATA[<p>Related with my post: <a href="https://abdulyadi.wordpress.com/2015/11/14/extension-for-qr-code-bitmap/">https://abdulyadi.wordpress.com/2015/11/14/extension-for-qr-code-bitmap/</a>. I have repackage the module and available on github: https://github.com/AbdulYadi/pgqr.</p>
<p>This project adds 2 functionality to QR code generator from repository <a href="https://github.com/swex/QR-Image-embedded">https://github.com/swex/QR-Image-embedded</a>:</p>
<ol>
<li>In-memory monochrome bitmap construction (1 bit per pixel).</li>
<li>Wrap the whole package as PostgreSQL extension.</li>
</ol>
<p>This project has been compiled successfully in Linux against PostgreSQL version 11.<br />
$ make clean<br />
$ make<br />
$ make install</p>
<p>On successful compilation, install this extension in PostgreSQL environment<br />
$ create extension pgqr</p>
<p>Function <strong>pgqr</strong> has 4 parameters:</p>
<ol>
<li><strong>t</strong> text: text to be encoded.</li>
<li><strong>correction_level</strong> integer: 0 to 3.</li>
<li><strong>model_number</strong> integer: 0 to 2.</li>
<li><strong>scale</strong> integer: pixels for each dot.</li>
</ol>
<p>Let us create a QR Code<br />
$ select pgqr(&#8216;QR Code with PostgreSQL&#8217;, 0, 0, 4);<br />
The output is a monochrome bitmap ready for display.</p>
<p><img data-attachment-id="658" data-permalink="https://abdulyadi.wordpress.com/image-2/" data-orig-file="https://abdulyadi.wordpress.com/wp-content/uploads/2019/01/image-1.png" data-orig-size="100,100" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-medium-file="https://abdulyadi.wordpress.com/wp-content/uploads/2019/01/image-1.png?w=100" data-large-file="https://abdulyadi.wordpress.com/wp-content/uploads/2019/01/image-1.png?w=100" class="alignnone size-full wp-image-658" src="https://abdulyadi.wordpress.com/wp-content/uploads/2019/01/image-1.png?w=545" alt="image"   /></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://abdulyadi.wordpress.com/2019/01/12/pgqr-a-qr-code-generator/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">648</post-id>
		<media:content url="https://1.gravatar.com/avatar/da81f4cbd1a6974053ebad2a0d12754bc3e60f9f9a899d47b00020f827d0a59d?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>

		<media:content url="https://abdulyadi.wordpress.com/wp-content/uploads/2019/01/image-1.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
		<item>
		<title>pgAdmin3 Adjustment for PostgreSQL 11.0</title>
		<link>https://abdulyadi.wordpress.com/2018/11/03/pgadmin3-adjustment-for-postgresql-11-0/</link>
					<comments>https://abdulyadi.wordpress.com/2018/11/03/pgadmin3-adjustment-for-postgresql-11-0/#comments</comments>
		
		<dc:creator><![CDATA[abdulyadi]]></dc:creator>
		<pubDate>Sat, 03 Nov 2018 06:01:57 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=646</guid>

					<description><![CDATA[What is my favourite PostgreSQL GUI-admin tool? pgAdmin3. I love its light weight user interface and simple navigation. Thanks to BigSQL Development Team for surviving the tool from freeze. With PostgreSQL release 11.0, here is my patch file corresponding catalog table changes: pgadmin3-patch-text-file First, clone pgAdmin3 project: clone git clone https://bitbucket.org/openscg/pgadmin3-lts.git Then, apply the patch: patch &#8230;<p><a href="https://abdulyadi.wordpress.com/2018/11/03/pgadmin3-adjustment-for-postgresql-11-0/" class="more-link">Read More</a></p>]]></description>
										<content:encoded><![CDATA[<p>What is my favourite PostgreSQL GUI-admin tool? pgAdmin3. I love its light weight user interface and simple navigation. Thanks to BigSQL Development Team for surviving the tool from freeze.</p>
<p>With PostgreSQL release 11.0, here is my patch file corresponding catalog table changes: <a href="https://abdulyadi.wordpress.com/wp-content/uploads/2018/11/pgadmin3patch.doc">pgadmin3-patch-text-file</a></p>
<p>First, clone pgAdmin3 project: <strong>clone git clone <a href="https://bitbucket.org/openscg/pgadmin3-lts.git" rel="nofollow">https://bitbucket.org/openscg/pgadmin3-lts.git</a></strong></p>
<p>Then, apply the patch: <strong>patch -p0 -i [patch-text-file]</strong></p>
<p>Oldies but goldies.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://abdulyadi.wordpress.com/2018/11/03/pgadmin3-adjustment-for-postgresql-11-0/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">646</post-id>
		<media:content url="https://1.gravatar.com/avatar/da81f4cbd1a6974053ebad2a0d12754bc3e60f9f9a899d47b00020f827d0a59d?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>pgsocket: Extension for Simple TCP/IP Socket Client</title>
		<link>https://abdulyadi.wordpress.com/2018/09/11/pgsocket-extension-for-simple-socket-client/</link>
					<comments>https://abdulyadi.wordpress.com/2018/09/11/pgsocket-extension-for-simple-socket-client/#respond</comments>
		
		<dc:creator><![CDATA[abdulyadi]]></dc:creator>
		<pubDate>Tue, 11 Sep 2018 02:05:32 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=635</guid>

					<description><![CDATA[pgsocket is an extension for PostgreSQL server to send bytes to remote TCP/IP socket server. For the first version only single function provided for one way data send in bytearray. This extension is compiled in Linux against PostgreSQL version 10. Download source code from https://github.com/AbdulYadi/pgsocket. Build in Linux as usual: $ make clean $ make &#8230;<p><a href="https://abdulyadi.wordpress.com/2018/09/11/pgsocket-extension-for-simple-socket-client/" class="more-link">Read More</a></p>]]></description>
										<content:encoded><![CDATA[<p>pgsocket is an extension for PostgreSQL server to send bytes to remote TCP/IP socket server. For the first version only single function provided for one way data send in bytearray.</p>
<p>This extension is compiled in Linux against PostgreSQL version 10.</p>
<p>Download source code from <a href="https://github.com/AbdulYadi/pgsocket" rel="nofollow">https://github.com/AbdulYadi/pgsocket</a>. Build in Linux as usual:<br />
$ make clean<br />
$ make<br />
$ make install</p>
<p>On successful compilation, install this extension in PostgreSQL environment<br />
$ create extension pgsocket</p>
<p>Let us send bytes to &#8211;for example&#8211; host with IP address nnn.nnn.nnn.nnn, port 9090, send time out 30 seconds, messages &#8220;Hello&#8221;<br />
$ select pgsocketsend(&#8216;nnn.nnn.nnn.nnn&#8217;, 9090, 30, (E&#8217;\\x&#8217; || encode(&#8216;Hello&#8217;, &#8216;hex&#8217;))::bytea);</p>
<p>Or using address host name instead of IP address<br />
$ select pgsocketsend(&#8216;thesocketserver&#8217;, 9090, 30, (E&#8217;\\x&#8217; || encode(&#8216;Hello&#8217;, &#8216;hex&#8217;))::bytea);</p>
<p>Now, sending text from a table to remote TCP/IP socket server is easy. Assuming there is a table <strong>words</strong>:<br />
id    txt<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
1    Life is easy<br />
2    with PostgreSQL<br />
just do:<br />
$ select pgsocketsend(&#8216;thesocketserver&#8217;, 9090, 30, (E&#8217;\\x&#8217; || encode(<strong>t.txt</strong>, &#8216;hex&#8217;))::bytea)<br />
from <strong>words t</strong> WHERE t.id = 1;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://abdulyadi.wordpress.com/2018/09/11/pgsocket-extension-for-simple-socket-client/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">635</post-id>
		<media:content url="https://1.gravatar.com/avatar/da81f4cbd1a6974053ebad2a0d12754bc3e60f9f9a899d47b00020f827d0a59d?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>Upsert and Before Insert/Update Trigger</title>
		<link>https://abdulyadi.wordpress.com/2018/02/10/upsert-and-before-insert-update-trigger/</link>
					<comments>https://abdulyadi.wordpress.com/2018/02/10/upsert-and-before-insert-update-trigger/#comments</comments>
		
		<dc:creator><![CDATA[abdulyadi]]></dc:creator>
		<pubDate>Sat, 10 Feb 2018 03:48:51 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=574</guid>

					<description><![CDATA[Upsert feature in PostgreSQL drove me to shorten SQL statement in my user defined functions. But somehow I overlook PostgreSQL version 10 documentation explaining trigger behavior: &#8220;&#8230;If an INSERT contains an ON CONFLICT DO UPDATE clause, it is possible that the effects of row-level BEFORE INSERT triggers and row-level BEFORE UPDATE triggers can both be &#8230;<p><a href="https://abdulyadi.wordpress.com/2018/02/10/upsert-and-before-insert-update-trigger/" class="more-link">Read More</a></p>]]></description>
										<content:encoded><![CDATA[<p>Upsert feature in PostgreSQL drove me to shorten SQL statement in my user defined functions. But somehow I overlook PostgreSQL version 10 documentation explaining trigger behavior:</p>
<p>&#8220;&#8230;If an INSERT contains an ON CONFLICT DO UPDATE clause, it is possible that the effects of row-level BEFORE INSERT triggers and row-level BEFORE UPDATE triggers can both be applied in a way that is apparent from the final state of the updated row, if an EXCLUDED column is referenced&#8230;&#8221;</p>
<p>For example, I have 2 tables:</p>
<p>CREATE TABLE public.sample<br />
(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id integer NOT NULL,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;code text NOT NULL,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CONSTRAINT &#8220;sample: id must be unique&#8221; PRIMARY KEY (id)<br />
)<br />
WITH (OIDS=FALSE);</p>
<p>CREATE TABLE public.audit<br />
(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id integer NOT NULL,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;codechanges integer NOT NULL DEFAULT 0,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CONSTRAINT &#8220;audit: id must be unique&#8221; PRIMARY KEY (id)<br />
)<br />
WITH (OIDS=FALSE);</p>
<p>Any record inserted into public.sample will be inserted into public.audit with codechanges 0. Any code changes to existing record in public.sample will increment codechanges in public.audit. For any reason, I implement the behavior in trigger:</p>
<p>CREATE OR REPLACE FUNCTION public.trig_sample() RETURNS trigger AS<br />
$BODY$<br />
BEGIN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF TG_WHEN=&#8217;BEFORE&#8217; THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF TG_OP=&#8217;INSERT&#8217; THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INSERT INTO audit (id) VALUES (NEW.id);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ELSIF TG_OP=&#8217;UPDATE&#8217; AND OLD.code IS DISTINCT FROM NEW.code THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UPDATE audit SET codechanges=codechanges+1 WHERE id = OLD.id;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN NEW;<br />
END$BODY$<br />
  LANGUAGE plpgsql VOLATILE;</p>
<p>CREATE TRIGGER trig_sample_before BEFORE INSERT OR UPDATE ON public.sample FOR EACH ROW EXECUTE PROCEDURE public.trig_sample();</p>
<p>And a user defined function to encapsulate the complexity:</p>
<h2>Old Style Update/Insert</h2>
<p>CREATE OR REPLACE FUNCTION public.sample_update(IN i_id integer, IN t_code text)<br />
RETURNS void AS<br />
$BODY$<br />
BEGIN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UPDATE public.sample SET code = t_code WHERE id = i_id;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF NOT FOUND THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INSERT INTO public.sample (id, code) VALUES (i_id, t_code);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN;<br />
END;<br />
$BODY$ LANGUAGE plpgsql VOLATILE SECURITY DEFINER;<br />
GRANT EXECUTE ON FUNCTION public.sample_update(integer, text) TO public;  </p>
<p>Let us give it a try:<br />
SELECT public.sample_update(1, &#8216;TEST-1&#8217;);<br />
SELECT * FROM public.sample;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;code<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8220;TEST-1&#8221;<br />
SELECT * FROM public.audit;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;codechanges<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0</p>
<p>SELECT public.sample_update(1, &#8216;TEST-2&#8217;);<br />
SELECT * FROM public.sample;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;code<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8220;TEST-2&#8221;<br />
SELECT * FROM public.audit;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;codechanges<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1</p>
<h2>Go Shorter with Upsert Version</h2>
<p>Now, I modify user defined function with Upsert feature:</p>
<p>CREATE OR REPLACE FUNCTION public.sample_update(IN i_id integer, IN t_code text) RETURNS void AS<br />
$BODY$<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INSERT INTO public.sample (id, code) VALUES ($1, $2)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ON CONFLICT (id) DO UPDATE SET code = EXCLUDED.code;<br />
$BODY$ LANGUAGE sql VOLATILE SECURITY DEFINER;<br />
GRANT EXECUTE ON FUNCTION public.sample_update(integer, text) TO public;</p>
<p>And repeat the test:<br />
SELECT public.sample_update(1, &#8216;TEST-3&#8217;);</p>
<p>But PostgreSQL complains:</p>
<div style="color:red;margin-bottom:1em;">ERROR:  duplicate key value violates unique constraint &#8220;audit: id must be unique&#8221;<br />
DETAIL:  Key (id)=(1) already exists.<br />
CONTEXT:  SQL statement &#8220;INSERT INTO audit (id) VALUES (NEW.id)&#8221;<br />
PL/pgSQL function trig_sample() line 5 at SQL statement<br />
SQL function &#8220;sample_update&#8221; statement 1</div>
<p>I realize that I overlook the Overview of Trigger Behavior clause in PostgreSQL documentation. So, I modify my trigger, move the logic from BEFORE to AFTER:</p>
<p>CREATE OR REPLACE FUNCTION public.trig_sample() RETURNS trigger AS<br />
$BODY$<br />
BEGIN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color:#808080;">/*IF TG_WHEN=&#8217;BEFORE&#8217; THEN*/</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF TG_WHEN=&#8217;AFTER&#8217; THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF TG_OP=&#8217;INSERT&#8217; THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;INSERT INTO audit (id) VALUES (NEW.id);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ELSIF TG_OP=&#8217;UPDATE&#8217; AND OLD.code IS DISTINCT FROM NEW.code THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UPDATE audit SET codechanges=codechanges+1 WHERE id = OLD.id;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN NEW;<br />
END$BODY$ LANGUAGE plpgsql VOLATILE;</p>
<p>DROP TRIGGER trig_sample_before ON public.sample; </p>
<p>CREATE TRIGGER trig_sample_after AFTER INSERT OR UPDATE ON public.sample FOR EACH ROW EXECUTE PROCEDURE public.trig_sample(); </p>
<p>Try the test once more:<br />
SELECT public.sample_update(1, &#8216;TEST-3&#8217;);</p>
<p>And no more complains:<br />
SELECT * FROM public.sample;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;code<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8220;TEST-3&#8221;<br />
SELECT * FROM public.audit;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;codechanges<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2</p>
<h4>A lesson learned.</h4>
]]></content:encoded>
					
					<wfw:commentRss>https://abdulyadi.wordpress.com/2018/02/10/upsert-and-before-insert-update-trigger/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">574</post-id>
		<media:content url="https://1.gravatar.com/avatar/da81f4cbd1a6974053ebad2a0d12754bc3e60f9f9a899d47b00020f827d0a59d?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>Cash Spell in Indonesian</title>
		<link>https://abdulyadi.wordpress.com/2017/11/30/cash-spell-in-indonesian/</link>
					<comments>https://abdulyadi.wordpress.com/2017/11/30/cash-spell-in-indonesian/#comments</comments>
		
		<dc:creator><![CDATA[abdulyadi]]></dc:creator>
		<pubDate>Thu, 30 Nov 2017 02:05:17 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=538</guid>

					<description><![CDATA[For those who interested in cash spelling in Indonesian, here I share PLPGSQL code: Usage: SELECT cash_spell(1200000000.45, true); 'Satu Milyar Dua Ratus Juta Rupiah Empat Puluh Lima Sen' Code: CREATE OR REPLACE FUNCTION int_spell(i_val integer) RETURNS text LANGUAGE 'plpgsql' IMMUTABLE STRICT AS $BODY$ DECLARE &#160;&#160;&#160;_t text:=''::text; &#160;&#160;&#160;_SYMBOL text[]:=ARRAY['satu', 'dua', 'tiga', 'empat', 'lima', 'enam', 'tujuh', 'delapan', &#8230;<p><a href="https://abdulyadi.wordpress.com/2017/11/30/cash-spell-in-indonesian/" class="more-link">Read More</a></p>]]></description>
										<content:encoded><![CDATA[<p>For those who interested in cash spelling in Indonesian, here I share PLPGSQL code:</p>
<p><strong>Usage:</strong><br />
<code>SELECT cash_spell(1200000000.45, true);<br />
'Satu Milyar Dua Ratus Juta Rupiah Empat Puluh Lima Sen'</code></p>
<p><strong>Code:</strong><br />
<code>CREATE OR REPLACE FUNCTION int_spell(i_val integer)<br />
RETURNS text LANGUAGE 'plpgsql' IMMUTABLE STRICT<br />
AS $BODY$<br />
DECLARE<br />
&nbsp;&nbsp;&nbsp;_t text:=''::text;<br />
&nbsp;&nbsp;&nbsp;_SYMBOL text[]:=ARRAY['satu', 'dua', 'tiga', 'empat', 'lima', 'enam', 'tujuh', 'delapan', 'sembilan', 'sepuluh'<br />
		, 'sebelas', 'dua belas', 'tiga belas', 'empat belas', 'lima belas', 'enam belas', 'tujuh belas'<br />
        , 'delapan belas', 'sembilan belas'];<br />
&nbsp;&nbsp;&nbsp;_val integer:=i_val;<br />
&nbsp;&nbsp;&nbsp;_i integer;<br />
BEGIN<br />
&nbsp;&nbsp;&nbsp;IF _val&lt;1 OR _val&gt;999 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RAISE EXCEPTION 'outside boundaries';<br />
&nbsp;&nbsp;&nbsp;END IF;</p>
<p>&nbsp;&nbsp;&nbsp;_i:=(_val - (_val % 100)) / 100;<br />
&nbsp;&nbsp;&nbsp;IF _i&gt;0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF _i&gt;9 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RAISE EXCEPTION 'hundreds failed';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF _i = 1 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:='seratus';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ELSE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:=_SYMBOL[_i] || ' ratus';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_val:=_val - (_i*100);<br />
&nbsp;&nbsp;&nbsp;END IF;    </p>
<p>&nbsp;&nbsp;&nbsp;IF _val&gt;0 AND _val&lt;20 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF LENGTH(_t) &gt; 0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:= _t || ' ';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:=_t || _SYMBOL[_val];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_val:=0;<br />
&nbsp;&nbsp;&nbsp;END IF;</p>
<p>&nbsp;&nbsp;&nbsp;_i:=(_val - (_val % 10)) / 10;<br />
&nbsp;&nbsp;&nbsp;IF _i&gt;0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF _i&gt;9 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RAISE EXCEPTION 'tenth failed';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF LENGTH(_t) &gt; 0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:= _t || ' ';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF _i = 1 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:= _t || 'sepuluh';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ELSE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:= _t || _SYMBOL[_i] || ' puluh';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_val:=_val - (_i*10);<br />
&nbsp;&nbsp;&nbsp;END IF;    </p>
<p>&nbsp;&nbsp;&nbsp;IF _val&gt;0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF LENGTH(_t) &gt; 0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:= _t || ' ';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:=_t || _SYMBOL[_val];<br />
&nbsp;&nbsp;&nbsp;END IF;</p>
<p>&nbsp;&nbsp;&nbsp;RETURN _t;<br />
END;<br />
$BODY$;<br />
GRANT EXECUTE ON FUNCTION int_spell(integer) TO public;</p>
<p>CREATE OR REPLACE FUNCTION cash_spell(n numeric, b_initcap boolean)<br />
RETURNS text LANGUAGE 'plpgsql' IMMUTABLE STRICT<br />
AS $BODY$<br />
DECLARE<br />
&nbsp;&nbsp;&nbsp;_t text:=''::text;<br />
&nbsp;&nbsp;&nbsp;_n numeric:=n;<br />
&nbsp;&nbsp;&nbsp;_frac numeric;<br />
&nbsp;&nbsp;&nbsp;_cent integer;<br />
&nbsp;&nbsp;&nbsp;_val integer;<br />
&nbsp;&nbsp;&nbsp;_suffix text[];<br />
&nbsp;&nbsp;&nbsp;_s text;<br />
&nbsp;&nbsp;&nbsp;_unit numeric;<br />
BEGIN<br />
&nbsp;&nbsp;&nbsp;IF _n &gt; 9999999999999999999999999999999999::numeric THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RAISE EXCEPTION 'outside boundaries';<br />
&nbsp;&nbsp;&nbsp;END IF;</p>
<p>&nbsp;&nbsp;&nbsp;IF _n &lt; 0::numeric THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RAISE EXCEPTION 'negative value';<br />
&nbsp;&nbsp;&nbsp;END IF;</p>
<p>&nbsp;&nbsp;&nbsp;IF _n = 0::numeric THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:='nol rupiah';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF b_initcap THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:=initcap(_t);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN _t;<br />
&nbsp;&nbsp;&nbsp;END IF;</p>
<p>&nbsp;&nbsp;&nbsp;_frac:= _n - floor(_n);<br />
&nbsp;&nbsp;&nbsp;_cent:= floor(_frac*100)::integer;</p>
<p>&nbsp;&nbsp;&nbsp;_n:= _n - _frac; --remove fraction</p>
<p>&nbsp;&nbsp;&nbsp;_suffix:=ARRAY['desiliun', 'noniliun', 'oktiliun', 'septiliun', 'sekstiliun', 'kuantiliun', 'kuadriliun',<br />
                  'triliun', 'milyar', 'juta', 'ribu'];<br />
&nbsp;&nbsp;&nbsp;_unit:=1000000000000000000000000000000000::numeric;<br />
&nbsp;&nbsp;&nbsp;FOREACH _s IN ARRAY _suffix LOOP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_val:=((_n - (_n % _unit)) / _unit)::integer;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF _val &gt; 0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF LENGTH(_t)&gt;0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:=_t || ' ';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF _s = 'ribu' AND _val=1 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:= _t || 'seribu';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ELSE<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:=_t || int_spell(_val) || ' ' || _s;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_n:=_n - (_val * _unit);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_unit:=_unit/1000;<br />
&nbsp;&nbsp;&nbsp;END LOOP;</p>
<p>&nbsp;&nbsp;&nbsp;IF _n&gt;0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF LENGTH(_t)&gt;0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:=_t || ' ';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:=_t || int_spell(_n::integer);<br />
&nbsp;&nbsp;&nbsp;END IF;</p>
<p>&nbsp;&nbsp;&nbsp;IF _cent&gt;0 AND LENGTH(_t)=0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:='nol';<br />
&nbsp;&nbsp;&nbsp;END IF;</p>
<p>&nbsp;&nbsp;&nbsp;_t:=_t || ' rupiah';</p>
<p>&nbsp;&nbsp;&nbsp;IF _cent&gt;0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:=_t || ' ';<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:=_t || int_spell(_cent) || ' sen';<br />
&nbsp;&nbsp;&nbsp;END IF;</p>
<p>&nbsp;&nbsp;&nbsp;IF b_initcap THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_t:=initcap(_t);<br />
&nbsp;&nbsp;&nbsp;END IF;</p>
<p>&nbsp;&nbsp;&nbsp;RETURN _t;<br />
END;<br />
$BODY$;<br />
GRANT EXECUTE ON FUNCTION cash_spell(numeric, boolean) TO public;</code></p>
]]></content:encoded>
					
					<wfw:commentRss>https://abdulyadi.wordpress.com/2017/11/30/cash-spell-in-indonesian/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">538</post-id>
		<media:content url="https://1.gravatar.com/avatar/da81f4cbd1a6974053ebad2a0d12754bc3e60f9f9a899d47b00020f827d0a59d?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>BDR 0.9.3 and Index on Expression (Part 3 &#8211; Solved)</title>
		<link>https://abdulyadi.wordpress.com/2015/12/29/bdr-0-9-3-and-index-on-expression-part-3-solved/</link>
					<comments>https://abdulyadi.wordpress.com/2015/12/29/bdr-0-9-3-and-index-on-expression-part-3-solved/#comments</comments>
		
		<dc:creator><![CDATA[abdulyadi]]></dc:creator>
		<pubDate>Tue, 29 Dec 2015 10:37:41 +0000</pubDate>
				<category><![CDATA[PostgreSQL]]></category>
		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=528</guid>

					<description><![CDATA[Go deeper into BDR and patched-PostgreSQL 9.4.5, eventually I find out the root cause. When new record INSERT-ed, BDR replicates it to other nodes. After simple_heap_insert, BDR calls UserTableUpdateOpenIndexes. For index on epression written in SQL, BDR code routes to GetActiveSnapshot() which fires Segmentation fault because ActiveSnapShot is invalid. Snapshot GetActiveSnapshot(void) { ... return ActiveSnapshot-&#62;as_snap;//invalid &#8230;<p><a href="https://abdulyadi.wordpress.com/2015/12/29/bdr-0-9-3-and-index-on-expression-part-3-solved/" class="more-link">Read More</a></p>]]></description>
										<content:encoded><![CDATA[<p>Go deeper into BDR and patched-PostgreSQL 9.4.5, eventually I find out the root cause. When new record INSERT-ed, BDR replicates it to other nodes. After <strong>simple_heap_insert</strong>, BDR calls <strong>UserTableUpdateOpenIndexes</strong>. For index on epression written in SQL, BDR code routes to <strong>GetActiveSnapshot()</strong> which fires Segmentation fault because ActiveSnapShot is invalid.</p>
<p><code>Snapshot<br />
GetActiveSnapshot(void)<br />
{<br />
	...<br />
	return ActiveSnapshot-&gt;as_snap;<span style="color:red;">//invalid ActiveSnapshot fires Segmentation fault</span><br />
}<br />
</code></p>
<p>Goes to <strong>bdr_apply.c</strong> in BDR package, I found out that <strong>ActiveSnapshot</strong> is set and cleared with <strong>PushActiveSnapshot</strong> and <strong>PopActiveSnapshot</strong> calls respectively in <strong>process_remote_update</strong> and <strong>process_remote_delete</strong> functions but not in <strong>process_remote_insert</strong>. </p>
<p>Then, I apply the function pair in <strong>process_remote_insert</strong> at the point before and after UserTableUpdateOpenIndexes calls :<br />
<code><br />
...<br />
<span style="color:red;">PushActiveSnapshot(GetTransactionSnapshot());</span><br />
if (conflict)<br />
{</p>
<div style="margin-left:3em;">
...<br />
if (apply_update)<br />
{</p>
<div style="margin-left:3em;">
...<br />
UserTableUpdateOpenIndexes(estate, newslot);<br />
...
</div>
<p>}
</p></div>
<p>}<br />
else<br />
{</p>
<div style="margin-left:3em;">
simple_heap_insert(rel-&gt;rel, newslot-&gt;tts_tuple);<br />
UserTableUpdateOpenIndexes(estate, newslot);<br />
...
</div>
<p>}<br />
<span style="color:red;">PopActiveSnapshot();</span><br />
...</code></p>
<p>Rebuild and reinstall the BDR package. Now no more replication crashes caused by updating index on expression written in SQL language. Case closed.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://abdulyadi.wordpress.com/2015/12/29/bdr-0-9-3-and-index-on-expression-part-3-solved/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">528</post-id>
		<media:content url="https://1.gravatar.com/avatar/da81f4cbd1a6974053ebad2a0d12754bc3e60f9f9a899d47b00020f827d0a59d?s=96&#38;d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
	</channel>
</rss>
