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

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | PHP Version 5                                                        |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1997-2012 The PHP Group                                |
        !             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: /* $Id: php_ibase_udf.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            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>