/* Discard accumulated COPY line */ static void CopyClear(void) { /* Make sure init is done */ CopyAppend(NULL); resetStringInfo(©String); }
/* Output and then clear accumulated COPY line */ static void CopyFlush(void) { /* Make sure init is done */ CopyAppend(NULL); printf("COPY: %s\n", copyString.data); CopyClear(); }
/* Decode a bool type */ static int decode_bool(const char *buffer, unsigned int buff_size, unsigned int *out_size) { if (buff_size < sizeof(bool)) return -1; CopyAppend(*(bool *) buffer ? "t" : "f"); *out_size = sizeof(bool); return 0; }
void CutAppend( LPCLASSDATA lpcd ) { /* * Append the selection to the clipboard. */ if ( CopyAppend( lpcd )) /* * Cut it. */ Delete( lpcd ); }
/* * Try to decode a tuple using a types string provided previously. * * Arguments: * tupleData - pointer to the tuple data * tupleSize - tuple size in bytes */ void FormatDecode(const char *tupleData, unsigned int tupleSize) { HeapTupleHeader header = (HeapTupleHeader) tupleData; const char *data = tupleData + header->t_hoff; unsigned int size = tupleSize - header->t_hoff; int curr_attr; CopyClear(); for (curr_attr = 0; curr_attr < ncallbacks; curr_attr++) { int ret; unsigned int processed_size = 0; if ((header->t_infomask & HEAP_HASNULL) && att_isnull(curr_attr, header->t_bits)) { CopyAppend("\\N"); continue; } if (size <= 0) { printf("Error: unable to decode a tuple, no more bytes left. Partial data: %s\n", copyString.data); return; } ret = callbacks[curr_attr] (data, size, &processed_size); if (ret < 0) { printf("Error: unable to decode a tuple, callback #%d returned %d. Partial data: %s\n", curr_attr + 1, ret, copyString.data); return; } size -= processed_size; data += processed_size; } if (size != 0) { printf("Error: unable to decode a tuple, %d bytes left, 0 expected. Partial data: %s\n", size, copyString.data); return; } CopyFlush(); }
static int ReadStringFromToast(const char *buffer, unsigned int buff_size, unsigned int* out_size) { int result = 0; /* If toasted value is on disk, we'll try to restore it. */ if (VARATT_IS_EXTERNAL_ONDISK(buffer)) { varatt_external toast_ptr; char *toast_data = NULL; /* Number of chunks the TOAST data is divided into */ int32 num_chunks; /* Actual size of external TOASTed value */ int32 toast_ext_size; /* Path to directory with TOAST realtion file */ char *toast_relation_path; /* Filename of TOAST relation file */ char toast_relation_filename[MAXPGPATH]; FILE *toast_rel_fp; unsigned int block_options = 0; unsigned int control_options = 0; VARATT_EXTERNAL_GET_POINTER(toast_ptr, buffer); printf(" TOAST value. Raw size: %8d, external size: %8d, " "value id: %6d, toast relation id: %6d\n", toast_ptr.va_rawsize, toast_ptr.va_extsize, toast_ptr.va_valueid, toast_ptr.va_toastrelid); /* Extract TOASTed value */ toast_ext_size = toast_ptr.va_extsize; num_chunks = (toast_ext_size - 1) / TOAST_MAX_CHUNK_SIZE + 1; printf(" Number of chunks: %d\n", num_chunks); /* Open TOAST relation file */ toast_relation_path = strdup(fileName); get_parent_directory(toast_relation_path); sprintf(toast_relation_filename, "%s/%d", toast_relation_path, toast_ptr.va_toastrelid); printf(" Read TOAST relation %s\n", toast_relation_filename); toast_rel_fp = fopen(toast_relation_filename, "rb"); if (!toast_rel_fp) { printf("Cannot open TOAST relation %s\n", toast_relation_filename); result = -1; } if (result == 0) { unsigned int toast_relation_block_size = GetBlockSize(toast_rel_fp); fseek(toast_rel_fp, 0, SEEK_SET); toast_data = malloc(toast_ptr.va_rawsize); result = DumpFileContents(block_options, control_options, toast_rel_fp, toast_relation_block_size, -1, /* no start block */ -1, /* no end block */ true, /* is toast relation */ toast_ptr.va_valueid, toast_ptr.va_extsize, toast_data); if (result == 0) { if (VARATT_EXTERNAL_IS_COMPRESSED(toast_ptr)) result = DumpCompressedString(toast_data, toast_ext_size); else CopyAppendEncode(toast_data, toast_ext_size); } else { printf("Error in TOAST file.\n"); } free(toast_data); } fclose(toast_rel_fp); free(toast_relation_path); } /* If tag is indirect or expanded, it was stored in memory. */ else { CopyAppend("(TOASTED IN MEMORY)"); } return result; }
/* Decode char(N), varchar(N), text, json or xml types */ static int decode_string(const char *buffer, unsigned int buff_size, unsigned int *out_size) { int padding = 0; /* Skip padding bytes. */ while (*buffer == 0x00) { if (buff_size == 0) return -1; buff_size--; buffer++; padding++; } if (VARATT_IS_1B_E(buffer)) { /* * 00000001 1-byte length word, unaligned, TOAST pointer */ uint32 len = VARSIZE_EXTERNAL(buffer); int result = 0; if (len > buff_size) return -1; if (blockOptions & BLOCK_DECODE_TOAST) { result = ReadStringFromToast(buffer, buff_size, out_size); } else { CopyAppend("(TOASTED)"); } *out_size = padding + len; return result; } if (VARATT_IS_1B(buffer)) { /* * xxxxxxx1 1-byte length word, unaligned, uncompressed data (up to * 126b) xxxxxxx is 1 + string length */ uint8 len = VARSIZE_1B(buffer); if (len > buff_size) return -1; CopyAppendEncode(buffer + 1, len - 1); *out_size = padding + len; return 0; } if (VARATT_IS_4B_U(buffer) && buff_size >= 4) { /* * xxxxxx00 4-byte length word, aligned, uncompressed data (up to 1G) */ uint32 len = VARSIZE_4B(buffer); if (len > buff_size) return -1; CopyAppendEncode(buffer + 4, len - 4); *out_size = padding + len; return 0; } if (VARATT_IS_4B_C(buffer) && buff_size >= 8) { /* * xxxxxx10 4-byte length word, aligned, *compressed* data (up to 1G) */ int decompress_ret; uint32 len = VARSIZE_4B(buffer); uint32 decompressed_len = VARRAWSIZE_4B_C(buffer); if (len > buff_size) return -1; if (decompressed_len > sizeof(decompress_tmp_buff)) { printf("WARNING: Unable to decompress a string since it's too " "large (%d bytes after decompressing). Consider increasing " "decompress_tmp_buff size.\n", decompressed_len); CopyAppend("(COMPRESSED)"); *out_size = padding + len; return 0; } decompress_ret = pglz_decompress(VARDATA_4B_C(buffer), len - 2 * sizeof(uint32), decompress_tmp_buff, decompressed_len); if ((decompress_ret != decompressed_len) || (decompress_ret < 0)) { printf("WARNING: Unable to decompress a string. Data is corrupted.\n"); CopyAppend("(COMPRESSED)"); *out_size = padding + len; return 0; } CopyAppendEncode(decompress_tmp_buff, decompressed_len); *out_size = padding + len; return 0; } return -9; }
/* * Append given string to current COPY line and encode special symbols * like \r, \n, \t and \\. */ static void CopyAppendEncode(const char *str, int orig_len) { /* * Should be enough in most cases. If it's not user can manually change * this limit. Unfortunately there is no way to know how much memory user * is willing to allocate. */ static char tmp_buff[64 * 1024]; /* Reserve one byte for a trailing zero. */ const int max_offset = sizeof(tmp_buff) - 2; int curr_offset = 0; int len = orig_len; while (len > 0) { /* * Make sure there is enough free space for at least one special * symbol and a trailing zero. */ if (curr_offset > max_offset - 2) { printf("ERROR: Unable to properly encode a string since it's too " "large (%d bytes). Try to increase tmp_buff size in CopyAppendEncode " "procedure.\n", orig_len); exit(1); } /* * Since we are working with potentially corrupted data we can * encounter \0 as well. */ if (*str == '\0') { tmp_buff[curr_offset] = '\\'; tmp_buff[curr_offset + 1] = '0'; curr_offset += 2; } else if (*str == '\r') { tmp_buff[curr_offset] = '\\'; tmp_buff[curr_offset + 1] = 'r'; curr_offset += 2; } else if (*str == '\n') { tmp_buff[curr_offset] = '\\'; tmp_buff[curr_offset + 1] = 'n'; curr_offset += 2; } else if (*str == '\t') { tmp_buff[curr_offset] = '\\'; tmp_buff[curr_offset + 1] = 'r'; curr_offset += 2; } else if (*str == '\\') { tmp_buff[curr_offset] = '\\'; tmp_buff[curr_offset + 1] = '\\'; curr_offset += 2; } else { /* It's a regular symbol. */ tmp_buff[curr_offset] = *str; curr_offset++; } str++; len--; } tmp_buff[curr_offset] = '\0'; CopyAppend(tmp_buff); }