varlena.c 16.0 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * varlena.c
4
 *	  Functions for the variable-length built-in types.
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.55 2000/01/15 02:59:38 petere Exp $
11 12 13 14 15 16 17
 *
 *-------------------------------------------------------------------------
 */
#include <ctype.h>

#include "postgres.h"

M
 
Marc G. Fournier 已提交
18
#include "mb/pg_wchar.h"
B
Bruce Momjian 已提交
19
#include "utils/builtins.h"
M
Marc G. Fournier 已提交
20

21 22 23
static int	text_cmp(text *arg1, text *arg2);


24 25
/*****************************************************************************
 *	 USER I/O ROUTINES														 *
26 27 28
 *****************************************************************************/


29 30
#define VAL(CH)			((CH) - '0')
#define DIG(VAL)		((VAL) + '0')
31 32

/*
33
 *		byteain			- converts from printable representation of byte array
34
 *
35 36
 *		Non-printable characters must be passed as '\nnn' (octal) and are
 *		converted to internal form.  '\' must be passed as '\\'.
37
 *		elog(ERROR, ...) if bad form.
38
 *
39 40 41
 *		BUGS:
 *				The input is scaned twice.
 *				The error checking of input is minimal.
42
 */
T
Thomas G. Lockhart 已提交
43
text *
44 45
byteain(char *inputText)
{
T
Thomas G. Lockhart 已提交
46 47 48 49
	char	   *tp;
	char	   *rp;
	int			byte;
	text	   *result;
50 51

	if (inputText == NULL)
52
		elog(ERROR, "Bad input string for type bytea");
53 54 55 56 57 58 59 60 61

	for (byte = 0, tp = inputText; *tp != '\0'; byte++)
		if (*tp++ == '\\')
		{
			if (*tp == '\\')
				tp++;
			else if (!isdigit(*tp++) ||
					 !isdigit(*tp++) ||
					 !isdigit(*tp++))
62
				elog(ERROR, "Bad input string for type bytea");
63 64
		}
	tp = inputText;
B
Bruce Momjian 已提交
65
	byte += VARHDRSZ;
T
Thomas G. Lockhart 已提交
66
	result = (text *) palloc(byte);
67 68 69 70 71 72 73 74 75 76 77 78 79
	result->vl_len = byte;		/* varlena? */
	rp = result->vl_dat;
	while (*tp != '\0')
		if (*tp != '\\' || *++tp == '\\')
			*rp++ = *tp++;
		else
		{
			byte = VAL(*tp++);
			byte <<= 3;
			byte += VAL(*tp++);
			byte <<= 3;
			*rp++ = byte + VAL(*tp++);
		}
80
	return result;
81 82 83
}

/*
84
 *		byteaout		- converts to printable representation of byte array
85
 *
86 87
 *		Non-printable characters are inserted as '\nnn' (octal) and '\' as
 *		'\\'.
88
 *
89
 *		NULL vlena should be an error--returning string with NULL for now.
90
 */
T
Thomas G. Lockhart 已提交
91 92
char *
byteaout(text *vlena)
93
{
T
Thomas G. Lockhart 已提交
94 95 96 97 98
	char	   *result;

	char	   *vp;
	char	   *rp;
	int			val;			/* holds unprintable chars */
99 100
	int			i;
	int			len;
101 102 103 104 105 106

	if (vlena == NULL)
	{
		result = (char *) palloc(2);
		result[0] = '-';
		result[1] = '\0';
107
		return result;
108
	}
109 110
	vp = vlena->vl_dat;
	len = 1;					/* empty string has 1 char */
B
Bruce Momjian 已提交
111
	for (i = vlena->vl_len - VARHDRSZ; i != 0; i--, vp++)
112 113 114 115 116
		if (*vp == '\\')
			len += 2;
		else if (isascii(*vp) && isprint(*vp))
			len++;
		else
117
			len += VARHDRSZ;
118 119
	rp = result = (char *) palloc(len);
	vp = vlena->vl_dat;
B
Bruce Momjian 已提交
120
	for (i = vlena->vl_len - VARHDRSZ; i != 0; i--)
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
		if (*vp == '\\')
		{
			vp++;
			*rp++ = '\\';
			*rp++ = '\\';
		}
		else if (isascii(*vp) && isprint(*vp))
			*rp++ = *vp++;
		else
		{
			val = *vp++;
			*rp = '\\';
			rp += 3;
			*rp-- = DIG(val & 07);
			val >>= 3;
			*rp-- = DIG(val & 07);
			val >>= 3;
			*rp = DIG(val & 03);
			rp += 3;
		}
	*rp = '\0';
142
	return result;
143 144 145 146
}


/*
147
 *		textin			- converts "..." to internal representation
148
 */
T
Thomas G. Lockhart 已提交
149
text *
150 151
textin(char *inputText)
{
T
Thomas G. Lockhart 已提交
152
	text	   *result;
153
	int			len;
154 155

	if (inputText == NULL)
156
		return NULL;
T
Thomas G. Lockhart 已提交
157

158
	len = strlen(inputText) + VARHDRSZ;
T
Thomas G. Lockhart 已提交
159
	result = (text *) palloc(len);
160
	VARSIZE(result) = len;
T
Thomas G. Lockhart 已提交
161

162
	memmove(VARDATA(result), inputText, len - VARHDRSZ);
163 164

#ifdef CYR_RECODE
165
	convertstr(VARDATA(result), len - VARHDRSZ, 0);
166 167
#endif

168
	return result;
169 170 171
}

/*
172
 *		textout			- converts internal representation to "..."
173
 */
T
Thomas G. Lockhart 已提交
174
char *
175

T
Thomas G. Lockhart 已提交
176
textout(text *vlena)
177
{
178 179
	int			len;
	char	   *result;
180 181 182 183 184 185

	if (vlena == NULL)
	{
		result = (char *) palloc(2);
		result[0] = '-';
		result[1] = '\0';
186
		return result;
187 188 189 190 191
	}
	len = VARSIZE(vlena) - VARHDRSZ;
	result = (char *) palloc(len + 1);
	memmove(result, VARDATA(vlena), len);
	result[len] = '\0';
192 193

#ifdef CYR_RECODE
194
	convertstr(result, len, 1);
195 196
#endif

197
	return result;
198 199 200 201 202
}


/* ========== PUBLIC ROUTINES ========== */

203 204
/*
 * textlen -
M
Marc G. Fournier 已提交
205
 *	  returns the logical length of a text*
206
 *	   (which is less than the VARSIZE of the text*)
207
 */
T
Thomas G. Lockhart 已提交
208
int32
209
textlen(text *t)
210
{
211
#ifdef MULTIBYTE
M
Marc G. Fournier 已提交
212
	unsigned char *s;
213 214 215 216
	int			len,
				l,
				wl;

M
Marc G. Fournier 已提交
217
#endif
218

219
	if (!PointerIsValid(t))
220
		elog(ERROR, "Null input to textlen");
221

222
#ifdef MULTIBYTE
M
Marc G. Fournier 已提交
223 224 225
	len = 0;
	s = VARDATA(t);
	l = VARSIZE(t) - VARHDRSZ;
226 227 228 229 230 231
	while (l > 0)
	{
		wl = pg_mblen(s);
		l -= wl;
		s += wl;
		len++;
M
Marc G. Fournier 已提交
232
	}
233
	return (len);
M
Marc G. Fournier 已提交
234
#else
235
	return VARSIZE(t) - VARHDRSZ;
M
Marc G. Fournier 已提交
236
#endif
237

238
}	/* textlen() */
239

M
Marc G. Fournier 已提交
240 241 242 243 244 245 246 247 248 249 250
/*
 * textoctetlen -
 *	  returns the physical length of a text*
 *	   (which is less than the VARSIZE of the text*)
 */
int32
textoctetlen(text *t)
{
	if (!PointerIsValid(t))
		elog(ERROR, "Null input to textoctetlen");

251
	return VARSIZE(t) - VARHDRSZ;
M
Marc G. Fournier 已提交
252 253 254

}	/* textoctetlen() */

255 256
/*
 * textcat -
257 258
 *	  takes two text* and returns a text* that is the concatentation of
 *	  the two.
259 260 261 262 263
 *
 * Rewritten by Sapa, sapa@hq.icb.chel.su. 8-Jul-96.
 * Updated by Thomas, Thomas.Lockhart@jpl.nasa.gov 1997-07-10.
 * Allocate space for output in all cases.
 * XXX - thomas 1997-07-10
264
 */
T
Thomas G. Lockhart 已提交
265
text *
266
textcat(text *t1, text *t2)
267
{
268 269 270 271 272
	int			len1,
				len2,
				len;
	char	   *ptr;
	text	   *result;
273

274
	if (!PointerIsValid(t1) || !PointerIsValid(t2))
275
		return NULL;
276

277
	len1 = (VARSIZE(t1) - VARHDRSZ);
278 279
	if (len1 < 0)
		len1 = 0;
280 281 282
	while (len1 > 0 && VARDATA(t1)[len1 - 1] == '\0')
		len1--;

283
	len2 = (VARSIZE(t2) - VARHDRSZ);
284 285
	if (len2 < 0)
		len2 = 0;
286 287
	while (len2 > 0 && VARDATA(t2)[len2 - 1] == '\0')
		len2--;
288

289 290 291 292 293
	len = len1 + len2 + VARHDRSZ;
	result = palloc(len);

	/* Set size of result string... */
	VARSIZE(result) = len;
294

295 296
	/* Fill data field of result string... */
	ptr = VARDATA(result);
297
	if (len1 > 0)
298
		memcpy(ptr, VARDATA(t1), len1);
299
	if (len2 > 0)
300
		memcpy(ptr + len1, VARDATA(t2), len2);
301

302
	return result;
303
}	/* textcat() */
T
Thomas G. Lockhart 已提交
304 305 306 307 308 309 310

/*
 * text_substr()
 * Return a substring starting at the specified position.
 * - thomas 1997-12-31
 *
 * Input:
311 312 313
 *	- string
 *	- starting position (is one-based)
 *	- string length
T
Thomas G. Lockhart 已提交
314
 *
315
 * If the starting position is zero or less, then return from the start of the string
B
Bruce Momjian 已提交
316
 *	adjusting the length to be consistant with the "negative start" per SQL92.
T
Thomas G. Lockhart 已提交
317 318 319
 * If the length is less than zero, return the remaining string.
 *
 * Note that the arguments operate on octet length,
320
 *	so not aware of multi-byte character sets.
M
Marc G. Fournier 已提交
321 322 323
 *
 * Added multi-byte support.
 * - Tatsuo Ishii 1998-4-21
324 325 326
 * Changed behavior if starting position is less than one to conform to SQL92 behavior.
 * Formerly returned the entire string; now returns a portion.
 * - Thomas Lockhart 1998-12-10
T
Thomas G. Lockhart 已提交
327 328 329 330 331 332
 */
text *
text_substr(text *string, int32 m, int32 n)
{
	text	   *ret;
	int			len;
333

334
#ifdef MULTIBYTE
335 336 337
	int			i;
	char	   *p;

M
Marc G. Fournier 已提交
338
#endif
T
Thomas G. Lockhart 已提交
339

340
	if (string == (text *) NULL)
T
Thomas G. Lockhart 已提交
341 342 343
		return string;

	len = VARSIZE(string) - VARHDRSZ;
344
#ifdef MULTIBYTE
345
	len = pg_mbstrlen_with_len(VARDATA(string), len);
M
Marc G. Fournier 已提交
346
#endif
T
Thomas G. Lockhart 已提交
347

348
	/* starting position after the end of the string? */
349
	if (m > len)
T
Thomas G. Lockhart 已提交
350
	{
351
		m = 1;
T
Thomas G. Lockhart 已提交
352 353
		n = 0;
	}
B
Bruce Momjian 已提交
354 355 356 357 358

	/*
	 * starting position before the start of the string? then offset into
	 * the string per SQL92 spec...
	 */
359
	else if (m < 1)
T
Thomas G. Lockhart 已提交
360
	{
B
Bruce Momjian 已提交
361
		n += (m - 1);
362
		m = 1;
T
Thomas G. Lockhart 已提交
363 364
	}

365 366 367 368 369
	/* m will now become a zero-based starting position */
	m--;
	if (((m + n) > len) || (n < 0))
		n = (len - m);

370
#ifdef MULTIBYTE
M
Marc G. Fournier 已提交
371
	p = VARDATA(string);
372 373
	for (i = 0; i < m; i++)
		p += pg_mblen(p);
M
Marc G. Fournier 已提交
374
	m = p - VARDATA(string);
375 376
	for (i = 0; i < n; i++)
		p += pg_mblen(p);
M
Marc G. Fournier 已提交
377 378
	n = p - (VARDATA(string) + m);
#endif
379
	ret = (text *) palloc(VARHDRSZ + n);
T
Thomas G. Lockhart 已提交
380 381
	VARSIZE(ret) = VARHDRSZ + n;

382
	memcpy(VARDATA(ret), VARDATA(string) + m, n);
T
Thomas G. Lockhart 已提交
383 384

	return ret;
385
}	/* text_substr() */
386 387 388

/*
 * textpos -
389 390 391
 *	  Return the position of the specified substring.
 *	  Implements the SQL92 POSITION() function.
 *	  Ref: A Guide To The SQL Standard, Date & Darwen, 1997
392
 * - thomas 1997-07-27
M
Marc G. Fournier 已提交
393 394 395
 *
 * Added multi-byte support.
 * - Tatsuo Ishii 1998-4-21
396 397
 */
int32
398
textpos(text *t1, text *t2)
399
{
400 401 402 403 404
	int			pos;
	int			px,
				p;
	int			len1,
				len2;
405
	pg_wchar   *p1,
406
			   *p2;
407

408
#ifdef MULTIBYTE
409 410 411
	pg_wchar   *ps1,
			   *ps2;

M
Marc G. Fournier 已提交
412
#endif
413 414

	if (!PointerIsValid(t1) || !PointerIsValid(t2))
415
		return 0;
416 417

	if (VARSIZE(t2) <= 0)
418
		return 1;
419 420 421

	len1 = (VARSIZE(t1) - VARHDRSZ);
	len2 = (VARSIZE(t2) - VARHDRSZ);
422
#ifdef MULTIBYTE
423 424
	ps1 = p1 = (pg_wchar *) palloc((len1 + 1) * sizeof(pg_wchar));
	(void) pg_mb2wchar_with_len((unsigned char *) VARDATA(t1), p1, len1);
M
Marc G. Fournier 已提交
425
	len1 = pg_wchar_strlen(p1);
426 427
	ps2 = p2 = (pg_wchar *) palloc((len2 + 1) * sizeof(pg_wchar));
	(void) pg_mb2wchar_with_len((unsigned char *) VARDATA(t2), p2, len2);
M
Marc G. Fournier 已提交
428 429
	len2 = pg_wchar_strlen(p2);
#else
430 431
	p1 = VARDATA(t1);
	p2 = VARDATA(t2);
M
Marc G. Fournier 已提交
432
#endif
433 434 435 436
	pos = 0;
	px = (len1 - len2);
	for (p = 0; p <= px; p++)
	{
437
#ifdef MULTIBYTE
M
Marc G. Fournier 已提交
438 439
		if ((*p2 == *p1) && (pg_wchar_strncmp(p1, p2, len2) == 0))
#else
440
		if ((*p2 == *p1) && (strncmp(p1, p2, len2) == 0))
M
Marc G. Fournier 已提交
441
#endif
442 443 444 445 446
		{
			pos = p + 1;
			break;
		};
		p1++;
447
	};
448
#ifdef MULTIBYTE
M
Marc G. Fournier 已提交
449 450 451
	pfree(ps1);
	pfree(ps2);
#endif
452
	return pos;
453
}	/* textpos() */
454 455

/*
456 457
 *		texteq			- returns 1 iff arguments are equal
 *		textne			- returns 1 iff arguments are not equal
458
 */
459
bool
T
Thomas G. Lockhart 已提交
460
texteq(text *arg1, text *arg2)
461
{
T
Thomas G. Lockhart 已提交
462 463
	int			len;
	char	   *a1p,
464
			   *a2p;
465 466

	if (arg1 == NULL || arg2 == NULL)
467
		return (bool) NULL;
468
	if ((len = arg1->vl_len) != arg2->vl_len)
469
		return (bool) 0;
470 471 472 473 474 475 476 477 478 479 480
	a1p = arg1->vl_dat;
	a2p = arg2->vl_dat;

	/*
	 * Varlenas are stored as the total size (data + size variable)
	 * followed by the data. Use VARHDRSZ instead of explicit sizeof() -
	 * thomas 1997-07-10
	 */
	len -= VARHDRSZ;
	while (len-- != 0)
		if (*a1p++ != *a2p++)
481 482
			return (bool) 0;
	return (bool) 1;
483
}	/* texteq() */
484

485
bool
T
Thomas G. Lockhart 已提交
486
textne(text *arg1, text *arg2)
487
{
488
	return (bool) !texteq(arg1, arg2);
489 490
}

B
Hello!  
Bruce Momjian 已提交
491 492
/* varstr_cmp()
 * Comparison function for text strings with given lengths.
493
 * Includes locale support, but must copy strings to temporary memory
494
 *	to allow null-termination for inputs to strcoll().
B
Hello!  
Bruce Momjian 已提交
495
 * Returns -1, 0 or 1
496
 */
B
Hello!  
Bruce Momjian 已提交
497
int
498
varstr_cmp(char *arg1, int len1, char *arg2, int len2)
499
{
500 501 502
	int			result;
	char	   *a1p,
			   *a2p;
503

504
#ifdef USE_LOCALE
B
Hello!  
Bruce Momjian 已提交
505 506
	a1p = (unsigned char *) palloc(len1 + 1);
	a2p = (unsigned char *) palloc(len2 + 1);
507

B
Hello!  
Bruce Momjian 已提交
508 509 510 511
	memcpy(a1p, arg1, len1);
	*(a1p + len1) = '\0';
	memcpy(a2p, arg2, len2);
	*(a2p + len2) = '\0';
512

B
Hello!  
Bruce Momjian 已提交
513
	result = strcoll(a1p, a2p);
514

515 516
	pfree(a1p);
	pfree(a2p);
B
Hello!  
Bruce Momjian 已提交
517

518
#else
519

B
Hello!  
Bruce Momjian 已提交
520 521
	a1p = arg1;
	a2p = arg2;
522

B
Hello!  
Bruce Momjian 已提交
523 524 525
	result = strncmp(a1p, a2p, Min(len1, len2));
	if ((result == 0) && (len1 != len2))
		result = (len1 < len2) ? -1 : 1;
526
#endif
527

528
	return result;
B
Hello!  
Bruce Momjian 已提交
529
}	/* varstr_cmp() */
530

531

B
Hello!  
Bruce Momjian 已提交
532
/* text_cmp()
533 534
 * Comparison function for text strings.
 * Includes locale support, but must copy strings to temporary memory
535
 *	to allow null-termination for inputs to strcoll().
536
 * XXX HACK code for textlen() indicates that there can be embedded nulls
537
 *	but it appears that most routines (incl. this one) assume not! - tgl 97/04/07
B
Hello!  
Bruce Momjian 已提交
538
 * Returns -1, 0 or 1
539
 */
540
static int
B
Hello!  
Bruce Momjian 已提交
541
text_cmp(text *arg1, text *arg2)
542
{
543 544 545 546
	char	   *a1p,
			   *a2p;
	int			len1,
				len2;
547 548

	if (arg1 == NULL || arg2 == NULL)
549
		return (bool) FALSE;
550

551 552
	a1p = VARDATA(arg1);
	a2p = VARDATA(arg2);
553

B
Hello!  
Bruce Momjian 已提交
554 555
	len1 = VARSIZE(arg1) - VARHDRSZ;
	len2 = VARSIZE(arg2) - VARHDRSZ;
556

B
Hello!  
Bruce Momjian 已提交
557 558
	return varstr_cmp(a1p, len1, a2p, len2);
}	/* text_cmp() */
559

B
Hello!  
Bruce Momjian 已提交
560 561 562 563 564 565
/* text_lt()
 * Comparison function for text strings.
 */
bool
text_lt(text *arg1, text *arg2)
{
566
	return (bool) (text_cmp(arg1, arg2) < 0);
B
Hello!  
Bruce Momjian 已提交
567 568 569 570 571 572 573 574
}	/* text_lt() */

/* text_le()
 * Comparison function for text strings.
 */
bool
text_le(text *arg1, text *arg2)
{
575
	return (bool) (text_cmp(arg1, arg2) <= 0);
576
}	/* text_le() */
577

578
bool
T
Thomas G. Lockhart 已提交
579
text_gt(text *arg1, text *arg2)
580
{
581
	return (bool) !text_le(arg1, arg2);
582 583
}

584
bool
T
Thomas G. Lockhart 已提交
585
text_ge(text *arg1, text *arg2)
586
{
587
	return (bool) !text_lt(arg1, arg2);
588 589
}

590 591 592
text *
text_larger(text *arg1, text *arg2)
{
B
Bruce Momjian 已提交
593 594
	text	   *result;
	text	   *temp;
595

B
Bruce Momjian 已提交
596
	temp = ((text_cmp(arg1, arg2) <= 0) ? arg2 : arg1);
597 598 599 600 601 602 603 604 605 606 607 608

	/* Make a copy */

	result = (text *) palloc(VARSIZE(temp));
	memmove((char *) result, (char *) temp, VARSIZE(temp));

	return (result);
}

text *
text_smaller(text *arg1, text *arg2)
{
B
Bruce Momjian 已提交
609 610
	text	   *result;
	text	   *temp;
611

B
Bruce Momjian 已提交
612
	temp = ((text_cmp(arg1, arg2) > 0) ? arg2 : arg1);
613 614 615 616 617 618 619 620 621

	/* Make a copy */

	result = (text *) palloc(VARSIZE(temp));
	memmove((char *) result, (char *) temp, VARSIZE(temp));

	return (result);
}

622 623 624 625 626 627 628
/*-------------------------------------------------------------
 * byteaGetSize
 *
 * get the number of bytes contained in an instance of type 'bytea'
 *-------------------------------------------------------------
 */
int32
T
Thomas G. Lockhart 已提交
629
byteaGetSize(text *v)
630
{
T
Thomas G. Lockhart 已提交
631
	int			len;
632 633 634

	len = v->vl_len - sizeof(v->vl_len);

635
	return len;
636 637 638 639 640 641 642 643 644 645 646
}

/*-------------------------------------------------------------
 * byteaGetByte
 *
 * this routine treats "bytea" as an array of bytes.
 * It returns the Nth byte (a number between 0 and 255) or
 * it dies if the length of this array is less than n.
 *-------------------------------------------------------------
 */
int32
T
Thomas G. Lockhart 已提交
647
byteaGetByte(text *v, int32 n)
648
{
649 650
	int			len;
	int			byte;
651 652 653 654 655

	len = byteaGetSize(v);

	if (n >= len)
	{
656
		elog(ERROR, "byteaGetByte: index (=%d) out of range [0..%d]",
657 658
			 n, len - 1);
	}
B
Bruce Momjian 已提交
659
#ifdef USE_LOCALE
660
	byte = (unsigned char) (v->vl_dat[n]);
B
Bruce Momjian 已提交
661 662 663
#else
	byte = v->vl_dat[n];
#endif
664
	return (int32) byte;
665 666 667 668 669 670 671 672 673 674 675 676
}

/*-------------------------------------------------------------
 * byteaGetBit
 *
 * This routine treats a "bytea" type like an array of bits.
 * It returns the value of the Nth bit (0 or 1).
 * If 'n' is out of range, it dies!
 *
 *-------------------------------------------------------------
 */
int32
T
Thomas G. Lockhart 已提交
677
byteaGetBit(text *v, int32 n)
678
{
679 680 681
	int			byteNo,
				bitNo;
	int			byte;
682 683 684 685 686 687 688

	byteNo = n / 8;
	bitNo = n % 8;

	byte = byteaGetByte(v, byteNo);

	if (byte & (1 << bitNo))
689
		return (int32) 1;
690
	else
691
		return (int32) 0;
692
}
693

694 695 696 697 698 699 700 701
/*-------------------------------------------------------------
 * byteaSetByte
 *
 * Given an instance of type 'bytea' creates a new one with
 * the Nth byte set to the given value.
 *
 *-------------------------------------------------------------
 */
T
Thomas G. Lockhart 已提交
702 703
text *
byteaSetByte(text *v, int32 n, int32 newByte)
704
{
705
	int			len;
T
Thomas G. Lockhart 已提交
706
	text	   *res;
707 708 709 710 711

	len = byteaGetSize(v);

	if (n >= len)
	{
712
		elog(ERROR,
713 714 715 716 717 718 719
			 "byteaSetByte: index (=%d) out of range [0..%d]",
			 n, len - 1);
	}

	/*
	 * Make a copy of the original varlena.
	 */
T
Thomas G. Lockhart 已提交
720
	res = (text *) palloc(VARSIZE(v));
721 722
	if (res == NULL)
	{
723
		elog(ERROR, "byteaSetByte: Out of memory (%d bytes requested)",
724 725 726 727 728 729 730 731 732
			 VARSIZE(v));
	}
	memmove((char *) res, (char *) v, VARSIZE(v));

	/*
	 * Now set the byte.
	 */
	res->vl_dat[n] = newByte;

733
	return res;
734 735 736 737 738 739 740 741 742 743
}

/*-------------------------------------------------------------
 * byteaSetBit
 *
 * Given an instance of type 'bytea' creates a new one with
 * the Nth bit set to the given value.
 *
 *-------------------------------------------------------------
 */
T
Thomas G. Lockhart 已提交
744 745
text *
byteaSetBit(text *v, int32 n, int32 newBit)
746
{
T
Thomas G. Lockhart 已提交
747
	text	   *res;
748 749 750 751
	int			oldByte,
				newByte;
	int			byteNo,
				bitNo;
752 753 754 755 756

	/*
	 * sanity check!
	 */
	if (newBit != 0 && newBit != 1)
757
		elog(ERROR, "byteaSetByte: new bit must be 0 or 1");
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778

	/*
	 * get the byte where the bit we want is stored.
	 */
	byteNo = n / 8;
	bitNo = n % 8;
	oldByte = byteaGetByte(v, byteNo);

	/*
	 * calculate the new value for that byte
	 */
	if (newBit == 0)
		newByte = oldByte & (~(1 << bitNo));
	else
		newByte = oldByte | (1 << bitNo);

	/*
	 * NOTE: 'byteaSetByte' creates a copy of 'v' & sets the byte.
	 */
	res = byteaSetByte(v, byteNo, newByte);

779
	return res;
780
}
781 782 783 784 785


/* text_name()
 * Converts a text() type to a NameData type.
 */
786
NameData   *
787 788 789 790 791 792
text_name(text *s)
{
	NameData   *result;
	int			len;

	if (s == NULL)
793
		return NULL;
794 795

	len = VARSIZE(s) - VARHDRSZ;
796 797
	if (len > NAMEDATALEN)
		len = NAMEDATALEN;
798 799

#ifdef STRINGDEBUG
800 801
	printf("text- convert string length %d (%d) ->%d\n",
		   VARSIZE(s) - VARHDRSZ, VARSIZE(s), len);
802 803 804
#endif

	result = palloc(NAMEDATALEN);
805
	StrNCpy(NameStr(*result), VARDATA(s), NAMEDATALEN);
806 807

	/* now null pad to full length... */
808 809
	while (len < NAMEDATALEN)
	{
810
		*(NameStr(*result) + len) = '\0';
811 812 813
		len++;
	}

814
	return result;
815
}	/* text_name() */
816 817 818 819 820 821 822 823 824 825 826

/* name_text()
 * Converts a NameData type to a text type.
 */
text *
name_text(NameData *s)
{
	text	   *result;
	int			len;

	if (s == NULL)
827
		return NULL;
828

829
	len = strlen(NameStr(*s));
830 831

#ifdef STRINGDEBUG
832 833
	printf("text- convert string length %d (%d) ->%d\n",
		   VARSIZE(s) - VARHDRSZ, VARSIZE(s), len);
834 835 836
#endif

	result = palloc(VARHDRSZ + len);
837
	strncpy(VARDATA(result), NameStr(*s), len);
838 839
	VARSIZE(result) = len + VARHDRSZ;

840
	return result;
841
}	/* name_text() */