tag:blogger.com,1999:blog-132650582024-03-08T11:15:24.659+11:00Sydney Oracle LabI am a proud Oracle developer and this is my blog. <br>
My website is
<a href="http://www.sydoracle.com/"> here</a>
<br>
This blog is OPINION, SUGGESTION and DEBATE.
Please correct anything I write that is misleading.SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.comBlogger262125tag:blogger.com,1999:blog-13265058.post-77572052971824290302023-10-12T19:23:00.004+11:002023-10-12T19:23:55.188+11:00Whatever happened to SydOracle<p></p><p class="MsoNormal"><span lang="EN-AU"><o:p> </o:p></span></p>
<p><span style="color: black; font-family: "Times New Roman",serif; font-size: 13.5pt;"> So I haven't posted in <i>mumble</i> years. What
happened ?<o:p></o:p></span></p>
<p style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"><span style="color: black; font-family: "Times New Roman",serif; font-size: 13.5pt;"><o:p> </o:p></span></p>
<p style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"><span style="color: black; font-family: "Times New Roman",serif; font-size: 13.5pt;">Firstly there was this thing called Twitter. There seemed to be
less blogging and more tweeting, and the twitter thing never suited me. I'd
consume my RSS feed collection at times that were convenient to me (mostly on
the train), and the tweets all seemed to come overnight or while I was actually
working, and by the time I saw them, the sequencing and lack of nuance in the
content made it all too hard.<o:p></o:p></span></p>
<p style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"><span style="color: black; font-family: "Times New Roman",serif; font-size: 13.5pt;"><o:p> </o:p></span></p>
<p style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"><span style="color: black; font-family: "Times New Roman",serif; font-size: 13.5pt;">Secondly, back in 2014 I switched from gigs, either contracting or
consulting, into a permanent, full-time job. Gigging meant never being entirely
sure what was going to come next, so I consumed and played with stuff pretty
widely. While I've still been doing a range of stuff in my job, there has been
greater direction and focus, and a bunch of the rabbit holes I've followed have
been deep and of little interest to a wider community.<o:p></o:p></span></p>
<p style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"><span style="color: black; font-family: "Times New Roman",serif; font-size: 13.5pt;">Also (and this is probably 2b, rather than 3), it is quite an
atypical workplace, especially from an Oracle perspective. I've worked in large
telcos, utilities, government, logistics, insurance, defense... And this isn't a large organization
with thousands or tens of thousands of users. It isn't enterprise-y, and
some of the challenges would be almost incomprehensible to
people used to larger organizations. And unlike the consulting organizations I
worked for, it isn't pushing for exposure and I would be limited in what
details I could include to explain the context of some of the work.<o:p></o:p></span></p>
<p style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"><span style="color: black; font-family: "Times New Roman",serif; font-size: 13.5pt;"><o:p> </o:p></span></p>
<p style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"><span style="color: black; font-family: "Times New Roman",serif; font-size: 13.5pt;">And of course, there's been family and similar grown-up stuff.
Kids, house, medical things (a detached retina and resulting eye surgeries - recommend avoiding if possible),
those ugly Trump years. Oh and that pandemic. <o:p></o:p></span></p>
<p style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"><span style="color: black; font-family: "Times New Roman",serif; font-size: 13.5pt;"><o:p> </o:p></span></p>
<p style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"><span style="color: black; font-family: "Times New Roman",serif; font-size: 13.5pt;">Which brings me to now-ish. I've been doing the work-from-home thing
since the early days of the pandemic with every sign of that continuing. The youngest of my children finished
school almost a year ago. And the end of some of those ties to location has led
to the end of the 'Sydney' part of Syd-Oracle. Moved a bit further down south,
close enough that the train will still get me to Sydney in 90 minutes, but the
car will get me to the beach in less than 15 and the lake in half that. Plus
I'm no longer working out of a corner of the bedroom, but have a room that I
can call my 'Office'. <o:p></o:p></span></p>
<p style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"><span style="color: black; font-family: "Times New Roman",serif; font-size: 13.5pt;"><o:p> </o:p></span></p>
<p style="-webkit-text-stroke-width: 0px; font-variant-caps: normal; font-variant-ligatures: normal; orphans: 2; text-decoration-color: initial; text-decoration-style: initial; text-decoration-thickness: initial; widows: 2; word-spacing: 0px;"><span style="color: black; font-family: "Times New Roman",serif; font-size: 13.5pt;">I don't plan to start blogging again. </span><span style="font-family: "Times New Roman", serif; font-size: 18px;">The permie job continues.</span><span style="font-family: "Times New Roman", serif; font-size: 18px;"> Maybe next year, I'll do a post to explain<a href="https://en.wikipedia.org/wiki/Long_service_leave"> Long Service Leave</a> . </span><span style="font-family: "Times New Roman", serif; font-size: 13.5pt;">Yes Twitter may be sinking
slowly into the swamp, but there's still Trump. </span></p><br /><p></p>sydoraclehttp://www.blogger.com/profile/10404756950638119562noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-20421712492995153942016-02-29T20:00:00.000+11:002016-02-29T20:00:13.652+11:00Client support for WITH using PL/SQL<span style="font-family: "trebuchet ms" , sans-serif;">My employer has been using 12c for about a year now, migrating away from 11gR2. It's fun working out the new functionality, including wider use of PL/SQL.</span><br />
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">In the 'old' world, you had SQL statements that <u>had</u> to include PL/SQL, such as CREATE TRIGGER, PROCEDURE etc). And you had statements that could <u>never</u> include PL/SQL, such as CREATE SYNONYM, CREATE SEQUENCE. DML (SELECT, INSERT, UPDATE, DELETE and MERGE) were in the latter category.</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">One of the snazzy new 12c features is the use of PL/SQL in SELECTs, so we have a new category of statements which <u>may</u> include PL/SQL. In some cases that confuses clients that try to interpret the semi-colons in PL/SQL as SQL statement terminators.</span></div>
<h4>
<span style="font-family: "trebuchet ms" , sans-serif;">SQL Plus</span></h4>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">The good news is the the 12c SQL Plus client works great (or at least I haven't got it confused yet), so gets a grade A pass. However, if you're stuck with an older 11g client, you have to make accommodations to use this 12 stuff.</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">Fortunately, even the older sqlplus clients have a SET SQLTERMINATOR statement. By setting the value to OFF, the client will ignore the semi-colons. That means you'll be using the slash character on a new line to execute your SQL statements. Given the necessary workaround, I'll give it a B grade, but that's not bad for a superseded version of the client.</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SET SQLTERMINATOR OFF</span></div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT r123 val</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<h4>
<span style="font-family: "trebuchet ms" , sans-serif;">SQLCL</span></h4>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">If you grab the latest version of SQLcl (mentioned by Jeff Smith <a href="http://www.thatjeffsmith.com/archive/2016/02/sqlcl-updated-bug-fixes/">here</a>) you'll be fine with the WITH...SELECT option. It also seemed to work fine for the other DML statements. Note that, as per the <a href="https://docs.oracle.com/database/121/SQLRF/statements_10002.htm#SQLRF55665">docs</a>, "</span><span style="background-color: white; color: #222222; font-family: "helvetica neue" , "neue helvetica" , "arial" , sans-serif; font-size: 14px; line-height: 15.68px;">If the top-level statement is a </span><code dir="ltr" style="background-color: white; box-sizing: border-box; font-family: menlo, monaco, 'Courier New', Courier, mono, serif; font-size: 13px; line-height: 1.615; padding: 3px 0px;">DELETE</code><span style="background-color: white; color: #222222; font-family: "helvetica neue" , "neue helvetica" , "arial" , sans-serif; font-size: 14px; line-height: 15.68px;">, </span><code dir="ltr" style="background-color: white; box-sizing: border-box; font-family: menlo, monaco, 'Courier New', Courier, mono, serif; font-size: 13px; line-height: 1.615; padding: 3px 0px;">MERGE</code><span style="background-color: white; color: #222222; font-family: "helvetica neue" , "neue helvetica" , "arial" , sans-serif; font-size: 14px; line-height: 15.68px;">, </span><code dir="ltr" style="background-color: white; box-sizing: border-box; font-family: menlo, monaco, 'Courier New', Courier, mono, serif; font-size: 13px; line-height: 1.615; padding: 3px 0px;">INSERT</code><span style="background-color: white; color: #222222; font-family: "helvetica neue" , "neue helvetica" , "arial" , sans-serif; font-size: 14px; line-height: 15.68px;">, or </span><code dir="ltr" style="background-color: white; box-sizing: border-box; font-family: menlo, monaco, 'Courier New', Courier, mono, serif; font-size: 13px; line-height: 1.615; padding: 3px 0px;">UPDATE</code><span style="background-color: white; color: #222222; font-family: "helvetica neue" , "neue helvetica" , "arial" , sans-serif; font-size: 14px; line-height: 15.68px;"> statement, then it must have the </span><code dir="ltr" style="background-color: white; box-sizing: border-box; font-family: menlo, monaco, 'Courier New', Courier, mono, serif; font-size: 13px; line-height: 1.615; padding: 3px 0px;">WITH_PLSQL</code><span style="background-color: white; color: #222222; font-family: "helvetica neue" , "neue helvetica" , "arial" , sans-serif; font-size: 14px; line-height: 15.68px;"> hint." </span></div>
<div>
<br /></div>
</div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">INSERT /*+WITH_PLSQL */ INTO t123 </span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT r123</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
</div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">It does fall down on the CREATE statements. The CREATE TABLE, CREATE VIEW and CREATE MATERIALIZED VIEW statements all allow WITH PL/SQL, and do not require the hint. The following works fine in SQL Plus (or if you send it straight to the SQL engine via JDBC or OCI, or through dynamic SQL).</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">CREATE TABLE t123 AS</span></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT r123 val</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
</div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;">Again, there's a workaround, and sqlcl will process the statement if it does contain the WITH_PLSQL hint. However that hint isn't genuine as far as the database is concerned (ie not in the data dictionary and won't be pulled out via a DBMS_METADATA.GET_DDL). Also sqlcl doesn't support the SQL Plus SET SQLTERMINATOR command, so we can't use that workaround. Still, I'll give it a B grade.</span></div>
<div>
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">CREATE /*+WITH_PLSQL */ TABLE t123 AS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT r123 val</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<h4 style="font-family: 'Times New Roman';">
<span style="font-family: "trebuchet ms" , sans-serif;">SQL Developer</span></h4>
<div style="font-family: 'Times New Roman';">
<span style="font-family: "trebuchet ms" , sans-serif;">As of 4.1.3, SQL Developer offers the weakest support for this 12c functionality. </span><br />
<span style="font-family: "trebuchet ms" , sans-serif;">[Note: Scott in Perth noted the <a href="http://www.grassroots-oracle.com/2014/12/oracle-12c-with-inline-plsql.html">problems back in 2014</a>.]</span></div>
<div style="font-family: 'Times New Roman';">
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div style="font-family: 'Times New Roman';">
<span style="font-family: "trebuchet ms" , sans-serif;">Currently the plain WITH...SELECT works correctly, but DML and CREATE statements all fail when it hits the semi-colon and it tries to run the statement as two or more separate SQLs. The only work around is to execute the statement as dynamic SQL through PL/SQL.</span></div>
<div style="font-family: 'Times New Roman';">
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div style="font-family: 'Times New Roman';">
<span style="font-family: "trebuchet ms" , sans-serif;">Since it seems to share most of the parsing logic with sqlcl, I'd expect it to catch up with its younger sibling on the next release. Hopefully they'll be quicker supporting any 12cR2 enhancements.</span></div>
<div style="font-family: 'Times New Roman';">
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div style="font-family: 'Times New Roman';">
<span style="font-family: "trebuchet ms" , sans-serif;">I'll give it a 'D' until the next release. In the meantime, pair it up with SQL Plus</span></div>
<h4 style="font-family: 'Times New Roman';">
<span style="font-family: "trebuchet ms" , sans-serif;">TOAD 11</span></h4>
<div style="font-family: 'Times New Roman';">
<span style="font-family: "trebuchet ms" , sans-serif;">While I very rarely use it, I do have access to TOAD at work. TOAD recognizes blank lines as the separator between statements, so doesn't have an issue with semi-colons in the middle of SQL statements. Grade A for this functionality.</span></div>
<div style="font-family: 'Times New Roman';">
<span style="font-family: "trebuchet ms" , sans-serif;"><br /></span></div>
<div>
<a name='more'></a><span style="font-family: "trebuchet ms" , sans-serif;">Just for completeness, these are the test statements I used</span></div>
<div style="font-family: 'Times New Roman';">
<br /></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">CLEAR SCREEN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SET SQLTERMINATOR OFF</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">DROP TABLE t123</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">DROP VIEW v123</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">DROP MATERIALIZED VIEW mv123</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">PROMPT SELECT </span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT r123 val</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">PROMPT CREATES</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">CREATE TABLE t123 AS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT r123 val</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">CREATE VIEW v123 AS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT r123 val</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">CREATE MATERIALIZED VIEW mv123 AS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT r123 val</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">PROMPT INSERT/DELETE/MERGE</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">INSERT /*+WITH_PLSQL */ INTO t123 </span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT r123</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">DELETE /*+WITH_PLSQL */FROM t123</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WHERE val =</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> (WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> SELECT r123</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">MERGE /*+WITH_PLSQL */ INTO t123 D</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> USING (WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> SELECT r123 val</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual) s</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> ON (d.val = s.val )</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> WHEN NOT MATCHED THEN INSERT (val) VALUES (s.val)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">PROMPT UPDATES</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">UPDATE /*+WITH_PLSQL */</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> (WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> SELECT val, r123</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM t123)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SET val = r123</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">UPDATE /*+WITH_PLSQL */ t123</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SET val =</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> (WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> SELECT r123</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual)</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/ </span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">CREATE /*+WITH_PLSQL */ TABLE t123 AS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT r123 val</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">CREATE /*+WITH_PLSQL */ VIEW v123 AS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT r123 val</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">CREATE /*+WITH_PLSQL */ MATERIALIZED VIEW mv123 AS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">WITH</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FUNCTION r123 RETURN NUMBER IS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> BEGIN</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> RETURN 123;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> END;</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">SELECT r123 val</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> FROM dual</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/</span></div>
<div style="font-family: 'Times New Roman';">
<br /></div>
</div>
</div>
</div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-48826117804761897362016-01-31T17:27:00.000+11:002016-01-31T17:27:26.491+11:00Multisessioning with PythonI'll admit that I pretty constantly have at least one window either open into SQL*Plus or at the command line ready to run a deployment script through it. But there's time when it is worth taking a step beyond.<br />
<br />
One problem with the architecture of most SQL clients is they connect to a database, send off a SQL statement and do nothing until the database responds back with an answer. That's a great model when it takes no more than a second or two to get the response. It is cumbersome when the statement can take minutes to complete. Complex clients, like SQL Developer, allow the user to have multiple sessions open, even against a single schema if you use "unshared" worksheets. But they don't co-ordinate those sessions in any way.<br />
<br />
Recently I needed to run a task in a number of schemas. We're all nicely packaged up and all I needed to do was execute a procedure in each of the schemas and we can do that from a master schema with appropriate grants. However the tasks would take several minutes for each schema, and we had dozens of schemas to process. Running them consecutively in a single stream would have taken many hours and we also didn't want to set them all off at once through the job scheduler due to the workload. Ideally we wanted a few running concurrently, and when one finished another would start. I haven't found an easy way to do that in the database scheduler.<br />
<br />
Python, on the other hand, makes it so darn simple.<br />
[Credit to <a href="http://stackoverflow.com/questions/3033952/python-thread-pool-similar-to-the-multiprocessing-pool">Stackoverflow</a>, of course]<br />
<br />
proc connects to the database, executes the procedure (in this demo just setting the client info with a delay so you can see it), and returns.<br />
Strs is a collection of parameters.<br />
pool tells it how many concurrent operation to run. And then it maps the strings to the pool, so A, B and C will start, then as they finish D,E,F and G will be processed as threads become available.<br />
<br />
I could my collection was a list of the schema names, and the statement was more like 'begin ' + arg + '.task; end;'<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">#!/usr/bin/python</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">"""</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">Global variables</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">"""</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">db = 'host:port/service'</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">user = 'scott'</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">pwd = 'tiger'</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">def proc(arg):</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> con = cx_Oracle.connect(user + '/' + pwd + '@' + db)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> cur = con.cursor()</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> cur.execute('begin sys.dbms_application_info.set_client_info(:info); end;',{'info':arg})</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> time.sleep(10) </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> cur.close()</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> con.close()</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> return</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">import cx_Oracle, time</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">from multiprocessing.dummy import Pool as ThreadPool </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">strs = [</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 'A', 'B', 'C', 'D', 'E', 'F', 'G'</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> ]</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"># Make the Pool of workers</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">pool = ThreadPool(3) </span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"># Pass the elements of the array to the procedure using the pool </span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"># In this case no values are returned so the results is a dummy</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">results = pool.map(proc, strs)</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">#close the pool and wait for the work to finish </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">pool.close() </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">pool.join() </span><br />
<br />
PS. In this case, I used cx_Oracle as the glue between Python and the database.<br />
The <a href="http://catherinedevlin.blogspot.com.au/">pyOraGeek blog</a> is a good starting point for that.<br />
<br />
If/when I get around to blogging again, I'll discuss jaydebeapi / jpype as an alternative. In short, cx_Oracle goes through the OCI client (eg Instant Client) and jaydebeapi takes the JVM / JDBC route.<br />
<br />
<br />
<br />sydoraclehttp://www.blogger.com/profile/10404756950638119562noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-70405441636369145492015-05-17T16:45:00.000+10:002015-05-17T16:45:45.599+10:00With PL/SQL and LONGs (and PRODUCT_USER_PROFILE)<span style="font-family: Verdana, sans-serif;">One use for the 12.1.0.2 addition of PL/SQL functions in the WITH clause is to get the HIGH_VALUE of a partition in a usable column format.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">with</span><br />
<span style="font-family: Courier New, Courier, monospace;"> FUNCTION char2000(i_tab in varchar2, i_part in varchar2) </span><br />
<span style="font-family: Courier New, Courier, monospace;"> RETURN VARCHAR2 IS</span><br />
<span style="font-family: Courier New, Courier, monospace;"> v_char varchar2(2000);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> BEGIN</span><br />
<span style="font-family: Courier New, Courier, monospace;"> select high_value into v_char</span><br />
<span style="font-family: Courier New, Courier, monospace;"> from user_tab_partitions a</span><br />
<span style="font-family: Courier New, Courier, monospace;"> where a.table_name = i_tab</span><br />
<span style="font-family: Courier New, Courier, monospace;"> and a.partition_name = i_part;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace;"> if v_char like </span><br />
<span style="font-family: Courier New, Courier, monospace;"> <span style="font-size: x-small;">'TO_DATE(''%'', ''SYYYY-MM-DD HH24:MI:SS'', ''NLS_CALENDAR=GREGORIAN'')'</span></span><br />
<span style="font-family: Courier New, Courier, monospace;"> then</span><br />
<span style="font-family: Courier New, Courier, monospace;"> v_char := regexp_substr(v_char,q'{'[^']+'}');</span><br />
<span style="font-family: Courier New, Courier, monospace;"> end if;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace;"> RETURN v_char;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> END;</span><br />
<span style="font-family: Courier New, Courier, monospace;">select table_name, partition_name, </span><br />
<span style="font-family: Courier New, Courier, monospace;"> char2000(table_name, partition_name) high_val,</span><br />
<span style="font-family: Courier New, Courier, monospace;"> partition_position, tablespace_name, </span><br />
<span style="font-family: Courier New, Courier, monospace;"> segment_created, num_rows, last_analyzed, </span><br />
<span style="font-family: Courier New, Courier, monospace;"> global_stats, user_stats</span><br />
<span style="font-family: Courier New, Courier, monospace;">from user_tab_partitions ut</span><br />
<span style="font-family: Courier New, Courier, monospace;">where segment_created='YES'</span><br />
<span style="font-family: Courier New, Courier, monospace;">order by table_name, high_val;</span><br />
<span style="font-family: Courier New, Courier, monospace;">/</span><br />
<div>
<span style="font-family: Verdana, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Verdana, sans-serif;">Oracle have spent well over a decade telling us that <a href="http://docs.oracle.com/cd/A84870_01/doc/server.816/a76962/ch6.htm#6690">LONG</a> is deprecated, but still persist in using it in their data dictionary. PL/SQL is the only practical way of getting the values into a more usable data type.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">You will want the last version of the SQL Plus client. For SQL, sqlplus treats the semi-colon as a "go off and execute this". PL/SQL has traditionally needed a period on an otherwise empty line to switch from the statement editor to the command prompt.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">For example:</span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtMZq6-pDf7Oh4PviGMHm9gTU-3woTPwukcowPXg-W7mmQzeScbs_z60K8_vPnHSs7Z3oavyM0Jm2aND9urNcrY4TN0Y0LI8Ow7-hq8rvFFGQ3Bnu1YwZFyxKWdoXhqgFb4bk_/s1600/2015-05-17+15_56_24-Command+Prompt+-+sqlplus++gary_gary@192.168.1.104_1521_orcl.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Verdana, sans-serif;"><img border="0" height="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtMZq6-pDf7Oh4PviGMHm9gTU-3woTPwukcowPXg-W7mmQzeScbs_z60K8_vPnHSs7Z3oavyM0Jm2aND9urNcrY4TN0Y0LI8Ow7-hq8rvFFGQ3Bnu1YwZFyxKWdoXhqgFb4bk_/s320/2015-05-17+15_56_24-Command+Prompt+-+sqlplus++gary_gary@192.168.1.104_1521_orcl.png" width="320" /></span></a></div>
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">Having PL/SQL embedded in the SQL statement confuses the older clients, and we get a bout of premature execution.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNP0vSM1utWTg79Sl0zg1ZVK6RqgX7-HrpENpmQeXQLim3nWrijQWibFmWKPcB8PbenRS97Soxgi3EliZoFMUyHoLEfPkdAfjvf2-Hj5TgPQOSaCsEr029Z7rYZPyZ9oAPtisl/s1600/2015-05-17+15_49_56-Command+Prompt+-+sqlplus++gary_gary@192.168.1.104_1521_orcl.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Verdana, sans-serif;"><img border="0" height="249" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNP0vSM1utWTg79Sl0zg1ZVK6RqgX7-HrpENpmQeXQLim3nWrijQWibFmWKPcB8PbenRS97Soxgi3EliZoFMUyHoLEfPkdAfjvf2-Hj5TgPQOSaCsEr029Z7rYZPyZ9oAPtisl/s640/2015-05-17+15_49_56-Command+Prompt+-+sqlplus++gary_gary@192.168.1.104_1521_orcl.png" width="640" /></span></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: Verdana, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Verdana, sans-serif;">In the 12.1.0.2 client, a WITH statement is treated as a PL/SQL statement if it contains PL/SQL (ie needing the period statement terminator). If it doesn't contain PL/SQL then it doesn't (so there's no change required for older scripts). That said, I'd recommend consistently using the period terminator for PL/SQL and SQL. </span></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: Verdana, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTub2m6AfdcW-cZ68iqBJZncNKIjZRdIaX8-WVlPrZ2RXx0qpCc5-guZxKGlqlXgX96SaXgjacX_AfRRw7Q8BnoOchsvs4YsPGeiYydN9_bs62MqD-_skQ1ukqKNWvMU7AJDcr/s1600/2015-05-17+15_59_47-Command+Prompt+-+sqlplus++gary_gary@192.168.1.104_1521_orcl.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Verdana, sans-serif;"><img border="0" height="472" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTub2m6AfdcW-cZ68iqBJZncNKIjZRdIaX8-WVlPrZ2RXx0qpCc5-guZxKGlqlXgX96SaXgjacX_AfRRw7Q8BnoOchsvs4YsPGeiYydN9_bs62MqD-_skQ1ukqKNWvMU7AJDcr/s640/2015-05-17+15_59_47-Command+Prompt+-+sqlplus++gary_gary@192.168.1.104_1521_orcl.png" width="640" /></span></a></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Verdana, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Verdana, sans-serif;">The SQLcl client (still beta/early adopter) currently manages the straight select okay, but fails if it is part of a CREATE VIEW. </span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Verdana, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKEfoPO5iEKHFd9t6rjaWenA3tVjzBBWNGjWsPJnUN5KzLMos5xQIZQwxc62TKJGcRbP9bIwiLpTqrGHxlbI00EORk32Fxv3I62aitvXlGkF0KWpoxG-l6kwHOQhWeJkk_tCFl/s1600/2015-05-17+16_07_01-Command+Prompt+-+sql.bat++gary_gary@192.168.1.104_1521_orcl.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Verdana, sans-serif;"><img border="0" height="604" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKEfoPO5iEKHFd9t6rjaWenA3tVjzBBWNGjWsPJnUN5KzLMos5xQIZQwxc62TKJGcRbP9bIwiLpTqrGHxlbI00EORk32Fxv3I62aitvXlGkF0KWpoxG-l6kwHOQhWeJkk_tCFl/s640/2015-05-17+16_07_01-Command+Prompt+-+sql.bat++gary_gary@192.168.1.104_1521_orcl.png" width="640" /></span></a></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Verdana, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Verdana, sans-serif;">Tim Hall has already <a href="http://oracle-base.com/articles/12c/with-clause-enhancements-12cr1.php">noted that the WITH PL/SQL</a> doesn't currently work when embedded in a PL/SQL block (such as a procedure), but that is expected in a future release. </span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Verdana, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Verdana, sans-serif;">Oh, and while it isn't documented in <a href="http://docs.oracle.com/database/121/SQPUG/ch_nine.htm#i1058732">manual</a>, WITH is its own statement for the purposes of PRODUCT_USER_PROFILE. I can't imagine anyone on the planet is still using PRODUCT_USER_PROFILE for security. If they are, they need to rethink in light of WITH statements and result sets being returned by PL/SQL. </span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Verdana, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEis0sejg_BKCAVUmE4hSa-5R0gLvH27aAht72NS4XG4814qrEGjWleQTFxLjB6Z3bgE_ABqTQgOypXjCsFDDvYB_QkzuH4BQtXvr4lWXbglj1CjlQYQtzHS6LLlSl1-Ms8stgiM/s1600/2015-05-17+16_38_37-Command+Prompt+-+sqlplus++gary_gary@192.168.1.104_1521_orcl.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="542" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEis0sejg_BKCAVUmE4hSa-5R0gLvH27aAht72NS4XG4814qrEGjWleQTFxLjB6Z3bgE_ABqTQgOypXjCsFDDvYB_QkzuH4BQtXvr4lWXbglj1CjlQYQtzHS6LLlSl1-Ms8stgiM/s640/2015-05-17+16_38_37-Command+Prompt+-+sqlplus++gary_gary@192.168.1.104_1521_orcl.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Verdana, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
</div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-48293425115954186742015-05-10T16:33:00.003+10:002015-05-10T16:33:53.623+10:00Oracle things that piss me off (pt 2) - No Direction<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The SQL Developer team has been chugging forward with it's SQL Command Line (sqlcl) tool.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">As I developer, I understand where they are coming from. SQL Developer benefited from being able to run scripts built for the SQL*Plus command line tool. Then there's the temptation to add a few more useful titbits to the tool. </span><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">And if it is built 'properly', then it would be relatively easy to decouple it from the GUI and have it as a stand-alone.</span><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"> </span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">BUT.....</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">where's the big picture ?</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">I'm pretty sure (but happy to be corrected) that "SQL Developer" is part of the 12.1 database installation. It is certainly referenced in the <a href="http://docs.oracle.com/database/121/LADBI/rev_precon_db.htm#LADBI7808">guides</a>. So I'd assume that the next 12.2 release will have "SQL Developer" and "sqlcl" command line tool and SQL Plus. I couldn't guess whether the sqlplus will be offered as a last gasp, "to be deprecated" option or whether the long term plan is to supply two SQL command line tools.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Unix/Linux users are probably used to something similar, as they generally have the options of different shells, such as bash, ksh, csh etc. But to remedy any confusion, scripts are generally written with a <a href="http://en.wikipedia.org/wiki/Shebang_%28Unix%29">shebang</a> so it can automatically work out which of the available shells it should use.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">What DBAs are most likely to end up with is a script for which they'll have to guess whether it is aimed at sqlplus or sqlcl (or, if they are lucky, a comment at the start of the code).</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Having the clients "sort of" compatible makes it worse. It is harder to tell what it is aimed at, and what might go wrong if the incorrect client is used. Plus opting for compatibility perpetuates some of the dumb crud that has accumulated in sqlplus over the decades.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><u>For example:</u></span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">This is an SQL statement:</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">SET ROLE ALL;</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">This is a directive to the SQLPlus client</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">SET TIMING ON</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">You could tell the subtle difference between the SET as SQL statement and SET as sqlplus directive by the semi-colon at the end. Except that both sqlplus and sqlcl will happily accept a semicolon on the end of a 'local' SET command.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">If you think it is hard keeping track of what commands are processed by the database, and what are processed by the client, we also have commands that do both.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">16:01:49 SQL> select sysdate, to_char(sysdate), cast(sys_context('USERENV','NLS_DATE_FORMAT') as varchar2(20)) dt_fmt,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 2 cast(sys_context('USERENV','NLS_CALENDAR') as varchar2(20)) cal</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 3 from dual;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">SYSDATE TO_CHAR(SYSDATE) DT_FMT CAL</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">----------------------- ------------------ -------------------- --------------------</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">10/MAY/15 10/MAY/15 DD/MON/RR GREGORIAN</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">16:02:35 SQL> alter session set nls_date_format = 'DD/Mon/YYYY';</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Session altered.</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">16:02:40 SQL> select sysdate, to_char(sysdate), cast(sys_context('USERENV','NLS_DATE_FORMAT') as varchar2(20)) dt_fmt,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 2 cast(sys_context('USERENV','NLS_CALENDAR') as varchar2(20)) cal</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 3 from dual;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">SYSDATE TO_CHAR(SYSDATE) DT_FMT CAL</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">------------------ -------------------- -------------------- --------------------</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">10/May/2015 10/May/2015 DD/Mon/YYYY GREGORIAN</span><br />
<div>
<br /></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">To clarify this, the statement returns one column as a DATE, which will be converted to a string by the client according to its set of rules, and one column as a string converted from a DATE by the database's set of rules.</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The ALTER SESSION has been interpreted by both the client AND the server.</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">This becomes obvious when we do this:</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">16:02:44 SQL> alter session set nls_calendar='Persian';</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">Session altered.</span></div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">16:06:22 SQL> select sysdate, to_char(sysdate),</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 2 cast(sys_context('USERENV','NLS_DATE_FORMAT') as varchar2(20)) dt_fmt,</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 3 cast(sys_context('USERENV','NLS_CALENDAR') as varchar2(20)) cal</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 4 from dual;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">SYSDATE TO_CHAR(SYSDATE) DT_FMT CAL</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">----------------------- ---------------------- -------------------- ---</span><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">-------</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">10 May 2015 20 Ordibehesht 1394 DD Month YYYY Persian</span></div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
<br /></div>
</div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
The database knows what to do with the Persian calendar, but the sqlcl client didn't bother. SQLPlus copes with this without a problem, and can also detect when the NLS_DATE_FORMAT is changed in a stored procedure in the database rather than via ALTER SESSION. I assume some NLS values are available/fed back to the client via OCI.</div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
<br /></div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
If I was going for a brand-new SQL client, I'd draw a VERY strong line between commands meant for the client and commands intended for the database (maybe a : prefix, reminiscent of vi). I'd also consider that some years down the track, I might be using the same client to extract data from the regular Oracle RDBMS, their mySQL database, a cloud service.... </div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
<br /></div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
To be honest, I'd want one tool that is aimed at deploying DDL to databases (procedures, new columns etc) and maybe data changes (perhaps through creating and executing a procedure). A lot of the rest would be better off supplied as a collection of libraries to be used with a programming language, rather than as a client tool. That way you'd get first class support for error/exception handling, looping, conditions....</div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
<br /></div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
PS.</div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
When it comes to naming this tool, bear in mind this is how the XE install refers to the SQL Plus client:</div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7DCkz6wrdGJ8chYHpDMS9Mm2SO4KYI1sS6Tk-uQBbEqJhnlO3TrX-KAp4NT6iyCIK-st7Q93UdF8PJ9u60G-Ry4dlKm3I6jFeYCbnMpoSsTk6_jFRjwJUWvX9e4LzgKiCemO0/s1600/Start+menu_2015-05-10_16-31-51.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7DCkz6wrdGJ8chYHpDMS9Mm2SO4KYI1sS6Tk-uQBbEqJhnlO3TrX-KAp4NT6iyCIK-st7Q93UdF8PJ9u60G-Ry4dlKm3I6jFeYCbnMpoSsTk6_jFRjwJUWvX9e4LzgKiCemO0/s1600/Start+menu_2015-05-10_16-31-51.png" /></a></div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
<br /></div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
<br /></div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com1tag:blogger.com,1999:blog-13265058.post-18574364489429710552015-04-26T08:27:00.000+10:002015-04-26T08:27:03.692+10:00Oracle things that piss me off (pt 1)<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">This annoys me.</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The fact that Oracle thinks it is appropriate to sell me to 'Ask' whenever I update my Oracle JRE. </span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIRutnu3p2cnQpguLUyzB1I-C9_cgzUoHHJKrlqMJjIkX29GzWmC1DpRhucudqoZ2yMWUcx7QBN7BtObTnUpjIyUmhVbU7Rr9VP4GRiNbMMP3caBv_m8JGLq4p1ydzu9AiEFSx/s1600/2015-04-26+07_54_06-Java+Setup.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIRutnu3p2cnQpguLUyzB1I-C9_cgzUoHHJKrlqMJjIkX29GzWmC1DpRhucudqoZ2yMWUcx7QBN7BtObTnUpjIyUmhVbU7Rr9VP4GRiNbMMP3caBv_m8JGLq4p1ydzu9AiEFSx/s1600/2015-04-26+07_54_06-Java+Setup.png" height="448" width="640" /></a></div>
<br />
<div class="separator" style="clear: both;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">On my home machines,I've ditched the Oracle route for JRE. Java runtime is a requirement for running Minecraft (now owned by Microsoft) and they've now incorporated keeping the JRE updated as part of their updates. No attempts to install some crappy piece of spyware on my machine. </span></div>
<div class="separator" style="clear: both;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">And it is at the stage where I trust Microsoft over Oracle any day of the week.</span></div>
<div class="separator" style="clear: both;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both;">
<br /></div>
<div class="separator" style="clear: both;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com2tag:blogger.com,1999:blog-13265058.post-80514697192270165382015-04-04T19:00:00.000+11:002015-04-04T19:00:05.478+11:00A world of confusion<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">It has got to the stage where I often don't even know what day it is. No, not premature senility (although some may disagree). But time zones.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Mostly I've had it fairly easy in my career. When I worked in the UK, I just had the one time zone to work with. The only time things got complicated was when I was working at one of the power generation companies, and we had to make provision for the 23-hour and 25-hour days that go with Daylight Savings.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">And in Australia we only have a handful of timezones, and when I start and finish work, it is the same day for any part of Australia. I did work on one system where the database clock was set to UTC, but dates weren't important on that application.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Now it is different. I'm dealing with events that happen all over the world. Again the database clock is UTC, with the odd effect that TRUNC(SYSDATE) 'flips over' around lunchtime. Now when I want to look at 'recent' entries (eg a log table) I've got into the habit of asking WHERE LOG_DATE > SYSDATE - INTERVAL '9' HOUR</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">And we also have columns that are TIMESTAMP WITH TIMEZONE. So I'm getting into the habit of selecting COL_TS AT TIME ZONE DBTIMEZONE . I could use sessiontimezone, but then the time component of DATE columns would be inconsistent. This becomes just a little more confusing this time of year as various places slip in and out of Daylight Savings.</span><br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Now things are getting even more complicated for me.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Again, during my career, I've been lucky enough to be pretty oblivious to character set issues. Most things have squeezed in to my databases without any significant trouble. Occasionally I've had to look for some accented characters in people's names, but that's been it.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">In the past few months, I've been working with some European data where the issues have been more pronounced. Aside from a few issues in emails, I've been coping quite well (with a lot of help from Google Translate). </span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Now I get to work with some Japanese data. And things get complicated.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">"</span><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px;">The modern </span><b style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px;">Japanese writing system</b><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px;"> is a combination of two character types: logographic </span><a href="http://en.wikipedia.org/wiki/Kanji" style="background: none rgb(255, 255, 255); color: #0b0080; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px; text-decoration: none;" title="Kanji">kanji</a><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px;">, which are adopted </span><a class="mw-redirect" href="http://en.wikipedia.org/wiki/Chinese_character" style="background: none rgb(255, 255, 255); color: #0b0080; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px; text-decoration: none;" title="Chinese character">Chinese characters</a><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px;">, and syllabic </span><a href="http://en.wikipedia.org/wiki/Kana" style="background: none rgb(255, 255, 255); color: #0b0080; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px; text-decoration: none;" title="Kana">kana</a><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px;">. Kana itself consists of a pair of </span><a class="mw-redirect" href="http://en.wikipedia.org/wiki/Syllabaries" style="background: none rgb(255, 255, 255); color: #0b0080; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px; text-decoration: none;" title="Syllabaries">syllabaries</a><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px;">: </span><a href="http://en.wikipedia.org/wiki/Hiragana" style="background: none rgb(255, 255, 255); color: #0b0080; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px; text-decoration: none;" title="Hiragana">hiragana</a><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px;">, used for native or naturalised Japanese words and grammatical elements, and </span><a href="http://en.wikipedia.org/wiki/Katakana" style="background: none rgb(255, 255, 255); color: #0b0080; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px; text-decoration: none;" title="Katakana">katakana</a><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px;">, used for foreign words and names, </span><a href="http://en.wikipedia.org/wiki/Gairaigo" style="background: none rgb(255, 255, 255); color: #0b0080; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px; text-decoration: none;" title="Gairaigo">loanwords</a><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px;">, </span><a href="http://en.wikipedia.org/wiki/Onomatopoeia" style="background: none rgb(255, 255, 255); color: #0b0080; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px; text-decoration: none;" title="Onomatopoeia">onomatopoeia</a><span style="background-color: white; color: #252525; font-family: sans-serif; font-size: 14px; line-height: 22.3999996185303px;">, scientific names, and sometimes for emphasis. Almost all Japanese sentences contain a mixture of kanji and kana. Because of this mixture of scripts, in addition to a large inventory of kanji characters, the Japanese writing system is often considered to be the most complicated in use anywhere in the world.</span><sup class="reference" id="cite_ref-1" style="background-color: white; color: #252525; font-family: sans-serif; font-size: 11.1999998092651px; line-height: 1; unicode-bidi: -webkit-isolate;"><a href="http://en.wikipedia.org/wiki/Japanese_writing_system#cite_note-1" style="background: none; color: #0b0080; text-decoration: none; white-space: nowrap;">[1]</a></sup><sup class="reference" id="cite_ref-2" style="background-color: white; color: #252525; font-family: sans-serif; font-size: 11.1999998092651px; line-height: 1; unicode-bidi: -webkit-isolate;"><a href="http://en.wikipedia.org/wiki/Japanese_writing_system#cite_note-2" style="background: none; color: #0b0080; text-decoration: none; white-space: nowrap;">[2]</a>"<a href="http://en.wikipedia.org/wiki/Japanese_writing_system">Japanese writing system</a></sup><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Firstly I hit katakana. With some tables, I can get syllables corresponding to the characters and work out something that I can eyeball and match up to some English data. As an extra complication, </span><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">there are also </span><a href="http://en.wikipedia.org/wiki/Half-width_kana#Encoding" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">half-width</a><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"> characters which are semantically equivalent but occupy different codepoints in Unicode. That has parallels to upper/lower case in English, but is a modern development that came about from trying to fit the previously squarish forms into print, typewriters and computer screens.</span><br />
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">Kanji is a different order of shock. Primary school children in Japan learn the first 1000 or so characters. Another thousand plus get taught in high school. The character set is significantly larger in total.</span><br />
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">I will have to see if the next few months cause my head to explode. In the mean time, I can recommend reading this article about the politics involved in getting characters (glyphs ? letters ?) into Unicode. <a href="https://modelviewculture.com/pieces/i-can-text-you-a-pile-of-poo-but-i-cant-write-my-name">I Can Text You A Pile of Poo, But I Can’t Write My Name</a></span><br />
<br />
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">Oh, and I'm still trying to find the most useful character/font set I can have on my PC and use practically in SQL Developer. My current choice shows the Japanese characters when I click in the field in the dataset, but only little rectangles when I'm not in the field. The only one I've found that does show up all the time is really UGLY. </span><br />
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-72989732340755415852015-02-21T13:00:00.000+11:002015-02-21T13:00:16.498+11:00NVARCHAR2, UTL-16 and EmailsDevelopment is often the case of trying several paths through the forest, hoping to find one that leads out the other end. That was the start of my week.<br />
<br />
Until we get our shiny new 12c database running on its shiny new box (and all the data shifted to it), we are living with a mix of databases. To begin with, the data we managed was mostly AU/NZ and Europeans stuff, and the character set is set accordingly. By which I mean one of those Eurocentric things and not UTF-8. We also have a bunch of columns in NVARCHAR2 with AL16UTF16 as the alternative character set.<br />
<br />
I'm pretty sure the new database will start with UTF-8. But in the mean time I was responsible for trying to get emails out of the current database with data in various European and non-European character sets. My paths through that forest went as follows...<br />
<br />
<ul>
<li>It should just work. Let me test it.....Oh bugger.</li>
<li>Okay, maybe if I put "utf-8" in various bits of the message.</li>
<li>And switch the code so it uses NVARCHAR2 rather than defaulting to VARCHAR2.</li>
<li>Oh....UTF-16 isn't the same as UTF-8. I need to convert it somehow</li>
<li>So I can't put UTF-8 values in either my Eurocentric VARCHAR2 or UTF-16 NVARCHAR2.</li>
<li>And I have to get this through SMTP, where you can still see the exposed bones of 7-bit ASCII, </li>
</ul>
<br />
<br />
AHA ! HTML Entities. That means I can get away with using ASCIISTR to convert the UTF-16 strings into a sequence of Hex values for each two-byte character. Then I stick a &#x in front of each character, and I have an HTML representation of the string !<br />
<br />
It stinks of an ugly solution.<br />
I think there should be a way of sending utf-16 in the content, but I couldn't get to it.<br />
<br />
It doesn't help that email HTML is less capable than browser HTML, and has to support a variety of older clients (plus presenting an HTML email body inside of the HTML of a webmail client is always going to be awkward).SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com1tag:blogger.com,1999:blog-13265058.post-6777154791494564232015-01-03T18:11:00.000+11:002015-01-03T18:11:26.374+11:00SQL with Friends ?<span style="font-family: Verdana, sans-serif;">I'm a regular player of the WordsWithFriends game from Zynga. With some of my regular opponents, we have some side chat. That might be something as simple as letting them know you won't be playing for a few days, or a joke arising from an odd sequence of words.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">Recently </span><span style="font-family: Verdana, sans-serif;">I'd been sent an URL as a chat message, with a picture from a holiday. It was quite a long URL, with a dubious few characters that may have been the number zero or the letter "O" etc. </span><span style="font-family: Verdana, sans-serif;">The chat doesn't allow copying, so rather than trying the variations manually, I took the geek road.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">Starting with a <a href="http://cheeky4n6monkey.blogspot.com.au/2014/07/android-has-some-words-with-monkey.html">Cheeky Monkey</a> post, </span><span style="font-family: Verdana, sans-serif;">I learnt that the chat messages were probably in an SQLLite file for the application in a relatively inaccessible 'data/data' location on my Android phone or tablet. </span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;"><a href="http://stackoverflow.com/questions/13006315/how-to-access-data-data-folder-in-android-device">Stackoverflow</a> told me that I can pull the information from there using the Android debugger's backup command (adb). </span><span style="font-family: Verdana, sans-serif;"><i>You may need to install a bunch of stuff, such as an up-to-date Java JDK, to get that running. I'd done that before so it was pretty painless.</i> You also need to <a href="http://motorola-g.blogspot.com.au/2013/12/how-to-enable-usb-debugging-and.html">enable USB debugging</a> on your device.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">Those backups are almost, but not quite, a TAR file. I grabbed a <a href="http://sourceforge.net/projects/adbextractor/">Java tool</a> to convert my backup file into a regular TAR, and then unzipped them with 7-Zip.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">It wasn't too hard to find the relevant db file that contained the chat messages. I've got a newer version of the game than the one Cheeky Monkey used, so I had to dig a bit more. My package was called "</span><span style="font-family: Verdana, sans-serif;">com.zynga.wwf2.free" rather than the older "com.zynga.words" (but I still had the data from the older version on my phone).</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">Once I found the right package, the db file was in the db directory as "wf_database.sqlite". </span><span style="font-family: Verdana, sans-serif;">sqlite3 was conveniently in the same toolkit as the android debugger.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">Back to <a href="http://stackoverflow.com/questions/75675/how-do-i-dump-the-data-of-some-sqlite3-tables">Stackoverflow</a> for some quick sqlite info and I had a set of CREATE TABLE and INSERT statements.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">I could have simply grepped for the URL, but being a database person I couldn't resist a final stage.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">A few find/replaces were need to switch the DDL to Oracle syntax (different data type names and Oracle is constrained by the 30 character column names). I then imported the users (players), games, moves and chat messages into my XE database and came up with a query to extract the chat messages and the player who posted it.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">I <b>think</b> the chat for a deleted game would be a lot harder to recover. While you don't need to root your device, you will need to enable debugging and authorise the backup and so you need regular access to the device. If you can't get past the lock screen, this won't help.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">I mentioned that I still had the data files for the older version of the game. I mistakenly opened these first, and was surprised to find that the user data included email addresses for many entries. None were for my regular opponents, but some were for people I recall playing once or twice. I don't recall many of the users, who may have been people I played as a random pick, or may have been on a 'leaderboard'. The data for the newer version of the game only had the email address for my user. </span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">My player name (sydoracle) is pretty easy to track back to the "real" me, and I use a unique email address when I sign up to most services. But others might have been more concerned to find the email addresses were being shared, even in a concealed manner. </span><br />
<br />SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com1tag:blogger.com,1999:blog-13265058.post-2447030098160657112014-10-12T14:11:00.003+11:002014-10-12T14:16:35.572+11:00Latest Oracle allows SELECT without SELECT...FOR UPDATEDigging through a backlog of Oracle blogs, I came across an gem in a presentation from <a href="http://technology.amis.nl/2014/10/03/everything-that-is-really-useful-in-oracle-database-12c-for-application-developers-oracle-openworld-2014/">AMIS</a> (on <a href="http://www.slideshare.net/lucasjellema/everything-thatisreallyusefulinoracledatabase12cforapplicationdevelopers-oow2014">Slideshare</a>). Got to bullet point 5 on slide 63 and boom !<br />
<br />
You all know that when you grant SELECT on a table to a user, they can do a SELECT FOR UPDATE, locking records in the table and preventing other updates or deletes. [Some client tools may do that in the background. ]<br />
<br />
Well finally Oracle have cottoned on to that too, and there's a lighter-weight <a href="http://docs.oracle.com/database/121/SQLRF/statements_9013.htm#r54c1-t54">"READ" privilege in 12.1.0.2</a> which won't allow SELECT FOR UPDATE.<br />
<br />
This will make DBAs very happy. Actually it won't. The natural state of a DBA is grumpy, at least when in the vicinity of a developer or salesman.<br />
<br />
<br />
PS. Why would SELECT FOR UPDATE ever be a good idea for a user with no UPDATE privilege ?<br />
If I had to guess, I'd say it went back to a 'pre-read consistency' model when you might use a SELECT FOR UPDATE to try to select data that wasn't being updated.sydoraclehttp://www.blogger.com/profile/10404756950638119562noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-82044663079220738812014-07-20T19:53:00.000+10:002014-07-20T19:53:49.162+10:00Putting my DB / Apex install through the wringer<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">I was mucking around trying to get APEX on one of my PCs to be visible on the internet.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><i>This was just a proof-of-concept, not something I intend to actually leave running.</i></span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><b><u>EPG on Port 8080</u></b></span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">I do other testing on the home network too, so I already had my router configured to forward port 80 to another environment. That meant the router's web admin had been shifted to port 8080, and it wouldn't let me use that. Yes, I should find a open source firmware, but <a href="http://wiki.openwrt.org/toh/tp-link/td-w8960n">OpenWRT</a> says it is unsupported and will "brick the router" and I can't see anything for Tomato.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">So I figured I'd just use any incoming router port and forward it to the PC's 8080. I chose 6000. This was not a good choice. Looks like Chrome comes with a <a href="http://superuser.com/questions/188058/which-ports-are-considered-unsafe-on-chrome">list of ports</a> which it thinks shouldn't be talking http. 6000 is one of them, since it is supposed to be used for X11 traffic so Chrome told me it was unsafe and refused to co-operate.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Since it is a black-list of ports to avoid, I just happened to be unlucky (or stupid) in picking a bad one. Once I selected another, I got past that issue.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">My task list was:</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><u>Server</u></span><br />
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><ol>
<li>Install <b>Oracle XE 11gR2</b> (Windows 64-bit)</li>
<li>Configure the EPG for Apex. I ran <b>apex_epg_config.sql</b> as, I had switched straight from the pre-installed Apex 4.0 to 4.2.5 rather than upgrading a version I had actively used. </li>
<li>Unlocked the <b>ANONYMOUS</b> database account</li>
<li>Checked <b>DBMS_XDB.GETHTTPPORT</b> returned 8080 </li>
</ol>
</span><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">(At this point, you can test that you have connectivity to apex on the machine on which XE / Apex is installed, through 127.0.0.1 and localhost).</span><div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><u>Local Network</u></span><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><ol>
<li>Enabled external access by setting <b>DBMS_XDB.SETLISTENERLOCALACCESS(false);</b> </li>
</ol>
</span><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"></span><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">(Now you can test connectivity from another machine on the same local network through whatever hostname and/or IP address is assigned to that machine, such as 10.x.x.x or 192.168.x.x)</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><u>Remote Network</u></span><ul>
<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">I got a handy Dynamic DNS via <a href="http://www.noip.com/">NoIP</a> because my home IP can potentially change (though it is very rare). [Yes, there was a whole mess about <a href="http://www.noip.com/blog/2014/07/03/update-microsoft-takedown/">Microsoft temporarily hijackinging some noip domains</a>, but I'm not using this for anything important.] This was an option in my router setup.</span></li>
<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The machine that runs XE / Apex should be assigned a specific 192.168.1.nnn IP address by the router (based on it's MAC address). </span><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">This configuration is specific to the router hardware, so I won't go into my details here. But it is essential for the next step.</span></li>
<li><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Configure the port forwarding on the router to push incoming traffic on the router's port 8088 off to port 8080 for the IP address of the machine running XE / Apex. This is also router specific. </span></li>
</ul>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">When everything is switched on, I can get to my Apex install from outside the local network based on the hostname set up with noip, and the port configured in the router. I used my phone's 3G internet connection to test this. </span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><b><u>Apex Listener</u></b></span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">My next step was to use the Apex Listener rather than the EPG. Oracle have actually retagged the Apex Listener as RDS (Restful Data Services) so that search engines can confuse it with <a href="http://aws.amazon.com/rds/oracle/">Amazon RDS</a> (Relational Database Service).</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">This one is relatively easy to set up, especially since </span><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">I stuck with <a href="http://docs.oracle.com/cd/E37099_01/doc/doc.20/e25066/install.htm#AELIG7023">"standalone" mode</a> for this test. </span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">A colleague had pointed me to this <a href="http://www.oracle.com/webfolder/technetwork/tutorials/obe/db/apex/r42/PDF_Printing_oll/PDF_Printing_oll.html?cid=8191&ssid=14893065526597">OBE walkthrough on Apex PDF reports via RDS</a>, so I took a spin through that and it all worked seamlessly.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">My next step would be a regular web server/container for RDS rather than standalone. </span><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">I'm tempted to give Jetty a try as the web server and container for the listener rather than Tomcat etc, but the Jetty documentation seems pretty sketchy. I'm used to the thoroughness of the documentation for Apache (as well as Oracle).</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
</div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-41600120952179581602014-06-21T13:14:00.001+10:002014-06-21T13:14:55.499+10:00Literally speaking<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Reading <a href="http://www.grassroots-oracle.com/2014/06/sql-analytics-ranking-with-ordinal.html">Scott Wesley's blog</a> from a days ago, and he made a remark about being unable to concatenate strings when using the ANSI date construct.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The construct </span><span style="font-family: Courier New, Courier, monospace;"><b style="background-color: yellow;">date '1900-01-01'</b></span><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"> is an example of a <i><a href="http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements003.htm#SQLRF51072">literal</a></i>, in the same way as </span><span style="font-family: Courier New, Courier, monospace;"><b style="background-color: yellow;">'01-01'</b></span><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"> is string literal and </span><span style="background-color: yellow; font-family: Courier New, Courier, monospace;"><b>1900</b></span><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"> is a numeric literal. We even have use some more exotic numeric literals such as </span><b><span style="background-color: yellow; font-family: Courier New, Courier, monospace;">1e3</span></b><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"> and </span><span style="font-family: Courier New, Courier, monospace;"><b style="background-color: yellow;">3d</b></span><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"> .</span><br />
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Oracle is pretty generous with implicit conversions from strings to numbers and vice versa, so it doesn't object when we assign a numeric literal to a CHAR or VARCHAR2 variable, or a string to a NUMBER variable (as long as the content is appropriate). </span><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">We are allowed to assign the string literal '1e3' to a number since the content is numeric, albeit in scientific notation.</span><br />
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">So there are no problems with executing the following:</span><br />
<span style="font-family: Courier New, Courier, monospace;">declare</span><br />
<span style="font-family: Courier New, Courier, monospace;"> v number := '1e3';</span><br />
<span style="font-family: Courier New, Courier, monospace;">begin</span><br />
<span style="font-family: Courier New, Courier, monospace;"> dbms_output.put_line(v);</span><br />
<span style="font-family: Courier New, Courier, monospace;">end;</span><br />
<span style="font-family: Courier New, Courier, monospace;">/</span><br />
<br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">However while </span><span style="font-family: Courier New, Courier, monospace;"><b style="background-color: yellow;">3d</b></span><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"> and </span><span style="font-family: Courier New, Courier, monospace;"><b style="background-color: yellow;">4.5f</b></span><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"> can be used as numeric literals, Oracle <b>will</b> object to converting the strings '3d' or '4.5f' into a number because the 'f' and 'd' relate to the data type (Binary Float and Binary Double) and not to the content.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Similarly, we're not allowed to try to use string expressions (or varchar2/char variables) within a date literal, or the related timestamp literal. It </span><u style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">must</u><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"> be the correct sequence of numbers and separators enclosed by single quotes. </span><i><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">It doesn't complain if you use the alternative quoting mechanism, such as </span><span style="font-family: Courier New, Courier, monospace;"><b style="background-color: yellow;">date q'[1902-05-01]'</b></span></i><i><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"> but I'd recommend against it as being undocumented and superfluous.</span></i><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Going further, we have interval literals such as </span><span style="font-family: Courier New, Courier, monospace;"><b style="background-color: yellow;">interval '15' minute</b></span><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"> .In these constructs we are not allowed to omit the quotes around the numeric component. And we're not allowed to use scientific notation for the 'number' either (but again the alternative quoting mechanism is permitted). </span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">I've built an affection for interval literals, which are well suited to flashback queries.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">select versions_operation, a.* </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">from test versions between timestamp sysdate - interval '1' minute and sysdate a;</span><br />
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Confusingly the TIMESTAMP keyword in the query above is part of the flashback syntax, and you have to repeat the word if you are using a timestamp literal in a flashback query. </span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">select versions_operation, a.*</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">from test versions between timestamp timestamp '2014-06-21 12:50:00' </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> and sysdate a</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-77747378543755384182014-06-07T11:05:00.003+10:002014-06-07T11:05:55.090+10:00Apex theme fun<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Sometimes you are working with an off-the-shelf product and find something odd, and you're not quite sure whether it is a bug, a feature or whether you've lost the plot.</span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">I use Oracle's Application Express, and was digging into the included theme_18. The templates refer to classes "t18success" and "t18notification"</span></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD1LwYbG4yRharef4zhREXXumeuYEm7DGWkw90HlV-gewL0fzgEBNXKrVNsrjP8jKZO-Izg-tclhXHdBk-is8qAeLMHecYT5Jw_88hVVUhorSvzzO3EK2zymhEh4cxW9UEYvQP/s1600/theme_18_Page_Template.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD1LwYbG4yRharef4zhREXXumeuYEm7DGWkw90HlV-gewL0fzgEBNXKrVNsrjP8jKZO-Izg-tclhXHdBk-is8qAeLMHecYT5Jw_88hVVUhorSvzzO3EK2zymhEh4cxW9UEYvQP/s1600/theme_18_Page_Template.png" height="315" width="640" /></a></div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<br />
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">And then I go looking into the CSS and see hash / ID selectors.</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">#t18Success{margin:5px auto;font-size:12px;color:#333;background:#DAEED2;width:600px;background-repeat:no-repeat;padding:5px;border:1px #95C682 solid;border-right:none;border-left:none;}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">#t18Notification{margin:5px auto;padding:5px;font-size:12px;color:#333;text-align:center;vertical-align:top;border:1px #ffd700 solid;border-right:none;border-left:none;background-color:#ffffcc;width:600px;}</span></div>
</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">For added confusion, HTML class names are case-sensitive, but CSS selectors are case-<a href="http://stackoverflow.com/questions/12533926/are-class-names-in-css-selectors-case-sensitive">insensitive</a>, so the case differences may or may not be relevant.</span></div>
</div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The application looks nicer if I change the CSS to class selectors, and then I get coloured, dismissable boxes rather than hard to read, unstyled messages. I could probably get the same effect by changing the id="MESSAGE" in the templates, but that seems riskier. At least with the CSS, I am confident that I am just changing the appearance and it shouldn't affect the logic.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Digging deeper, the CSS for more than a dozen of the built-in themes utilise the ID selector "#notification-message" in the CSS. About half a dozen have only a class selector, and another three have both (with the prefix of t followed by the theme number). Finally three just have the ID selector with the theme prefix.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">My gut feel is that they switched from the ID to the class selectors stopping in various places on the way. And some of those places aren't very pretty.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">I'm not sure I see the benefit in having the theme number embedded in templates and selectors. The template tells it which theme CSS file to get, and as long as the template and CSS are consistent, the use of the theme number just seems to add more place you have to edit when you want to customise a theme.</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">This was all checked on a fresh Apex 4.0 instance because I just installed the new Windows 64-bit version of Oracle Express Edition. I'll do an upgrade of that default to the latest 4.2 this weekend too.</span></div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com1tag:blogger.com,1999:blog-13265058.post-89964173102724061132014-04-18T12:08:00.000+10:002014-04-18T12:08:11.966+10:00I Love Logs<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">It occurred to me a few days ago, as I was reading this <a href="http://jeffknupp.com/blog/2014/04/15/how-devops-is-killing-the-developer/">article on DevOps</a>, that I might actually be a DevOps.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">I think of myself as a developer, but my current role is in a small team running a small system. And by running, I mean that we are </span><br />
<br />
<ul>
<li><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">'root' and 'Administrator' on our Linux and Windows servers</span></li>
<li><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">'oracle / sysdba' on the database side, </span></li>
<li><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">the apex administrator account and the apex workspace administrators,</span></li>
<li><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">the developers and testers, </span></li>
<li><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">the people who set up (and revoke) application users and </span></li>
<li><span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">the people on the receiving end of the support email</span></li>
</ul>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Flashbacked to Jeff Smith's article on <a href="http://www.thatjeffsmith.com/archive/2011/06/developers-in-prooooooood/">Developers in Prod</a>. But the truth is that there's a lot of people wearing multiple hats out there, and the job titles of old are getting a bit thin. </span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The advantage of having all those hats, or at least all those passwords, is that when I'm looking at issues, I get to look pretty much EVERYWHERE. </span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">I look at the SSH, FTP and mailserver logs owned by root. The SSH logs generally tell me who logged on where and from where. Some of that is for file transfers (some are SFTP, some are still FTP), some of it is the other members of the team logging on to run jobs. The system sends out lots of mail notifications, and occasionally they don't arrive so I check that log to see that it was sent (and if it may have been too big, or rejected by the gateway).</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Also on the server are the Apache logs. We've got these on daily rotate going back a couple of years because it is a small enough system that the logs sizes don't matter. But Apex stuffs most of those field values into the URL as a GET, so they all get logged by Apache. I can get a good idea of what IP address was inquiring about a particular location or order by grepping the logs for the period in question.</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">I haven't often had the need to look in the Oracle alert logs or dump directories, but they are there if I want to run a trace on some code. </span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">In contracts, I'm often looking at the V$ (and DBA_) views and tables. The database has some audit trail settings so we can track DDL and (some) logons. Most of the database access is via the Apex component, so there's only a connection pool there.</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The SELECT ANY TABLE also gives us access to the underlying Apex tables that tell us the 'private' session state of variables, collections etc. (<a href="http://www.grassroots-oracle.com/2013/01/using-sql-to-view-apex-session-state.html">Scott Wesley blogged on this a while back</a>). Oh, and it amazing how many people DON'T log out of an application, but just shut their browser (or computer) down. At least it amazed me. </span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">The apex workspace logs stick around for a couple of weeks too, so they can be handy to see who was looking at which pages (because sometimes email us a screenshot of an error message without telling us how or where it popped up). Luckily error messages are logged in that workspace log. </span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">We have internal application logs too. Emails sent, batch jobs run, people logging on, navigation menu items clicked. And some of our tables include columns with a DEFAULT from <a href="http://docs.oracle.com/cd/E11882_01/server.112/e26088/functions184.htm#SQLRF51825">SYS_CONTEXT/USERENV</a> (Module, Action, Client Identifier/Info) so we can automatically pick up details when a row is inserted.</span><br />
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">All this metadata makes it a lot easier to find the cause of problems. It isn't voyeurism or spying. Honest. </span><br />
<br /></div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-42277111014268056782014-04-12T14:39:00.005+10:002014-04-12T14:39:56.653+10:00Unique identifiers - but what do they identify<span style="font-family: Arial, Helvetica, sans-serif;">Most of the readers of this blog will be developers, or DBAs, who got the rules of Normalisation drummed into them during some phase of the education or training. But often we get to work with people who don't have that grounding. This post is for them. Feel free to point them at it.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Through normalisation, the tendency is to start with a data set, and by a methodical process extract candidate keys and their dependent attributes. In many cases there isn't a genuine or usable candidate key and artificial / surrogate keys need to be generated. While your bank can generally work out who you are based on your name and address, either of those could change and so they assign you a more permanent customer or account number.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">The difficulty comes when those identifiers take on a life of their own. </span><br />
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;">Consider the phone number. When I dial my wife's phone number, out of all the phones in Australia (or the world), it is her's alone that will ring. Why that one ? </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">In the dark ages, the phone number would indicate a particular exchange and a copper wire leading out of that exchange hard wired to a receiver (or a set of receivers in the case of <a href="http://en.wikipedia.org/wiki/Party_line_%28telephony%29">Party Lines</a>). Now all the routing is electronic, telephones can be mobile and the routing for calls to a particular number can be changed in an instant. A phone number no longer identifies a device, but a service, and a new collection of other identifiers have risen up to support the implementation of that service. An <a href="http://en.wikipedia.org/wiki/International_Mobile_Station_Equipment_Identity">IMEI</a> can identify a mobile handset and the <a href="http://en.wikipedia.org/wiki/International_mobile_subscriber_identity">IMSI</a> indicates a SIM card from a network provider, and we can change the <a href="http://www.acma.gov.au/Citizen/Consumer-info/All-about-numbers/Keeping-your-number/mobile-number-portability-faq">SIM card / IMSI that corresponds to a phone number</a>, or swap SIM cards between handsets. Outside the cellular world, VOIP can shunt 'phone number' calls around innumerable devices using IP addresses. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Time is another factor. While I may 'own' a given phone number at a particular time, I may give that up and someone else might take it over. That may get represented by adding dates, or date ranges to the key, or it can be looked at as a sequence. For example, <a href="http://en.wikipedia.org/wiki/Elizabeth_Taylor#Marriages.2C_romances.2C_and_children">Elizabeth Taylor's husband</a> may indicate one of seven men depending on context. The "fourth husband" or "her husband on 1st Jan 1960" would be Eddie Fisher.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Those without a data modelling background that includes normalisation may flinch at the proliferation of entities and tables in a relational environment. As developers and architects look at newer technologies some of the discipline of the relational model will be passed over. Ephemeral transactions can cluster the attributes together in XML or JSON formats with no need for consistency of data definitions beyond the period of processing. Data warehousing quickly discarded relational formats in favour of 'facts' and 'dimensions'. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">The burden of managing a continuous and connected set of data extending over a long period of time, during which the identifiers and attributes morph, is an ongoing challenge in database design.</span><br />
<br />SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-90602157197778642882014-03-09T20:03:00.000+11:002014-03-09T20:03:14.661+11:00Pre-digested authentication<span style="font-family: Arial, Helvetica, sans-serif;">A bit of a follow-up to my previous post on Digest authentication.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">The fun thing about doing the hard yards to code up the algorithm is that you get a deeper level of understanding about what's going on. Take these lines:</span><br />
<br />
<div style="background-color: white; color: #444444; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; line-height: 18.200000762939453px;">
<span style="font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">v_in_str := </span><span style="font-family: 'Courier New', Courier, monospace;">utl_raw.cast_to_raw(</span><span style="font-family: 'Courier New', Courier, monospace;">i_username||':'||i_realm||':'||i_password);</span></span></div>
<div style="background-color: white; color: #444444; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; line-height: 18.200000762939453px;">
<span style="font-family: 'Courier New', Courier, monospace;"><span style="font-size: x-small;"> v_ha1 := lower(DBMS_OBFUSCATION_TOOLKIT.md5(input => v_in_raw));</span></span></div>
<div style="background-color: white; color: #444444; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.200000762939453px;">
<br /></div>
<div style="background-color: white; color: #444444; line-height: 18.200000762939453px;">
<div style="color: black; font-family: 'Times New Roman'; line-height: normal;">
<span style="font-family: Arial, Helvetica, sans-serif;">Every time we build the "who we are" component for this site, we start with exactly the same hash made up of the username, realm (site) and password. This is a batch routine, which means somewhere we would store the username and password for the site - whether that is a parameter in a scheduling tool, coded into a shell script or OS file, or somewhere in the database. <i>If you've got the security option for Oracle, you can use the Wallet, with its own security layers.</i></span></div>
<div style="color: black; font-family: 'Times New Roman'; line-height: normal;">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div style="color: black; font-family: 'Times New Roman'; line-height: normal;">
<span style="font-family: Arial, Helvetica, sans-serif;">But digest authentication gives us another option. Since we actually use the hashed value of the user/site/password, we can store that instead. The receiving site has no idea the code doesn't actually know the REAL password.</span></div>
<div style="color: black; font-family: 'Times New Roman'; line-height: normal;">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div style="color: black; line-height: normal;">
<span style="font-family: Arial, Helvetica, sans-serif;">Now turn that over in your head. We can call the web service as this user WITHOUT knowing the password, just by knowing the hash. I don't know about you, but it makes me a little bit more worried when I hear of user details being leaked or hacked from sites. It's all very well reassuring us the passwords are hashed and can't be reverse engineered (assuming your own password can't be brute-forced). But depending on the security mechanism, a leak of those hashes can be dangerous. <b>If a hacked provider advises people to change their passwords, take their advice.</b> </span></div>
<div style="color: black; line-height: normal;">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div style="color: black; line-height: normal;">
<span style="font-family: Arial, Helvetica, sans-serif;">'Basic' authentication doesn't have the same weakness. In that environment the provider can store the password hash after applying their own 'secret sauce' mechanism (mostly a <a href="http://en.wikipedia.org/wiki/Salt_(cryptography)">salt</a>). When you authenticate, you send the password, they apply the secret sauce and compare the result. You can't get away without knowing the password, because all the work is done at their end.</span></div>
<div style="color: black; line-height: normal;">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div style="color: black; line-height: normal;">
<span style="font-family: Arial, Helvetica, sans-serif;">There's no secret sauce for digest authentication, and there can't be. Even if the provider had the password in the clear, there's no way they can be sure the client has the password since all the client needs is the result of the hash. The provider must store, or be able to work out, the result of that hash because they need to replicate the final hash result using both the client and server nonces. They can store either that same user/realm/password hash as is, or they can encrypt it in a reversible manner, but a one-way hash wouldn't be usable.</span></div>
<div style="color: black; line-height: normal;">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div style="color: black; line-height: normal;">
<span style="font-family: Arial, Helvetica, sans-serif;">In short, digest authentication means that our batch routine doesn't need to 'know' the actual password, just a hash. But it also makes those hashes a lot more dangerous.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><i>I'm an amateur in this field. I checked around and it does seem this is a recognized limitation of digest authentication. EG: This <a href="http://security.stackexchange.com/questions/43696/is-http-digest-md5-still-an-alternative-to-consume-my-own-api">Q&A</a> and <a href="http://mark-kirby.co.uk/2013/how-to-authenticate-apis-http-basic-vs-http-digest/">this comparison of Digest and Basic</a>.</i></span></div>
<div style="font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif;">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
</div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-68969265808436412042014-03-08T10:28:00.002+11:002014-03-08T10:35:16.478+11:00PL/SQL, UTL_HTTP and Digest Authentication<span style="font-family: Verdana, sans-serif;">For the first time in what seems like ages, I've actually put together a piece of code worth sharing. It's not that I haven't been working, but just that it has all been very 'in-house' specific.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">However I had a recent requirement to use a web service that makes use of Digest Authentication. If you have look at the UTL_HTTP <a href="http://docs.oracle.com/cd/E11882_01/appdev.112/e40758/u_http.htm#ARPLS71080">SET_AUTHENTICATION</a> subprogram, it only addresses Basic authentication (and, apparently, Amazon S3 which looks intriguing).</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">In Basic authentication, the username and password get sent across as part of the request. Going through SSL, that doesn't seem too bad, as it is encrypted over the transfer and the certificates should ensure you are talking to the legitimate destination. However if that destination has been compromised, you've handed over your username and password. In an ideal world, the server shouldn't need to know your password, which is why database should only have hashed versions of passwords. </span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">Outside of SSL, you might as well just print the username and password on the back of a postcard.</span><span style="font-family: Verdana, sans-serif;"><br /></span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">In Digest authentication, you get a more complex interaction that keeps the password secret. You ask for a page, the server responds with an "Authentication Required" plus some bits of information including a nonce. You come up with a hashed value based on the server nonce, your own nonce and a <u>hash of your username and password</u> and send it back with the next request. The server has its own record of your <u>username/password hash</u> and can duplicate the calculations. If everyone is happy, the server can fulfill your request and nobody ever actually needs to know the password.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">Our server used SSL, and thanks to Tim's article on <a href="http://www.oracle-base.com/articles/misc/utl_http-and-ssl.php">SSL and UTL_HTTP</a>, it was a simple set up. I've done it before, but that was in the days when it seemed a lot hard to get certificates OUT of a browser to put them in your Oracle Wallet.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">The Interwebs were a lot less forthcoming on a PL/SQL implementation of Digest authentication though. The closest I got was <a href="https://community.oracle.com/thread/1030453?tstart=0">this discussion</a>, which can be summed up as "</span><span style="background-color: white; color: #575757; font-family: 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 13px; line-height: 19.5px;">This may be complex, but I do not see these offhand as being impossible to do in PL/SQL....</span><span style="background-color: white; color: #575757; font-family: 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 13px; line-height: 19.5px;">No Digest configured web server nearby or I would definitely have had a bash at this</span><span style="background-color: white; color: #575757; font-family: 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; font-size: 13px; line-height: 19.5px;">"</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">A read through the <a href="http://en.wikipedia.org/wiki/Digest_access_authentication">Wikipedia article</a>, and I came up with the code below:</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">Firstly, after the initial request, go through the header to get the 'WWW-Authenticate' item. Take the value associated with that header, and pass it to the "auth_digest" procedure. </span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_max := UTL_HTTP.GET_HEADER_COUNT(l_http_response);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_ind := 1;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_name := '-';</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> while l_ind <= l_max AND l_name != 'WWW-Authenticate' LOOP</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> UTL_HTTP.GET_HEADER(l_http_response, l_ind, l_name, l_value);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> IF l_name = 'WWW-Authenticate'</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> AND l_http_response.status_code = UTL_HTTP.HTTP_UNAUTHORIZED THEN</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> -- Unauthorized. Using the Authorization response header, we can come up with the</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> -- required values to allow a re-request with the authentication/authorisation details</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> dbms_application_info.set_action('auth:'||$$PLSQL_LINE);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> UTL_HTTP.END_RESPONSE(l_http_response);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> dbms_application_info.set_action('auth_req:'||$$PLSQL_LINE);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_http_request := UTL_HTTP.BEGIN_REQUEST(l_server||l_method);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> auth_digest (io_http_request => l_http_request, i_auth_value => l_value,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> i_username => nvl(i_username,'xxxx'), i_password => nvl(i_password,'xxxx'), </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> i_req_path => l_method, </span><span style="font-family: 'Courier New', Courier, monospace; font-size: xx-small;">i_client_nonce => null);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> dbms_output.put_line($$PLSQL_LINE||':Get Response from authenticated request');</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> dbms_application_info.set_action('auth_resp:'||$$PLSQL_LINE);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_http_response := UTL_HTTP.GET_RESPONSE(l_http_request);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> dump_resp (l_http_response);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> dump_hdr (l_http_response);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> END IF;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_ind := l_ind + 1;</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> END LOOP;</span><br />
<div>
<br /></div>
<span style="font-family: Verdana, sans-serif;">The auth_digest starts with an extraction of the 'valuables' from that value string. I've used regular expressions here. I spent time working with grep, awk and perl, and regexes are habit forming.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> procedure extract_auth_items</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> (i_text in varchar2,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> o_realm out varchar2, o_qop out varchar2, o_nonce out varchar2, o_opaque out varchar2) is</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> begin</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> o_realm := substr(regexp_substr(i_text, 'realm="[^"]+' ),8);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> o_qop := substr(regexp_substr(i_text, 'qop="[^"]+' ),6);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> o_nonce := substr(regexp_substr(i_text, 'nonce="[^"]+' ),8);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> o_opaque := substr(regexp_substr(i_text, 'opaque="[^"]+'),9);</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> end extract_auth_items;</span><br />
<div>
<br /></div>
<div>
Next is the 'meat' where the values are combined in the various hashes. Yes, there's a hard-coded default client nonce in there that, by a strange coincidence, matches on in the wikipedia article. That's how this stuff gets developed, by following through a worked example. Just like school.</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> function digest_auth_md5_calcs</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> (i_username in varchar2, i_password in varchar2, i_req_path in varchar2,</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> i_realm in varchar2, i_server_nonce in varchar2,</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> i_qop in varchar2 default 'auth',</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> i_client_nonce in varchar2 default '0a4f113b',</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> i_req_type in varchar2 default 'GET', i_req_cnt IN NUMBER default 1)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> return varchar2 is</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_in_str varchar2(2000);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_in_raw raw(2000);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_out varchar2(60);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_ha1 varchar2(40);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_ha2 varchar2(40);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_response varchar2(40);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> begin</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_in_str := i_username||':'||i_realm||':'||i_password;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_in_raw := utl_raw.cast_to_raw(v_in_str);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_out := DBMS_OBFUSCATION_TOOLKIT.md5(input => v_in_raw);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_ha1 := lower(v_out);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_in_str := i_req_type||':'||i_req_path;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_in_raw := utl_raw.cast_to_raw(v_in_str);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_out := DBMS_OBFUSCATION_TOOLKIT.md5(input => v_in_raw);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_ha2 := lower(v_out);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_in_str := v_ha1||':'||i_server_nonce||':'||lpad(i_req_cnt,8,0)||':'||</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> i_client_nonce||':'||i_qop||':'||v_ha2;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_in_raw := utl_raw.cast_to_raw(v_in_str);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_out := DBMS_OBFUSCATION_TOOLKIT.md5(input => v_in_raw);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> v_response := lower(v_out);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> return v_response;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> end digest_auth_md5_calcs;</span></div>
</div>
<div>
<br /></div>
<span style="font-family: Verdana, sans-serif;">And this is the full auth_digest bit</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> procedure auth_digest</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> (io_http_request in out UTL_HTTP.REQ, i_auth_value in varchar2,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> i_username in varchar2, i_password in varchar2,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> i_req_path in varchar2, i_qop in varchar2 default 'auth',</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> i_req_cnt in number default 1, i_client_nonce in varchar2 default null)</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> is</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_realm varchar2(400);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_qop varchar2(30);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_server_nonce VARCHAR2(400);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_opaque varchar2(100);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_response varchar2(40);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_value VARCHAR2(1024);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_client_nonce varchar2(30);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> begin</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> -- Apply the username / password for Digest authentication</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> extract_auth_items (i_auth_value,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_realm, l_qop, l_server_nonce, l_opaque);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> IF i_client_nonce is not null then</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_client_nonce := i_client_nonce;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> ELSE</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_client_nonce := lower(utl_raw.cast_to_raw(DBMS_OBFUSCATION_TOOLKIT.md5(</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> input_string=>dbms_random.value)));</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> END IF;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_response := digest_auth_md5_calcs</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> (i_username => i_username, i_password => i_password, i_req_path => i_req_path,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> i_realm => l_realm, i_server_nonce => l_server_nonce,</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> i_client_nonce => l_client_nonce);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --i_qop default to auth, i_req_type default to GET and i_req_cnt default to 1</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_value := 'Digest username="' ||i_username ||'",'||</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> ' realm="' ||l_realm ||'",'||</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> ' nonce="' ||l_server_nonce ||'",'||</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> ' uri="' ||i_req_path ||'",'||</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> ' response="' ||l_response ||'",'||</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> ' qop=' ||i_qop ||',' ||</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> ' nc=' ||lpad(i_req_cnt,8,0) ||',' ||</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> ' cnonce="' ||i_client_nonce ||'"'</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> ;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> IF l_opaque is not null then</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> l_value := l_value||',opaque="'||l_opaque||'"';</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> END IF;</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> dbms_output.put_line(l_value);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> UTL_HTTP.SET_HEADER(io_http_request, 'Authorization', l_value);</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> --</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> end auth_digest;</span><br />
<div>
<br /></div>
<div>
<span style="font-family: Verdana, sans-serif;">A package with the code is available from my <a href="http://www.sydoracle.com/Codespace">CodeSpace</a> page, or directly <a href="http://www.sydoracle.com/Codespace/digest_auth.sql?attredirects=0&d=1">here</a>. There's a lot of debug 'stuff' in there. The code I'm using is still tailored to my single specific need, and I've stripped specific values from this published variant. You'll need to hard-code or parameterize it for any real use. I may be able to do a 'cleaned-up' version in the future, but don't hold your breath.</span></div>
<div>
<br /></div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com1tag:blogger.com,1999:blog-13265058.post-24739354770852604782014-02-09T18:53:00.003+11:002014-02-09T18:53:49.739+11:00Chrome's HOST-RULE flag<span style="font-family: Trebuchet MS, sans-serif;">I'm currently working in an Apex environment, and we will soon be running some of our apex applications off a second domain name mapped to the same host.</span><div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;">For me this has mean a little playing around with VirtualHost in the httpd.conf which is something I don't get to do very often. But I am having to wait on others to actually set up the new DNS entry to map the domain name to the server.</span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;">If this was a brand new server with its own IP, then I could simply use the IP address. But since it is sharing a server and request using the IP goes straight to the old 'default' VirtualHost.</span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;">On the server itself I can touch up the hosts file to hard-code the entry. But the only browser I can use on the server is very dated and nearly unusable. And on my PC, I don't have admin rights to amend the PC hosts file.</span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;">Fortunately we do get chrome on our machines (tucked away as chrome-frame, but chrome nonetheless). And chrome has a handy little command line flag called "--host-rules". </span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;">Using: </span><span style="background-color: white; color: #222222; font-family: Calibri, sans-serif; font-size: 15px;">--host-rules="MAP newdev.site.com</span><span style="background-color: white; color: #222222; font-family: Calibri, sans-serif; font-size: 15px;"> 10.16.100.200"</span><span style="font-family: 'Trebuchet MS', sans-serif;"> I can map the new hostname to its planned IP address and bypass the DNS lookup on the PC. Very handy when you are waiting for the DNS entry or if you want to override an existing name to point to a test or dev environment.</span></div>
<div>
<span style="font-family: Trebuchet MS, sans-serif;"><br /></span></div>
<div>
<br /></div>
<div>
<span style="background-color: white; color: #222222; font-family: Calibri, sans-serif; font-size: 15px;"><br /></span></div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-61354433451090876882013-10-30T22:25:00.002+11:002013-10-30T22:26:55.653+11:00Oracle 11g XE installed on Windows 8.1<span style="font-family: Verdana, sans-serif;">I count myself lucky if a post here gets a few hundred views. I have two posts that have hit 4000+ views, and a third edging towards 3000.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">In third place is a reference to <a href="http://blog.sydoracle.com/2011/02/when-does-foreign-key-not-reference.html">foreign keys</a> referencing unique constraints rather than a primary key.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">In second place, and heading towards its second birthday, was my desire for SQL Developer to have a "<a href="http://blog.sydoracle.com/2011/11/how-to-prevent-your-sql-developer.html">keep awake</a>" function that stops sessions being killed. It still doesn't but will restore connections. </span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">In first place, was an almost throwaway article from when I <a href="http://blog.sydoracle.com/2012/11/windows-8-running-oracle-11g-xe.html">migrated my netbook from XP to Windows 8</a>. I installed Oracle 11g XE on it, and apparently a lot of people are (or were) interested in that. I guess people get Windows 8 on a machine and wonder if it is worth trying an XE install. The XE install on Windows is trivially simple:</span><br />
<br />
<ol>
<li><span style="font-family: Verdana, sans-serif;">Download</span></li>
<li><span style="font-family: Verdana, sans-serif;">Unzip</span></li>
<li><span style="font-family: Verdana, sans-serif;">Run the setup program</span></li>
<li><span style="font-family: Verdana, sans-serif;">Choose a directory</span></li>
<li><span style="font-family: Verdana, sans-serif;">Enjoy a cup of coffee while it churns through. You have time for a biscuit too.</span></li>
</ol>
<br />
<span style="font-family: Verdana, sans-serif;">That article is nearing its first anniversary. In honour of that occasion, I upgraded to Windows 8.1. Oracle XE broke. Specifically I couldn't find the services that ran the listener or the database or anything Oracle related. A repair install of XE didn't fix things. </span><i style="font-family: Verdana, sans-serif;">Disclaimer: I don't use Oracle a lot on that machine, and it possible that something other than the 8.1 upgrade broke it.</i><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">I uninstalled it (that would have been the 'repaired' install), blew away all the database files as I had nothing I wanted to keep, and re-installed (instructions above - my biscuit was a Tim Tam, but people in the UK may substitute a p-p-p-penguin). It seems to work fine now.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>
<span style="font-family: Verdana, sans-serif;">So Oracle 11g XE works on Windows 8.1, as far as I can see. Bear in mind that XE doesn't have any real support anyway, so the difference between a 'supported' and 'unsupported' configuration is purely imaginary. I don't do anything like RMAN backups and restores, let alone between OS upgrades. I can't see why they wouldn't work, but I'm not a DBA.</span><br />
<span style="font-family: Verdana, sans-serif;"><br /></span>SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-42896568637168443012013-10-13T19:31:00.002+11:002013-10-13T19:31:55.925+11:00'Medalling' in HumourYesterday I competed, and came third, in the Humorous Speech contest of the <a href="http://www.d70toastmasters.org.au/district-70/divisions/hawkesbury/">Hawkesbury Division</a> of Toastmasters. I'm pretty chuffed with that.<br />
<br />
Partly, I'll blame <a href="http://www.linkedin.com/in/yuryvelikanov">Yuri</a> for this. He recommended Toastmasters as a way of getting some extra public speaking skills. Luckily for me, there's a group that meets one lunchtime a week at work, which makes attendance relatively easy. Much easier than trying to fit in an evening on top of my kids' busy social and sporting calendars. I started going just before Christmas and became a paid up member in January this year.<br />
<br />
Next, I'll blame <a href="http://www.linkedin.com/profile/view?id=185236065">Neil Sequeira</a> who prompted me to enter the club contest a month ago on the basis that attendees regularly laughed at my speeches....in a nice way. I won that, and then it dawned on me that I'd be going into the Area level contest. Our club was hosting that event, so I had a slight 'home ground' advantage, but I was still in front of a bunch of people I didn't know, most of whom have been honing their speaking skills for YEARS.<br />
<br />
I won that, which meant going up to the Division level contest last night. That was in a church hall, unfamiliar territory for me. We were speaking from an elevated stage, and with a headset microphone. Getting into the big leagues.<br />
<br />
I was a bit ruffled because my trip there was delayed with my phone unaccountably deciingd it couldn't find any GPS signal, and refusing to tell me where I was or how to get where I was supposed to be. My <a href="https://www.google.com.au/maps?q=St.+Kieran's+Catholic+Church+Manly+Vale,+King+Street,+Manly+Vale+NSW&t=m&z=16">destination</a> was the other side of Middle Harbour so my regular tactic of pointing the car vaguely in the right direction and hoping for the best was foiled by its inability to fly across the water. Resorting to my trusty and dusty Gregory's Street Directory I made the 40 minute journey in a mere 80 minutes.<br />
<br />
My speech starts with the other <a href="http://www.garymyers.com.au/#!biography">Gary Myers</a>, multi-time champion of <a href="http://www.themotorreport.com.au/gallery/4834/2013-summernats-26-gallery/68686/2013summernats26themotorreport00?">Summernats</a> (which I've mentioned before in my <a href="http://blog.sydoracle.com/2011/01/on-coincidences.html">blog</a> ) and <a href="https://ssltw.servers121.com/~dlra00/profiles/266.htm">land speed record holder</a>. Oh, and <a href="http://www.narranderaargus.com.au/ArticleDetails/tabid/65/ArticleID/847/Driven-to-politics.aspx">candidate for one of the NSW Senate</a> spots for Federal parliament. He didn't win, but a candidate for the same party did get a spot for Victoria. I suspect this came as somewhat a surprise to him, as the Senate voting system is complex and highly unpredictable. An <a href="http://www.heraldsun.com.au/news/victoria/australian-motoring-enthusiast-hopeful-ricky-muir-says-he-is-ready-for-life-as-a-politician-in-canberra/story-fni0fit3-1226724468307">unemployed ex-sawmill worker</a> who didn't own a suit and has kangaroo poo chucking as a hobby will be an interesting addition to the chamber.<br />
<br />
I was more than happy with my third place finish in the contest. The winner, who also took the Table Topics contest top prize, was excellent. And second place went to a <a href="http://www.davethehappysinger.com/">Dave the Happy Singer</a> who took the mick out of homoeopathy and similar rubbish, so I won't criticise that. I get a small trophy and a certificate. And an update to my LinkedIn profile.<br />
<br />
And, for posterity, my certificates:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDn9N335fBXMAtHQa9KZNKuh2wGIcJMmjKwBl3jkd2N3qckokA18MKOnSmfFsSGskXfJO-wzemfxNNGS0Mm1_H_Is5-aOftuamYb6BJHJd4iyiyx18ixz55YkMy2vK2iZzJ8lj/s1600/scan0001.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="234" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDn9N335fBXMAtHQa9KZNKuh2wGIcJMmjKwBl3jkd2N3qckokA18MKOnSmfFsSGskXfJO-wzemfxNNGS0Mm1_H_Is5-aOftuamYb6BJHJd4iyiyx18ixz55YkMy2vK2iZzJ8lj/s320/scan0001.jpg" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw1nqjkMsRZaYFOnzrpvX5rozKNhmvus2-LBcgTPOS4b7TRQgTplZOMKHF7vi7DM8P-4p7KOq5icfdH5vMh_XTWYbUjIiWSmPxlnN6lrOj36WjPzI1B50fPs1jlmukRCxbKZat/s1600/scan0002.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiw1nqjkMsRZaYFOnzrpvX5rozKNhmvus2-LBcgTPOS4b7TRQgTplZOMKHF7vi7DM8P-4p7KOq5icfdH5vMh_XTWYbUjIiWSmPxlnN6lrOj36WjPzI1B50fPs1jlmukRCxbKZat/s320/scan0002.jpg" width="320" /></a></div>
<br />
<br />SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-5516447345367889792013-09-22T11:50:00.000+10:002013-09-22T13:23:50.968+10:00Tracking email receipts through images<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">I pinched a technique from EMail marketeers last week. It goes by the cool name of a web beacon or <a href="http://en.wikipedia.org/wiki/Web_beacons">web bug</a> and is used to detect when someone reads (or at least opens) an email.</span><br />
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Our application is like a work flow system and it sends out a whole bunch of emails. I'm a little sceptical about who reads them, especially since I've got a bunch of rules that automatically ignore about 20-30 emails a day.</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">For a new email alert to a distribution list, I decided to code in a beacon. </span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">First for each email sent, it grabs a unique identifier. You can use a plain sequence, but I opted for a GUID. It is harder for anyone to guess other values for GUIDs and it is easy for me to tell which ones come from the test environment and which ones from production.</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> declare</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> v_guid_vc varchar2(32);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> begin</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> v_guid_vc := sys_guid();</span></div>
<div style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">
<br /></div>
</div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Then, the email HTML body included an image link</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<pre><span style="font-family: Courier New, Courier, monospace; font-size: x-small;">v_body := v_body || </span></pre>
<pre><span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 'img src="http://'||v_host||'/PKG_MAIL.image?i_val='||v_guid_vc||''' ';
</span></pre>
<div>
<br /></div>
<pre><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><mg arial="" font-family:="" helvetica="" neue="" sans-serif="" src="http://'||v_host||'/PKG_MAIL.image?i_val='||v_guid_vc||''' />';
</pre>
</div>
<div>
<span style=">These mails go out to internal users, and Outlook is the primary email tool. The technique doesn't work for users reading their mail through Outlook webmail or the iOS email. The host is behind our firewall and will be unreachable from a home email account. But our company</mg> standard Outlook config will happily try to render that image when the user opens the email at their desk. And when that happens, it tries to get the image content by calling PKG_MAIL.image and telling us the GUID we associated with that email.</span></pre>
</div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">When we get that image request, we record the GUID, timestamp, IP address, user agent and cookie data. If the user happens to be logged into our system at that time, the cookie will tell us who the reader is. If not, the IP address will give us a clue. [When someone logs into the application, we record the userid and IP address, so we can see if someone logged in from that address recently.] Once we've recorded that data, we return a standard image content, irrespective of the GUID passed in.</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><b>No one has to click any link for the picture rendering / email read to be logged.</b></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;">Rather than sending one email to ten recipients (with the same GUID), you will be better off sending ten variations with their own GUIDs. </span><span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">If you are sending the email to a specific individual, you may not need that excess logging (unless you want to track forwarded emails too). </span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">Personal email clients, such as Thunderbird and GMail, tend not to open remote images by default, offering a vague "privacy" warning. This is what they are warning you about. It means that Dominos probably know that I read their email vouchers about 5 minutes before ordering a pizza. And they will know whether I am using Thunderbird or Chome, and a bunch of other stuff about me. But, cheaper pizza !</span></div>
<div>
<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<pre style="white-space: pre-wrap; word-wrap: break-word;"></pre>
</div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-3688633201268335612013-08-18T12:40:00.002+10:002013-08-18T12:40:57.509+10:00Session based sequences in 12c.Catching up on some blogs, and I saw this 12c gem by <a href="http://allthingsoracle.com/oracle-database-12c-new-features-part-4/">Syed Jaffar Hussain</a>.<br />
<br />
Sequences are great. But sometimes they're just a little more unique than you actually need. Sort of like <a href="http://docs.oracle.com/cd/B12037_01/server.101/b10759/functions153.htm">GUID</a>s. Start churning through them and they're quickly nine or ten digits. There's nothing wrong with long keys from a technical perspective as the extra byte or two of storage is rarely significant. But they can be greedy from a screen layout point of view (especially in tabular forms). And there's a greater chance of getting digits mixed up in email or conversations about them.<br />
<br />
If you are doing a nightly or weekly load, it can be nice to load up your half-a-million rows with a 'batch id' and a 'sequence in batch'. <a href="http://docs.oracle.com/cd/E16655_01/server.121/e17209/statements_6016.htm">Session based sequences</a> are a nice concept that give you scope for keeping those values in a smaller range.<br />
<br />
Another trick for reducing the size of IDs is to covert them into HEX. You'll probably only save one character there though, but the mix of alphabetic and numeric characters. TO_CHAR and TO_NUMBER are both happy to use 'XXXXXXXX' format masks to convert between decimal and hex.<br />
<br />
<br />SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-16664452359019862252013-07-30T06:30:00.000+10:002013-07-30T06:30:00.751+10:00WITH enhancements in 12c There's been some mentions of this feature on <a href="http://www.oracle-base.com/articles/12c/with-clause-enhancements-12cr1.php">Oracle-base</a> and <a href="http://sqlplsql.wordpress.com/2013/07/09/work-with-with-option/">elsewhere</a>, but here's an example of what excites me.<br />
<br />
If you deal with nested arrays/tables in SQL, then you quickly bump into an impedance match. You can't readily get that embedded list into horizontal columns.<br />
<br />
I'll use the example I'm most familiar with - 2-D geometry data types.<br />
<br />
There's a concept called the MBR (minimum bounding rectangle). You can basically think of it as the most northerly, southerly, easterly and westerly points of an area.<br />
<br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">select a.mbr from LGA_2012_AUST a where lga_name12 = 'Darwin (C)';</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">MBR(SDO_GTYPE, SDO_SRID, SDO_POINT(X, Y, Z), SDO_ELEM_INFO, SDO_ORDINATES)</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">--------------------------------------------------------------------------------</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">SDO_GEOMETRY(2003, 8311, NULL, </span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> SDO_ELEM_INFO_ARRAY(1, 1003, 3), </span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> SDO_ORDINATE_ARRAY(130.815117, -12.469386, 130.938563, -12.33006))</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
The MBR is a geometry column with an ordinate array listing the four points.<br />
<br />
We can do a Collection Unnesting operation, but then we end up with rows.<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">select b.* from LGA_2012_AUST a, table(a.mbr.sdo_ordinates) b </span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">where lga_name12 = 'Darwin (C)';</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">COLUMN_VALUE</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">------------</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 130.815117</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -12.469386</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> 130.938563</span><br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;"> -12.33006</span><br />
<br />
To get back to columns, you'd need a PIVOT operation. But because we've lost any sense of the order of those values in the array, that has limitations. In Australia we can easily tell the difference between our latitudes and longitudes, but that isn't possible for many locations.<br />
<br />
The WITH operator allows us to extract those array elements easily, and without recourse to a stored function. Though the PRAGMA UDF mention by Tim may mean I don't need to fret about the context switches of switching between SQL and PL/SQL as much.<br />
<br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">SQL> l</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> 1 WITH</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> 2 FUNCTION ext_val (i_arr in MDSYS.SDO_ORDINATE_ARRAY, i_val in number) RETURN NUMBER IS</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> 3 BEGIN</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> 4 return i_arr(i_val);</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> 5 END;</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> 6 select ext_val(a.mbr.SDO_ORDINATES,1) v1, ext_val(a.mbr.SDO_ORDINATES,2) v2,</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> 7 ext_val(a.mbr.SDO_ORDINATES,3) v3, ext_val(a.mbr.SDO_ORDINATES,4) v4</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> 8 from LGA_2012_AUST a</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> 9* where lga_name12 = 'Darwin (C)'</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">SQL> /</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> V1 V2 V3 V4</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">---------- ---------- ---------- ----------</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">130.815117 -12.469386 130.938563 -12.33006</span><br />
<br />
My demo in SQL*Plus works fine in version 12c.<br />
In the 11.2 Instant Client, I could get it to run using<br />
<span style="color: red; font-family: Courier New, Courier, monospace;">set sqlterminator #</span><br />
<br />
That stops it treating the ";" in line 4 as a terminator, and allows it to pull in the whole statement. The backslash will send it off to the DB for processing, and it works fine then<br />
<br />
SQL Developer 4 also seems to choke on the syntax. I'll have to work up the strength to see if it is already logged as an issue. I assume it won't work in 3.2, and that a 12c rollout will require SQL*Plus and SQL Developer installs to be upgraded. Not sure about TOAD and any other clients.SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com1tag:blogger.com,1999:blog-13265058.post-62105471782846620922013-05-27T12:02:00.000+10:002013-05-27T12:02:49.464+10:00The Adventures of the Trickster developer - Aliases<span style="font-family: Arial, Helvetica, sans-serif;">The <a href="http://en.wikipedia.org/wiki/Trickster">Trickster</a> is a mythological being who enjoys potentially dangerous counter-intuitive behaviour. You'll often find him deep within the source code of large systems.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;"><b><u>The Alias Trap</u></b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Generally an alias in a query is there to make it easier to understand, either for the developer or the database. H</span><span style="font-family: Arial, Helvetica, sans-serif;">owever the Trickster can reuse aliases within a query to make things more confusing.</span><br />
<br />
<br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">desc scott.emp</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> Name Null? Type</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> ---------- -------- --------------------</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">1 EMPNO NOT NULL NUMBER(4)</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">2 ENAME VARCHAR2(10)</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">3 JOB VARCHAR2(9)</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">4 MGR NUMBER(4)</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">5 HIREDATE DATE</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">6 SAL NUMBER(7,2)</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">7 COMM NUMBER(7,2)</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">8 DEPTNO NUMBER(2)</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">desc scott.salgrade</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> Name Null? Type</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> --------- -------- --------------------</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">1 GRADE NUMBER</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">2 LOSAL NUMBER</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">3 HISAL NUMBER</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"></span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">desc scott.dept</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> Name Null? Type</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> --------- -------- --------------------</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">1 DEPTNO NOT NULL NUMBER(2)</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">2 DNAME VARCHAR2(14)</span><br />
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">3 LOC VARCHAR2(13)</span><br />
<span style="color: red; font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">The trickster can try queries such as</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="color: red; font-family: Courier New, Courier, monospace; font-size: x-small;">SELECT e.ename, e.grade</span><br />
<span style="color: red; font-family: Courier New, Courier, monospace; font-size: x-small;">FROM scott.emp e </span><br />
<span style="color: red; font-family: Courier New, Courier, monospace; font-size: x-small;"> JOIN scott.salgrade e ON e.sal BETWEEN e.losal AND e.hisal;</span><br />
<span style="color: red; font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">and</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="color: red; font-family: Courier New, Courier, monospace; font-size: x-small;"></span><br />
<span style="color: red; font-family: Courier New, Courier, monospace; font-size: x-small;">SELECT x.ename, x.dname</span><br />
<span style="color: red; font-family: Courier New, Courier, monospace; font-size: x-small;">from scott.emp x join scott.dept x using (deptno);</span><br />
<div>
<span style="color: red; font-family: Courier New, Courier, monospace; font-size: x-small;"><br /></span></div>
<br />
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">As long as any prefixed column names involved are unique to a table, the database can work out what to do. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">If you find this in a 'live' query, it is normally one with at least half a dozen tables where an extra join has been added without noticing that the alias is already in use. And you'll discover it when a column is added to one of those tables causing the database to throw up its hands in surrender. </span><span style="font-family: Arial, Helvetica, sans-serif;">Sometimes you will find it in a dynamically constructed query, when it will fail seemingly at random. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Once discovered, it isn't a mentally difficult bug to resolve. But first you have to get past the mental roadblock of "But all the columns already have an alias pointing to the table they come from".</span><br />
<br />
</div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0tag:blogger.com,1999:blog-13265058.post-72454360939388273132013-05-16T21:05:00.000+10:002013-05-16T21:05:00.148+10:00SCNs and TimestampsThe function ORA_ROWSCN returns an SCN from a row (or more commonly the block, unless ROWDEPENDENCIES has been used).<div>
<br /></div>
<div>
<div>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">select distinct ora_rowscn from PLAN_TABLE;</span></div>
<div>
<br /></div>
<div>
But unless you're a database, that SCN doesn't mean much. You can put things in some sort of order, but not much more.</div>
</div>
<div>
<br /></div>
<div>
Much better is</div>
<div>
<br /></div>
<div>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">select sys.scn_to_timestamp(ora_rowscn) from PLAN_TABLE;</span></div>
<div>
<br /></div>
<div>
unless it gives you</div>
<div>
<br /></div>
<div>
<span style="color: red; font-family: Courier New, Courier, monospace;">ORA-08181: specified number is not a valid system change number</span></div>
<div>
<br /></div>
<div>
which is database-speak for "I can't remember exactly".</div>
<div>
<br /></div>
<div>
That's when you might be able to fall back on this, plugging the SCN in place of the <u>****</u> :</div>
<div>
<br /></div>
<div>
<div>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">select * from </span></div>
<div>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> (select first_time, first_change# curr_change, </span></div>
<div>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> lag(first_change#) over (order by first_change#) prev_change,</span></div>
<div>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> lead(first_change#) over (order by first_change#) next_change</span></div>
<div>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;"> FROM v$log_history)</span></div>
<div>
<span style="color: blue; font-family: Courier New, Courier, monospace; font-size: x-small;">where <b><u>****</u></b> between curr_change and next_change</span></div>
</div>
<div>
<br /></div>
<div>
It won't be exact, and it doesn't stretch back forever. But it is better than nothing.</div>
<div>
<br /></div>
<div>
PS. This isn't a perfect way to find when a row was really inserted/updated. It is probably at the block level, and there's 'stuff' that can happen which doesn't actually change the row but might still reset the SCN. If you're looking for perfection, you at the wrong blog :)</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
SydOraclehttp://www.blogger.com/profile/08828771074492585943noreply@blogger.com0