Back to index

php5  5.3.10
Defines | Functions | Variables
php_ibase_udf.c File Reference
#include "zend.h"
#include "zend_API.h"
#include "php.h"
#include "php_ini.h"
#include "ibase.h"

Go to the source code of this file.

Defines

#define min(a, b)   ((a)<(b)?(a):(b))
 This UDF library adds the ability to call PHP functions from SQL statements.
#define LL_LIT(lit)   lit ## ll
#define LOCK()
#define UNLOCK()

Functions

void exec_php (BLOBCALLBACK b, PARAMDSC *res, ISC_SHORT *init)
 Gets the contents of the BLOB b and offers it to Zend for parsing/execution.
static void call_php (char *name, PARAMDSC *r, int argc, PARAMDSC **argv)
void udf_call_php1 (char *name, PARAMDSC *r, PARAMDSC *arg1)
void udf_call_php2 (char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2)
void udf_call_php3 (char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3)
void udf_call_php4 (char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, PARAMDSC *arg4)
void udf_call_php5 (char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, PARAMDSC *arg4, PARAMDSC *arg5)
void udf_call_php6 (char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, PARAMDSC *arg4, PARAMDSC *arg5, PARAMDSC *arg6)
void udf_call_php7 (char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, PARAMDSC *arg4, PARAMDSC *arg5, PARAMDSC *arg6, PARAMDSC *arg7)
void udf_call_php8 (char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, PARAMDSC *arg4, PARAMDSC *arg5, PARAMDSC *arg6, PARAMDSC *arg7, PARAMDSC *arg8)

Variables

static ISC_INT64 const scales []

Define Documentation

#define LL_LIT (   lit)    lit ## ll

Definition at line 110 of file php_ibase_udf.c.

#define LOCK ( )

Definition at line 122 of file php_ibase_udf.c.

#define min (   a,
 
)    ((a)<(b)?(a):(b))

This UDF library adds the ability to call PHP functions from SQL statements.

Because of SQL's strong typing, you will have to declare an external function for every combination { output type, #args } that your application requires.

Declare the functions like this:

DECLARE EXTERNAL FUNCTION CALL_PHP1
    CSTRING(xx),
    <return type> BY DESCRIPTOR,
    INTEGER BY DESCRIPTOR
    RETURNS PARAMETER 2
    ENTRY_POINT 'udf_call_php1' MODULE_NAME 'php_ibase_udf'

DECLARE EXTERNAL FUNCTION CALL_PHP2
    CSTRING(xx),
    <return type> BY DESCRIPTOR, 
    INTEGER BY DESCRIPTOR,
    INTEGER BY DESCRIPTOR
    RETURNS PARAMETER 2
    ENTRY_POINT 'udf_call_php2' MODULE_NAME 'php_ibase_udf'

... and so on. [for up to 8 input arguments]

The first input parameter contains the name of the PHP function you want to call. The second argument is the result. (omit this argument when calling the function) The return type of the function is the declared type of the result. The value returned from the PHP function being called will automatically be converted if necessary. The arguments should have their types declared as well, but you're free to pass arguments of other types instead. They will be converted to the best matching PHP type before being passed to the PHP function.

The declared functions can be called from SQL like:

SELECT * FROM <table> WHERE CALL_PHP1('soundex',<field>) NOT LIKE ?

or UPDATE

<field> = CALL_PHP1('ucwords',<field>)

Additionally, there's a function 'exec_php' which allows the contents of text BLOB fields to be parsed and executed by PHP. This is most useful for declaring functions that can then be called with CALL_PHPx.

DECLARE EXTERNAL FUNCTION EXEC_PHP BLOB, INTEGER BY DESCRIPTOR, SMALLINT RETURNS PARAMETER 2 ENTRY_POINT 'exec_php' MODULE_NAME 'php_ibase_udf'

The function will return 1 if execution succeeded and 0 if an error occurred. The result that is returned from the executed PHP code is ignored. You can pass a non-zero value as second argument to force the embedded PHP engine to re-initialise.

There are several ways to build this library, depending on which way the database is accessed. If you're using the classic server on a local connection, you should compile the library like this:

gcc -shared `php-config --includes` `php-config --ldflags` \
    `php-config --libs` -o php_ibase_udf.so php_ibase_udf.c

If you connect to the classic server by TCP/IP, you should build the PHP embedded static library and link against that.

gcc -shared `php-config --includes` `php-config --ldflags` \
    `php-config --libs` -o php_ibase_udf.so php_ibase_udf.c \
    /usr/lib/libphp5.a

If you use the super server, you should also link against the embedded library, but be sure to enable thread safety, as the super server is multi-threaded. After building, copy the resulting file to the folder where your database expects to find its UDFs.

Definition at line 105 of file php_ibase_udf.c.

#define UNLOCK ( )

Definition at line 123 of file php_ibase_udf.c.


Function Documentation

static void call_php ( char *  name,
PARAMDSC *  r,
int  argc,
PARAMDSC **  argv 
) [static]

If we end up here, we should report an error back to the DB engine, but that's not possible. We can however report it back to PHP.

Definition at line 185 of file php_ibase_udf.c.

{
       do {
              zval callback, args[4], *argp[4], return_value;
              PARAMVARY *res = (PARAMVARY*)r->dsc_address;
              int i;

              INIT_ZVAL(callback);
              ZVAL_STRING(&callback,name,0);

              LOCK();
              
              /* check if the requested function exists */
              if (!zend_is_callable(&callback, 0, NULL TSRMLS_CC)) {
                     break;
              }
              
              UNLOCK();
       
              /* create the argument array */
              for (i = 0; i < argc; ++i) {

                     INIT_ZVAL(args[i]);
                     argp[i] = &args[i];
                     
                     /* test arg for null */
                     if (argv[i]->dsc_flags & DSC_null) {
                            ZVAL_NULL(argp[i]);
                            continue;
                     }

                     switch (argv[i]->dsc_dtype) {
                            ISC_INT64 l;
                            struct tm t;
                            char const *fmt;
                            char d[64];

                            case dtype_cstring:
                                   ZVAL_STRING(argp[i], (char*)argv[i]->dsc_address,0);
                                   break;

                            case dtype_text:
                                   ZVAL_STRINGL(argp[i], (char*)argv[i]->dsc_address, argv[i]->dsc_length,0);
                                   break;

                            case dtype_varying:
                                   ZVAL_STRINGL(argp[i], ((PARAMVARY*)argv[i]->dsc_address)->vary_string,
                                          ((PARAMVARY*)argv[i]->dsc_address)->vary_length,0);
                                   break;

                            case dtype_short:
                                   if (argv[i]->dsc_scale == 0) {
                                          ZVAL_LONG(argp[i], *(short*)argv[i]->dsc_address);
                                   } else {
                                          ZVAL_DOUBLE(argp[i],
                                                 ((double)*(short*)argv[i]->dsc_address)/scales[-argv[i]->dsc_scale]);
                                   }
                                   break;

                            case dtype_long:
                                   if (argv[i]->dsc_scale == 0) {
                                          ZVAL_LONG(argp[i], *(ISC_LONG*)argv[i]->dsc_address);
                                   } else {
                                          ZVAL_DOUBLE(argp[i],
                                                 ((double)*(ISC_LONG*)argv[i]->dsc_address)/scales[-argv[i]->dsc_scale]);
                                   }
                                   break;

                            case dtype_int64:
                                   l = *(ISC_INT64*)argv[i]->dsc_address;

                                   if (argv[i]->dsc_scale == 0 && l <= LONG_MAX && l >= LONG_MIN) {
                                          ZVAL_LONG(argp[i], (long)l);
                                   } else {
                                          ZVAL_DOUBLE(argp[i], ((double)l)/scales[-argv[i]->dsc_scale]);
                                   }
                                   break;

                            case dtype_real:
                                   ZVAL_DOUBLE(argp[i], *(float*)argv[i]->dsc_address);
                                   break;

                            case dtype_double:
                                   ZVAL_DOUBLE(argp[i], *(double*)argv[i]->dsc_address);
                                   break;

                            case dtype_sql_date:
                                   isc_decode_sql_date((ISC_DATE*)argv[i]->dsc_address, &t);
                                   ZVAL_STRINGL(argp[i], d, strftime(d, sizeof(d), INI_STR("ibase.dateformat"), &t),1); 
                                   break;

                            case dtype_sql_time:
                                   isc_decode_sql_time((ISC_TIME*)argv[i]->dsc_address, &t);
                                   ZVAL_STRINGL(argp[i], d, strftime(d, sizeof(d), INI_STR("ibase.timeformat"), &t),1); 
                                   break;

                            case dtype_timestamp:
                                   isc_decode_timestamp((ISC_TIMESTAMP*)argv[i]->dsc_address, &t);
                                   ZVAL_STRINGL(argp[i], d, strftime(d, sizeof(d), INI_STR("ibase.timestampformat"), &t),1); 
                                   break;
                     }
              }

              LOCK();

              /* now call the function */
              if (FAILURE == call_user_function(EG(function_table), NULL,
                            &callback, &return_value, argc, argp TSRMLS_CC)) {
                     UNLOCK();
                     break;
              }
              
              UNLOCK();

              for (i = 0; i < argc; ++i) {
                     switch (argv[i]->dsc_dtype) {
                            case dtype_sql_date:
                            case dtype_sql_time:
                            case dtype_timestamp:
                                   zval_dtor(argp[i]);
                                   
                     }
              }

              /* return whatever type we got back from the callback: let DB handle conversion */
              switch (Z_TYPE(return_value)) {

                     case IS_LONG:
                            r->dsc_dtype = dtype_long;
                            *(long*)r->dsc_address = Z_LVAL(return_value);
                            r->dsc_length = sizeof(long);
                            break;

                     case IS_DOUBLE:
                            r->dsc_dtype = dtype_double;
                            *(double*)r->dsc_address = Z_DVAL(return_value);
                            r->dsc_length = sizeof(double);
                            break;

                     case IS_NULL:
                            r->dsc_flags |= DSC_null;
                            break;

                     default:
                            convert_to_string(&return_value);

                     case IS_STRING:
                            r->dsc_dtype = dtype_varying;
                            memcpy(res->vary_string, Z_STRVAL(return_value),
                                   (res->vary_length = min(r->dsc_length-2,Z_STRLEN(return_value))));
                            r->dsc_length = res->vary_length+2;
                            break;
              }
                            
              zval_dtor(&return_value);

              return;

       } while (0);
       
       LOCK();
       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error calling function '%s' from database", name);
       UNLOCK();
}

Here is the call graph for this function:

Here is the caller graph for this function:

void exec_php ( BLOBCALLBACK  b,
PARAMDSC *  res,
ISC_SHORT *  init 
)

Gets the contents of the BLOB b and offers it to Zend for parsing/execution.

Definition at line 145 of file php_ibase_udf.c.

{
       int result, remaining = b->blob_total_length, i = 0;
       char *code = pemalloc(remaining+1, 1);
       ISC_USHORT read;

       for (code[remaining] = '\0'; remaining > 0; remaining -= read)
              b->blob_get_segment(b->blob_handle, &code[i++<<16],min(0x10000,remaining), &read); 

       LOCK();

       switch (init && *init) {

              default:
#ifdef PHP_EMBED
                     php_request_shutdown(NULL);
                     if (FAILURE == (result = php_request_startup(TSRMLS_C))) {
                            break;
                     }
              case 0:
#endif
                     /* feed it to the parser */
                     zend_first_try {
                            result = zend_eval_stringl(code, b->blob_total_length, NULL, "Firebird Embedded PHP engine" TSRMLS_CC);
                     } zend_end_try();
       }
       
       UNLOCK();

       free(code);

       res->dsc_dtype = dtype_long;
       *(ISC_LONG*)res->dsc_address = (result == SUCCESS);
}

Here is the call graph for this function:

void udf_call_php1 ( char *  name,
PARAMDSC *  r,
PARAMDSC *  arg1 
)

Definition at line 357 of file php_ibase_udf.c.

{
       PARAMDSC *args[1] = { arg1 };
       call_php(name, r, 1, args);
}

Here is the call graph for this function:

void udf_call_php2 ( char *  name,
PARAMDSC *  r,
PARAMDSC *  arg1,
PARAMDSC *  arg2 
)

Definition at line 363 of file php_ibase_udf.c.

{
       PARAMDSC *args[2] = { arg1, arg2 };
       call_php(name, r, 2, args);
}

Here is the call graph for this function:

void udf_call_php3 ( char *  name,
PARAMDSC *  r,
PARAMDSC *  arg1,
PARAMDSC *  arg2,
PARAMDSC *  arg3 
)

Definition at line 369 of file php_ibase_udf.c.

{
       PARAMDSC *args[3] = { arg1, arg2, arg3 };
       call_php(name, r, 3, args);
}

Here is the call graph for this function:

void udf_call_php4 ( char *  name,
PARAMDSC *  r,
PARAMDSC *  arg1,
PARAMDSC *  arg2,
PARAMDSC *  arg3,
PARAMDSC *  arg4 
)

Definition at line 375 of file php_ibase_udf.c.

{
       PARAMDSC *args[4] = { arg1, arg2, arg3, arg4 };
       call_php(name, r, 4, args);
}

Here is the call graph for this function:

void udf_call_php5 ( char *  name,
PARAMDSC *  r,
PARAMDSC *  arg1,
PARAMDSC *  arg2,
PARAMDSC *  arg3,
PARAMDSC *  arg4,
PARAMDSC *  arg5 
)

Definition at line 382 of file php_ibase_udf.c.

{
       PARAMDSC *args[5] = { arg1, arg2, arg3, arg4, arg5 };
       call_php(name, r, 5, args);
}

Here is the call graph for this function:

void udf_call_php6 ( char *  name,
PARAMDSC *  r,
PARAMDSC *  arg1,
PARAMDSC *  arg2,
PARAMDSC *  arg3,
PARAMDSC *  arg4,
PARAMDSC *  arg5,
PARAMDSC *  arg6 
)

Definition at line 389 of file php_ibase_udf.c.

{
       PARAMDSC *args[6] = { arg1, arg2, arg3, arg4, arg5, arg6 };
       call_php(name, r, 6, args);
}

Here is the call graph for this function:

void udf_call_php7 ( char *  name,
PARAMDSC *  r,
PARAMDSC *  arg1,
PARAMDSC *  arg2,
PARAMDSC *  arg3,
PARAMDSC *  arg4,
PARAMDSC *  arg5,
PARAMDSC *  arg6,
PARAMDSC *  arg7 
)

Definition at line 396 of file php_ibase_udf.c.

{
       PARAMDSC *args[7] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7 };
       call_php(name, r, 7, args);
}

Here is the call graph for this function:

void udf_call_php8 ( char *  name,
PARAMDSC *  r,
PARAMDSC *  arg1,
PARAMDSC *  arg2,
PARAMDSC *  arg3,
PARAMDSC *  arg4,
PARAMDSC *  arg5,
PARAMDSC *  arg6,
PARAMDSC *  arg7,
PARAMDSC *  arg8 
)

Definition at line 403 of file php_ibase_udf.c.

{
       PARAMDSC *args[8] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 };
       call_php(name, r, 8, args);
}

Here is the call graph for this function:


Variable Documentation

ISC_INT64 const scales[] [static]
Initial value:
 { 1, 10, 100, 1000, 10000, 100000, 1000000, 100000000, 1000000000,
       1000000000, LL_LIT(10000000000),LL_LIT(100000000000),LL_LIT(10000000000000),LL_LIT(100000000000000),
       LL_LIT(1000000000000000),LL_LIT(1000000000000000),LL_LIT(1000000000000000000) }

Definition at line 180 of file php_ibase_udf.c.