MacLochlainns Weblog

Michael McLaughlin's Technical Blog

Site Admin

Fedora LAMP Steps

without comments

I posted earlier in the year how to configure a Fedora instance to test PHP code on a local VM. However, I’ve got a few questions on how to find those posts. Here’s a consolidation with links on those steps:

  1. Go to this blog post and install the httpd and php libraries with the yum installer.
  2. In the same blog post as step 1 (you can put the sample PHP code into the /var/www/html directory for testing), connect to the yum shell and remove the php-mysql library and then install the mysqlnd library.
  3. Go to this blog post and install the php-gd libraries, which enable you to render PNG images stored as binary streams in MySQL.

As always, I hope that helps.

Written by maclochlainn

December 9th, 2015 at 9:44 am

REGEXP_LIKE Behavior

with one comment

Often, the biggest problem with regular expressions is that those who use them sometimes don’t use them correctly. A great example occurs in the Oracle Database with the REGEXP_LIKE function. For example, some developer use the following to validate whether a string is a number but it only validates whether the first character is a number.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
DECLARE
  lv_input  VARCHAR2(100);
BEGIN
  /* Assign input value. */
  lv_input := '&input';
 
  /* Check for numeric string. */
  IF REGEXP_LIKE(lv_input,'[[:digit:]]') THEN
    dbms_output.put_line('It''s a number.');
  ELSE
    dbms_output.put_line('It''s a string.');
  END IF;
END;
/

When they test numbers it appears to works, it even appears to work when the test string start with number, but it fails with any string that starts with a character. That’s because the REGEXP_LIKE function on line 8 only checks the first character, but the following checks all the characters in the string.

8
  IF REGEXP_LIKE(lv_inputs(i),'[[:digit:]]{'||LENGTH(lv_inputs(i))||'}') THEN

You can also fix it with the following non-Posix solution:

8
  IF REGEXP_LIKE(lv_input,'[[0-9]]') THEN

You can add a collection to the program and use it to test single-digit, double-digit, and string with a leading integer. Save the program as test.sql and you can test three conditions with one call.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
DECLARE
  /* Declare the local collection type. */
  TYPE inputs IS TABLE OF VARCHAR2(100);
 
  /* Declare a local variable of the collection type. */
  lv_inputs  INPUTS;
BEGIN
  /* Assign the inputs to the collection variable. */
  lv_inputs := inputs('&1','&2','&3');
 
  /* Read through the collection and print whether it's an number or string. */
  FOR i IN 1..lv_inputs.COUNT LOOP
    IF REGEXP_LIKE(lv_inputs(i),'[[:digit:]]{'||LENGTH(lv_inputs(i))||',}') THEN
      dbms_output.put_line('It''s a number.');
    ELSE
      dbms_output.put_line('It''s a string.');
    END IF;
  END LOOP;
END;
/

You can run the test.sql program like this:

SQL> @test.sql 1 12 1a

It prints:

It's a number.
It's a number.
It's a string.

As always, I hope this helps those looking for a solution.

Written by maclochlainn

September 30th, 2015 at 7:23 pm

Create MySQL Index

without comments

Indexes are separate data structures that provide alternate pathways to finding data. They can and do generally speed up the processing of queries and other DML commands, like the INSERT, UPDATE, REPLACE INTO, and DELETE statements. Indexes are also called fast access paths.

In the scope of the InnoDB Database Engine, the MySQL database maintains the integrity of indexes after you create them. The upside of indexes is that they can improve SQL statement performance. The downside is that they impose overhead on every INSERT, UPDATE, REPLACE INTO, and DELETE statement, because the database maintains them by inserting, updating, or deleting items for each related change in the tables that the indexes support.

Indexes have two key properties—usability and visibility. Indexes are both usable and visible by default. That means they are visible to the MySQL cost-based optimizer and usable when statements run against the tables they support.

You have the ability to make any index invisible, in which case queries and DML statements won’t use the index because they won’t see it. However, the cost-based optimizer still sees the index and maintains it with any DML statement change. That means making an index invisible isn’t quite like making the index unusable or like dropping it temporarily. An invisible index becomes overhead and thus is typically a short-term solution to run a resource-intensive statement that behaves better without the index while avoiding the cost of rebuilding it after the statement runs.

It is also possible to make an index unusable, in which case it stops collecting information and becomes obsolete and the database drops its index segment. You rebuild the index when you change it back to a usable index.

Indexes work on the principal of a key. A key is typically a set of columns or expressions on which you can build an index, but it’s possible that a key can be a single column. An index based on a set of columns is a composite, or concatenated, index.

Indexes can be unique or non-unique. You create a unique index anytime you constrain a column by assigning a primary key or unique constraint, but they’re indirect indexes. You create a direct unique index on a single column with the following syntax against two non-unique columns:

1
2
CREATE INDEX common_lookup_u1
ON common_lookup (common_lookup_table) USING BTREE;

You could convert this to a non-unique index on two columns by using this syntax:

1
2
CREATE INDEX common_lookup_u1
ON common_lookup (common_lookup_table, common_lookup_column) USING BTREE;

Making the index unique is straightforward;, you only need to add a UNIQUE key wordk to the CREATE INDEX statement, like

1
2
3
4
CREATE UNIQUE INDEX common_lookup_u1
ON common_lookup ( common_lookup_table
                 , common_lookup_column
                 , common_lookup_type) USING BTREE;

Most indexes use a B-tree (balanced tree). A B-tree is composed of three types of blocks—a root branch block for searching next-level blocks, branch blocks for searching other branch blocks, or and leaf blocks that store pointers to row values. B-trees are balanced because all leaf-blocks are at the same level, which means the length of search is the same to any element in the tree. All branch blocks store the minimum key prefix required to make branching decisions through the B-tree.

Written by maclochlainn

September 29th, 2015 at 6:41 pm

SQL*Plus Tricks

with 3 comments

Have you ever wondered how to leverage substitution variables in anonymous block programs? There are several tricks that you can use beyond passing numeric and string values to local variable. The generic default appears to take a number unless you cast it as a string but that’s not really the whole story. The first two are standard examples of how to use numeric and string substitution values.

The following accept a numeric substitution value:

1
2
3
4
5
6
7
8
9
10
DECLARE
  lv_input  NUMBER;
BEGIN
  /* Assign substitution value to local variable. */
  lv_input := &input;
 
  /* Print the local variable. */
  dbms_output.put_line('['||lv_input||']');
END;
/

The following accept a string substitution value, casts the input as a string, assigns the string value to a 4,000 character length local variable, checks whether the 4,000 character length is greater than 10, and assigns the first 10 characters to the lv_parse_input variable:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DECLARE
  lv_unparsed_input  VARCHAR2(4000);
  lv_parsed_input    VARCHAR2(10);
BEGIN
  /* Assign substitution value to local variable. */
  lv_unparsed_input := '&input';
 
  /* Check size of input value. */
  IF LENGTH(lv_unparsed_input) > 10 THEN
    lv_parsed_input := SUBSTR(lv_unparsed_input,1,10);
  END IF;
 
  /* Print the local variable. */
  dbms_output.put_line('Print {lv_parsed_input}: ['||lv_parsed_input||']');
END;
/

Next, let’s examine two tricks. The first passes a case insensitive variable name and the second passes a case sensitive variable name as a parameter to an anonymous block program.

This declares an anonymous block program that uses a substitution value as a variable name:

1
2
3
4
5
6
7
DECLARE
  mine  VARCHAR2(10) := 'Default';
BEGIN
  /* Print the local variable's value. */
  dbms_output.put_line('Print {mine} variable value: ['||&input||']');
END;
/

When you run the anonymous block, you’re prompted for an input variable. You provide a case insensitive variable name as the input value:

Enter value for input: MINE
old   5:   dbms_output.put_line('['||&input||']');
new   5:   dbms_output.put_line('['||MINE||']');
Print {mine} variable value: [Default]

The downside of this approach, yields an ORA-06550 and PLS-00201 exception. Neither of these can be caught because Oracle raises the errors during parsing when the variable name isn’t a 100% case insensitive match. The same type of problem occurs in the next example when the input variable isn’t a 100% case sensitive match.

You can rewrite the program to handle case insensitive variables like this:

1
2
3
4
5
6
7
DECLARE
  "Mine"  VARCHAR2(10) := 'Default';
BEGIN
  /* Print the local variable's value. */
  dbms_output.put_line('Print {mine} variable value: ['||"&input"||']');
END;
/

When you run the anonymous block, you’re prompted for an input variable. You provide a case sensitive variable name as the input value:

Enter value for input: Mine
old   5:   dbms_output.put_line('['||&input||']');
new   5:   dbms_output.put_line('['||"Mine"||']');
Print {Mine} variable value: [Default]

Hope this helps those looking for a solution.

Written by maclochlainn

September 24th, 2015 at 1:19 am

Using CALIBRATE_IO

without comments

Using Oracle’s Resource Manager requires you to understand the IO dynamics. The first step requires you to run the CALIBRATE_IO procedure from the DBMS_RESOURCE_MANAGER package.

Oracle provides some great examples about how to use the CALIBRATE_IO procedure of the DBMS_RESOURCE_MANAGER package in the Oracle Database Database PL/SQL Packages and Types Reference. The CALIBRATE_IO procedure returns the best answer when you provide a valid number of files, which you can capture by querying the V$ASM_DISK view.

The following code queries the view and assigns the value to a session level variable:

CLEAR BREAKS
CLEAR COLUMNS
CLEAR COMPUTES
 
VARIABLE files NUMBER
 
BEGIN
  SELECT COUNT(DISTINCT name) disks
  INTO :files
  FROM v$asm_disk;
END;
/

When you have the number of files, you can calibrate the IO with the following anonymous block. The query should always work but just in case the NVL function on line 9 assigns the default number of files.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
DECLARE
  lv_num_physical_disks BINARY_INTEGER; — v$asm_disk
  lv_max_latency BINARY_INTEGER := 10;
  lv_max_iops BINARY_INTEGER;
  lv_max_mbps BINARY_INTEGER;
  lv_actual_latency BINARY_INTEGER;
BEGIN
  /* Assign actual files to anonymous block variable. */
  lv_num_physical_disks := NVL(:files,2);
 
  /* Run the calibrate_io procedure. */
  DBMS_RESOURCE_MANAGER.CALIBRATE_IO(
      num_physical_disks => lv_num_physical_disks
    , max_latency => lv_max_latency
    , max_iops => lv_max_iops
    , max_mbps => lv_max_mbps
    , actual_latency => lv_actual_latency);
END;
/

You can query the results like this:

SELECT max_iops
,      max_mbps
,      max_pmbps
,      latency
,      num_physical_disks
FROM   dba_rsrc_io_calibrate;

It should show results like these:

MAX_IOPS MAX_MBPS MAX_PMBPS LATENCY NUM_PHYSICAL_DISKS
-------- -------- --------- ------- ------------------
    8894      443       294       9                 18

Hope this helps those using the CALIBRATE_IO procedure of the DBMS_RESOURCE_MANAGER package.

Written by maclochlainn

August 31st, 2015 at 8:59 pm

Free Oracle Tuning Book

with 2 comments

Quick Start Guide to Oracle Query TuningWho can resist a free Rich Nimeiec book on SQL Tuning? O.K., those who know everything can resist. If you’re like me, this is an opportunity to learn from Rich. Click on the book image or this link to get a free copy, or if you want to pay $10 for a copy click here to buy Quick Start Guide to Oracle Query Tuning: Tips for DBAs and Developers from Amazon.com.

The book is four chapters long, is a 129 pages in length, and is in a PDF format. The outline is:

  1. Query Tuning: Developer and Beginning DBA
  2. Query Tuning: Basics for DBAs and Developers
  3. Advanced Performance Tuning
  4. Tips for Tuning When You Have Everything Tuned

Enjoy reading it. His more comprehensive book is Oracle Database 11g Release 2 Performance Tuning Tips & Techniques (Oracle Press) and it’s $30, but it’s written for an advanced audience (more or less OCA or higher).

Written by maclochlainn

August 31st, 2015 at 11:24 am

Use an object in a query?

without comments

Using an Oracle object type’s instance in a query is a powerful capability. Unfortunately, Oracle’s SQL syntax doesn’t make it immediately obvious how to do it. Most get far enough to put it in a runtime view (a subquery in the FROM clause), but then they get errors like this:

SELECT	 instance.get_type()
         *
ERROR AT line 4:
ORA-00904: "INSTANCE"."GET_TYPE": invalid identifier

The problem is how Oracle treats runtime views, which appears to me as a casting error. Somewhat like the ORDER BY clause irregularity that I noted in July, the trick is complete versus incomplete syntax. The following query fails and generates the foregoing error:

1
2
3
4
SELECT instance.get_type() AS object_type
,      instance.to_string() AS object_content
FROM  (SELECT dependent()AS instance
       FROM   dual);

If you add a table alias, or name, to the runtime view on line 4, it works fine:

1
2
3
4
SELECT cte.instance.get_type() AS object_type
,      cte.instance.to_string() AS object_content
FROM  (SELECT dependent() AS instance
       FROM   dual) cte;

That is the trick. You use an alias for the query, which assigns the alias like a table reference. The reference lets you access instance methods in the scope of a query. Different columns in the query’s SELECT-list may return different results from different methods from the same instance of the object type.

You can also raise an exception if you forget the open and close parentheses for a method call to a UDT, which differs from how Oracle treats no argument functions and procedures. That type of error would look like this:

SELECT cte.instance.get_type AS object_type
       *
ERROR AT line 1:
ORA-00904: : invalid identifier

It is an invalid identifier because there’s no public variable get_type, and a method is only found by using the parenthesis and a list of parameters where they’re required.

The object source code is visible by clicking on the expandable label below.

As always, I hope this helps those solving problems.

Written by maclochlainn

August 22nd, 2015 at 5:23 pm

ORDER BY CASE

with 8 comments

Sometimes I give parts of a solution to increase the play time to solve a problem. I didn’t anticipate a problem when showing how to perform a sort operation with a CASE statement. It’s a sweet solution when you need to sort something differently than a traditional ascending or descending sort.

I gave my students this ORDER BY clause as an example:

  CASE
    WHEN filter = 'Debit' THEN 1
    WHEN filter = 'Credit' THEN 2
    WHEN filter = 'Total' THEN 3
  END;

It raises the following error in MySQL for students:

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ORDER BY
  CASE
    WHEN filter = 'Debit' THEN 1
    WHEN filter = 'Credit' THEN' at line 6

It raises the following error in Oracle for some students:

  CASE
  *
ERROR AT line 7:
ORA-01785: ORDER BY item must be the NUMBER OF a SELECT-list expression

So, I built a little test case to replicate the problem and error message they encountered:

SQL> SELECT 'Debit' AS filter FROM dual
  2  UNION ALL
  3  SELECT 'Credit' AS filter FROM dual
  4  UNION ALL
  5  SELECT 'Total' AS filter FROM dual
  6  ORDER BY
  7    CASE
  8      WHEN filter = 'Debit' THEN 1
  9      WHEN filter = 'Credit' THEN 2
 10      WHEN filter = 'Total' THEN 3
 11    END;

They said, great but how can you fix it? That’s simple, with a Common Table Expression (CTE) in Oracle or with an inline view in MySQL. The Oracle CTE solution is:

  1  WITH results AS
  2  (SELECT 'Debit' AS filter FROM dual
  3   UNION ALL
  4   SELECT 'Credit' AS filter FROM dual
  5   UNION ALL
  6   SELECT 'Total' AS filter FROM dual)
  7  SELECT filter
  8  FROM   results
  9  ORDER BY
 10    CASE
 11	 WHEN filter = 'Debit'  THEN 1
 12	 WHEN filter = 'Credit' THEN 2
 13	 WHEN filter = 'Total'  THEN 3
 14    END;

There are two MySQL solutions. One simply removes the FROM dual clauses from the query components and the other uses an inline view in the FROM clause. This is the inline view:

SELECT filter
FROM  (SELECT 'Debit' AS filter FROM dual
       UNION ALL
       SELECT 'Credit' AS filter FROM dual
       UNION ALL
       SELECT 'Total' AS filter FROM dual) resultset
ORDER BY
  CASE
    WHEN filter = 'Debit' THEN 1
    WHEN filter = 'Credit' THEN 2
    WHEN filter = 'Total' THEN 3
  END;

This is the solution without the FROM dual clauses:

SELECT 'Debit' AS filter
UNION ALL
SELECT 'Credit' AS filter
UNION ALL
SELECT 'Total' AS filter
ORDER BY
  CASE
    WHEN filter = 'Debit' THEN 1
    WHEN filter = 'Credit' THEN 2
    WHEN filter = 'Total' THEN 3
  END;

Both MySQL solutions yield the following:

+--------+
| filter |
+--------+
| Debit  |
| Credit |
| Total  |
+--------+
3 rows in set (0.00 sec)

It puts the fabricating query inside a result set, and then lets you use the column alias to filter the set. If you have a better approach, please share it.

Written by maclochlainn

July 8th, 2015 at 10:06 pm

Mac SQL Developer Install

without comments

This how you install SQL Developer on Mac OS Yosemite. The first thing you need to do is download and install Java 8, not Java 7 on your Mac OS Yosemite as suggested on some web sites. You can determine whether or not Java is installed by running the following command:

Mac-Pro-3:~ username$ java -version
No Java runtime present, requesting install.

You must accept the Java license to install Java 8 on the Mac OS X operating system:

YosemiteInstallJava_01

You have the option of installing the Java SDK or JDK. I’ve opted to install Netbeans 8 with JDK 8u45, as you can tell from the screen capture after you launched the file:

YosemiteInstallJava_02

It is a standard Mac OS installation, which is why I didn’t bother showing any dialog messages. After installing the Java JDK or SDK, you should download SQL Developer 4.1 from Oracle’s web site. Below is a screen shot of the Oracle download web page where I’ve accepted the license agreement:

SQLDeveloperDownload

If you attempt to launch the installation and you’ve set your Mac Security to the “Mac App Store and identified developers” setting, you should raise the following exception:

SQLDeveloperInstall_01

If you reset the Mac Security to an “Anywhere” setting, you can install Oracle SQL Developer on Yosemite. Just make sure you reset it to the “Mac App Store and identified developers” setting after you install SQL Developer.

If you launch SQL Developer with the Security “Anywhere” setting, it displays the following dialog:

SQLDeveloperInstall_02

After you launch the program, you will see the following progress dialog:

SQLDeveloperInstall_03

The last step of the installation launches SQL Developer, as shown below:

SQLDeveloperInstall_04

Click the Connections icon to create an initial connection, like the following:

SQLDeveloperInstall_05

After connecting to the database, you can write and execute a query as shown in the next screen capture:

SQLDeveloperInstall_06

As always, I hope that this helps those who require an example to install SQL Server on a Mac OS.

Written by maclochlainn

June 12th, 2015 at 3:08 am

Run X11 Apps on Mac

without comments

It’s possible folks didn’t notice but Mac OS X no longer includes XQuartz by default from Maverick forward. You need to download XQuartz and install it. I’d recommend after you install Xcode.

Launch XQuartz and then either use the bash shell it opens or open a Terminal bash shell session. Inside the shell, you might start Secure Shell (ssh) like this:

Mac-Pro-3:~ michaelmclaughlin$ ssh student@192.168.2.170
student@192.168.2.170's password: 
Last login: Thu Jun  4 14:33:37 2015
[student@localhost ~]$ xclock &
[1] 10422
[student@localhost ~]$ Error: Can't open display:

Granted that’s a trivial error and running the xclock X11 applications isn’t crucial, an error that makes it more important is the following from Oracle’s old Designer/2000 application:

FRM-91111: Internal Error: window system startup failure.
FRM-10039: Unable to start up the Form Builder.

This is the desired behavior. Secure shell (ssh) can’t run it unless you make the connection with the -Y flag. You should use the following syntax:

Mac-Pro-3:~ michaelmclaughlin$ ssh -Y student@192.168.2.170
student@192.168.2.170's password: 
Last login: Tue Jun  9 14:56:55 2015 from 192.168.2.1
/usr/bin/xauth:  file /home/student/.Xauthority does not exist
[student@localhost ~]$ xclock &
[1] 10760

You can safely ignore the .Xauthority does not exist warning message because it’ll create a .Xauthority file and store the magic cookie after the warning message. You should see the xclock program running in the upper left hand corner of your console, like:

X11MacXclock

It’s terrific that you don’t get a font warning like you typically would using UTF-8 on Linux. Nice that the Mac OS fonts are so well done that there isn’t a raised exception.

Using xclock or xeyes isn’t very useful as a rule, but this method also lets you run any of the Linux GUI applications. For example, the following gedit command lets you run the gedit utility from a Mac OS console. If you’ve installed the gedit plug-ins, you also can use the Terminal console on the remote system.

X11GeditTerminal

The process sequence for the command-line is shown below:

1030     1  /usr/sbin/sshd -D     - The root process launches the ssh daemon
3145  1030  sshd: student [priv]  - The sshd launches a ssh session to manage a student ssh session
3152  3145  sshd: student@pts/1   - The ssh session launched to manage the ssh session
3166  3152  -bash                 - The bash shell launched by connecting through the ssh session
3240  3166  gedit                 - The gedit command issued inside a ssh session
3166  3240  gnome-pty-helper      - Launching the gedit session across X11 
3169  3240  /bin/bash             - Launching the Terminal session inside the gedit session across X11
3269  3884  ps -ef                - Command run inside the gedit Terminal session

Hope that helps those who want to use X11 applications on the Mac OS.

Written by maclochlainn

June 9th, 2015 at 4:51 pm