8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.264 2006/05/21 20:05:19 tgl Exp $
11
+ * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.265 2006/05/25 18:42:17 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -243,8 +243,8 @@ static Datum CopyReadBinaryAttribute(CopyState cstate,
243
243
int column_no , FmgrInfo * flinfo ,
244
244
Oid typioparam , int32 typmod ,
245
245
bool * isnull );
246
- static void CopyAttributeOutText (CopyState cstate , char * server_string );
247
- static void CopyAttributeOutCSV (CopyState cstate , char * server_string ,
246
+ static void CopyAttributeOutText (CopyState cstate , char * string );
247
+ static void CopyAttributeOutCSV (CopyState cstate , char * string ,
248
248
bool use_quote , bool single_attr );
249
249
static List * CopyGetAttnums (Relation rel , List * attnamelist );
250
250
static char * limit_printout_length (const char * str );
@@ -2884,91 +2884,123 @@ CopyReadBinaryAttribute(CopyState cstate,
2884
2884
/*
2885
2885
* Send text representation of one attribute, with conversion and escaping
2886
2886
*/
2887
+ #define DUMPSOFAR () \
2888
+ do { \
2889
+ if (ptr > start) \
2890
+ CopySendData(cstate, start, ptr - start); \
2891
+ } while (0)
2892
+
2887
2893
static void
2888
- CopyAttributeOutText (CopyState cstate , char * server_string )
2894
+ CopyAttributeOutText (CopyState cstate , char * string )
2889
2895
{
2890
- char * string ;
2896
+ char * ptr ;
2897
+ char * start ;
2891
2898
char c ;
2892
2899
char delimc = cstate -> delim [0 ];
2893
- int mblen ;
2894
2900
2895
2901
if (cstate -> need_transcoding )
2896
- string = pg_server_to_client (server_string , strlen (server_string ));
2902
+ ptr = pg_server_to_client (string , strlen (string ));
2897
2903
else
2898
- string = server_string ;
2904
+ ptr = string ;
2899
2905
2900
- for (; (c = * string ) != '\0' ; string += mblen )
2906
+ /*
2907
+ * We have to grovel through the string searching for control characters
2908
+ * and instances of the delimiter character. In most cases, though, these
2909
+ * are infrequent. To avoid overhead from calling CopySendData once per
2910
+ * character, we dump out all characters between replaceable characters
2911
+ * in a single call. The loop invariant is that the data from "start"
2912
+ * to "ptr" can be sent literally, but hasn't yet been.
2913
+ */
2914
+ start = ptr ;
2915
+ while ((c = * ptr ) != '\0' )
2901
2916
{
2902
- mblen = 1 ;
2903
-
2904
2917
switch (c )
2905
2918
{
2906
2919
case '\b' :
2920
+ DUMPSOFAR ();
2907
2921
CopySendString (cstate , "\\b" );
2922
+ start = ++ ptr ;
2908
2923
break ;
2909
2924
case '\f' :
2925
+ DUMPSOFAR ();
2910
2926
CopySendString (cstate , "\\f" );
2927
+ start = ++ ptr ;
2911
2928
break ;
2912
2929
case '\n' :
2930
+ DUMPSOFAR ();
2913
2931
CopySendString (cstate , "\\n" );
2932
+ start = ++ ptr ;
2914
2933
break ;
2915
2934
case '\r' :
2935
+ DUMPSOFAR ();
2916
2936
CopySendString (cstate , "\\r" );
2937
+ start = ++ ptr ;
2917
2938
break ;
2918
2939
case '\t' :
2940
+ DUMPSOFAR ();
2919
2941
CopySendString (cstate , "\\t" );
2942
+ start = ++ ptr ;
2920
2943
break ;
2921
2944
case '\v' :
2945
+ DUMPSOFAR ();
2922
2946
CopySendString (cstate , "\\v" );
2947
+ start = ++ ptr ;
2923
2948
break ;
2924
2949
case '\\' :
2950
+ DUMPSOFAR ();
2925
2951
CopySendString (cstate , "\\\\" );
2952
+ start = ++ ptr ;
2926
2953
break ;
2927
2954
default :
2928
2955
if (c == delimc )
2956
+ {
2957
+ DUMPSOFAR ();
2929
2958
CopySendChar (cstate , '\\' );
2959
+ start = ptr ; /* we include char in next run */
2960
+ }
2930
2961
2931
2962
/*
2932
2963
* We can skip pg_encoding_mblen() overhead when encoding is
2933
2964
* safe, because in valid backend encodings, extra bytes of a
2934
2965
* multibyte character never look like ASCII.
2935
2966
*/
2936
- if (cstate -> encoding_embeds_ascii && IS_HIGHBIT_SET (c ))
2937
- mblen = pg_encoding_mblen (cstate -> client_encoding , string );
2938
- CopySendData (cstate , string , mblen );
2967
+ if (IS_HIGHBIT_SET (c ) && cstate -> encoding_embeds_ascii )
2968
+ ptr += pg_encoding_mblen (cstate -> client_encoding , ptr );
2969
+ else
2970
+ ptr ++ ;
2939
2971
break ;
2940
2972
}
2941
2973
}
2974
+
2975
+ DUMPSOFAR ();
2942
2976
}
2943
2977
2944
2978
/*
2945
- * Send CSV representation of one attribute, with conversion and
2946
- * CSV type escaping
2979
+ * Send text representation of one attribute, with conversion and
2980
+ * CSV-style escaping
2947
2981
*/
2948
2982
static void
2949
- CopyAttributeOutCSV (CopyState cstate , char * server_string ,
2983
+ CopyAttributeOutCSV (CopyState cstate , char * string ,
2950
2984
bool use_quote , bool single_attr )
2951
2985
{
2952
- char * string ;
2986
+ char * ptr ;
2987
+ char * start ;
2953
2988
char c ;
2954
2989
char delimc = cstate -> delim [0 ];
2955
2990
char quotec = cstate -> quote [0 ];
2956
2991
char escapec = cstate -> escape [0 ];
2957
- char * tstring ;
2958
- int mblen ;
2959
2992
2960
- /* force quoting if it matches null_print */
2961
- if (!use_quote && strcmp (server_string , cstate -> null_print ) == 0 )
2993
+ /* force quoting if it matches null_print (before conversion!) */
2994
+ if (!use_quote && strcmp (string , cstate -> null_print ) == 0 )
2962
2995
use_quote = true;
2963
2996
2964
2997
if (cstate -> need_transcoding )
2965
- string = pg_server_to_client (server_string , strlen (server_string ));
2998
+ ptr = pg_server_to_client (string , strlen (string ));
2966
2999
else
2967
- string = server_string ;
3000
+ ptr = string ;
2968
3001
2969
3002
/*
2970
- * have to run through the string twice, first time to see if it needs
2971
- * quoting, second to actually send it
3003
+ * Make a preliminary pass to discover if it needs quoting
2972
3004
*/
2973
3005
if (!use_quote )
2974
3006
{
@@ -2977,41 +3009,57 @@ CopyAttributeOutCSV(CopyState cstate, char *server_string,
2977
3009
* alone on a line so it is not interpreted as the end-of-data
2978
3010
* marker.
2979
3011
*/
2980
- if (single_attr && strcmp (string , "\\." ) == 0 )
3012
+ if (single_attr && strcmp (ptr , "\\." ) == 0 )
2981
3013
use_quote = true;
2982
3014
else
2983
3015
{
2984
- for (tstring = string ; (c = * tstring ) != '\0' ; tstring += mblen )
3016
+ char * tptr = ptr ;
3017
+
3018
+ while ((c = * tptr ) != '\0' )
2985
3019
{
2986
3020
if (c == delimc || c == quotec || c == '\n' || c == '\r' )
2987
3021
{
2988
3022
use_quote = true;
2989
3023
break ;
2990
3024
}
2991
- if (cstate -> encoding_embeds_ascii && IS_HIGHBIT_SET (c ))
2992
- mblen = pg_encoding_mblen (cstate -> client_encoding , tstring );
3025
+ if (IS_HIGHBIT_SET (c ) && cstate -> encoding_embeds_ascii )
3026
+ tptr + = pg_encoding_mblen (cstate -> client_encoding , tptr );
2993
3027
else
2994
- mblen = 1 ;
3028
+ tptr ++ ;
2995
3029
}
2996
3030
}
2997
3031
}
2998
3032
2999
3033
if (use_quote )
3034
+ {
3000
3035
CopySendChar (cstate , quotec );
3001
3036
3002
- for (; (c = * string ) != '\0' ; string += mblen )
3003
- {
3004
- if (use_quote && (c == quotec || c == escapec ))
3005
- CopySendChar (cstate , escapec );
3006
- if (cstate -> encoding_embeds_ascii && IS_HIGHBIT_SET (c ))
3007
- mblen = pg_encoding_mblen (cstate -> client_encoding , string );
3008
- else
3009
- mblen = 1 ;
3010
- CopySendData (cstate , string , mblen );
3011
- }
3037
+ /*
3038
+ * We adopt the same optimization strategy as in CopyAttributeOutText
3039
+ */
3040
+ start = ptr ;
3041
+ while ((c = * ptr ) != '\0' )
3042
+ {
3043
+ if (c == quotec || c == escapec )
3044
+ {
3045
+ DUMPSOFAR ();
3046
+ CopySendChar (cstate , escapec );
3047
+ start = ptr ; /* we include char in next run */
3048
+ }
3049
+ if (IS_HIGHBIT_SET (c ) && cstate -> encoding_embeds_ascii )
3050
+ ptr += pg_encoding_mblen (cstate -> client_encoding , ptr );
3051
+ else
3052
+ ptr ++ ;
3053
+ }
3054
+ DUMPSOFAR ();
3012
3055
3013
- if (use_quote )
3014
3056
CopySendChar (cstate , quotec );
3057
+ }
3058
+ else
3059
+ {
3060
+ /* If it doesn't need quoting, we can just dump it as-is */
3061
+ CopySendString (cstate , ptr );
3062
+ }
3015
3063
}
3016
3064
3017
3065
/*
0 commit comments