Recital

Login Register

We are pleased to announce the release of Recital 10.0.2.

Here is a brief list of features and functionality that you will find in the 10.0.2 release. 

  • New commands
    SAVE/RESTORE DATASESSION [TO variable]
    CONNECT "connectString"
    DISCONNECT 
  • New functions (OData compatible)
    startsWith(haystack as character, needle as character)
    endsWith(haystack as character, needle as character)
    indexOf(haystack as character, needle as character)
    substringOf(haystack as character, needle as character)
    concat(expC1, expC2)
  • New system variables
    _LASTINSERTEDSYNCNUM
  • Enhanced commands
    Added CONNSTRING "connectingString" to the USE command to connect to remote servers (Recital, MySQL, PostgreSQL, Oracle, ODBC)
  • Further SQL query optimizer improvements to boost performance
  • Performance improvements in Recital Web
  • Forced all temporary files into temp directory (improves performance when local tmpfs is used as temp directory and reduces network i/o)
  • Fixed cookie and session variable problems in Recital Web
  • Fixed problem with temporary files being left after some server queries involving memos and object data types
  • Improved performance of the Windows ODBC driver
  • Fixed a security flaw in Recital Web
  • Fixed all reported bugs 
Published in Blogs
Read more...

Many motherboards nowadays have integrated gigabit ethernet that use the Realtek NIC chipset.

The Realtek r8168B network card does not work out of the box in Redhat/Centos 5.3: instead of loading the r8168 driver, modprobe loads the r8169 driver, which is broken as can be seen with ifconfig which shows large amounts of dropped packets. A solution is to download the r8168 driver from the Realtek website and install it using the following steps:

Check whether the built-in driver, r8169.ko (or r8169.o for kernel 2.4.x), is installed.

# lsmod | grep r8169

If it is installed remove it.

# rmmod r8169

Download the R8168B linux driver from here into /root.

Unpack the tarball :

# cd /root
# tar vjxf r8168-8.012.00.tar.bz2

Change to the directory:

# cd r8168-8.012.00

If you are running the target kernel, then you should be able to do :

# make clean modules   
# make install
# depmod -a
# insmod ./src/r8168.ko (or r8168.o in linux kernel 2.4.x)

make sure modprobe knows not to use r8169, and that depmod doesn’t find the r8169 module.

# echo "blacklist r8169" >> /etc/modprobe.d/blacklist
# mv /lib/modules/`uname -r`/kernel/drivers/net/r8169.ko   \ /lib/modules/`uname -r`/kernel/drivers/net/r8169.ko.bak

You can check whether the driver is loaded by using the following commands.

# lsmod | grep r8168
# ifconfig -a

If there is a device name, ethX, shown on the monitor, the linux driver is loaded. Then, you can use the following command to activate it.

# ifconfig ethX up

After this you should not see any more dropped packets reported.

Published in Blogs
Read more...

In this article Yvonne Milne looks at the use of the Recital Remote Data Connectivity Functions with Recital Database Gateways.

Published in Blogs
Read more...
When debugging C code it is common to write debugging to an external text file using the __FILE__ and __LINE__ preprocessor defines to trace execution flow.

Unfortunately java does not support __FILE__ and __LINE__ but you can get the same functionality with this code which can be placed in one of your libraries.
	
public static void showTrace(String msg)
{
	if (msg.length() > 0) System.out.println(msg);
	System.out.println("Trace: " + 
				   "file " + new Throwable().getStackTrace()[1].getFileName() +
				   " class " + new Throwable().getStackTrace()[1].getClassName() +
				   " method " + new Throwable().getStackTrace()[1].getMethodName() +
				   " line " + new Throwable().getStackTrace()[1].getLineNumber());
}
Published in Blogs
Read more...

In this article Barry Mavin, CEO and Chief Software Architect for Recital details how to Build C Extension Libraries to use with Recital.

Overview

It is possible to extend the functionaliy of Recital products using "Extension libraries" that can be written in C. These extension libraries, written using the Recital/SDK API, are dynamically loadable from all Recital 9 products. This includes:

  • Recital
  • Recital Server
  • Recital Web

Building C Extension Libraries

You can create C wrappers for virtually any native operating system function and access these from the Recital 4GL. Unlike traditional APIs which only handle the development of C functions that are callable from the 4GL, the Recital/SDK allows you to build Classes that are accessible from all Recital products. e.g. You could create a GUI framework for Linux that handles VFP system classes!

To deploy your C Extension Libraries, copy them to the following location:

Windows:

\Program Files\Recital\extensions

Linux/Unix:

/opt/recital/extensions

Please see the Recital/SDK API Reference documentation for further details.

Sample code

Listed below is the complete example of a C Extension Library.:

////////////////////////////////////////////////////////////////////////////////
#include "mirage_demo.h"  
      
////////////////////////////////////////////////////////////////////////////////
// Declare your functions and classes below as follows:
//
//    Recital Function Name, C Function Name, Type (Function or Class)
//
#define MAX_ELEMENTS    7
static  struct  API_SHARED_FUNCTION_TABLE api_function_table[MAX_ELEMENTS] = {
        {"schar",   "fnSamplesCharacter",   API_FUNCTION},
        {"stype",   "fnSamplesType",           API_FUNCTION},
        {"slog",    "fnSamplesLogical",        API_FUNCTION},
        {"snum",    "fnSamplesNumeric",    API_FUNCTION},
        {"sopen",   "fnSamplesOpen",         API_FUNCTION},
        {"myclass", "clsMyClass",               API_CLASS},
        {NULL,      NULL,                   -1}
};

////////////////////////////////////////////////////////////////////////////////
// Recital API initialization. This should be in only ONE of your C files
// **IT SHOULD NEVER BE EDITED OR REMOVED**  
INIT_API;


///////////////////////////////////////////////////////////////////////
// This is an example of passing a character parameter and returning one.
RECITAL_FUNCTION fnSamplesCharacter(void)
{
    char    *arg1;
    
    if (!_parse_parameters(PCOUNT, "C", &arg1)) { 
        ERROR(-1, "Incorrect parameters");
    }
    
    _retc(arg1);
}


///////////////////////////////////////////////////////////////////////
// This is an example of passing a numeric parameter and returning one.
RECITAL_FUNCTION fnSamplesNumeric(void)
{
    int arg1;
    
    if (!_parse_parameters(PCOUNT, "N", &arg1)) { 
        ERROR(-1, "Incorrect parameters");
    }
    
    _retni(arg1);
}


///////////////////////////////////////////////////////////////////////
// This is an example returns the data type of the parameter passed.
RECITAL_FUNCTION fnSamplesType(void)
{
    char    result[10];

    if (PCOUNT != 1) { 
        ERROR(-1, "Incorrect parameters");
    }
    
    switch (_parinfo(1)) {
        case API_CTYPE:
            strcpy(result, "Character");
            break;
        case API_NTYPE:
            strcpy(result, "Numeric");
            break;
        case API_LTYPE:
            strcpy(result, "Logical");
            break;
        case API_DTYPE:
            strcpy(result, "Date");
            break;
        case API_TTYPE:
            strcpy(result, "DateTime");
            break;
        case API_YTYPE:
            strcpy(result, "Currency");
            break;
        case API_ATYPE:
            strcpy(result, "Array");
            break;
        default:
            strcpy(result, "Unkown");
            break;
    }

    _retc(result);
}


///////////////////////////////////////////////////////////////////////
// This is an example returns "True" or False.
RECITAL_FUNCTION  fnSamplesLogical(void)
{
    char    result[10];
    int     arg1;
    
    if (!_parse_parameters(PCOUNT, "L", &arg1)) { 
        ERROR(-1, "Incorrect parameters");
    }
    
    if (arg1) strcpy(result, "True");
    else strcpy(result, "False");

    _retc(result);
}


///////////////////////////////////////////////////////////////////////
// This example opens a table.
RECITAL_FUNCTION fnSamplesOpen(void)
{
    char    *arg1;
    
    if (!_parse_parameters(PCOUNT, "C", &arg1)) { 
        ERROR(-1, "Incorrect parameters");
    }
    
    if (_parinfo(1) == API_CTYPE) {
        _retni(COMMAND(arg1));
    } else {
        _retni(-1);
    }
}

///////////////////////////////////////////////////////////////////////
// Define the MyClass CLASS using the API macros
///////////////////////////////////////////////////////////////////////
RECITAL_EXPORT int DEFINE_CLASS(clsMyClass)
{
    /*-------------------------------------*/ 
    /* Dispatch factory methods and return */
    /*-------------------------------------*/
    DISPATCH_FACTORY();
 
    /*---------------------------------*/
    /* Dispatch constructor and return */ 
    /*---------------------------------*/ 
    DISPATCH_METHOD(clsMyClass, Constructor);

    /*--------------------------------*/
    /* Dispatch destructor and return */
    /*--------------------------------*/
    DISPATCH_METHOD(clsMyClass, Destructor); 

    /*-----------------------------------*/
    /* Dispatch DEFINE method and return */
    /*-----------------------------------*/
    DISPATCH_METHOD(clsMyClass, Define);

    /*------------------------------*/
    /* Dispatch SET or GET PROPERTY */
    /* method for property NumValue */
    /* then return.                 */
    /*------------------------------*/
    DISPATCH_PROPSET(clsMyClass, NumValue);
    DISPATCH_PROPGET(clsMyClass, NumValue); 

    /*------------------------------*/
    /* Dispatch SET or GET PROPERTY */
    /* method for property LogValue */
    /* then return.                 */
    /*------------------------------*/
    DISPATCH_PROPSET(clsMyClass, LogValue);
    DISPATCH_PROPGET(clsMyClass, LogValue);

    /*-------------------------------*/
    /* Dispatch SET or GET PROPERTY  */
    /* method for property DateValue */
    /* then return.                 */
    /*-------------------------------*/
    DISPATCH_PROPSET(clsMyClass, DateValue);
    DISPATCH_PROPGET(clsMyClass, DateValue);

    /*-------------------------------*/
    /* Dispatch SET or GET PROPERTY  */
    /* method for property TimeValue */
    /* then return.                  */
    /*-------------------------------*/
    DISPATCH_PROPSET(clsMyClass, TimeValue);
    DISPATCH_PROPGET(clsMyClass, TimeValue);
 
    /*-------------------------------*/
    /* Dispatch SET or GET PROPERTY  */
    /* method for property CurrValue */
    /* then return.                  */
    /*-------------------------------*/
    DISPATCH_PROPSET(clsMyClass, CurrValue);
    DISPATCH_PROPGET(clsMyClass, CurrValue);

    /*-------------------------------*/
    /* Dispatch SET or GET PROPERTY  */
    /* method for property CharValue */
    /* then return.                  */
    /*-------------------------------*/
    DISPATCH_PROPSET(clsMyClass, CharValue); 
    DISPATCH_PROPGET(clsMyClass, CharValue);

    /*------------------------------*/
    /* Dispatch SET or GET PROPERTY */ 
    /* method for property ObjValue */ 
    /* then return.                 */
    /*------------------------------*/
    DISPATCH_PROPSET(clsMyClass, ObjValue);
    DISPATCH_PROPGET(clsMyClass, ObjValue);

    /*-----------------------------------*/
    /* If message not found return error */
    /*-----------------------------------*/
    OBJECT_RETERROR("Unknown message type");
}

////////////////////////////////////////////////////////////////////////////////
// Define METHOD handlers
////////////////////////////////////////////////////////////////////////////////
DEFINE_METHOD(clsMyClass, Constructor) 
{
        struct example_data *objectDataArea;

        /* Allocate memory for objects objectData area */
        objectDataArea = (struct example_data *) 
           malloc(sizeof(struct example_data));
        if (objectDataArea == NULL) return(-1);
    
        /* Assign the default property values */
        strcpy(objectDataArea->prop_charvalue, "Test API object");
        objectDataArea->prop_numvalue = 15.2827;
        objectDataArea->prop_logvalue = 'F';
        strcpy(objectDataArea->prop_datevalue, DATE_DATE());
        strcpy(objectDataArea->prop_timevalue, DATE_DATETIME());
        strcpy(objectDataArea->prop_currvalue, "15.2827");
        strcpy(objectDataArea->object_name, "APIobject");
        objectDataArea->prop_objvalue 
             = OBJECT_NEW(objectDataArea->object_name, "exception", NULL);
    
        /* Set the object objectData area */
        OBJECT_SETDATA((char *)objectDataArea);
    
        return(0);
}
  
DEFINE_METHOD(clsMyClass, Destructor) 
{
        struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

        if (objectData != NULL) {
            if (objectData->prop_objvalue != NULL) 
              OBJECT_DELETE(objectData->prop_objvalue);
            free(objectData);
            objectData = NULL;
        }
        return(0);
}

DEFINE_METHOD(clsMyClass, Define) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct      API_EXPRESSION result;
    char        buffer[512];
    int         rc;

/* Check the object class */
    OBJECT_GETPROPERTY(objectData->prop_objvalue, "class", buffer);
    rc = OBJECT_GETARG(buffer, &result);
    if (result.errno == 0 && result.type == 'C' 
        && strcmp(result.character, "Exception") == 0) { 
        switch (OBJECT_GETARGC()) {
            case 1: 
                rc = OBJECT_GETPARAMETER(1, &result);
                if (result.errno == 0 && result.type == 'C') {
                    OBJECT_SETARG(buffer, &result);
                    rc = OBJECT_SETPROPERTY(objectData->prop_objvalue,
                         "message", buffer);
                }
                break;
            case 2: 
                rc = OBJECT_GETPARAMETER(2, &result);
                if (result.errno == 0 && result.type == 'N') {
                    OBJECT_SETARG(buffer, &result);
                    rc = OBJECT_SETPROPERTY(objectData->prop_objvalue,
                         "errorno", buffer);
                }
         }
    }

    result.type = 'L';
    result.logical = (rc == 0 ? 'T' : 'F');  
    OBJECT_RETRESULT(&result);
}

////////////////////////////////////////////////////////////////////////////////
// Define GET property handlers
////////////////////////////////////////////////////////////////////////////////
DEFINE_PROPERTYGET(clsMyClass, NumValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('N', objectData->prop_numvalue);
}

DEFINE_PROPERTYGET(clsMyClass, LogValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('L', objectData->prop_logvalue);
}  

DEFINE_PROPERTYGET(clsMyClass, DateValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('D', objectData->prop_datevalue);
}

DEFINE_PROPERTYGET(clsMyClass, TimeValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('T', objectData->prop_timevalue);
}

DEFINE_PROPERTYGET(clsMyClass, CurrValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('Y', objectData->prop_currvalue);
}

DEFINE_PROPERTYGET(clsMyClass, CharValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('C', objectData->prop_charvalue);
}

DEFINE_PROPERTYGET(clsMyClass, ObjValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();

    if (objectData == NULL) return(-1);

    OBJECT_RETPROPERTY('O', objectData->prop_objvalue);
} 


////////////////////////////////////////////////////////////////////////////////
// Define SET property handlers
////////////////////////////////////////////////////////////////////////////////
DEFINE_PROPERTYSET(clsMyClass, NumValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct API_EXPRESSION result;
    int rc = OBJECT_ERROR;

    OBJECT_GETVALUE(&result);
    if (result.errno == 0 && result.type == 'N') {
        objectData->prop_numvalue = result.number;
        rc = OBJECT_SUCCESS;
    }

    return(rc);
}

DEFINE_PROPERTYSET(clsMyClass, LogValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct API_EXPRESSION result;
    int rc = OBJECT_ERROR;

    OBJECT_GETVALUE(&result);
    if (result.errno == 0 && result.type == 'L') {
        objectData->prop_logvalue = result.logical;
        rc = OBJECT_SUCCESS;
    }

    return(rc);
}

DEFINE_PROPERTYSET(clsMyClass, DateValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct API_EXPRESSION result;
    int rc = OBJECT_ERROR;
    OBJECT_GETVALUE(&result);
    if (result.errno == 0 && result.type == 'D') {
        strcpy(objectData->prop_datevalue, DATE_DTOS(result.date));
        rc = OBJECT_SUCCESS;
    }

    return(rc);
}

DEFINE_PROPERTYSET(clsMyClass, TimeValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct API_EXPRESSION result;
    int rc = OBJECT_ERROR;

    OBJECT_GETVALUE(&result);
    if (result.errno == 0 && result.type == 'T') {
        strcpy(objectData->prop_timevalue, DATE_TTOS(result.datetime));
        rc = OBJECT_SUCCESS;
    }

    return(rc); 
}

DEFINE_PROPERTYSET(clsMyClass, CurrValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct API_EXPRESSION result;
    int rc = OBJECT_ERROR;

    OBJECT_GETVALUE(&result);
    if (result.errno == 0 && result.type == 'Y') {
        strcpy(objectData->prop_currvalue, CURR_YTOS(result.currency));
        rc = OBJECT_SUCCESS;
    }

    return(rc);
}

DEFINE_PROPERTYSET(clsMyClass, CharValue)  
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    struct API_EXPRESSION result;
    int rc = OBJECT_ERROR;

    OBJECT_GETVALUE(&result);
    if (result.errno == 0 && result.type == 'C') {
        strcpy(objectData->prop_currvalue, result.character);
        rc = OBJECT_SUCCESS;
    }

    return(rc);
}

DEFINE_PROPERTYSET(clsMyClass, ObjValue) 
{
    struct example_data *objectData = (struct example_data *)OBJECT_GETDATA();
    OBJECT  objvalue;
    int rc = OBJECT_ERROR;

    if (OBJECT_GETTYPE() == 'O') {
        objvalue = OBJECT_GETOBJECT(); 
        objectData->prop_objvalue = OBJECT_ASSIGN(objvalue, objectData->object_name);
        rc = OBJECT_SUCCESS;
    }

    return(rc);
}
Published in Blogs
Read more...
This MSDN article provides good details about IE CSS compatibility issues.
http://msdn.microsoft.com/en-us/library/cc351024(VS.85).aspx
 
Published in Blogs
Read more...
 


Recital provides the following additional benefits:

  • Easy to Install and Deploy - Users can set up Recital in minutes enabling organizations to deliver new applications faster than other databases.
  • Easy to Administer - Recital is a low administration database that eliminates the need for highly trained, skilled, and costly database administrators to maintain the database.
  • High Performance - Superior database performance for the most demanding of OLTP applications. Additionally, Clustered Recital provides 99.999% availability.
  • Embeddable Library - Recital Embedded Edition provides in-process data storage engine that delivers all the features of a traditional relational database but in a size which makes it ideally suited for ISVs/VARs who need a small footprint and easy to use toolkit.
  • Platform Independence - Recital runs on Linux, Solaris, AIX, HP-UX, Windows, and Mac OS X giving organizations complete flexibility in delivering a solution on the platform of their choice.
Published in Blogs
Read more...

SE Linux is a feature of the Linux kernel that provides mandatory access control. This policy based access control system grants far greater control over the resources on a machine than standard Linux access controls such as permissions.

Many modern Linux distributions are shipping with SELinux enabled by default, Fedora 14 and Rhel 6 both install with it enabled.

When you run Recital Web on a SELinux enabled machine and navigate to the default.rsp page you will see something similar to the screen shot below.

1
If you launch the SELinux troubleshooter you will see the following problem.

SELinux is blocking the apache server from accessing the Recital server running on port 8001.

2
To manage you SELinux policy you must have the policycoreutils package group installed. The policycoreutils contains the policy core utilities that are required for basic operation of a SELinux system.

If you wish to use a GUI tool, you must install the policycoreutils-gui package.

At the command prompt execute the following:

As root

$ yum install policycoreutils

$ semanage port -a -t http_port_t -p tcp 8001

$ service recital restart

$ service httpd restart 
 

We use the semanage command here to allow the http server access to port 8001. Once you have completed the steps detailed above you can go and navigate back to the default.rsp page in your borwser, where you will find the permission denied message is now replaced by the default.rsp page.


4
SELinux does a great job of restricting services and daemons so rather than simply disabling it, why not work with it!

When it comes to security, every little bit helps...

Published in Blogs
Read more...

There's a nice article on IBM developerworks describing how to package software using RPM. You can read it here.

Published in Blogs
Read more...
Recital is a dynamic programming language particularly suited to the development of database applications. While Recital still supports standard procedural programming, new extensions to the language give you the power and flexibility of object-oriented programming. Object-oriented design and object-oriented programming represent a change in focus from standard procedural programming. This short primer will give you a good understanding of how to program object-oriented Recital.
Published in Blogs
Read more...
Twitter

Copyright © 2024 Recital Software Inc.

Login

Register

User Registration
or Cancel