Friday 18 July 2014

Avoiding ORA-04068

This is a nasty error that can occur when a package is recompiled during an Oracle session. I work now in an environment where this occasionally happens and sometimes minutes of data entry are lost.
The same statement will execute without problem when re-issued but for this the software needs to be  thoroughly revised. 
The ORA-04068 problem is explained very well in a number of posts like Avoiding ORA-04068: existing state of packages has been discarded. One of the solutions is avoiding state fullness of packages, i.e. no global constants or variables. When inspecting the packages in the system I found that quite a number of packages only had global constants and no variables. At first I thought about moving the constants to a separate package. Then only changes to this package would cause a ORA-04068. The drawback of this solution is that code throughout the packages would have to be modified. 
Another solution is to replace the constants by functions. This way there is no global state and no code to be changed when the functions get the same name as the constants. This also works for public constants. So
 
 LF      VARCHAR2(10) := CHR(10);

is changed to
 
  FUNCTION LF RETURNS VARCHAR2 IS
  BEGIN
    RETURN(CHR(10));
  END;

To make things even easier I have coded a conversion utility where you can input your constant declarations a retrieve the corresponding functions. You find it here.

Enjoy!





Monday 24 March 2014

The advantage of fonts over images

-->
Imagine your boss wants you to create an application with iconic buttons, He has an image that is to be used for menu buttons, and for the landing page, and as an image on some pages.



You start editing the image with photoshop creating the neccesary images. After some time you are ready. Some days later your boss says, there has bene a feedback session with the user and they want the buttons changed, different color with gradient effect and rouneded corners, and they should be a bit larger:


Again you start up PhotoShop and change the images. And you are lucky if this is the only time the specifications change.

All this image editing could be avoided when you would use images from a font. In a previous post I described how to create iconic buttons using existing fonts.  But it is also possible to define your own custom font containing the images you need ( how do you think Font Awesome is made?). 
Above appearances are all images generated using CSS and only one character in a custom font ( unfortunately I am not able to load the font in this blog).

The images you see in this blog are font characters styled with CSS. It is very easy to change the color and size of the image or the background, just change the CSS properties.

When you have a single color image you can incorporate it in a font. You need the image in SVG format, You can use tools like Inkscape to convert your image to SVG.
With your images in SVG you can build a font from them using icomoon.

It takes some time and effort to creatie a custom font. I did not have the time nor the patience to do it so I asked my 17-year old son Michiel to do it for me. He is  very good at this kind of thing (amongst others) and he has introduced me to many interesting new developments, like AngularJS and NodeJS. If you can use his help you can reach him here.





Tuesday 18 February 2014

Splitting an Apex report into several columns

The other day I was asked to create a page where a large number of properties should be connected to an object. I created a report consisting of the rows with the property name and a check box. This resulted in a very long and narrow report. All of the data could not be seen without scrolling. So I decided the report should be split into a number of columns. And I wanted to avoid special constructs in Apex and SQL (I have done that before and it was very compex). So I decided to use JavaScript to move the rows. By using JavaScript the Apex transaction mechanism keeps functioning, Apex does not know or notice that anything in the layout of the page has been changed.



I want to achieve the right side situation starting with the left report ( that by the way continues a long way below where the picture ends)

With JavaScript a number of extra table elements are created on the same level as the table element containing the report. The thead element of the original table element will be copied to the other table nodes to provide the same heading and a tbody element will be created to house the rows. After that the rows can be distributed among the tables. With CSS the table elements are positioned next to each other. The only limit to the number of columns is the available horizontal space.
You should call the JavaScript function below at startup or in the refresh event when using partial page rendering.

function reportToColumns ( tabSelector, numCols )
{ var numRows = 0;
  // bereken aantal rijen per kolom
  var rowsPerCol = Math.ceil( ( $(tabSelector+' tr').length-1 )/numCols);
  var baseName = 'reportColumn'; 

  $(tabSelector).addClass('reportColumn');
  // maak kolommen aan
  for ( i = 2; i <= numCols; i++)
  { $(tabSelector).parent().append('
'); $(tabSelector+' thead').clone().appendTo( $('#'+baseName+i) ); $('#'+baseName+i).append(''); } // verdeel de rijen over de kolommen var id = 2; var dest = ''; $(tabSelector+' tr').each( function(index) { if (index > rowsPerCol) { dest = '#'+baseName+id+' tbody'; $(dest).append( $(this) ); numRows = numRows + 1; // wissel de kolom als rijen per kolom is bereikt if ( numRows >= rowsPerCol) { id = id + 1; numRows = 0; } } } ); }

I used classes for the layout of a specific report. You might need to change that according to your needs.
To make sure the div’s are placed next to each other a little bit of CSS is needed:
.reportColumn {
    display: block;
    float: left;
    margin-right: 30px;
    position: relative;
}

You can see this in action right here.
Note 03-10-2015: The software is dependent of the template used. The link above is suited for Theme 25. You will find a version for the Universal Theme here.

This method can be used on either Apex Reports or Apex Tabular Forms. In fact it is not a specific Apex solution and can be used on any HTML table. Happy Apexing