void pqt_getfmtinfo(const PGconn *conn, PGtypeFormatInfo *info) { const char *value; memset(info, 0, sizeof(PGtypeFormatInfo)); if ((value = PQparameterStatus(conn, "DateStyle"))) pqt_strcpy(info->datestyle, sizeof(info->datestyle), value); if ((value = PQparameterStatus(conn, "integer_datetimes"))) info->integer_datetimes = strcmp(value, "on")==0 ? TRUE : FALSE; info->sversion = PQserverVersion(conn); info->pversion = PQprotocolVersion(conn); }
static int get_inet2(PGtypeArgs *args, int is_cidr) { DECLVALUE(args); unsigned short family; PGinet *inet = va_arg(args->ap, PGinet *); CHKGETVALS(args, inet); if (args->format == TEXTFMT) { int r; char *p; char ipstr[80]; struct addrinfo *ai = NULL; struct addrinfo hints; pqt_strcpy(ipstr, sizeof(ipstr), value); if ((p = strrchr(ipstr, '/'))) { *p = 0; inet->mask = atoi(p+1); } else { inet->mask = 32; } inet->is_cidr = is_cidr; /* suppress hostname lookups */ memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_NUMERICHOST; /* Without this, windows chokes with WSAHOST_NOT_FOUND */ #ifdef PQT_WIN32 hints.ai_family = AF_INET; #endif if ((r = getaddrinfo(ipstr, NULL, &hints, &ai)) || !ai) { if(r == EAI_BADFLAGS) { hints.ai_flags = 0; r = getaddrinfo(ipstr, NULL, &hints, &ai); } /* Another WSAHOST_NOT_FOUND work around, but for IPv6 */ #if defined(PQT_WIN32) && defined(AF_INET6) else if(r == WSAHOST_NOT_FOUND) { hints.ai_flags = 0; hints.ai_family = AF_INET6; r = getaddrinfo(ipstr, NULL, &hints, &ai); } #endif if(r) RERR_STR2INT(args); } inet->sa_buf_len = (int) ai->ai_addrlen; memcpy(inet->sa_buf, ai->ai_addr, inet->sa_buf_len); /* Some platforms, lika AIX 4.3, do not zero this structure properly. * The family and port are dirty, so set the first 4 bytes to 0 and * then re-set the family. I saw "0x1002" as the first 2 bytes of * this structure (dumb getaddrinfo), it should be "0x0002" for AF_INET. */ memset(inet->sa_buf, 0, 4); ((struct sockaddr *)inet->sa_buf)->sa_family = ai->ai_addr->sa_family; /* Uninitialized memory, postgres inet/cidr types don't store this. * Make sure its set to 0. Another AIX problem (maybe other platforms). */ #ifdef AF_INET6 if (ai->ai_addr->sa_family == AF_INET6) ((struct sockaddr_in6 *)inet->sa_buf)->sin6_flowinfo = 0; #endif freeaddrinfo(ai); return 0; } family = (unsigned short) *value++; if (family == PGSQL_AF_INET) { struct sockaddr_in *sa = (struct sockaddr_in *) inet->sa_buf; sa->sin_family = AF_INET; inet->mask = (unsigned char) *value++; inet->is_cidr = *value++; memcpy(&sa->sin_addr, value + 1, *value); inet->sa_buf_len = (int) sizeof(struct sockaddr_in); } #ifdef AF_INET6 else if (family == PGSQL_AF_INET6) { struct sockaddr_in6 *sa = (struct sockaddr_in6 *) inet->sa_buf; sa->sin6_family = AF_INET6; inet->mask = (unsigned char) *value++; inet->is_cidr = *value++; memcpy(&sa->sin6_addr, value + 1, *value); inet->sa_buf_len = (int) sizeof(struct sockaddr_in6); } #endif else { return args->errorf(args, "Unknown inet address family %d", family); } return 0; }
static void vseterror(const char *format, va_list ap, int append) { int n; int curlen = 0; int size; va_list ap2; char *msg = NULL; pqterr_t *err = geterr(); if (!err) return; if (append) curlen = (int) strlen(err->msg); else *err->msg = 0; va_copy(ap2, ap); n = pqt_vsnprintf(err->msg + curlen, sizeof(err->msg) - curlen, format, ap2); va_end(ap2); if (n > -1) return; /* pqterr_t msg buffer is too small for the complete message. We have * use a temporary buffer to get a successful sprintf so we can * pqt_strcpy() the result; which truncates to fit. */ size = (int) sizeof(err->msg) * 2; if (!(msg = (char *) malloc(size))) return; while (1) { char *p; va_copy(ap2, ap); n = pqt_vsnprintf(msg + curlen, size - curlen, format, ap2); va_end(ap2); /* success */ if (n > -1) break; /* need more space */ n = size * 2; if (!(p = pqt_realloc(msg, n))) { /* we're here because sprintf failed, don't trust buffer contents */ *msg = 0; break; } msg = p; size = n; } pqt_strcpy(err->msg, sizeof(err->msg), msg); free(msg); }
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; }
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; }