/* * Like GetExtTableEntry(Oid), but returns NULL instead of throwing * an error if no pg_exttable entry is found. */ ExtTableEntry* GetExtTableEntryIfExists(Oid relid) { Relation pg_exttable_rel; ScanKeyData skey; SysScanDesc scan; HeapTuple tuple; ExtTableEntry *extentry; Datum locations, fmtcode, fmtopts, command, rejectlimit, rejectlimittype, fmterrtbl, encoding, iswritable; bool isNull; bool locationNull = false; pg_exttable_rel = heap_open(ExtTableRelationId, RowExclusiveLock); ScanKeyInit(&skey, Anum_pg_exttable_reloid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); scan = systable_beginscan(pg_exttable_rel, ExtTableReloidIndexId, true, SnapshotNow, 1, &skey); tuple = systable_getnext(scan); if (!HeapTupleIsValid(tuple)) { systable_endscan(scan); heap_close(pg_exttable_rel, RowExclusiveLock); return NULL; } extentry = (ExtTableEntry *) palloc0(sizeof(ExtTableEntry)); /* get the location list */ locations = heap_getattr(tuple, Anum_pg_exttable_location, RelationGetDescr(pg_exttable_rel), &isNull); if (isNull) { Insist(false); /* location list is always populated (url or ON X) */ } else { Datum *elems; int nelems; int i; char* loc_str = NULL; deconstruct_array(DatumGetArrayTypeP(locations), TEXTOID, -1, false, 'i', &elems, NULL, &nelems); for (i = 0; i < nelems; i++) { loc_str = DatumGetCString(DirectFunctionCall1(textout, elems[i])); /* append to a list of Value nodes, size nelems */ extentry->locations = lappend(extentry->locations, makeString(pstrdup(loc_str))); } if(loc_str && (IS_FILE_URI(loc_str) || IS_GPFDIST_URI(loc_str) || IS_GPFDISTS_URI(loc_str))) extentry->isweb = false; else extentry->isweb = true; } /* get the execute command */ command = heap_getattr(tuple, Anum_pg_exttable_command, RelationGetDescr(pg_exttable_rel), &isNull); if(isNull) { if(locationNull) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("got invalid pg_exttable tuple. location and command are both NULL"))); extentry->command = NULL; } else { extentry->command = DatumGetCString(DirectFunctionCall1(textout, command)); } /* get the format code */ fmtcode = heap_getattr(tuple, Anum_pg_exttable_fmttype, RelationGetDescr(pg_exttable_rel), &isNull); Insist(!isNull); extentry->fmtcode = DatumGetChar(fmtcode); Insist(extentry->fmtcode == 'c' || extentry->fmtcode == 't' || extentry->fmtcode == 'b' || extentry->fmtcode == 'a' || extentry->fmtcode == 'p'); /* get the format options string */ fmtopts = heap_getattr(tuple, Anum_pg_exttable_fmtopts, RelationGetDescr(pg_exttable_rel), &isNull); Insist(!isNull); extentry->fmtopts = DatumGetCString(DirectFunctionCall1(textout, fmtopts)); /* get the reject limit */ rejectlimit = heap_getattr(tuple, Anum_pg_exttable_rejectlimit, RelationGetDescr(pg_exttable_rel), &isNull); if(!isNull) extentry->rejectlimit = DatumGetInt32(rejectlimit); else extentry->rejectlimit = -1; /* mark that no SREH requested */ /* get the reject limit type */ rejectlimittype = heap_getattr(tuple, Anum_pg_exttable_rejectlimittype, RelationGetDescr(pg_exttable_rel), &isNull); extentry->rejectlimittype = DatumGetChar(rejectlimittype); if(!isNull) Insist(extentry->rejectlimittype == 'r' || extentry->rejectlimittype == 'p'); else extentry->rejectlimittype = -1; /* get the error table oid */ fmterrtbl = heap_getattr(tuple, Anum_pg_exttable_fmterrtbl, RelationGetDescr(pg_exttable_rel), &isNull); if(isNull) extentry->fmterrtbl = InvalidOid; else extentry->fmterrtbl = DatumGetObjectId(fmterrtbl); /* get the table encoding */ encoding = heap_getattr(tuple, Anum_pg_exttable_encoding, RelationGetDescr(pg_exttable_rel), &isNull); Insist(!isNull); extentry->encoding = DatumGetInt32(encoding); Insist(PG_VALID_ENCODING(extentry->encoding)); /* get the table encoding */ iswritable = heap_getattr(tuple, Anum_pg_exttable_writable, RelationGetDescr(pg_exttable_rel), &isNull); Insist(!isNull); extentry->iswritable = DatumGetBool(iswritable); /* Finish up scan and close pg_exttable catalog. */ systable_endscan(scan); heap_close(pg_exttable_rel, RowExclusiveLock); return extentry; }
/* * ParseExternalTableUri * * This routines converts a string to a supported external * table URI object. It is also used to validate the URI format. */ Uri * ParseExternalTableUri(const char *uri_str) { Uri *uri = (Uri *) palloc0(sizeof(Uri)); char *start, *end; int protocol_len, len; uri->port = -1; uri->hostname = NULL; uri->path = NULL; uri->customprotocol = NULL; /* * parse protocol */ if (IS_FILE_URI(uri_str)) { uri->protocol = URI_FILE; protocol_len = strlen(PROTOCOL_FILE); } else if (pg_strncasecmp(uri_str, PROTOCOL_FTP, strlen(PROTOCOL_FTP)) == 0) { uri->protocol = URI_FTP; protocol_len = strlen(PROTOCOL_FTP); } else if (IS_HTTP_URI(uri_str)) { uri->protocol = URI_HTTP; protocol_len = strlen(PROTOCOL_HTTP); } else if (IS_GPFDIST_URI(uri_str)) { uri->protocol = URI_GPFDIST; protocol_len = strlen(PROTOCOL_GPFDIST); } else if (IS_GPFDISTS_URI(uri_str)) { uri->protocol = URI_GPFDISTS; protocol_len = strlen(PROTOCOL_GPFDISTS); } else /* not recognized. treat it as a custom protocol */ { char *post_protocol = strstr(uri_str, "://"); if(!post_protocol) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid URI \'%s\' : undefined structure", uri_str), errOmitLocation(true))); } else { protocol_len = post_protocol - uri_str; uri->customprotocol = (char *) palloc (protocol_len + 1); strncpy(uri->customprotocol, uri_str, protocol_len); uri->customprotocol[protocol_len] = '\0'; uri->protocol = URI_CUSTOM; return uri; /* we let the user parse it himself later on */ } /* this is a non existing protocol */ protocol_len = 0; /* shut compiler up */ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid URI \'%s\' : undefined protocol", uri_str), errOmitLocation(true))); } /* make sure there is more to the uri string */ if (strlen(uri_str) <= protocol_len) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid URI \'%s\' : missing host name and path", uri_str), errOmitLocation(true))); /* * parse host name */ start = (char *) uri_str + protocol_len; if (*start == '/') /* format "prot:///" ? (no hostname) */ { /* the default is "localhost" */ const char *lh = "localhost"; len = strlen(lh); uri->hostname = (char *) palloc(len + 1); strncpy(uri->hostname, lh, len); uri->hostname[len] = '\0'; end = start; } else { end = strchr(start, '/'); if (end == NULL) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid URI \'%s\' : missing host name or path", uri_str), errOmitLocation(true))); } else { char *colon, *p; len = end - start; /* * host */ uri->hostname = (char *) palloc(len + 1); strncpy(uri->hostname, start, len); uri->hostname[len] = '\0'; /* * MPP-13617, if we have an ipv6 address in the URI hostname * (e.g. [2620:0:170:610::11]:8080/path/data.txt ) then we * we start our search for the :port after the closing ]. */ p = strchr(uri->hostname, ']'); if (p) { colon = strchr(p, ':'); /* * Eliminate the [ ] from the hostname. * note we don't change the uri->hostname pointer because we pfree() it later */ *p = '\0'; for (p = strchr(uri->hostname, '['); p && *p; p++) { p[0] = p[1]; } } else { colon = strchr(uri->hostname, ':'); } /* * port */ if (colon) { int portlen = 0; uri->port = atoi(colon + 1); portlen = strlen(colon); /* now truncate ":<port>" from hostname */ uri->hostname[len - portlen] = '\0'; *colon = 0; } else { uri->port = -1; /* no port was indicated. will use default if needed */ } } } /* * We continue from the trailing host '/' since the * path is an absolute path. Our previous ending point * is the beginning of the file path, until the end of * the uri string. */ start = end; len = strlen(start); /* make sure there is more to the uri string */ if (len <= 1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid URI \'%s\' : missing path", uri_str), errOmitLocation(true))); uri->path = (char *) palloc(len + 1); strcpy(uri->path, start); uri->path[len] = '\0'; return uri; }