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; }
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; }
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; }