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

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

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