Annotation of embedaddon/php/ext/interbase/php_ibase_udf.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.3 ! misho       5:    | Copyright (c) 1997-2013 The PHP Group                                |
1.1       misho       6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Author: Ard Biesheuvel <a.k.biesheuvel@ewi.tudelft.nl>               |
                     16:    +----------------------------------------------------------------------+
                     17:  */
                     18: 
1.1.1.2   misho      19: /* $Id$ */
1.1       misho      20: 
                     21: /**
                     22: * This UDF library adds the ability to call PHP functions from SQL
                     23: * statements. Because of SQL's strong typing, you will have to declare
                     24: * an external function for every combination { output type, #args } that
                     25: * your application requires. 
                     26: * 
                     27: * Declare the functions like this:
                     28: * 
                     29: *     DECLARE EXTERNAL FUNCTION CALL_PHP1
                     30: *         CSTRING(xx),
                     31: *         <return type> BY DESCRIPTOR,
                     32: *         INTEGER BY DESCRIPTOR
                     33: *         RETURNS PARAMETER 2
                     34: *         ENTRY_POINT 'udf_call_php1' MODULE_NAME 'php_ibase_udf'
                     35: * 
                     36: *     DECLARE EXTERNAL FUNCTION CALL_PHP2
                     37: *         CSTRING(xx),
                     38: *         <return type> BY DESCRIPTOR, 
                     39: *         INTEGER BY DESCRIPTOR,
                     40: *         INTEGER BY DESCRIPTOR
                     41: *         RETURNS PARAMETER 2
                     42: *         ENTRY_POINT 'udf_call_php2' MODULE_NAME 'php_ibase_udf'
                     43: * 
                     44: *     ... and so on. [for up to 8 input arguments]
                     45: * 
                     46: * The first input parameter contains the name of the PHP function you want
                     47: * to call. The second argument is the result. (omit this argument when calling
                     48: * the function) The return type of the function is the declared type of the
                     49: * result. The value returned from the PHP function being called will
                     50: * automatically be converted if necessary.
                     51: * The arguments should have their types declared as well, but you're free
                     52: * to pass arguments of other types instead. They will be converted to the
                     53: * best matching PHP type before being passed to the PHP function.
                     54: * 
                     55: * The declared functions can be called from SQL like:
                     56: * 
                     57: *     SELECT * FROM <table> WHERE CALL_PHP1('soundex',<field>) NOT LIKE ?
                     58: * or
                     59: *     UPDATE <table> SET <field> = CALL_PHP1('ucwords',<field>)
                     60: * 
                     61: * Additionally, there's a function 'exec_php' which allows the contents
                     62: * of text BLOB fields to be parsed and executed by PHP. This is most useful
                     63: * for declaring functions that can then be called with CALL_PHPx.
                     64: *
                     65: *    DECLARE EXTERNAL FUNCTION EXEC_PHP
                     66: *        BLOB,
                     67: *        INTEGER BY DESCRIPTOR,
                     68: *        SMALLINT
                     69: *        RETURNS PARAMETER 2
                     70: *        ENTRY_POINT 'exec_php' MODULE_NAME 'php_ibase_udf'
                     71: *
                     72: * The function will return 1 if execution succeeded and 0 if an error
                     73: * occurred. The result that is returned from the executed PHP code is
                     74: * ignored. You can pass a non-zero value as second argument to force
                     75: * the embedded PHP engine to re-initialise.
                     76: *
                     77: * There are several ways to build this library, depending on which way the
                     78: * database is accessed. If you're using the classic server on a local
                     79: * connection, you should compile the library like this:
                     80: *
                     81: *     gcc -shared `php-config --includes` `php-config --ldflags` \
                     82: *         `php-config --libs` -o php_ibase_udf.so php_ibase_udf.c
                     83: *
                     84: * If you connect to the classic server by TCP/IP, you should build the
                     85: * PHP embedded static library and link against that. 
                     86: *
                     87: *     gcc -shared `php-config --includes` `php-config --ldflags` \
                     88: *         `php-config --libs` -o php_ibase_udf.so php_ibase_udf.c \
                     89: *         /usr/lib/libphp5.a
                     90: *
                     91: * If you use the super server, you should also link against the embedded
                     92: * library, but be sure to enable thread safety, as the super server is
                     93: * multi-threaded. After building, copy the resulting file to the folder
                     94: * where your database expects to find its UDFs.
                     95: */
                     96: 
                     97: #include "zend.h"
                     98: #include "zend_API.h"
                     99: 
                    100: #include "php.h"
                    101: #include "php_ini.h"
                    102: 
                    103: #include "ibase.h"
                    104: 
                    105: #define min(a,b) ((a)<(b)?(a):(b))
                    106: 
                    107: #ifdef PHP_WIN32
                    108: #define LL_LIT(lit) lit ## I64
                    109: #else
                    110: #define LL_LIT(lit) lit ## ll
                    111: #endif
                    112: 
                    113: #ifdef ZTS
                    114: #  include <pthread.h>
                    115: 
                    116: static void ***tsrm_ls;
                    117: pthread_mutex_t mtx_res = PTHREAD_MUTEX_INITIALIZER;
                    118: 
                    119: #define LOCK() do { pthread_mutex_lock(&mtx_res); } while (0)
                    120: #define UNLOCK() do { pthread_mutex_unlock(&mtx_res); } while (0)
                    121: #else
                    122: #define LOCK()
                    123: #define UNLOCK()
                    124: #endif
                    125: 
                    126: #ifdef PHP_EMBED
                    127: # include "php_main.h"
                    128: # include "sapi/embed/php_embed.h"
                    129: 
                    130: static void __attribute__((constructor)) init()
                    131: {
                    132:        php_embed_init(0, NULL PTSRMLS_CC);
                    133: }
                    134: 
                    135: static void __attribute__((destructor)) fini()
                    136: {
                    137:        php_embed_shutdown(TSRMLS_C);
                    138: }
                    139: 
                    140: #endif
                    141: 
                    142: /**
                    143: * Gets the contents of the BLOB b and offers it to Zend for parsing/execution
                    144: */
                    145: void exec_php(BLOBCALLBACK b, PARAMDSC *res, ISC_SHORT *init)
                    146: {
                    147:        int result, remaining = b->blob_total_length, i = 0;
                    148:        char *code = pemalloc(remaining+1, 1);
                    149:        ISC_USHORT read;
                    150: 
                    151:        for (code[remaining] = '\0'; remaining > 0; remaining -= read)
                    152:                b->blob_get_segment(b->blob_handle, &code[i++<<16],min(0x10000,remaining), &read); 
                    153: 
                    154:        LOCK();
                    155: 
                    156:        switch (init && *init) {
                    157: 
                    158:                default:
                    159: #ifdef PHP_EMBED
                    160:                        php_request_shutdown(NULL);
                    161:                        if (FAILURE == (result = php_request_startup(TSRMLS_C))) {
                    162:                                break;
                    163:                        }
                    164:                case 0:
                    165: #endif
                    166:                        /* feed it to the parser */
                    167:                        zend_first_try {
                    168:                                result = zend_eval_stringl(code, b->blob_total_length, NULL, "Firebird Embedded PHP engine" TSRMLS_CC);
                    169:                        } zend_end_try();
                    170:        }
                    171:        
                    172:        UNLOCK();
                    173: 
                    174:        free(code);
                    175: 
                    176:        res->dsc_dtype = dtype_long;
                    177:        *(ISC_LONG*)res->dsc_address = (result == SUCCESS);
                    178: }
                    179: 
                    180: static ISC_INT64 const scales[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 100000000, 1000000000,
                    181:        1000000000, LL_LIT(10000000000),LL_LIT(100000000000),LL_LIT(10000000000000),LL_LIT(100000000000000),
                    182:        LL_LIT(1000000000000000),LL_LIT(1000000000000000),LL_LIT(1000000000000000000) };
                    183: 
                    184: 
                    185: static void call_php(char *name, PARAMDSC *r, int argc, PARAMDSC **argv)
                    186: {
                    187:        do {
                    188:                zval callback, args[4], *argp[4], return_value;
                    189:                PARAMVARY *res = (PARAMVARY*)r->dsc_address;
                    190:                int i;
                    191: 
                    192:                INIT_ZVAL(callback);
                    193:                ZVAL_STRING(&callback,name,0);
                    194: 
                    195:                LOCK();
                    196:                
                    197:                /* check if the requested function exists */
                    198:                if (!zend_is_callable(&callback, 0, NULL TSRMLS_CC)) {
                    199:                        break;
                    200:                }
                    201:                
                    202:                UNLOCK();
                    203:        
                    204:                /* create the argument array */
                    205:                for (i = 0; i < argc; ++i) {
                    206: 
                    207:                        INIT_ZVAL(args[i]);
                    208:                        argp[i] = &args[i];
                    209:                        
                    210:                        /* test arg for null */
                    211:                        if (argv[i]->dsc_flags & DSC_null) {
                    212:                                ZVAL_NULL(argp[i]);
                    213:                                continue;
                    214:                        }
                    215: 
                    216:                        switch (argv[i]->dsc_dtype) {
                    217:                                ISC_INT64 l;
                    218:                                struct tm t;
                    219:                                char const *fmt;
                    220:                                char d[64];
                    221: 
                    222:                                case dtype_cstring:
                    223:                                        ZVAL_STRING(argp[i], (char*)argv[i]->dsc_address,0);
                    224:                                        break;
                    225: 
                    226:                                case dtype_text:
                    227:                                        ZVAL_STRINGL(argp[i], (char*)argv[i]->dsc_address, argv[i]->dsc_length,0);
                    228:                                        break;
                    229: 
                    230:                                case dtype_varying:
                    231:                                        ZVAL_STRINGL(argp[i], ((PARAMVARY*)argv[i]->dsc_address)->vary_string,
                    232:                                                ((PARAMVARY*)argv[i]->dsc_address)->vary_length,0);
                    233:                                        break;
                    234: 
                    235:                                case dtype_short:
                    236:                                        if (argv[i]->dsc_scale == 0) {
                    237:                                                ZVAL_LONG(argp[i], *(short*)argv[i]->dsc_address);
                    238:                                        } else {
                    239:                                                ZVAL_DOUBLE(argp[i],
                    240:                                                        ((double)*(short*)argv[i]->dsc_address)/scales[-argv[i]->dsc_scale]);
                    241:                                        }
                    242:                                        break;
                    243: 
                    244:                                case dtype_long:
                    245:                                        if (argv[i]->dsc_scale == 0) {
                    246:                                                ZVAL_LONG(argp[i], *(ISC_LONG*)argv[i]->dsc_address);
                    247:                                        } else {
                    248:                                                ZVAL_DOUBLE(argp[i],
                    249:                                                        ((double)*(ISC_LONG*)argv[i]->dsc_address)/scales[-argv[i]->dsc_scale]);
                    250:                                        }
                    251:                                        break;
                    252: 
                    253:                                case dtype_int64:
                    254:                                        l = *(ISC_INT64*)argv[i]->dsc_address;
                    255: 
                    256:                                        if (argv[i]->dsc_scale == 0 && l <= LONG_MAX && l >= LONG_MIN) {
                    257:                                                ZVAL_LONG(argp[i], (long)l);
                    258:                                        } else {
                    259:                                                ZVAL_DOUBLE(argp[i], ((double)l)/scales[-argv[i]->dsc_scale]);
                    260:                                        }
                    261:                                        break;
                    262: 
                    263:                                case dtype_real:
                    264:                                        ZVAL_DOUBLE(argp[i], *(float*)argv[i]->dsc_address);
                    265:                                        break;
                    266: 
                    267:                                case dtype_double:
                    268:                                        ZVAL_DOUBLE(argp[i], *(double*)argv[i]->dsc_address);
                    269:                                        break;
                    270: 
                    271:                                case dtype_sql_date:
                    272:                                        isc_decode_sql_date((ISC_DATE*)argv[i]->dsc_address, &t);
                    273:                                        ZVAL_STRINGL(argp[i], d, strftime(d, sizeof(d), INI_STR("ibase.dateformat"), &t),1); 
                    274:                                        break;
                    275: 
                    276:                                case dtype_sql_time:
                    277:                                        isc_decode_sql_time((ISC_TIME*)argv[i]->dsc_address, &t);
                    278:                                        ZVAL_STRINGL(argp[i], d, strftime(d, sizeof(d), INI_STR("ibase.timeformat"), &t),1); 
                    279:                                        break;
                    280: 
                    281:                                case dtype_timestamp:
                    282:                                        isc_decode_timestamp((ISC_TIMESTAMP*)argv[i]->dsc_address, &t);
                    283:                                        ZVAL_STRINGL(argp[i], d, strftime(d, sizeof(d), INI_STR("ibase.timestampformat"), &t),1); 
                    284:                                        break;
                    285:                        }
                    286:                }
                    287: 
                    288:                LOCK();
                    289: 
                    290:                /* now call the function */
                    291:                if (FAILURE == call_user_function(EG(function_table), NULL,
                    292:                                &callback, &return_value, argc, argp TSRMLS_CC)) {
                    293:                        UNLOCK();
                    294:                        break;
                    295:                }
                    296:                
                    297:                UNLOCK();
                    298: 
                    299:                for (i = 0; i < argc; ++i) {
                    300:                        switch (argv[i]->dsc_dtype) {
                    301:                                case dtype_sql_date:
                    302:                                case dtype_sql_time:
                    303:                                case dtype_timestamp:
                    304:                                        zval_dtor(argp[i]);
                    305:                                        
                    306:                        }
                    307:                }
                    308: 
                    309:                /* return whatever type we got back from the callback: let DB handle conversion */
                    310:                switch (Z_TYPE(return_value)) {
                    311: 
                    312:                        case IS_LONG:
                    313:                                r->dsc_dtype = dtype_long;
                    314:                                *(long*)r->dsc_address = Z_LVAL(return_value);
                    315:                                r->dsc_length = sizeof(long);
                    316:                                break;
                    317: 
                    318:                        case IS_DOUBLE:
                    319:                                r->dsc_dtype = dtype_double;
                    320:                                *(double*)r->dsc_address = Z_DVAL(return_value);
                    321:                                r->dsc_length = sizeof(double);
                    322:                                break;
                    323: 
                    324:                        case IS_NULL:
                    325:                                r->dsc_flags |= DSC_null;
                    326:                                break;
                    327: 
                    328:                        default:
                    329:                                convert_to_string(&return_value);
                    330: 
                    331:                        case IS_STRING:
                    332:                                r->dsc_dtype = dtype_varying;
                    333:                                memcpy(res->vary_string, Z_STRVAL(return_value),
                    334:                                        (res->vary_length = min(r->dsc_length-2,Z_STRLEN(return_value))));
                    335:                                r->dsc_length = res->vary_length+2;
                    336:                                break;
                    337:                }
                    338:                                
                    339:                zval_dtor(&return_value);
                    340: 
                    341:                return;
                    342: 
                    343:        } while (0);
                    344:        
                    345:        /**
                    346:        * If we end up here, we should report an error back to the DB engine, but
                    347:        * that's not possible. We can however report it back to PHP.
                    348:        */
                    349:        LOCK();
                    350:        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error calling function '%s' from database", name);
                    351:        UNLOCK();
                    352: }
                    353: 
                    354: 
                    355: /* Entry points for the DB engine */
                    356: 
                    357: void udf_call_php1(char *name, PARAMDSC *r, PARAMDSC *arg1)
                    358: {
                    359:        PARAMDSC *args[1] = { arg1 };
                    360:        call_php(name, r, 1, args);
                    361: }
                    362: 
                    363: void udf_call_php2(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2)
                    364: {
                    365:        PARAMDSC *args[2] = { arg1, arg2 };
                    366:        call_php(name, r, 2, args);
                    367: }
                    368: 
                    369: void udf_call_php3(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3)
                    370: {
                    371:        PARAMDSC *args[3] = { arg1, arg2, arg3 };
                    372:        call_php(name, r, 3, args);
                    373: }
                    374: 
                    375: void udf_call_php4(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 
                    376:        PARAMDSC *arg4)
                    377: {
                    378:        PARAMDSC *args[4] = { arg1, arg2, arg3, arg4 };
                    379:        call_php(name, r, 4, args);
                    380: }
                    381: 
                    382: void udf_call_php5(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 
                    383:        PARAMDSC *arg4, PARAMDSC *arg5)
                    384: {
                    385:        PARAMDSC *args[5] = { arg1, arg2, arg3, arg4, arg5 };
                    386:        call_php(name, r, 5, args);
                    387: }
                    388: 
                    389: void udf_call_php6(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 
                    390:        PARAMDSC *arg4, PARAMDSC *arg5, PARAMDSC *arg6)
                    391: {
                    392:        PARAMDSC *args[6] = { arg1, arg2, arg3, arg4, arg5, arg6 };
                    393:        call_php(name, r, 6, args);
                    394: }
                    395: 
                    396: void udf_call_php7(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 
                    397:        PARAMDSC *arg4, PARAMDSC *arg5, PARAMDSC *arg6, PARAMDSC *arg7)
                    398: {
                    399:        PARAMDSC *args[7] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7 };
                    400:        call_php(name, r, 7, args);
                    401: }
                    402: 
                    403: void udf_call_php8(char *name, PARAMDSC *r, PARAMDSC *arg1, PARAMDSC *arg2, PARAMDSC *arg3, 
                    404:        PARAMDSC *arg4, PARAMDSC *arg5, PARAMDSC *arg6, PARAMDSC *arg7, PARAMDSC *arg8)
                    405: {
                    406:        PARAMDSC *args[8] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 };
                    407:        call_php(name, r, 8, args);
                    408: }
                    409: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>