varlena.c 14.7 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.34 1998/05/09 22:42:07 thomas Exp $
11 12 13 14 15 16 17 18
 *
 *-------------------------------------------------------------------------
 */
#include <ctype.h>
#include <string.h>

#include "postgres.h"
#include "utils/palloc.h"
19
#include "utils/builtins.h"		/* where function declarations go */
20

Marc G. Fournier's avatar
Marc G. Fournier committed
21 22
#include "regex/pg_wchar.h"

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


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

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

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

	for (byte = 0, tp = inputText; *tp != '\0'; byte++)
		if (*tp++ == '\\')
		{
			if (*tp == '\\')
				tp++;
			else if (!isdigit(*tp++) ||
					 !isdigit(*tp++) ||
					 !isdigit(*tp++))
61
				elog(ERROR, "Bad input string for type bytea");
62 63
		}
	tp = inputText;
Bruce Momjian's avatar
Bruce Momjian committed
64
	byte += VARHDRSZ;
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
65
	result = (text *) palloc(byte);
66 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++);
		}
	return (result);
80 81 82
}

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

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

	if (vlena == NULL)
	{
		result = (char *) palloc(2);
		result[0] = '-';
		result[1] = '\0';
		return (result);
107
	}
108 109
	vp = vlena->vl_dat;
	len = 1;					/* empty string has 1 char */
Bruce Momjian's avatar
Bruce Momjian committed
110
	for (i = vlena->vl_len - VARHDRSZ; i != 0; i--, vp++)
111 112 113 114 115
		if (*vp == '\\')
			len += 2;
		else if (isascii(*vp) && isprint(*vp))
			len++;
		else
116
			len += VARHDRSZ;
117 118
	rp = result = (char *) palloc(len);
	vp = vlena->vl_dat;
Bruce Momjian's avatar
Bruce Momjian committed
119
	for (i = vlena->vl_len - VARHDRSZ; i != 0; i--)
120 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';
	return (result);
142 143 144 145
}


/*
146
 *		textin			- converts "..." to internal representation
147
 */
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
148
text *
149 150
textin(char *inputText)
{
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
151
	text	   *result;
152
	int			len;
153 154 155

	if (inputText == NULL)
		return (NULL);
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
156

157
	len = strlen(inputText) + VARHDRSZ;
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
158
	result = (text *) palloc(len);
159
	VARSIZE(result) = len;
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
160

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

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

167
	return (result);
168 169 170
}

/*
171
 *		textout			- converts internal representation to "..."
172
 */
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
173 174
char *
textout(text *vlena)
175
{
176 177
	int			len;
	char	   *result;
178 179 180 181 182 183 184 185 186 187 188 189

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

#ifdef CYR_RECODE
192
	convertstr(result, len, 1);
193 194
#endif

195
	return (result);
196 197 198 199 200
}


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

201 202
/*
 * textlen -
Marc G. Fournier's avatar
Marc G. Fournier committed
203
 *	  returns the logical length of a text*
204
 *	   (which is less than the VARSIZE of the text*)
205
 */
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
206
int32
207
textlen(text *t)
208
{
Marc G. Fournier's avatar
Marc G. Fournier committed
209 210 211 212 213
#ifdef MB
	unsigned char *s;
	int len, l, wl;
#endif
        
214
	if (!PointerIsValid(t))
215
		elog(ERROR, "Null input to textlen");
216

Marc G. Fournier's avatar
Marc G. Fournier committed
217 218 219 220 221 222 223 224 225 226 227 228
#ifdef MB
	len = 0;
	s = VARDATA(t);
	l = VARSIZE(t) - VARHDRSZ;
	while (l > 0) {
	  wl = pg_mblen(s);
	  l -= wl;
	  s += wl;
	  len++;
	}
	return(len);
#else
229
	return (VARSIZE(t) - VARHDRSZ);
Marc G. Fournier's avatar
Marc G. Fournier committed
230 231
#endif
	
232
}	/* textlen() */
233

Marc G. Fournier's avatar
Marc G. Fournier committed
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
/*
 * 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");

	return (VARSIZE(t) - VARHDRSZ);

}	/* textoctetlen() */

249 250
/*
 * textcat -
251 252
 *	  takes two text* and returns a text* that is the concatentation of
 *	  the two.
253 254 255 256 257
 *
 * 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
258
 */
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
259
text *
260
textcat(text *t1, text *t2)
261
{
262 263 264 265 266
	int			len1,
				len2,
				len;
	char	   *ptr;
	text	   *result;
267

268
	if (!PointerIsValid(t1) || !PointerIsValid(t2))
269
		return (NULL);
270

271
	len1 = (VARSIZE(t1) - VARHDRSZ);
272 273
	if (len1 < 0)
		len1 = 0;
274 275 276
	while (len1 > 0 && VARDATA(t1)[len1 - 1] == '\0')
		len1--;

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

283 284 285 286 287
	len = len1 + len2 + VARHDRSZ;
	result = palloc(len);

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

289 290
	/* Fill data field of result string... */
	ptr = VARDATA(result);
291
	if (len1 > 0)
292
		memcpy(ptr, VARDATA(t1), len1);
293
	if (len2 > 0)
294
		memcpy(ptr + len1, VARDATA(t2), len2);
295

296
	return (result);
297
}	/* textcat() */
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
298 299 300 301 302 303 304

/*
 * text_substr()
 * Return a substring starting at the specified position.
 * - thomas 1997-12-31
 *
 * Input:
305 306 307
 *	- string
 *	- starting position (is one-based)
 *	- string length
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
308 309 310
 *
 * If the starting position is zero or less, then return the entire string.
 * XXX Note that this may not be the right behavior:
311
 *	if we are calculating the starting position we might want it to start at one.
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
312 313 314
 * If the length is less than zero, return the remaining string.
 *
 * Note that the arguments operate on octet length,
315
 *	so not aware of multi-byte character sets.
Marc G. Fournier's avatar
Marc G. Fournier committed
316 317 318
 *
 * Added multi-byte support.
 * - Tatsuo Ishii 1998-4-21
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
319 320 321 322 323 324
 */
text *
text_substr(text *string, int32 m, int32 n)
{
	text	   *ret;
	int			len;
Marc G. Fournier's avatar
Marc G. Fournier committed
325 326 327 328
#ifdef MB
	int i;
	char *p;
#endif
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
329 330 331 332 333

	if ((string == (text *) NULL) || (m <= 0))
		return string;

	len = VARSIZE(string) - VARHDRSZ;
Marc G. Fournier's avatar
Marc G. Fournier committed
334 335 336
#ifdef MB
	len = pg_mbstrlen_with_len(VARDATA(string),len);
#endif
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
337 338

	/* m will now become a zero-based starting position */
339
	if (m > len)
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
340 341 342 343 344 345 346
	{
		m = 0;
		n = 0;
	}
	else
	{
		m--;
347 348
		if (((m + n) > len) || (n < 0))
			n = (len - m);
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
349 350
	}

Marc G. Fournier's avatar
Marc G. Fournier committed
351 352 353 354 355 356 357 358 359 360 361
#ifdef MB
	p = VARDATA(string);
	for (i=0;i<m;i++) {
	  p += pg_mblen(p);
	}
	m = p - VARDATA(string);
	for (i=0;i<n;i++) {
	  p += pg_mblen(p);
	}
	n = p - (VARDATA(string) + m);
#endif
362
	ret = (text *) palloc(VARHDRSZ + n);
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
363 364
	VARSIZE(ret) = VARHDRSZ + n;

365
	memcpy(VARDATA(ret), VARDATA(string) + m, n);
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
366 367

	return ret;
368
}	/* text_substr() */
369 370 371

/*
 * textpos -
372 373 374
 *	  Return the position of the specified substring.
 *	  Implements the SQL92 POSITION() function.
 *	  Ref: A Guide To The SQL Standard, Date & Darwen, 1997
375
 * - thomas 1997-07-27
Marc G. Fournier's avatar
Marc G. Fournier committed
376 377 378
 *
 * Added multi-byte support.
 * - Tatsuo Ishii 1998-4-21
379 380
 */
int32
381
textpos(text *t1, text *t2)
382
{
383 384 385 386 387
	int			pos;
	int			px,
				p;
	int			len1,
				len2;
Marc G. Fournier's avatar
Marc G. Fournier committed
388
	pg_wchar	   *p1,
389
			   *p2;
Marc G. Fournier's avatar
Marc G. Fournier committed
390 391 392
#ifdef MB
	pg_wchar	*ps1, *ps2;
#endif
393 394 395 396 397 398 399 400 401

	if (!PointerIsValid(t1) || !PointerIsValid(t2))
		return (0);

	if (VARSIZE(t2) <= 0)
		return (1);

	len1 = (VARSIZE(t1) - VARHDRSZ);
	len2 = (VARSIZE(t2) - VARHDRSZ);
Marc G. Fournier's avatar
Marc G. Fournier committed
402 403 404 405 406 407 408 409
#ifdef MB
	ps1 = p1 = (pg_wchar *) palloc((len1 + 1)*sizeof(pg_wchar));
	(void)pg_mb2wchar_with_len((unsigned char *)VARDATA(t1),p1,len1);
	len1 = pg_wchar_strlen(p1);
	ps2 = p2 = (pg_wchar *) palloc((len2 + 1)*sizeof(pg_wchar));
	(void)pg_mb2wchar_with_len((unsigned char *)VARDATA(t2),p2,len2);
	len2 = pg_wchar_strlen(p2);
#else
410 411
	p1 = VARDATA(t1);
	p2 = VARDATA(t2);
Marc G. Fournier's avatar
Marc G. Fournier committed
412
#endif
413 414 415 416
	pos = 0;
	px = (len1 - len2);
	for (p = 0; p <= px; p++)
	{
Marc G. Fournier's avatar
Marc G. Fournier committed
417 418 419
#ifdef MB
		if ((*p2 == *p1) && (pg_wchar_strncmp(p1, p2, len2) == 0))
#else
420
		if ((*p2 == *p1) && (strncmp(p1, p2, len2) == 0))
Marc G. Fournier's avatar
Marc G. Fournier committed
421
#endif
422 423 424 425 426
		{
			pos = p + 1;
			break;
		};
		p1++;
427
	};
Marc G. Fournier's avatar
Marc G. Fournier committed
428 429 430 431
#ifdef MB
	pfree(ps1);
	pfree(ps2);
#endif
432
	return (pos);
433
}	/* textpos() */
434 435

/*
436 437
 *		texteq			- returns 1 iff arguments are equal
 *		textne			- returns 1 iff arguments are not equal
438
 */
439
bool
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
440
texteq(text *arg1, text *arg2)
441
{
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
442 443
	int			len;
	char	   *a1p,
444
			   *a2p;
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462

	if (arg1 == NULL || arg2 == NULL)
		return ((bool) NULL);
	if ((len = arg1->vl_len) != arg2->vl_len)
		return ((bool) 0);
	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++)
			return ((bool) 0);
	return ((bool) 1);
463
}	/* texteq() */
464

465
bool
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
466
textne(text *arg1, text *arg2)
467
{
468
	return ((bool) !texteq(arg1, arg2));
469 470
}

471 472 473
/* text_lt()
 * Comparison function for text strings.
 * Includes locale support, but must copy strings to temporary memory
474
 *	to allow null-termination for inputs to strcoll().
475
 * XXX HACK code for textlen() indicates that there can be embedded nulls
476
 *	but it appears that most routines (incl. this one) assume not! - tgl 97/04/07
477
 */
478
bool
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
479
text_lt(text *arg1, text *arg2)
480
{
481
	bool		result;
482 483

#ifdef USE_LOCALE
484
	int			cval;
485

486
#endif
487 488 489
	int			len;
	unsigned char *a1p,
			   *a2p;
490 491 492 493 494 495

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

	len = (((VARSIZE(arg1) <= VARSIZE(arg2)) ? VARSIZE(arg1) : VARSIZE(arg2)) - VARHDRSZ);

496
#ifdef USE_LOCALE
497 498
	a1p = (unsigned char *) palloc(len + 1);
	a2p = (unsigned char *) palloc(len + 1);
499

500 501 502 503
	memcpy(a1p, VARDATA(arg1), len);
	*(a1p + len) = '\0';
	memcpy(a2p, VARDATA(arg2), len);
	*(a2p + len) = '\0';
504

505 506
	cval = strcoll(a1p, a2p);
	result = ((cval < 0) || ((cval == 0) && (VARSIZE(arg1) < VARSIZE(arg2))));
507

508 509
	pfree(a1p);
	pfree(a2p);
510
#else
511 512 513 514 515 516 517 518 519 520 521
	a1p = (unsigned char *) VARDATA(arg1);
	a2p = (unsigned char *) VARDATA(arg2);

	while (len != 0 && *a1p == *a2p)
	{
		a1p++;
		a2p++;
		len--;
	};

	result = (len ? (*a1p < *a2p) : (VARSIZE(arg1) < VARSIZE(arg2)));
522
#endif
523

524
	return (result);
525
}	/* text_lt() */
526 527 528 529

/* text_le()
 * Comparison function for text strings.
 * Includes locale support, but must copy strings to temporary memory
530
 *	to allow null-termination for inputs to strcoll().
531
 * XXX HACK code for textlen() indicates that there can be embedded nulls
532
 *	but it appears that most routines (incl. this one) assume not! - tgl 97/04/07
533
 */
534
bool
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
535
text_le(text *arg1, text *arg2)
536
{
537
	bool		result;
538 539

#ifdef USE_LOCALE
540
	int			cval;
541

542
#endif
543 544 545
	int			len;
	unsigned char *a1p,
			   *a2p;
546 547 548 549 550 551

	if (arg1 == NULL || arg2 == NULL)
		return ((bool) 0);

	len = (((VARSIZE(arg1) <= VARSIZE(arg2)) ? VARSIZE(arg1) : VARSIZE(arg2)) - VARHDRSZ);

552
#ifdef USE_LOCALE
553 554
	a1p = (unsigned char *) palloc(len + 1);
	a2p = (unsigned char *) palloc(len + 1);
555

556 557 558 559
	memcpy(a1p, VARDATA(arg1), len);
	*(a1p + len) = '\0';
	memcpy(a2p, VARDATA(arg2), len);
	*(a2p + len) = '\0';
560

561 562
	cval = strcoll(a1p, a2p);
	result = ((cval < 0) || ((cval == 0) && (VARSIZE(arg1) <= VARSIZE(arg2))));
563

564 565
	pfree(a1p);
	pfree(a2p);
566
#else
567 568 569 570 571 572 573 574 575 576 577
	a1p = (unsigned char *) VARDATA(arg1);
	a2p = (unsigned char *) VARDATA(arg2);

	while (len != 0 && *a1p == *a2p)
	{
		a1p++;
		a2p++;
		len--;
	};

	result = (len ? (*a1p <= *a2p) : (VARSIZE(arg1) <= VARSIZE(arg2)));
578
#endif
579

580
	return (result);
581
}	/* text_le() */
582

583
bool
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
584
text_gt(text *arg1, text *arg2)
585
{
586
	return ((bool) !text_le(arg1, arg2));
587 588
}

589
bool
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
590
text_ge(text *arg1, text *arg2)
591
{
592
	return ((bool) !text_lt(arg1, arg2));
593 594 595 596 597 598 599 600 601
}

/*-------------------------------------------------------------
 * byteaGetSize
 *
 * get the number of bytes contained in an instance of type 'bytea'
 *-------------------------------------------------------------
 */
int32
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
602
byteaGetSize(text *v)
603
{
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
604
	int			len;
605 606 607 608

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

	return (len);
609 610 611 612 613 614 615 616 617 618 619
}

/*-------------------------------------------------------------
 * 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
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
620
byteaGetByte(text *v, int32 n)
621
{
622 623
	int			len;
	int			byte;
624 625 626 627 628

	len = byteaGetSize(v);

	if (n >= len)
	{
629
		elog(ERROR, "byteaGetByte: index (=%d) out of range [0..%d]",
630 631 632 633 634 635
			 n, len - 1);
	}

	byte = (unsigned char) (v->vl_dat[n]);

	return ((int32) byte);
636 637 638 639 640 641 642 643 644 645 646 647
}

/*-------------------------------------------------------------
 * 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
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
648
byteaGetBit(text *v, int32 n)
649
{
650 651 652
	int			byteNo,
				bitNo;
	int			byte;
653 654 655 656 657 658 659 660 661 662 663 664 665 666

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

	byte = byteaGetByte(v, byteNo);

	if (byte & (1 << bitNo))
	{
		return ((int32) 1);
	}
	else
	{
		return ((int32) 0);
	}
667
}
668

669 670 671 672 673 674 675 676
/*-------------------------------------------------------------
 * byteaSetByte
 *
 * Given an instance of type 'bytea' creates a new one with
 * the Nth byte set to the given value.
 *
 *-------------------------------------------------------------
 */
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
677 678
text *
byteaSetByte(text *v, int32 n, int32 newByte)
679
{
680
	int			len;
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
681
	text	   *res;
682 683 684 685 686

	len = byteaGetSize(v);

	if (n >= len)
	{
687
		elog(ERROR,
688 689 690 691 692 693 694
			 "byteaSetByte: index (=%d) out of range [0..%d]",
			 n, len - 1);
	}

	/*
	 * Make a copy of the original varlena.
	 */
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
695
	res = (text *) palloc(VARSIZE(v));
696 697
	if (res == NULL)
	{
698
		elog(ERROR, "byteaSetByte: Out of memory (%d bytes requested)",
699 700 701 702 703 704 705 706 707 708
			 VARSIZE(v));
	}
	memmove((char *) res, (char *) v, VARSIZE(v));

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

	return (res);
709 710 711 712 713 714 715 716 717 718
}

/*-------------------------------------------------------------
 * byteaSetBit
 *
 * Given an instance of type 'bytea' creates a new one with
 * the Nth bit set to the given value.
 *
 *-------------------------------------------------------------
 */
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
719 720
text *
byteaSetBit(text *v, int32 n, int32 newBit)
721
{
Thomas G. Lockhart's avatar
Thomas G. Lockhart committed
722
	text	   *res;
723 724 725 726
	int			oldByte,
				newByte;
	int			byteNo,
				bitNo;
727 728 729 730 731 732

	/*
	 * sanity check!
	 */
	if (newBit != 0 && newBit != 1)
	{
733
		elog(ERROR, "byteaSetByte: new bit must be 0 or 1");
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
	}

	/*
	 * 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);

	return (res);
761
}