Beispiel #1
0
int
PQclearSpecs(PGconn *conn)
{
    PGtypeData *typeData;

    if (!conn)
    {
        PQseterror("PGConn cannot be NULL");
        return FALSE;
    }

    typeData = PQinstanceData(conn, pqt_eventproc);
    if (!typeData)
    {
        PQseterror("No type data exists for PGconn at %p", conn);
        return FALSE;
    }

    pqt_freespecs(typeData->typspecs, typeData->typspeccnt);
    typeData->typspecs = NULL;
    typeData->typspeccnt = 0;
    typeData->typspecmax = 0;

    return TRUE;
}
Beispiel #2
0
/* wraps pqt_parsetype to toggle out illegal flags during a register */
static char *parseType(const char *spec, char *typschema, char *typname,
	int typpos)
{
	char *s;
	int flags;

	if (!(s = pqt_parsetype(spec, typschema, typname, &flags, typpos)))
		return NULL;

	if (flags & TYPFLAG_INVALID)
		return NULL;

	if (flags & TYPFLAG_ARRAY)
	{
		PQseterror("Cannot use an array[] during a type handler registration.");
		return NULL;
	}

	if (flags & TYPFLAG_POINTER)
	{
		PQseterror("Cannot use a type* during a type handler registration.");
		return NULL;
	}

	return s;
}
Beispiel #3
0
static int
performRegisterQuery(PGconn *conn, int which, PGregisterType *types,
	int count, PGresult **res)
{
	int n = FALSE;
	PGtypeData *connData;
	PGarray names;
	PGarray schemas;
	int want_attrs = which == PQT_COMPOSITE;

	if (!(connData = (PGtypeData *) PQinstanceData(conn, pqt_eventproc)))
	{
		PQseterror("PGconn is missing event data");
		return FALSE;
	}

	if (!getTypeParams(conn, types, count, &names, &schemas))
		return FALSE;

	if (res)
		*res = execLookupTypes(conn, connData, &schemas, &names, want_attrs);
	else
		n = sendLookupTypes(conn, connData, &schemas, &names, want_attrs);

	PQparamClear(names.param);
	PQparamClear(schemas.param);

	if (res)
		return *res ? TRUE : FALSE;

	return n;
}
Beispiel #4
0
static int
checkTypeLookups(PGresult *res, PGregisterType *types, int count)
{
	int i;
	int ntups = PQntuples(res);

  /* The tuple count must match the requested count.  The server omits
   * tuples for types it did not find.  For those it did find, it returns
   * a sequenctial index.  The first gap found is our missing type.  This
   * only reports about the first missing type.
   */
  if (ntups == count)
		return TRUE;

 	for (i=0; i < ntups; i++)
	{
		int idx;

		if (!PQgetf(res, i, "%int4", 0, &idx))
			return FALSE;

		/* 'i' should always match idx-1, postgresql arrays are 1-based.
		 * This is a missing type, first gap in the sequence.
		 */
		if (i != idx-1)
			break;
	}

	PQseterror("server type lookup failed: could not find '%s'",
		types[i].typname);

	return FALSE;
}
Beispiel #5
0
/* This is part of a performance enhancement for getting arrays
 * and/or composites.  They require generating PGresults which
 * causes pqt_duphandlers() to run.  Its amazing how much a simple
 * malloc+memcpy costs after around 10000 or so.  The common case
 * avoids this by using a fixed length PGrecordAttDesc buffer.  If
 * there are a large number of attributes, the slower path is used.
 * Again this is small, maybe 10% of the overall 63% win.
 */
static PGrecordAttDesc *initAttDescs(PGtypeHandler *h, char *attrs)
{
	char *p;
	int nattrs = 1;
	PGrecordAttDesc *attDescs;

	for(p = attrs; *p; nattrs++, ++p)
		if(!(p = strchr(p, ' ')))
			break;

	if (nattrs < (int) (sizeof(h->attDescsBuf) / sizeof(h->attDescsBuf[0])))
	{
		h->freeAttDescs =  0;
		attDescs = h->attDescsBuf;
	}
	else
	{
		attDescs = (PGrecordAttDesc *) malloc(nattrs * sizeof(PGrecordAttDesc));
		if (!attDescs)
		{
			PQseterror(PQT_OUTOFMEMORY);
			return NULL;
		}

		h->freeAttDescs = 1;
	}

	return attDescs;
}
Beispiel #6
0
static int
expandSpecs(PGtypeData *typeData)
{
    int n;
    PGtypeSpec *specs;

    if (typeData->typspeccnt < typeData->typspecmax)
        return TRUE;

    n = typeData->typspecmax ? (typeData->typspecmax * 3) / 2 : 8;

    specs = (PGtypeSpec *) pqt_realloc(
                typeData->typspecs, sizeof(PGtypeSpec) * n);

    if (!specs)
    {
        PQseterror(PQT_OUTOFMEMORY);
        return FALSE;
    }

    memset(specs + typeData->typspeccnt, 0,
           (n - typeData->typspeccnt) * sizeof(PGtypeSpec));

    typeData->typspecs = specs;
    typeData->typspecmax = n;
    return TRUE;
}
Beispiel #7
0
/* skip quoted strings.  Doesn't need to account for E'' syntax. The
 * E is copied over prior to the quoted string.
 *
 * Returns a pointer to the next character after the closing quote or
 * NULL if there was an error.
 */
static char *
skipQuotes(char *s)
{
    char *end;

    if (*s != '\'')
        return s;

    end = s;
    while (*++end)
    {
        /* If we see a backslash, skip an extra char.  No need to dig any
         * further since this method works with \digits and \hex.
         */
        if (*end == '\\')
            end++;
        else if (*end == '\'')
            break;
    }

    /* unterminated quote */
    if (!*end)
    {
        PQseterror("unterminated single quoted string");
        return NULL;
    }

    return ++end; /* skip ending quote */
}
Beispiel #8
0
int
PQclearTypes(PGconn *conn)
{
	PGtypeData *connData;

	if (!conn)
	{
		PQseterror("PGconn cannot be NULL");
		return FALSE;
	}

	if (!(connData = (PGtypeData *) PQinstanceData(conn, pqt_eventproc)))
	{
		PQseterror("PGconn is missing event data");
		return FALSE;
	}

	pqt_cleartypes(connData);

	return TRUE;
}
Beispiel #9
0
/* errorf() callback for PGtypeArgs, see PQputf() and PQgetf().
 * Always returns -1.
 */
int
pqt_argserrorf(PGtypeArgs *args, const char *format, ...)
{
	va_list ap;
	char fqtn[200];

	if (!args || !format || !*format)
		return -1;

	pqt_fqtn(fqtn, sizeof(fqtn), args->typhandler->typschema,
		args->typhandler->typname);

	/* put the header */
	PQseterror("%s[pos:%d] - ", fqtn, args->typpos);

	/* append message from type handler */
	va_start(ap, format);
	vseterror(format, ap, TRUE);
	return -1;
}
Beispiel #10
0
static int
expandHandlers(PGtypeData *typeData)
{
	int hmax;
	PGtypeHandler *h;

	if (typeData->typhcnt < typeData->typhmax)
		return TRUE;

	hmax = typeData->typhmax ? (typeData->typhmax * 3) / 2 : 8;
	h = (PGtypeHandler *) pqt_realloc(
		typeData->typhandlers, sizeof(PGtypeHandler) * hmax);

	if (!h)
	{
		PQseterror(PQT_OUTOFMEMORY);
		return FALSE;
	}

	typeData->typhandlers = h;
	typeData->typhmax = hmax;
	return TRUE;
}
Beispiel #11
0
PGresult *
pqt_copyresult(PGtypeArgs *args, int nattrs)
{
	int i;
	PGresult *res;
	int tableid, columnid, format;
	PGresAttDesc *ad = (PGresAttDesc *) malloc(nattrs * sizeof(PGresAttDesc));

	if (!ad)
	{
		PQseterror(args->err, PQT_OUTOFMEMORY);
		return NULL;
	}

	tableid  = PQftable(args->get.result, args->get.field_num);
	columnid = PQftablecol(args->get.result, args->get.field_num);
	format   = PQfformat(args->get.result, args->get.field_num);

	for (i=0; i < nattrs; i++)
	{
		ad[i].tableid  = tableid;
		ad[i].columnid = columnid;
		ad[i].format   = format;

		/* simple array */
		if (args->typhandler->nattrs == 0)
		{
			ad[i].typid     = args->typhandler->typoid;
			ad[i].typlen    = args->typhandler->typlen;
			ad[i].name      = NULL;
			ad[i].atttypmod = -1;
		}
		/* composite/record */
		else
		{
			ad[i].typid     = args->typhandler->attDescs[i].attoid;
			ad[i].typlen    = args->typhandler->attDescs[i].attlen;
			ad[i].name      = args->typhandler->attDescs[i].attname;
			ad[i].atttypmod = args->typhandler->attDescs[i].atttypmod;
		}
	}

	res = PQcopyResult(args->get.result,
		PG_COPYRES_EVENTS | PG_COPYRES_NOTICEHOOKS);

	if (!res)
	{
		free(ad);
		PQseterror(args->err, PQT_OUTOFMEMORY);
		return NULL;
	}

	if (!PQsetResultAttrs(res, nattrs, ad))
	{
		PQclear(res);
		PQseterror(args->err, PQT_OUTOFMEMORY);
		res = NULL;
	}

	free(ad);
	return res;
}
Beispiel #12
0
int
PQputvf(PGparam *param, char *stmtBuf, size_t stmtBufLen,
	const char *format, va_list ap)
{
	int n=0;
	int flags;
	size_t stmtPos = 0;
	int save_vcnt;
	int typpos = 0;
	PGtypeHandler *h;
	PGtypeArgs args;
	char args_outbuf[4096];
	PGtypeSpec *spec = NULL;

	PQseterror(NULL);

	if (!param)
	{
		PQseterror("PGparam cannot be NULL");
		return FALSE;
	}

	if (!format || !*format)
	{
		PQseterror("param 'format' cannot be NULL or an empty string");
		return FALSE;
	}

	if (stmtBuf && stmtBufLen < 1)
	{
		PQseterror("Invalid argument: stmtBufLen must be >= 1");
		return FALSE;
	}

	save_vcnt = param->vcnt;
	va_copy(args.ap, ap);

	/* "@name" format, lookup typeSpec in cache */
	if(format && *format == '@')
	{

		spec = pqt_getspec(param->typspecs, param->typspeccnt, format + 1);

		/* If we didn't find a type spec, this is an error.  A format string
		 * with a '@' as its first character is reserved.
		 */
		if (!spec)
		{
			PQseterror("No such prepared specifier name: '%s'", format + 1);
			return FALSE;
		}
	}

	while (format && *format)
	{
		if (spec)
		{
			/* done, no more handlers in cached spec string. */
			if (typpos == spec->idcnt)
				break;

			h = pqt_gethandlerbyid(param->typhandlers, param->typhcnt,
				spec->idlist[typpos]);

			/* should be an unusual, or a "will never happen", situation */
			if (!h)
			{
				va_end(args.ap);
				PQseterror("Unknown type handler id at position %d", typpos+1);
				param->vcnt = save_vcnt;
				return FALSE;
			}

			flags = (int) spec->flags[typpos];
			typpos++;
		}
		else
		{
			format = pqt_parse(format, param->typhandlers, param->typhcnt,
				stmtBuf, stmtBufLen, &h, &stmtPos, &typpos, &flags);

			if (!format)
			{
				param->vcnt = save_vcnt;
				return FALSE;
			}

			if (!h)
				continue;
		}

		args.is_put           = 1;
		args.put.param        = param;
		args.fmtinfo          = &param->fmtinfo;
		args.put.out          = args_outbuf;
		args.put.__allocated_out = NULL;
		args.put.outl         = (int) sizeof(args_outbuf);
		args.is_ptr           = (flags & TYPFLAG_POINTER) ? 1 : 0;
		args.format           = BINARYFMT;
		args.put.expandBuffer = argsExpandBuffer;
		args.typpos           = typpos;
		args.typhandler       = h;
		args.errorf           = pqt_argserrorf;
		args.super            = pqt_argssuper;
		*args.put.out         = 0;

		if (flags & TYPFLAG_ARRAY)
			n = pqt_put_array(&args);
		else
			n = h->typput(&args);

		if (n == -1)
		{
			if (args.put.__allocated_out && args.put.__allocated_out != args_outbuf)
				free(args.put.__allocated_out);
			param->vcnt = save_vcnt;
			return FALSE;
		}

		if (args.put.out == NULL)
		{
			args.format = BINARYFMT;
			n = -1;
		}

		n = pqt_putparam(param, args.put.out, n, flags, args.format,
			(flags & TYPFLAG_ARRAY) ? h->typoid_array : h->typoid);

		if (args.put.__allocated_out && args.put.__allocated_out != args_outbuf)
			free(args.put.__allocated_out);

		if (!n)
		{
			param->vcnt = save_vcnt;
			return FALSE;
		}
	}

	if (stmtBuf)
		stmtBuf[stmtPos] = 0;

	return TRUE;
}
Beispiel #13
0
int
pqt_putparam(PGparam *param, const void *data, int datal,
	int flags, int format, Oid typoid)
{
	PGvalue *v;

	if (!param)
		return FALSE;

	if (!data)
		datal = -1;

	/* need to grow param vals array */
	if (param->vcnt == param->vmax)
	{
		PGvalue *vals;
		int vmax = param->vmax ? (param->vmax * 3) / 2 : 16;

		vals = (PGvalue *) pqt_realloc(param->vals, sizeof(PGvalue) * vmax);
		if (!vals)
		{
			PQseterror(PQT_OUTOFMEMORY);
			return FALSE;
		}

		/* zero out the new array elements */
		memset(vals + param->vcnt, 0, (vmax - param->vcnt) * sizeof(PGvalue));
		param->vmax = vmax;
		param->vals = vals;
	}

	/* grab next param value */
	v = &param->vals[param->vcnt];

	if (datal == -1)
	{
		v->data = NULL;
	}
	/* wants to put a direct pointer */
	else if (flags & TYPFLAG_POINTER)
	{
		v->data = (char *) data;
	}
	else
	{
		/* need more mem for param value ptr */
		if (v->ptrl < datal)
		{
			char *ptr = (char *) pqt_realloc(v->ptr, datal);

			if (!ptr)
			{
				PQseterror(PQT_OUTOFMEMORY);
				return FALSE;
			}

			v->ptrl = datal;
			v->ptr = ptr;
		}

		memcpy(v->ptr, data, datal);
		v->data = v->ptr;
	}

	v->datal	= datal;
	v->format = format;
	v->oid		= typoid;
	param->vcnt++;
	return TRUE;
}
Beispiel #14
0
PQT_EXPORT PGparam *
PQparamDup(PGparam *param)
{
	PGparam *new_param;

	PQseterror(NULL);

	if (!param)
	{
		PQseterror("PGparam to duplicate cannot be NULL");
		return NULL;
	}

	new_param = (PGparam *) malloc(sizeof(PGparam));
	if (!new_param)
	{
		PQseterror(PQT_OUTOFMEMORY);
		return NULL;
	}

	memset(new_param, 0, sizeof(PGparam));

	/* copy any handlers from conn object */
	if (param->typhcnt > 0)
	{
		new_param->typhandlers = pqt_duphandlers(
			param->typhandlers, param->typhcnt);

		if (!new_param->typhandlers)
		{
			PQparamClear(new_param);
			PQseterror(PQT_OUTOFMEMORY);
			return NULL;
		}

		new_param->typhcnt = param->typhcnt;
	}

	/* copy any typespecs from conn object */
	if (param->typspeccnt > 0)
	{
		new_param->typspecs = pqt_dupspecs(
			param->typspecs, param->typspeccnt);

		if (!new_param->typspecs)
		{
			PQparamClear(new_param);
			PQseterror(PQT_OUTOFMEMORY);
			return NULL;
		}

		new_param->typspeccnt = param->typspeccnt;
	}

	memcpy(&new_param->fmtinfo, &param->fmtinfo, sizeof(PGtypeFormatInfo));

	/* copy any values, don't bother if array is empty. */
	if (param->vcnt > 0)
	{
		int i;

		for (i=0; i < param->vcnt; i++)
		{
			int flags = 0;
			PGvalue *val = &param->vals[i];

			/* Is val->data is direct user pointer?  If so, set pointer flag
			 * so pqt_putparam doesn't deep copy it.
			 */
			if (val->ptr != val->data)
				flags |= TYPFLAG_POINTER;

			if (!pqt_putparam(new_param, val->data, val->datal, flags,
				val->format, val->oid))
			{
				PQparamClear(new_param);
				return NULL;
			}
		}
	}

	return new_param;
}
Beispiel #15
0
char *pqt_parse(const char *format, PGtypeHandler *h, int hcnt,
                char *stmtBuf, size_t stmtBufLen, PGtypeHandler **out, size_t *stmtPos,
                int *typpos, int *flags)
{
    int specMark;
    char *s = skipQuotes((char *) format);
    char typname[PQT_MAXIDLEN + 1];
    char schema[PQT_MAXIDLEN + 1];
    char tmp[200];

    *out = NULL;

    if (!s)
        return NULL;

    /* found quotes to skip */
    if (s != format)
    {
        if (stmtBuf)
        {
            size_t n = s - format;
            CHKSTMTBUF(n);
            memcpy(stmtBuf + *stmtPos, format, n);
            (*stmtPos) += n;
        }

        return s;
    }

    specMark = *format;
    if (specMark != '%' && specMark != '#')
    {
        if (stmtBuf)
        {
            CHKSTMTBUF(1);
            stmtBuf[*stmtPos] = *format;
            (*stmtPos)++;
        }

        format++;
        return (char *) format;
    }

    /* spec skips % or # */
    if (!(s = pqt_parsetype(format + 1, schema, typname, flags, *typpos + 1)))
        return NULL;

    if (*flags & TYPFLAG_INVALID)
    {
        if (stmtBuf)
        {
            CHKSTMTBUF(1);
            stmtBuf[*stmtPos] = *format++;
            (*stmtPos)++;
            PQseterror(NULL); /* set by pqt_parsetype */
            return (char *) format;
        }

        return NULL;
    }

    (*typpos)++;

    if (!(*out = pqt_gethandler(h, hcnt, schema, typname)))
    {
        PQseterror("Uknown type '%s' (position %d)",
                   pqt_fqtn(tmp, sizeof(tmp), schema, typname), *typpos);
        return NULL;
    }

    if (stmtBuf)
    {
        int n = pqt_snprintf(tmp, sizeof(tmp), "$%d", *typpos);
        CHKSTMTBUF(n);
        memcpy(stmtBuf + *stmtPos, tmp, n);
        (*stmtPos) += n;
    }

    if (!(*out)->typput)
    {
        PGtypeHandler *o = pqt_gethandlerbyid(h, hcnt, h->base_id);
        if (!o || !o->typput)
        {
            PQseterror(
                "Type '%s' doesn't support put operations (position %d)",
                pqt_fqtn(tmp, sizeof(tmp), (*out)->typschema, (*out)->typname), *typpos);

            *out = NULL;
            return NULL;
        }

        *out = o;
    }

    if ((*flags & TYPFLAG_POINTER) && !pqt_allowsptr(*out))
    {
        PQseterror(
            "Type '%s' doesn't support putting pointers (position %d)",
            pqt_fqtn(tmp, sizeof(tmp), (*out)->typschema, (*out)->typname), *typpos);

        *out = NULL;
        return NULL;
    }

    if (specMark == '#')
        (*flags) |= TYPFLAG_BYNAME;

    return s;
}
Beispiel #16
0
static int registerSubClass(PGtypeData *connData, const char *type_name,
	PGtypeProc typput, PGtypeProc typget)
{
	char *s;
	PGtypeHandler *h_sub;
	PGtypeHandler *h_base;
	char sub_typschema[PQT_MAXIDLEN + 1];
	char sub_typname[PQT_MAXIDLEN + 1];
	char base_typschema[PQT_MAXIDLEN + 1];
	char base_typname[PQT_MAXIDLEN + 1];
	char sub_fqtn[200];
	char base_fqtn[200];

	if (!(s = parseType(type_name, sub_typschema, sub_typname, 1)))
		return FALSE;

	if (*s != '=')
	{
		PQseterror("Missing inheritence operator '=': %s", type_name);
		return FALSE;
	}

	if (!parseType(s + 1, base_typschema, base_typname, 1))
		return FALSE;

	/* lookup the base handler */
	h_base = pqt_gethandler(connData->typhandlers, connData->typhcnt,
		base_typschema, base_typname);

	if (!h_base)
	{
		PQseterror("typname '%s' does not exist, '%s' cannot sub-class it",
			pqt_fqtn(base_fqtn, sizeof(base_fqtn), base_typschema, base_typname),
			pqt_fqtn(sub_fqtn, sizeof(sub_fqtn), sub_typschema, sub_typname));
		return FALSE;
	}

	/* cannot sub-class a record type */
	if (h_base->typoid == RECORDOID)
	{
		PQseterror("Cannot sub-class pg_catalog.record '%s'",
			pqt_fqtn(sub_fqtn, sizeof(sub_fqtn), sub_typschema, sub_typname));
		return FALSE;
	}

	if (!expandHandlers(connData))
		return FALSE;

	h_sub = &connData->typhandlers[connData->typhcnt];
	memset(h_sub, 0, sizeof(PGtypeHandler));

	h_sub->id = connData->typhcnt + countof(pg_handlers);
	h_sub->typlen = h_base->typlen;
	h_sub->typoid = h_base->typoid;
	h_sub->typoid_array = h_base->typoid_array;
	h_sub->typput = typput;
	h_sub->typget = typget;
	h_sub->base_id = h_base->id;

	pqt_strcpy(h_sub->typschema,
		sizeof(h_sub->typschema), sub_typschema);

	pqt_strcpy(h_sub->typname,
		sizeof(h_sub->typname), sub_typname);

	connData->typhcnt++;
	return TRUE;
}
Beispiel #17
0
int
PQregisterResult(PGconn *conn, int which, PGregisterType *types,
	int count, PGresult *res)
{
	int i;
	PGtypeData *connData;
	char typname[PQT_MAXIDLEN + 1];
	char typschema[PQT_MAXIDLEN + 1];
	/* inherit typput and typget from record type */
	PGtypeHandler *h_rec = pqt_gethandler(NULL, 0, "pg_catalog", "record");

	PQseterror(NULL);

	if (!conn)
	{
		PQseterror("PGconn cannot be NULL");
		return FALSE;
	}

	if (!res)
	{
		PQseterror("PGresult cannot be NULL");
		return FALSE;
	}

	if (which == PQT_SUBCLASS)
	{
		PQseterror("Cannot call PQregisterResult for a subclass registration.");
		return FALSE;
	}

	if (!(connData = (PGtypeData *) PQinstanceData(conn, pqt_eventproc)))
	{
		PQseterror("PGconn is missing event data");
		return FALSE;
	}

	if (!types)
	{
		PQseterror("PGregisterType[] cannot be NULL");
		return FALSE;
	}

	if (count < 0)
	{
		PQseterror("PGregisterType[] count cannot be less than zero");
		return FALSE;
	}

	if(!checkTypeLookups(res, types, count))
		return FALSE;

	for (i=0; i < PQntuples(res); i++)
	{
		int flags;
		PGint2 typlen;
		PGtypeHandler *h;

		if (which == PQT_USERDEFINED && !types[i].typput && !types[i].typget)
		{
			PQseterror("Must provide a put and/or a get routine: '%s'",
				types[i].typname);
			return FALSE;
		}

		/* make sure conn's type handlers array is large enough */
		if (!expandHandlers(connData))
			return FALSE;

		/* create the handler */
		h = &connData->typhandlers[connData->typhcnt];
		memset(h, 0, sizeof(PGtypeHandler));

		if (!PQgetf(res, i, "%oid %oid %int2", 1, &h->typoid,
			2, &h->typoid_array, 3, &typlen))
		{
			return FALSE;
		}

		h->id = connData->typhcnt + countof(pg_handlers);
		h->typlen = (int) typlen;
		h->base_id = -1;

		if (which == PQT_USERDEFINED)
		{
			h->typput = types[i].typput;
			h->typget = types[i].typget;
		}
		else
		{
			h->typput = h_rec->typput;
			h->typget = h_rec->typget;
		}

		/* parse out type and schema names again */
		(void ) pqt_parsetype(types[i].typname, typschema, typname, &flags, 1);
		pqt_strcpy(h->typschema, sizeof(h->typschema), typschema);
		pqt_strcpy(h->typname, sizeof(h->typname), typname);

		/* Process composite attributes */
		if(which == PQT_COMPOSITE)
		{
			PGtext attrs;
			int nattrs;
			PGrecordAttDesc *attDescs;

			if (!PQgetf(res, i, "%text", 4, &attrs))
			{
				return FALSE;
			}

			if (!(attDescs = initAttDescs(h, attrs)))
				return FALSE;

			for (nattrs=0; *attrs; nattrs++)
			{
				char *p;
				char *name;
				int len;

				/* Attribute Text Encoding:
				 *   "attoid,attlen,atttypmod,name_hex attoid,etc..."
				 */

				attDescs[nattrs].attoid    = (int) strtol(attrs, &attrs, 10);
				attDescs[nattrs].attlen    = (int) strtol(attrs + 1, &attrs, 10);
				attDescs[nattrs].atttypmod = (int) strtol(attrs + 1, &attrs, 10);

				/* skip comma before name */
				attrs++;

				/* attribute name in hex */
				if (!(p = strchr(attrs, ' ')))
					p = attrs + strlen(attrs); /* last attr, point at NUL */

				/* truncate name if it exceeds buffer */
				len = (int) (p - attrs);
				if (len >= (int) sizeof(attDescs[nattrs].attname))
					len = (int) (sizeof(attDescs[nattrs].attname) - 1);

				/* hex decode and copy */
				for (name = attDescs[nattrs].attname; attrs < p; attrs += 2)
					*name++ = (char) (pqt_hex_to_dec(attrs[0]) << 4)
						| pqt_hex_to_dec(attrs[1]);
				*name = 0;
			}

			h->nattrs = nattrs;
			h->attDescs = attDescs;
		}

		connData->typhcnt++;
	}

	return TRUE;
}
Beispiel #18
0
int
PQregisterTypes(PGconn *conn, int which, PGregisterType *types,
	int count, int async)
{
	int n = FALSE;

	PQseterror(NULL);

	if (!conn)
	{
		PQseterror("PGconn cannot be NULL");
		return FALSE;
	}

	if (!types)
	{
		PQseterror("PGregisterType[] cannot be NULL");
		return FALSE;
	}

	if (count < 0)
	{
		PQseterror("PGregisterType[] count cannot be less than zero");
		return FALSE;
	}

	/* nothing to do, silently ignore it */
	if (count == 0)
		return TRUE;

	if (which == PQT_SUBCLASS)
	{
		int i;
		PGtypeData *connData;

		if (!(connData = (PGtypeData *) PQinstanceData(conn, pqt_eventproc)))
		{
			PQseterror("PGconn is missing event data");
			return FALSE;
		}

		for (i=0; i < count; i++)
		{
			n = registerSubClass(connData, types[i].typname,
				types[i].typput, types[i].typget);

			if (!n)
				return FALSE;
		}
	}
	else
	{
		PGresult *res = NULL;

		n = performRegisterQuery(conn, which, types, count, async ? NULL : &res);

		/* If not async, register the result and clear it. */
		if (n && !async)
		{
			n = PQregisterResult(conn, which, types, count, res);
			PQclear(res);
		}
	}

	return n;
}
Beispiel #19
0
int
PQspecPrepare(PGconn *conn, const char *name, const char *format, int is_stmt)
{
    int flags;
    int typpos = 0;
    int idmax = 0;
    size_t stmtPos = 0;
    PGtypeHandler *h;
    PGtypeData *typeData;
    PGtypeSpec *spec;
    size_t stmtBufLen = 0;
    char *stmtBuf = NULL;
    char buffer[8192];

    if (!conn)
    {
        PQseterror("PGConn cannot be NULL");
        return FALSE;
    }

    if (!name || !*name)
    {
        PQseterror("Prepared specifier name cannot be NULL or an empty string");
        return FALSE;
    }

    if (format && !*format)
    {
        PQseterror("Specifier format string cannot be empty");
        return FALSE;
    }

    if (!isalnum(*name) && *name != '_')
    {
        PQseterror("Prepared specifier name must begin with an alpha, "
                   "number or underscore.");
        return FALSE;
    }

    typeData = PQinstanceData(conn, pqt_eventproc);
    if (!typeData)
    {
        PQseterror("No type data exists for PGconn at %p", conn);
        return FALSE;
    }

    /* This is a removal request */
    if (!format)
    {
        int i;

        for (i=0; i < typeData->typspeccnt; i++)
        {
            if (strcmp(typeData->typspecs[i].name, name) == 0)
            {
                /* clear it */
                pqt_clearspec(&typeData->typspecs[i]);

                /* remove from list, not needed if its the last element */
                if (i != typeData->typspeccnt - 1)
                    memmove(typeData->typspecs + i, typeData->typspecs + i + 1,
                            (typeData->typspeccnt - i - 1) * sizeof(PGtypeSpec));

                typeData->typspeccnt--;
                break;
            }
        }

        /* always return TRUE, an error is not useful here */
        return TRUE;
    }

    /* Already exists case */
    spec = pqt_getspec(typeData->typspecs, typeData->typspeccnt, name);
    if (spec)
    {
        PQseterror("Prepared spec already exists '%s'", name);
        return FALSE;
    }

    /* Make sure specs array is large enough */
    if (!expandSpecs(typeData))
        return FALSE;

    spec = &typeData->typspecs[typeData->typspeccnt];

    /* cache statement along with prepared type spec */
    if (is_stmt)
    {
        stmtBufLen = strlen(format) + 1;

        /* no room in stack, use heap */
        if (stmtBufLen > sizeof(buffer))
        {
            stmtBuf = (char *) malloc(stmtBufLen);
            if (!stmtBuf)
            {
                PQseterror(PQT_OUTOFMEMORY);
                return FALSE;
            }
        }
        else
        {
            stmtBuf = buffer;
            stmtBufLen = sizeof(buffer);
        }
    }

    while (format && *format)
    {
        format = pqt_parse(format, typeData->typhandlers, typeData->typhcnt,
                           stmtBuf, stmtBufLen, &h, &stmtPos, &typpos, &flags);

        if (!format)
        {
            pqt_clearspec(spec);
            FREESTMTBUF;
            return FALSE;
        }

        /* skipped harmless chars in format, like quoted sections. */
        if(!h)
            continue;

        if (!spec->idlist || spec->idcnt == idmax)
        {
            int c = idmax ? idmax * 2 : 8;
            void *p = pqt_realloc(spec->idlist, c * sizeof(int));

            if (!p)
            {
                PQseterror(PQT_OUTOFMEMORY);
                pqt_clearspec(spec);
                FREESTMTBUF;
                return FALSE;
            }

            spec->idlist = (int *) p;

            p = pqt_realloc(spec->flags, c * sizeof(char));
            if (!p)
            {
                PQseterror(PQT_OUTOFMEMORY);
                pqt_clearspec(spec);
                FREESTMTBUF;
                return FALSE;
            }

            spec->flags = (unsigned char *) p;
            idmax = c;
        }

        /* Parallel arrays, every handler needs type flags */
        spec->idlist[spec->idcnt] = h->id;
        spec->flags[spec->idcnt++] = (unsigned char) flags;
    }

    /* terminate stmtBuf, guarenteed to have room for NUL */
    if (stmtBuf)
        stmtBuf[stmtPos] = 0;

    /* copy name string */
    spec->name = strdup(name);
    if (!spec->name)
    {
        pqt_clearspec(spec);
        PQseterror(PQT_OUTOFMEMORY);
        FREESTMTBUF;
        return FALSE;
    }

    /* copy the parameterized stmt string */
    if (stmtBuf)
    {
        spec->stmt = strdup(stmtBuf);
        if (!spec->stmt)
        {
            pqt_clearspec(spec);
            PQseterror(PQT_OUTOFMEMORY);
            FREESTMTBUF;
            return FALSE;
        }
    }

    FREESTMTBUF;

    /* Success, increment type spec count */
    typeData->typspeccnt++;
    return TRUE;
}
Beispiel #20
0
PGparam *
PQparamCreate(const PGconn *conn)
{
	PGparam *param;
	PGtypeData *connData;

	PQseterror(NULL);

	if (!conn)
	{
		PQseterror("PGconn cannot be NULL");
		return NULL;
	}

	param = (PGparam *) malloc(sizeof(PGparam));
	if (!param)
	{
		PQseterror(PQT_OUTOFMEMORY);
		return NULL;
	}

	memset(param, 0, sizeof(PGparam));

	connData = (PGtypeData *) PQinstanceData(conn, pqt_eventproc);
	if (!connData)
	{
		PQparamClear(param);
		PQseterror("No type data exists for PGconn at %p", conn);
		return NULL;
	}

	/* copy any handlers from conn object */
	if (connData->typhcnt > 0)
	{
		param->typhandlers = pqt_duphandlers(
			connData->typhandlers, connData->typhcnt);

		if (!param->typhandlers)
		{
			PQparamClear(param);
			PQseterror(PQT_OUTOFMEMORY);
			return NULL;
		}

		param->typhcnt = connData->typhcnt;
	}

	/* copy any typespecs from conn object */
	if (connData->typspeccnt > 0)
	{
		param->typspecs = pqt_dupspecs(
			connData->typspecs, connData->typspeccnt);

		if (!param->typspecs)
		{
			PQparamClear(param);
			PQseterror(PQT_OUTOFMEMORY);
			return NULL;
		}

		param->typspeccnt = connData->typspeccnt;
	}

	pqt_getfmtinfo(conn, &param->fmtinfo);
	return param;
}
Beispiel #21
0
static char *
parseId(char *id, char **start, int *len, int *flags, int typpos)
{
    char *p = id;

    *flags = 0;
    *start = NULL;
    *len = 0;

    if (*p == '"')
        p++;

    /* check first character */
    if (!isalpha(*p) && *p != '_')
    {
        *flags |= TYPFLAG_INVALID;
        PQseterror(
            "Invalid first character for identifier '%c' (pos:%d)", *p, typpos);
        return p;
    }

    if (*id == '"')
    {
        id++;
        if (!(p = strchr(id, '"')))
        {
            *flags |= TYPFLAG_INVALID;
            PQseterror("Unterminated double quote '%s' (pos:%d)",
                       id-1, typpos);
            return p;
        }

        *len = (int) (p - id);
        *start = id;
        p++;
    }
    else
    {
        for (p=id+1; isalnum(*p) || *p=='_'; p++) ;

        *len = (int) (p - id);
        *start = id;
        *flags |= TYPFLAG_CASEFOLD;
    }

    /* range check */
    if (*len == 0 || *len > PQT_MAXIDLEN)
    {
        *flags |= TYPFLAG_INVALID;
        PQseterror("Identifier out of range %d (pos:%d), range is 1 to %d",
                   *len, typpos, PQT_MAXIDLEN);
        return p;
    }

    /* direct pointer request */
    if (*p == '*')
    {
        p++;
        *flags |= TYPFLAG_POINTER;
    }

    /* Is this an array?  Ex. %int4[] or %"a b"[] */
    if (p[0] == '[' && p[1] == ']')
    {
        if (*flags & TYPFLAG_POINTER)
        {
            PQseterror(
                "'*' specifer flag cannot be used with arrays[] '%s' (pos:%d)",
                id, typpos);
            return NULL;
        }

        *flags |= TYPFLAG_ARRAY;
        p += 2;
    }

    return p;
}