예제 #1
0
static PyObject *
psyco_parse_dsn(PyObject *self, PyObject *args, PyObject *kwargs)
{
    char *err = NULL;
    PQconninfoOption *options = NULL;
    PyObject *res = NULL, *dsn;

    static char *kwlist[] = {"dsn", NULL};
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &dsn)) {
        return NULL;
    }

    Py_INCREF(dsn); /* for ensure_bytes */
    if (!(dsn = psycopg_ensure_bytes(dsn))) { goto exit; }

    options = PQconninfoParse(Bytes_AS_STRING(dsn), &err);
    if (options == NULL) {
        if (err != NULL) {
            PyErr_Format(ProgrammingError, "invalid dsn: %s", err);
            PQfreemem(err);
        } else {
            PyErr_SetString(OperationalError, "PQconninfoParse() failed");
        }
        goto exit;
    }

    res = psycopg_dict_from_conninfo_options(options, /* include_password = */ 1);

exit:
    PQconninfoFree(options);    /* safe on null */
    Py_XDECREF(dsn);

    return res;
}
예제 #2
0
RAISES_NEG static int
_psyco_conn_parse_onoff(PyObject *pyval)
{
    int rv = -1;

    Py_INCREF(pyval);   /* for ensure_bytes */

    if (pyval == Py_None) {
        rv = STATE_DEFAULT;
    }
    else if (PyUnicode_CheckExact(pyval) || Bytes_CheckExact(pyval)) {
        if (!(pyval = psycopg_ensure_bytes(pyval))) {
            goto exit;
        }
        if (0 == strcasecmp("default", Bytes_AS_STRING(pyval))) {
            rv = STATE_DEFAULT;
        }
        else {
            PyErr_Format(PyExc_ValueError,
                "the only string accepted is 'default'; got %s",
                Bytes_AS_STRING(pyval));
            goto exit;
        }
    }
    else {
        int istrue;
        if (0 > (istrue = PyObject_IsTrue(pyval))) { goto exit; }
        rv = istrue ? STATE_ON : STATE_OFF;
    }

exit:
    Py_XDECREF(pyval);

    return rv;
}
예제 #3
0
RAISES_NEG int
conn_tpc_command(connectionObject *self, const char *cmd, xidObject *xid)
{
    PGresult *pgres = NULL;
    char *error = NULL;
    PyObject *tid = NULL;
    const char *ctid;
    int rv = -1;

    Dprintf("conn_tpc_command: %s", cmd);

    /* convert the xid into PostgreSQL transaction id while keeping the GIL */
    if (!(tid = psycopg_ensure_bytes(xid_get_tid(xid)))) { goto exit; }
    if (!(ctid = Bytes_AsString(tid))) { goto exit; }

    Py_BEGIN_ALLOW_THREADS;
    pthread_mutex_lock(&self->lock);

    if (0 > (rv = pq_tpc_command_locked(self, cmd, ctid,
                                        &pgres, &error, &_save))) {
        pthread_mutex_unlock(&self->lock);
        Py_BLOCK_THREADS;
        pq_complete_error(self, &pgres, &error);
        goto exit;
    }

    pthread_mutex_unlock(&self->lock);
    Py_END_ALLOW_THREADS;

exit:
    Py_XDECREF(tid);
    return rv;
}
예제 #4
0
/* Convert a Postgres encoding into Python encoding and decoding functions.
 *
 * Set clean_encoding to a clean version of the Postgres encoding name
 * and pyenc and pydec to python codec functions.
 *
 * Return 0 on success, else -1 and set an exception.
 */
RAISES_NEG static int
conn_get_python_codec(const char *encoding,
    char **clean_encoding, PyObject **pyenc, PyObject **pydec)
{
    int rv = -1;
    char *pgenc = NULL;
    PyObject *encname = NULL;
    PyObject *enc_tmp = NULL, *dec_tmp = NULL;

    /* get the Python name of the encoding as a C string */
    if (!(encname = conn_pgenc_to_pyenc(encoding, &pgenc))) { goto exit; }
    if (!(encname = psycopg_ensure_bytes(encname))) { goto exit; }

    /* Look up the codec functions */
    if (!(enc_tmp = PyCodec_Encoder(Bytes_AS_STRING(encname)))) { goto exit; }
    if (!(dec_tmp = PyCodec_Decoder(Bytes_AS_STRING(encname)))) { goto exit; }

    /* success */
    *pyenc = enc_tmp; enc_tmp = NULL;
    *pydec = dec_tmp; dec_tmp = NULL;
    *clean_encoding = pgenc; pgenc = NULL;
    rv = 0;

exit:
    Py_XDECREF(enc_tmp);
    Py_XDECREF(dec_tmp);
    Py_XDECREF(encname);
    PyMem_Free(pgenc);

    return rv;
}
예제 #5
0
/* Convert a PostgreSQL encoding to a Python codec.
 *
 * Set 'codec' to a new copy of the codec name allocated on the Python heap.
 * Return 0 in case of success, else -1 and set an exception.
 *
 * 'enc' should be already normalized (uppercase, no - or _).
 */
RAISES_NEG static int
conn_encoding_to_codec(const char *enc, char **codec)
{
    char *tmp;
    Py_ssize_t size;
    PyObject *pyenc = NULL;
    int rv = -1;

    /* Find the Py codec name from the PG encoding */
    if (!(pyenc = PyDict_GetItemString(psycoEncodings, enc))) {
        PyErr_Format(OperationalError,
            "no Python codec for client encoding '%s'", enc);
        goto exit;
    }

    /* Convert the codec in a bytes string to extract the c string. */
    Py_INCREF(pyenc);
    if (!(pyenc = psycopg_ensure_bytes(pyenc))) {
        goto exit;
    }

    if (-1 == Bytes_AsStringAndSize(pyenc, &tmp, &size)) {
        goto exit;
    }

    /* have our own copy of the python codec name */
    rv = psycopg_strdup(codec, tmp, size);

exit:
    Py_XDECREF(pyenc);
    return rv;
}
예제 #6
0
static const char *
_psyco_conn_parse_isolevel(connectionObject *self, PyObject *pyval)
{
    const IsolationLevel *isolevel = NULL;

    Py_INCREF(pyval);   /* for ensure_bytes */

    /* parse from one of the level constants */
    if (PyInt_Check(pyval)) {
        long level = PyInt_AsLong(pyval);
        if (level == -1 && PyErr_Occurred()) { goto exit; }
        if (level < 1 || level > 4) {
            PyErr_SetString(PyExc_ValueError,
                "isolation_level must be between 1 and 4");
            goto exit;
        }

        isolevel = conn_isolevels;
        while ((++isolevel)->value != level)
            ; /* continue */
    }

    /* parse from the string -- this includes "default" */
    else {
        isolevel = conn_isolevels;
        while ((++isolevel)->name) {
            if (!(pyval = psycopg_ensure_bytes(pyval))) {
                goto exit;
            }
            if (0 == strcasecmp(isolevel->name, Bytes_AS_STRING(pyval))) {
                break;
            }
        }
        if (!isolevel->name) {
            char msg[256];
            snprintf(msg, sizeof(msg),
                "bad value for isolation_level: '%s'", Bytes_AS_STRING(pyval));
            PyErr_SetString(PyExc_ValueError, msg);
        }
    }

    /* use only supported levels on older PG versions */
    if (isolevel && self->server_version < 80000) {
        if (isolevel->value == ISOLATION_LEVEL_READ_UNCOMMITTED
            || isolevel->value == ISOLATION_LEVEL_REPEATABLE_READ) {
            ++isolevel;
        }
    }

exit:
    Py_XDECREF(pyval);

    return isolevel ? isolevel->name : NULL;
}
예제 #7
0
RAISES_NEG static int
_psyco_conn_parse_isolevel(PyObject *pyval)
{
    int rv = -1;
    long level;

    Py_INCREF(pyval);   /* for ensure_bytes */

    /* None is default. This is only used when setting the property, because
     * set_session() has None used as "don't change" */
    if (pyval == Py_None) {
        rv = ISOLATION_LEVEL_DEFAULT;
    }

    /* parse from one of the level constants */
    else if (PyInt_Check(pyval)) {
        level = PyInt_AsLong(pyval);
        if (level == -1 && PyErr_Occurred()) { goto exit; }
        if (level < 1 || level > 4) {
            PyErr_SetString(PyExc_ValueError,
                "isolation_level must be between 1 and 4");
            goto exit;
        }

        rv = level;
    }

    /* parse from the string -- this includes "default" */
    else {
        if (!(pyval = psycopg_ensure_bytes(pyval))) {
            goto exit;
        }
        for (level = 1; level <= 4; level++) {
            if (0 == strcasecmp(srv_isolevels[level], Bytes_AS_STRING(pyval))) {
                rv = level;
                break;
            }
        }
        if (rv < 0 && 0 == strcasecmp("default", Bytes_AS_STRING(pyval))) {
            rv = ISOLATION_LEVEL_DEFAULT;
        }
        if (rv < 0) {
            PyErr_Format(PyExc_ValueError,
                "bad value for isolation_level: '%s'", Bytes_AS_STRING(pyval));
            goto exit;
        }
    }

exit:
    Py_XDECREF(pyval);

    return rv;
}
예제 #8
0
static PyObject *
psyco_parse_dsn(PyObject *self, PyObject *args, PyObject *kwargs)
{
    char *err = NULL;
    PQconninfoOption *options = NULL, *o;
    PyObject *dict = NULL, *res = NULL, *dsn;

    static char *kwlist[] = {"dsn", NULL};
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &dsn)) {
        return NULL;
    }

    Py_INCREF(dsn); /* for ensure_bytes */
    if (!(dsn = psycopg_ensure_bytes(dsn))) { goto exit; }

    options = PQconninfoParse(Bytes_AS_STRING(dsn), &err);
    if (options == NULL) {
        if (err != NULL) {
            PyErr_Format(ProgrammingError, "error parsing the dsn: %s", err);
            PQfreemem(err);
        } else {
            PyErr_SetString(OperationalError, "PQconninfoParse() failed");
        }
        goto exit;
    }

    if (!(dict = PyDict_New())) { goto exit; }
    for (o = options; o->keyword != NULL; o++) {
        if (o->val != NULL) {
            PyObject *value;
            if (!(value = Text_FromUTF8(o->val))) { goto exit; }
            if (PyDict_SetItemString(dict, o->keyword, value) != 0) {
                Py_DECREF(value);
                goto exit;
            }
            Py_DECREF(value);
        }
    }

    /* success */
    res = dict;
    dict = NULL;

exit:
    PQconninfoFree(options);    /* safe on null */
    Py_XDECREF(dict);
    Py_XDECREF(dsn);

    return res;
}
예제 #9
0
static PyObject *
psyco_quote_ident(PyObject *self, PyObject *args, PyObject *kwargs)
{
#if PG_VERSION_NUM >= 90000
    PyObject *ident = NULL, *obj = NULL, *result = NULL;
    connectionObject *conn;
    const char *str;
    char *quoted = NULL;

    static char *kwlist[] = {"ident", "scope", NULL};
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, &ident, &obj)) {
        return NULL;
    }

    if (PyObject_TypeCheck(obj, &cursorType)) {
        conn = ((cursorObject*)obj)->conn;
    }
    else if (PyObject_TypeCheck(obj, &connectionType)) {
        conn = (connectionObject*)obj;
    }
    else {
        PyErr_SetString(PyExc_TypeError,
                        "argument 2 must be a connection or a cursor");
        return NULL;
    }

    Py_INCREF(ident); /* for ensure_bytes */
    if (!(ident = psycopg_ensure_bytes(ident))) { goto exit; }

    str = Bytes_AS_STRING(ident);

    quoted = PQescapeIdentifier(conn->pgconn, str, strlen(str));
    if (!quoted) {
        PyErr_NoMemory();
        goto exit;
    }
    result = conn_text_from_chars(conn, quoted);

exit:
    PQfreemem(quoted);
    Py_XDECREF(ident);

    return result;
#else
    PyErr_SetString(NotSupportedError, "PQescapeIdentifier not available in libpq < 9.0");
    return NULL;
#endif
}
예제 #10
0
RAISES_NEG static int
obscure_password(connectionObject *conn)
{
    PQconninfoOption *options;
    PyObject *d = NULL, *v = NULL, *dsn = NULL;
    char *tmp;
    int rv = -1;

    if (!conn || !conn->dsn) {
        return 0;
    }

    if (!(options = PQconninfoParse(conn->dsn, NULL))) {
        /* unlikely: the dsn was already tested valid */
        return 0;
    }

    if (!(d = psycopg_dict_from_conninfo_options(
            options, /* include_password = */ 1))) {
        goto exit;
    }
    if (NULL == PyDict_GetItemString(d, "password")) {
        /* the dsn doesn't have a password */
        rv = 0;
        goto exit;
    }

    /* scrub the password and put back the connection string together */
    if (!(v = Text_FromUTF8("xxx"))) { goto exit; }
    if (0 > PyDict_SetItemString(d, "password", v)) { goto exit; }
    if (!(dsn = psycopg_make_dsn(Py_None, d))) { goto exit; }
    if (!(dsn = psycopg_ensure_bytes(dsn))) { goto exit; }

    /* Replace the connection string on the connection object */
    tmp = conn->dsn;
    psycopg_strdup(&conn->dsn, Bytes_AS_STRING(dsn), -1);
    PyMem_Free(tmp);

    rv = 0;

exit:
    PQconninfoFree(options);
    Py_XDECREF(v);
    Py_XDECREF(d);
    Py_XDECREF(dsn);

    return rv;
}
예제 #11
0
static PyObject *
typecast_repr(PyObject *self)
{
    PyObject *name = ((typecastObject *)self)->name;
    PyObject *rv;

    Py_INCREF(name);
    if (!(name = psycopg_ensure_bytes(name))) {
        return NULL;
    }

    rv = PyString_FromFormat("<%s '%s' at %p>",
        Py_TYPE(self)->tp_name, Bytes_AS_STRING(name), self);

    Py_DECREF(name);
    return rv;
}
예제 #12
0
static PyObject *
_pydatetime_string_date_time(pydatetimeObject *self)
{
    PyObject *rv = NULL;
    PyObject *iso = NULL;
    PyObject *tz;

    /* Select the right PG type to cast into. */
    char *fmt = NULL;
    switch (self->type) {
    case PSYCO_DATETIME_TIME:
        tz = PyObject_GetAttrString(self->wrapped, "tzinfo");
        if (!tz) { goto error; }
        fmt = (tz == Py_None) ? "'%s'::time" : "'%s'::timetz";
        Py_DECREF(tz);
        break;
    case PSYCO_DATETIME_DATE:
        fmt = "'%s'::date";
        break;
    case PSYCO_DATETIME_TIMESTAMP:
        tz = PyObject_GetAttrString(self->wrapped, "tzinfo");
        if (!tz) { goto error; }
        fmt = (tz == Py_None) ? "'%s'::timestamp" : "'%s'::timestamptz";
        Py_DECREF(tz);
        break;
    }

    if (!(iso = psycopg_ensure_bytes(
            PyObject_CallMethod(self->wrapped, "isoformat", NULL)))) {
        goto error;
    }

    rv = Bytes_FromFormat(fmt, Bytes_AsString(iso));

    Py_DECREF(iso);
    return rv;

error:
    Py_XDECREF(iso);
    return rv;
}
예제 #13
0
static PyObject *
_xid_base64_enc_dec(const char *funcname, PyObject *s)
{
    PyObject *base64 = NULL;
    PyObject *func = NULL;
    PyObject *rv = NULL;

    if (!(base64 = PyImport_ImportModule("base64"))) { goto exit; }
    if (!(func = PyObject_GetAttrString(base64, funcname))) { goto exit; }

    Py_INCREF(s);
    if (!(s = psycopg_ensure_bytes(s))) { goto exit; }
    rv = psycopg_ensure_text(PyObject_CallFunctionObjArgs(func, s, NULL));
    Py_DECREF(s);

exit:
    Py_XDECREF(func);
    Py_XDECREF(base64);

    return rv;
}
예제 #14
0
static PyObject *
psyco_quote_ident(PyObject *self, PyObject *args, PyObject *kwargs)
{
    PyObject *ident = NULL, *obj = NULL, *result = NULL;
    connectionObject *conn;
    char *quoted = NULL;

    static char *kwlist[] = {"ident", "scope", NULL};
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, &ident, &obj)) {
        return NULL;
    }

    if (PyObject_TypeCheck(obj, &cursorType)) {
        conn = ((cursorObject*)obj)->conn;
    }
    else if (PyObject_TypeCheck(obj, &connectionType)) {
        conn = (connectionObject*)obj;
    }
    else {
        PyErr_SetString(PyExc_TypeError,
                        "argument 2 must be a connection or a cursor");
        return NULL;
    }

    Py_INCREF(ident); /* for ensure_bytes */
    if (!(ident = psycopg_ensure_bytes(ident))) { goto exit; }

    if (!(quoted = psycopg_escape_identifier(conn,
        Bytes_AS_STRING(ident), Bytes_GET_SIZE(ident)))) { goto exit; }

    result = conn_text_from_chars(conn, quoted);

exit:
    PQfreemem(quoted);
    Py_XDECREF(ident);

    return result;
}
예제 #15
0
static PyObject *
psyco_encrypt_password(PyObject *self, PyObject *args, PyObject *kwargs)
{
    char *encrypted = NULL;
    PyObject *password = NULL, *user = NULL;
    PyObject *scope = Py_None, *algorithm = Py_None;
    PyObject *res = NULL;
    connectionObject *conn = NULL;

    static char *kwlist[] = {"password", "user", "scope", "algorithm", NULL};

    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|OO", kwlist,
            &password, &user, &scope, &algorithm)) {
        return NULL;
    }

    /* for ensure_bytes */
    Py_INCREF(user);
    Py_INCREF(password);
    Py_INCREF(algorithm);

    if (scope != Py_None) {
        if (PyObject_TypeCheck(scope, &cursorType)) {
            conn = ((cursorObject*)scope)->conn;
        }
        else if (PyObject_TypeCheck(scope, &connectionType)) {
            conn = (connectionObject*)scope;
        }
        else {
            PyErr_SetString(PyExc_TypeError,
                "the scope must be a connection or a cursor");
            goto exit;
        }
    }

    if (!(user = psycopg_ensure_bytes(user))) { goto exit; }
    if (!(password = psycopg_ensure_bytes(password))) { goto exit; }
    if (algorithm != Py_None) {
        if (!(algorithm = psycopg_ensure_bytes(algorithm))) {
            goto exit;
        }
    }

    /* If we have to encrypt md5 we can use the libpq < 10 API */
    if (algorithm != Py_None &&
            strcmp(Bytes_AS_STRING(algorithm), "md5") == 0) {
        encrypted = PQencryptPassword(
            Bytes_AS_STRING(password), Bytes_AS_STRING(user));
    }

    /* If the algorithm is not md5 we have to use the API available from
     * libpq 10. */
    else {
#if PG_VERSION_NUM >= 100000
        if (!conn) {
            PyErr_SetString(ProgrammingError,
                "password encryption (other than 'md5' algorithm)"
                " requires a connection or cursor");
            goto exit;
        }

        /* TODO: algo = None will block: forbid on async/green conn? */
        encrypted = PQencryptPasswordConn(conn->pgconn,
            Bytes_AS_STRING(password), Bytes_AS_STRING(user),
            algorithm != Py_None ? Bytes_AS_STRING(algorithm) : NULL);
#else
        PyErr_SetString(NotSupportedError,
            "password encryption (other than 'md5' algorithm)"
            " requires libpq 10");
        goto exit;
#endif
    }

    if (encrypted) {
        res = Text_FromUTF8(encrypted);
    }
    else {
        const char *msg = PQerrorMessage(conn->pgconn);
        PyErr_Format(ProgrammingError,
            "password encryption failed: %s", msg ? msg : "no reason given");
        goto exit;
    }

exit:
    if (encrypted) {
        PQfreemem(encrypted);
    }
    Py_XDECREF(user);
    Py_XDECREF(password);
    Py_XDECREF(algorithm);

    return res;
}