Beispiel #1
0
EjsArray *ejsCaptureStack(Ejs *ejs, int uplevels)
{
    EjsFrame        *fp;
    EjsState        *state;
    EjsArray        *stack;
    wchar           *source;
    EjsObj          *frame;
    char            *filename;
    int             index, lineNumber;

    assert(ejs);

    stack = ejsCreateArray(ejs, 0);
    index = 0;
    for (state = ejs->state; state; state = state->prev) {
        for (fp = state->fp; fp; fp = fp->caller) {
            if (uplevels-- <= 0) {
                frame = ejsCreateEmptyPot(ejs);
                if (ejsGetDebugInfo(ejs, (EjsFunction*) fp, fp->pc, &filename, &lineNumber, &source) >= 0) {
                    ejsSetPropertyByName(ejs, frame, EN("filename"), ejsCreatePathFromAsc(ejs, filename));
                    ejsSetPropertyByName(ejs, frame, EN("lineno"), ejsCreateNumber(ejs, lineNumber));
                    ejsSetPropertyByName(ejs, frame, EN("code"), ejsCreateString(ejs, source, wlen(source)));
                } else {
                    ejsSetPropertyByName(ejs, frame, EN("filename"), EST(undefined));
                }
                ejsSetPropertyByName(ejs, frame, EN("func"), fp->function.name);
                ejsSetProperty(ejs, stack, index++, frame);
            }
        }
    }
    return stack;
}
Beispiel #2
0
static EjsObj *getFileOptions(Ejs *ejs, EjsFile *fp, int argc, EjsObj **argv)
{
    EjsObj      *options;

    options = (EjsObj*) ejsCreateEmptyPot(ejs);
    ejsSetPropertyByName(ejs, options, EN("mode"), ejsCreateStringFromAsc(ejs, fp->modeString));
    ejsSetPropertyByName(ejs, options, EN("permissions"), ejsCreateNumber(ejs, fp->perms));
    return options;
}
Beispiel #3
0
/*
    Update an existing element
 */
static int updateElement(Ejs *ejs, EjsXML *list, EjsXML *elt, int index, EjsObj *value)
{
    EjsXML      *node;
    int         i, j;

    if (!ejsIsXML(ejs, value)) {
        /* Not XML or XMLList -- convert to string */
        value = ejsCast(ejs, value, String);                //  TODO - seem to be doing this in too many places
    }
    mprSetItem(list->elements, index, value);

    if (elt->kind == EJS_XML_ATTRIBUTE) {
        assure(ejsIs(ejs, value, String));
        i = mprLookupItem(elt->parent->elements, elt);
        assure(i >= 0);
        ejsSetXMLElement(ejs, elt->parent, i, elt);
        //  TODO - why do this. Doesn't above do this?
        ejsSetPropertyByName(ejs, elt->parent, elt->qname, value);
        elt->value = (EjsString*) value;
    }

    if (ejsIsXML(ejs, value) && ((EjsXML*) value)->kind == EJS_XML_LIST) {
        value = (EjsObj*) shallowCopy(ejs, (EjsXML*) value);
        if (elt->parent) {
            index = mprLookupItem(elt->parent->elements, elt);
            assure(index >= 0);
            for (j = 0; j < mprGetListLength(((EjsXML*) value)->elements); j++) {
                mprInsertItemAtPos(elt->parent->elements, index, value);
            }
        }

    } else if (ejsIsXML(ejs, value) || elt->kind != EJS_XML_ELEMENT) {
        if (elt->parent) {
            index = mprLookupItem(elt->parent->elements, elt);
            assure(index >= 0);
            mprSetItem(elt->parent->elements, index, value);
            ((EjsXML*) value)->parent = elt->parent;
            if (ejsIs(ejs, value, String)) {
                node = ejsCreateXML(ejs, EJS_XML_TEXT, N(NULL, NULL), list, (EjsString*) value);
                mprSetItem(list->elements, index, node);
            } else {
                mprSetItem(list->elements, index, value);
            }
        }

    } else {
        ejsSetPropertyByName(ejs, elt, N(NULL, "*"), value);
    }
    return index;
}
Beispiel #4
0
/*
    function setLimits(limits: Object): Void
 */
static EjsObj *hs_setLimits(Ejs *ejs, EjsHttpServer *sp, int argc, EjsObj **argv)
{
    EjsObj      *vp, *app, *cache, *cacheLimits;
    HttpLimits  *limits;

    if (sp->limits == 0) {
        sp->limits = ejsCreateEmptyPot(ejs);
        limits = (sp->endpoint) ? sp->endpoint->limits : ejs->http->serverLimits;
        assert(limits);
        ejsGetHttpLimits(ejs, sp->limits, limits, 1);
    }
    ejsBlendObject(ejs, sp->limits, argv[0], EJS_BLEND_OVERWRITE);
    if (sp->endpoint) {
        limits = (sp->endpoint) ? sp->endpoint->limits : ejs->http->serverLimits;
        ejsSetHttpLimits(ejs, limits, sp->limits, 1);
    }
    if ((vp = ejsGetPropertyByName(ejs, sp->limits, EN("sessionTimeout"))) != 0) {
        app = ejsGetPropertyByName(ejs, ejs->global, N("ejs", "App"));
        cache = ejsGetPropertyByName(ejs, app, N("ejs", "cache"));
        if (cache && cache != ESV(null)) {
            cacheLimits = ejsCreateEmptyPot(ejs);
            ejsSetPropertyByName(ejs, cacheLimits, EN("lifespan"), vp);
            ejsCacheSetLimits(ejs, cache, cacheLimits);
        }
    }
    return 0;
}
Beispiel #5
0
/*  
    Break a uri into components
  
    function components(): Object
 */
static EjsObj *uri_components(Ejs *ejs, EjsUri *up, int argc, EjsObj **argv)
{
    EjsObj      *obj;
    HttpUri     *uri;

    uri = up->uri;
    obj = ejsCreateEmptyPot(ejs);

    if (uri->scheme) {
        ejsSetPropertyByName(ejs, obj, EN("scheme"), ejsCreateStringFromAsc(ejs, uri->scheme));
    }
    if (uri->host) {
        ejsSetPropertyByName(ejs, obj, EN("host"), ejsCreateStringFromAsc(ejs, uri->host));
    }
    if (uri->port > 0) {
        ejsSetPropertyByName(ejs, obj, EN("port"), ejsCreateNumber(ejs, uri->port));
    }
    if (uri->path) {
        ejsSetPropertyByName(ejs, obj, EN("path"), ejsCreateStringFromAsc(ejs, uri->path));
    }
    if (uri->reference) {
        ejsSetPropertyByName(ejs, obj, EN("reference"), ejsCreateStringFromAsc(ejs, uri->reference));
    }
    if (uri->query) {
        ejsSetPropertyByName(ejs, obj, EN("query"), ejsCreateStringFromAsc(ejs, uri->query));
    }
    return obj;
}
Beispiel #6
0
/*  
    Return the (proposed) request headers
    function getRequestHeaders(): Object
 */
static EjsPot *http_getRequestHeaders(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv)
{
    MprKey          *kp;
    HttpConn        *conn;
    EjsPot          *headers;

    conn = hp->conn;
    headers = ejsCreateEmptyPot(ejs);
    for (kp = 0; conn->tx && (kp = mprGetNextKey(conn->tx->headers, kp)) != 0; ) {
        ejsSetPropertyByName(ejs, headers, EN(kp->key), ejsCreateStringFromAsc(ejs, kp->data));
    }
    return headers;
}
Beispiel #7
0
/*
 *  A header object from a given hash table
 */  
static EjsVar *createHeaderObject(Ejs *ejs, MprHashTable *table)
{
    MprHash     *hp;
    EjsVar      *headers, *header;
    EjsName     qname;
    int         index;
    
    headers = (EjsVar*) ejsCreateArray(ejs, mprGetHashCount(table));
    for (index = 0, hp = 0; (hp = mprGetNextHash(table, hp)) != 0; ) {
        header = (EjsVar*) ejsCreateSimpleObject(ejs);
        ejsSetPropertyByName(ejs, header, ejsName(&qname, "", hp->key), (EjsVar*) ejsCreateString(ejs, hp->data));
        ejsSetProperty(ejs, headers, index++, header);
    }
    return headers;
}
Beispiel #8
0
/*
    function get info(): Object
 */
static EjsObj *http_info(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv)
{
    EjsObj  *obj;
    char    *key, *next, *value;

    if (hp->conn && hp->conn->sock) {
        obj = ejsCreateEmptyPot(ejs);
        for (key = stok(mprGetSocketState(hp->conn->sock), ",", &next); key; key = stok(NULL, ",", &next)) {
            stok(key, "=", &value);
            ejsSetPropertyByName(ejs, obj, EN(key), ejsCreateStringFromAsc(ejs, value));
        }
        return obj;
    }
    return ESV(null);
}
Beispiel #9
0
/*  
    Get all environment vars
    function get env(): Object
 */
static EjsAny *app_env(Ejs *ejs, EjsObj *app, int argc, EjsObj **argv)
{
#if VXWORKS
    return ESV(null);
#else
    EjsPot  *result;
    char        **ep, *pair, *key, *value;

    result = ejsCreatePot(ejs, ESV(Object), 0);
    for (ep = environ; ep && *ep; ep++) {
        pair = sclone(*ep);
        key = ssplit(pair, "=", &value);
        ejsSetPropertyByName(ejs, result, EN(key), ejsCreateStringFromAsc(ejs, value));
    }
    return result;
#endif
}
Beispiel #10
0
/*  
    function get headers(): Object
 */
static EjsPot *http_headers(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv)
{
    MprHash         *hash;
    MprKey          *kp;
    EjsPot          *results;
    int             i;

    if (!waitForResponseHeaders(hp)) {
        return 0;
    }
    results = ejsCreateEmptyPot(ejs);
    hash = httpGetHeaderHash(hp->conn);
    if (hash == 0) {
        return results;
    }
    for (i = 0, kp = mprGetFirstKey(hash); kp; kp = mprGetNextKey(hash, kp), i++) {
        ejsSetPropertyByName(ejs, results, EN(kp->key), ejsCreateStringFromAsc(ejs, kp->data));
    }
    return results;
}
Beispiel #11
0
/*
    Resolve empty XML list objects to an actual XML object. This is used by SetPropertyByName to find the actual 
    object to update. This method resolves the value of empty XMLLists. If the XMLList is not empty, the list will 
    be returned. If list is empty, this method attempts to create an element based on the list targetObject and 
    targetProperty.
 */
static EjsXML *resolve(Ejs *ejs, EjsXML *xml)
{
    EjsXML  *targetObject, *targetPropertyList;

    if (!ejsIsXML(ejs, xml) || xml->kind != EJS_XML_LIST) {
        /* Resolved to an XML object */
        return xml;
    }
    if (mprGetListLength(xml->elements) > 0) {
        /* Resolved to a list of items */
        return xml;
    }
    if (xml->targetObject == 0 || xml->targetProperty.name == NULL || xml->targetProperty.name->value[0] == '*') {
        /* End of chain an no more target objects */
        return 0;
    }
    targetObject = resolve(ejs, xml->targetObject);
    if (targetObject == 0) {
        return 0;
    }
    //  TODO - OPT. targetPropertyList is also being created below.
    targetPropertyList = ejsGetPropertyByName(ejs, (EjsObj*) targetObject, xml->targetProperty);
    if (targetPropertyList == 0) {
        return 0;
    }
    if (ejsGetLength(ejs, (EjsObj*) targetPropertyList) == 0) {
        /*
            Property does not exist in the target.
         */
        if (targetObject->kind == EJS_XML_LIST && ejsGetLength(ejs, (EjsObj*) targetObject) > 1) {
            return 0;
        }
        /*
            Create the property as an element (The text value will be optimized away).
         */
        ejsSetPropertyByName(ejs, targetObject, xml->targetProperty, ESV(empty));
        targetPropertyList = ejsGetPropertyByName(ejs, (EjsObj*) targetObject, xml->targetProperty);
    }
    return targetPropertyList;
}
Beispiel #12
0
/*
    Set an alpha property by name.
 */
static int setAlphaPropertyByName(Ejs *ejs, EjsXML *list, EjsName qname, EjsObj *value)
{
    EjsXML      *elt, *targetObject;
    int         count;

    targetObject = 0;

    count = ejsGetLength(ejs, (EjsObj*) list);
    if (count > 1) {
        //  TODO - why no error in spec?
        assure(0);
        return 0;
    }

    if (count == 0) {
        /*
            Empty list so resolve the real target object and append it to the list.
         */
        targetObject = resolve(ejs, list);
        if (targetObject == 0) {
            return 0;
        }
        if (ejsGetLength(ejs, (EjsObj*) targetObject) != 1) {
            return 0;
        }
        ejsAppendToXML(ejs, list, targetObject);
    }

    /*
        Update the element
     */
    assure(ejsGetLength(ejs, (EjsObj*) list) == 1);
    elt = mprGetItem(list->elements, 0);                        //  TODO OPT - GetFirstItem
    assure(elt);
    ejsSetPropertyByName(ejs, elt, qname, value);
    return 0;
}
Beispiel #13
0
static void onWebSocketEvent(EjsWebSocket *ws, int event, EjsAny *data, HttpPacket *packet)
{
    Ejs             *ejs;
    EjsAny          *eobj;
    EjsFunction     *fn;
    HttpRx          *rx;
    cchar           *eventName, *reason;
    int             slot, status;

    ejs = ws->ejs;
    rx = ws->conn->rx;
    eobj = ejsCreateObj(ejs, ESV(Object), 0);
    slot = -1;
    eventName = 0;

    switch(event) {
    case HTTP_EVENT_READABLE:
        slot = ES_WebSocket_onmessage;
        eventName = "readable";
        assert(data);
        ejsSetPropertyByName(ejs, eobj, EN("data"), data);
        ejsSetPropertyByName(ejs, eobj, EN("last"), ejsCreateBoolean(ejs, packet->last));
        ejsSetPropertyByName(ejs, eobj, EN("type"), ejsCreateNumber(ejs, packet->type));
        break;

    case HTTP_EVENT_ERROR:
        eventName = "error";
        slot = ES_WebSocket_onerror;
        break;

    case HTTP_EVENT_APP_OPEN:
        slot = ES_WebSocket_onopen;
        eventName = "headers";
        if (rx->webSocket) {
            httpSetWebSocketPreserveFrames(ws->conn, ws->frames);
        }
        break;

    case HTTP_EVENT_DESTROY:
        if (ws->closed) {
            break;
        }
        ws->closed = 1;
        /* Fall through to close */

    case HTTP_EVENT_APP_CLOSE:
        eventName = "complete";
        slot = ES_WebSocket_onclose;
        status = rx ? rx->webSocket->closeStatus: WS_STATUS_COMMS_ERROR;
        reason = rx ? rx->webSocket->closeReason: 0;
        ejsSetPropertyByName(ejs, eobj, EN("code"), ejsCreateNumber(ejs, status));
        ejsSetPropertyByName(ejs, eobj, EN("reason"), ejsCreateStringFromAsc(ejs, reason));
        ejsSetPropertyByName(ejs, eobj, EN("wasClean"), ejsCreateBoolean(ejs, status != WS_STATUS_COMMS_ERROR));
        break;
    }
    if (slot >= 0) {
        if (ws->emitter) {
            ejsSendEvent(ejs, ws->emitter, eventName, ws, data);
        }
        fn = ejsGetProperty(ejs, ws, slot);
        if (ejsIsFunction(ejs, fn) && !ejs->exception) {
            ejsRunFunction(ejs, fn, ws, 1, &eobj);
        }
    }
}
Beispiel #14
0
/*
    Parse an object literal string pointed to by js->next into the given buffer. Update js->next to point
    to the next input token in the object literal. Supports nested object literals.
 */
static EjsObj *parseLiteralInner(Ejs *ejs, MprBuf *buf, JsonState *js)
{
    EjsAny      *obj, *vp;
    MprBuf      *valueBuf;
    wchar       *token, *key, *value;
    int         tid, isArray;

    isArray = 0;

    tid = getNextJsonToken(buf, &token, js);
    if (tid == TOK_ERR || tid == TOK_EOF) {
        return 0;
    }
    if (tid == TOK_LBRACKET) {
        isArray = 1;
        obj = (EjsObj*) ejsCreateArray(ejs, 0);
    } else if (tid == TOK_LBRACE) {
        obj = ejsCreateEmptyPot(ejs);
    } else {
        return ejsParse(ejs, token, S_String);
    }
    if (obj == 0) {
        ejsThrowMemoryError(ejs);
        return 0;
    }
    while (1) {
        vp = 0;
        tid = peekNextJsonToken(js);
        if (tid == TOK_ERR) {
            return 0;
        } else if (tid == TOK_EOF) {
            break;
        } else if (tid == TOK_RBRACE || tid == TOK_RBRACKET) {
            getNextJsonToken(buf, &key, js);
            break;
        }
        if (tid == TOK_LBRACKET) {
            /* For array values */
            vp = parseLiteral(ejs, js);
            assert(vp);
            
        } else if (tid == TOK_LBRACE) {
            /* For object values */
            vp = parseLiteral(ejs, js);
            assert(vp);
            
        } else if (isArray) {
            tid = getNextJsonToken(buf, &value, js);
            vp = ejsParse(ejs, value, (tid == TOK_QID) ? S_String: -1);
            assert(vp);
            
        } else {
            getNextJsonToken(buf, &key, js);
            tid = peekNextJsonToken(js);
            if (tid == TOK_ERR) {
                return 0;
            } else if (tid == TOK_EOF) {
                break;
            } else if (tid == TOK_LBRACE || tid == TOK_LBRACKET) {
                vp = parseLiteral(ejs, js);

            } else if (tid == TOK_ID || tid == TOK_QID) {
                valueBuf = mprCreateBuf(0, 0);
                getNextJsonToken(valueBuf, &value, js);
                if (tid == TOK_QID) {
                    vp = ejsCreateString(ejs, value, strlen(value));
                } else {
                    if (mcmp(value, "null") == 0) {
                        vp = ESV(null);
                    } else if (mcmp(value, "undefined") == 0) {
                        vp = ESV(undefined);
                    } else {
                        vp = ejsParse(ejs, value, -1);
                    }
                }
                assert(vp);
            } else {
                getNextJsonToken(buf, &value, js);
                js->error = js->next;
                return 0;
            }
        }
        if (vp == 0) {
            js->error = js->next;
            return 0;
        }
        if (isArray) {
            if (ejsSetProperty(ejs, obj, -1, vp) < 0) {
                ejsThrowMemoryError(ejs);
                return 0;
            }
        } else {
            if (ejsSetPropertyByName(ejs, obj, WEN(key), vp) < 0) {
                ejsThrowMemoryError(ejs);
                return 0;
            }
        }
    }
    return obj;
}
Beispiel #15
0
static EjsWorker *initWorker(Ejs *ejs, EjsWorker *worker, Ejs *baseVM, cchar *name, EjsArray *search, cchar *scriptFile)
{
    Ejs             *wejs;
    EjsWorker       *self;
    EjsName         sname;
    static int      workerSeqno = 0;

    ejsBlockGC(ejs);
    if (worker == 0) {
        worker = ejsCreateWorker(ejs);
    }
    worker->ejs = ejs;
    worker->state = EJS_WORKER_BEGIN;

    if (name) {
        worker->name = sclone(name);
    } else {
        lock(ejs);
        worker->name = sfmt("worker-%d", workerSeqno++);
        unlock(ejs);
    }
    /*
        Create a new interpreter and an "inside" worker object and pair it with the current "outside" worker.
        The worker interpreter gets a new dispatcher
     */
    if (baseVM) {
        if ((wejs = ejsCloneVM(baseVM)) == 0) {
            ejsThrowMemoryError(ejs);
            return 0;
        }
    } else {
        if ((wejs = ejsCreateVM(0, 0, ejs->flags)) == 0) {
            ejsThrowMemoryError(ejs);
            return 0;
        }
        if (ejsLoadModules(wejs, 0, 0) < 0) {
            return 0;
        }
    }
    worker->pair = self = ejsCreateWorker(wejs);
    self->state = EJS_WORKER_BEGIN;
    self->ejs = wejs;
    self->inside = 1;
    self->pair = worker;
    self->name = sjoin("inside-", worker->name, NULL);
#if MOB
    mprEnableDispatcher(wejs->dispatcher);
#endif
    if (search) {
        ejsSetSearchPath(ejs, (EjsArray*) search);
    }

    //  TODO - these should be don't delete
    ejsSetProperty(ejs, worker, ES_Worker_name, ejsCreateStringFromAsc(ejs, self->name));
    ejsSetProperty(wejs, self,  ES_Worker_name, ejsCreateStringFromAsc(wejs, self->name));

    sname = ejsName(wejs, EJS_WORKER_NAMESPACE, "self");
    ejsSetPropertyByName(wejs, wejs->global, sname, self);

    /*
        Workers have a dedicated namespace to enable viewing of the worker globals (self, onmessage, postMessage...)
     */
    ejsDefineReservedNamespace(wejs, wejs->global, NULL, EJS_WORKER_NAMESPACE);
    
    addWorker(ejs, worker);

    if (scriptFile) {
        worker->scriptFile = sclone(scriptFile);
        worker->state = EJS_WORKER_STARTED;
        if (mprCreateEvent(wejs->dispatcher, "workerMain", 0, (MprEventProc) workerMain, self, 0) < 0) {
            mprRemoveItem(ejs->workers, worker);
            ejsThrowStateError(ejs, "Cannot create worker event");
            return 0;
        }
    }
    return worker;
}
Beispiel #16
0
/*
 *  function sql(cmd: String): Array
 *
 *  Will support multiple sql cmds but will only return one result table.
 */
static EjsVar *sql(Ejs *ejs, EjsDb *db, int argc, EjsVar **argv)
{
    sqlite3         *sdb;
    sqlite3_stmt    *stmt;
    EjsArray        *result;
    EjsVar          *row, *svalue;
    EjsName         qname;
    cchar           *tail, *colName, *cmd, *value;
    int             i, ncol, rc, retries, rowNum;

    mprAssert(ejs);
    mprAssert(db);

    cmd = ejsGetString(argv[0]);
    
    ejsSetDbMemoryContext(db->tls, db->arena);

    rc = SQLITE_OK;
    retries = 0;
    sdb = db->sdb;

    if (sdb == 0) {
        ejsThrowIOError(ejs, "Database is closed");
        return 0;
    }
    mprAssert(sdb);

    result = ejsCreateArray(ejs, 0);
    if (result == 0) {
        return 0;
    }

    while (cmd && *cmd && (rc == SQLITE_OK || (rc == SQLITE_SCHEMA && ++retries < 2))) {

        stmt = 0;
        rc = sqlite3_prepare_v2(sdb, cmd, -1, &stmt, &tail);
        if (rc != SQLITE_OK) {
            continue;
        }
        if (stmt == 0) {
            /* Comment or white space */
            cmd = tail;
            continue;
        }

        ncol = sqlite3_column_count(stmt);

        for (rowNum = 0; ; rowNum++) {

            rc = sqlite3_step(stmt);

            if (rc == SQLITE_ROW) {

                row = (EjsVar*) ejsCreateSimpleObject(ejs);
                if (row == 0) {
                    sqlite3_finalize(stmt);
                    return 0;
                }
                if (ejsSetProperty(ejs, (EjsVar*) result, rowNum, row) < 0) {
                    /* TODO rc */
                }
                for (i = 0; i < ncol; i++) {
                    colName = sqlite3_column_name(stmt, i);
                    value = (cchar*) sqlite3_column_text(stmt, i);
                    ejsName(&qname, EJS_EMPTY_NAMESPACE, mprStrdup(row, colName));
                    if (ejsLookupProperty(ejs, row, &qname) < 0) {
                        svalue = (EjsVar*) ejsCreateString(ejs, mprStrdup(row, value));
                        if (ejsSetPropertyByName(ejs, row, &qname, svalue) < 0) {
                            /* TODO */
                        }
                    }
                }
            } else {
                rc = sqlite3_finalize(stmt);
                stmt = 0;

                if (rc != SQLITE_SCHEMA) {
                    //  TODO - what is this?
                    retries = 0;
                    for (cmd = tail; isspace(*cmd); cmd++) {
                        ;
                    }
                }
                break;
            }
#if UNUSED
            /* TODO -- should we be doing this */
            cmd = tail;
#endif
        }
    }

    if (stmt) {
        rc = sqlite3_finalize(stmt);
    }

    if (rc != SQLITE_OK) {
        if (rc == sqlite3_errcode(sdb)) {
            ejsThrowIOError(ejs, "SQL error: %s", sqlite3_errmsg(sdb));
        } else {
            ejsThrowIOError(ejs, "Unspecified SQL error");
        }
        return 0;
    }

    return (EjsVar*) result;
}