Re: [PATCHES] xpath_array with namespaces support

2007-03-17 Thread Nikolay Samokhvalov

What about it? W/o this not large patch XML functionality in 8.3 will be weak...
Will it be accepted?

On 3/5/07, Nikolay Samokhvalov [EMAIL PROTECTED] wrote:

On 3/4/07, Nikolay Samokhvalov [EMAIL PROTECTED] wrote:
 I'll fix these issues and extend the patch with resgression tests and
 docs for xpath_array(). I'll resubmit it very soon.

Here is a new version of the patch. I didn't change any part of docs yet.
Since there were no objections I've changed the name of the function
to xmlpath().




--
Best regards,
Nikolay
Index: src/backend/utils/adt/xml.c
===
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/xml.c,v
retrieving revision 1.34
diff -u -r1.34 xml.c
--- src/backend/utils/adt/xml.c	3 Mar 2007 19:32:55 -	1.34
+++ src/backend/utils/adt/xml.c	5 Mar 2007 01:14:57 -
@@ -47,6 +47,8 @@
 #include libxml/uri.h
 #include libxml/xmlerror.h
 #include libxml/xmlwriter.h
+#include libxml/xpath.h
+#include libxml/xpathInternals.h
 #endif /* USE_LIBXML */
 
 #include catalog/namespace.h
@@ -67,6 +69,7 @@
 #include utils/datetime.h
 #include utils/lsyscache.h
 #include utils/memutils.h
+#include access/tupmacs.h
 #include utils/xml.h
 
 
@@ -88,6 +91,7 @@
 static int		parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **encoding, int *standalone);
 static bool		print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int standalone);
 static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xmlChar *encoding);
+static text		*xml_xmlnodetotext(xmlNodePtr cur);
 
 #endif /* USE_LIBXML */
 
@@ -1463,7 +1467,6 @@
 	return buf.data;
 }
 
-
 /*
  * Map SQL value to XML value; see SQL/XML:2003 section 9.16.
  */
@@ -2403,3 +2406,247 @@
 	else
 		appendStringInfoString(result, /row\n\n);
 }
+
+
+/*
+ * XPath related functions
+ */
+
+#ifdef USE_LIBXML
+/* 
+ * Convert XML node to text (return value only, it's not dumping)
+ */
+text *
+xml_xmlnodetotext(xmlNodePtr cur)
+{
+	xmlChar		*str;
+	text			*result;
+	size_t			len;	
+	
+	str = xmlXPathCastNodeToString(cur);
+	len = strlen((char *) str);
+	result = (text *) palloc(len + VARHDRSZ);
+	SET_VARSIZE(result, len + VARHDRSZ);
+	memcpy(VARDATA(result), str, len);
+	
+	return result;
+}
+#endif
+
+/*
+ * Evaluate XPath expression and return array of XML values.
+ * As we have no support of XQuery sequences yet, this functions seems
+ * to be the most useful one (array of XML functions plays a role of
+ * some kind of substritution for XQuery sequences).
+
+ * Workaround here: we parse XML data in different way to allow XPath for
+ * fragments (see XPath for fragment TODO comment inside).
+ */
+Datum
+xmlpath(PG_FUNCTION_ARGS)
+{
+#ifdef USE_LIBXML
+	ArrayBuildState		*astate = NULL;
+	xmlParserCtxtPtr	ctxt = NULL;
+	xmlDocPtr			doc = NULL;
+	xmlXPathContextPtr	xpathctx = NULL;
+	xmlXPathCompExprPtr	xpathcomp = NULL;
+	xmlXPathObjectPtr	xpathobj = NULL;
+	int32len, xpath_len;
+	xmlChar*string, *xpath_expr;
+	boolres_is_null = FALSE;
+	int	i;
+	xmltype*data;
+	text*xpath_expr_text;
+	ArrayType			*namespaces;
+	int	*dims, ndims, ns_count = 0, bitmask = 1;
+	char*ptr;
+	bits8*bitmap;
+	char**ns_names = NULL, **ns_uris = NULL;
+	int16typlen;
+	booltypbyval;
+	chartypalign;
+	
+	/* the function is not strict, we must check first two args */
+	if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+		PG_RETURN_NULL();
+	
+	xpath_expr_text = PG_GETARG_TEXT_P(0);
+	data  = PG_GETARG_XML_P(1);
+	
+	/* Namespace mappings passed as text[].
+	 * Assume that 2-dimensional array has been passed, 
+	 * the 1st subarray is array of names, the 2nd -- array of URIs,
+	 * example: ARRAY[ARRAY['myns', 'myns2'], ARRAY['http://example.com', 'http://example2.com']]. 
+	 */
+	if (!PG_ARGISNULL(2))
+	{
+		namespaces = PG_GETARG_ARRAYTYPE_P(2);
+		ndims = ARR_NDIM(namespaces);
+		dims = ARR_DIMS(namespaces);
+		
+		/* Sanity check */
+		if (ndims != 2)
+			ereport(ERROR, (errmsg(invalid array passed for namespace mappings),
+			errdetail(Only 2-dimensional array may be used for namespace mappings.)));
+		
+		Assert(ARR_ELEMTYPE(namespaces) == TEXTOID);
+		
+		ns_count = ArrayGetNItems(ndims, dims) / 2;
+		get_typlenbyvalalign(ARR_ELEMTYPE(namespaces),
+			 typlen, typbyval, typalign);
+		ns_names = (char **) palloc(ns_count * sizeof(char *));
+		ns_uris = (char **) palloc(ns_count * sizeof(char *));
+		ptr = ARR_DATA_PTR(namespaces);
+		bitmap = ARR_NULLBITMAP(namespaces);
+		bitmask = 1;
+		
+		for (i = 0; i  ns_count * 2; i++)
+		{
+			if (bitmap  (*bitmap  bitmask) == 0)
+ereport(ERROR, (errmsg(neither namespace nor URI may be NULL))); /* TODO: better message */
+			else
+			{
+if (i  ns_count)
+	ns_names[i] = DatumGetCString(DirectFunctionCall1(textout,
+		  PointerGetDatum(ptr)));
+else
+	ns_uris[i - ns_count] = DatumGetCString(DirectFunctionCall1(textout,
+	

Re: [PATCHES] xpath_array with namespaces support

2007-03-17 Thread Andrew Dunstan



Nikolay Samokhvalov wrote:
What about it? W/o this not large patch XML functionality in 8.3 will 
be weak...

Will it be accepted?



In principle I am in favor of the patch.

Would it be better to use some more unlikely name for the dummy root 
element used to process fragments than x ?


Perhaps even something in a special namespace?

cheers

andrew




---(end of broadcast)---
TIP 9: In versions below 8.0, the planner will ignore your desire to
  choose an index scan if your joining column's datatypes do not
  match


Re: [PATCHES] xpath_array with namespaces support

2007-03-17 Thread Andrew Dunstan



Nikolay Samokhvalov wrote:

On 3/17/07, Andrew Dunstan [EMAIL PROTECTED] wrote:

In principle I am in favor of the patch.

Would it be better to use some more unlikely name for the dummy root
element used to process fragments than x ?

Perhaps even something in a special namespace?



I did think about it, but I didn't find any difficulties with simple
x.../x. The thing is that regardless the element name we have
corresponding shift in XPath epression -- so, there cannot be any
problem from my point of view... But maybe I don't see something and
it's better to avoid _possible_ problem. It depends on PostgreSQL code
style itself -- what is the best approach in such cases? To avoid
unknown possible difficulties or to be clear?



If you are sure that it won't cause a problem then I think it's ok to 
leave it, as long as there is a comment in the code that says why we are 
sure it's ok.


cheers

andrew

---(end of broadcast)---
TIP 6: explain analyze is your friend


[PATCHES] ecpg threading vs win32

2007-03-17 Thread Magnus Hagander
This patch replaces the pthreads code in ecpg with native win32 threads,
in order to make it threadsafe. The idea is not to have to download the
non-standard pthreads library on windows.

Does it seem like it should be doing the right thing? Does somebody have
a good test-case where ecpg breaks when not built thread-safe? (which
would then also break when built thread-safe with a broken implementation)

//Magnus
Index: connect.c
===
RCS file: /projects/cvsroot/pgsql/src/interfaces/ecpg/ecpglib/connect.c,v
retrieving revision 1.39
diff -u -r1.39 connect.c
--- connect.c   12 Jan 2007 10:00:12 -  1.39
+++ connect.c   14 Mar 2007 12:47:48 -
@@ -4,7 +4,11 @@
 #include postgres_fe.h
 
 #ifdef ENABLE_THREAD_SAFETY
+#ifndef WIN32
 #include pthread.h
+#else
+#include ecpg-pthread-win32.h
+#endif
 #endif
 #include ecpgtype.h
 #include ecpglib.h
@@ -13,9 +17,14 @@
 #include sqlca.h
 
 #ifdef ENABLE_THREAD_SAFETY
+#ifndef WIN32
 static pthread_mutex_t connections_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_key_t actual_connection_key;
 static pthread_once_t actual_connection_key_once = PTHREAD_ONCE_INIT;
+#else
+static HANDLE connections_mutex = INVALID_HANDLE_VALUE;
+static DWORD actual_connection_key;
+#endif /* WIN32 */
 #endif
 static struct connection *actual_connection = NULL;
 static struct connection *all_connections = NULL;
@@ -30,7 +39,13 @@
 void
 ecpg_pthreads_init(void)
 {
+#ifndef WIN32
pthread_once(actual_connection_key_once, ecpg_actual_connection_init);
+#else
+   static long has_run = 0;
+   if (InterlockedCompareExchange(has_run, 1, 0) == 0)
+   ecpg_actual_connection_init();
+#endif
 }
 #endif
 
Index: misc.c
===
RCS file: /projects/cvsroot/pgsql/src/interfaces/ecpg/ecpglib/misc.c,v
retrieving revision 1.34
diff -u -r1.34 misc.c
--- misc.c  12 Jan 2007 10:00:13 -  1.34
+++ misc.c  14 Mar 2007 12:48:03 -
@@ -6,7 +6,11 @@
 #include limits.h
 #include unistd.h
 #ifdef ENABLE_THREAD_SAFETY
+#ifndef WIN32
 #include pthread.h
+#else
+#include ecpg-pthread-win32.h
+#endif
 #endif
 #include ecpgtype.h
 #include ecpglib.h
@@ -58,9 +62,13 @@
 };
 
 #ifdef ENABLE_THREAD_SAFETY
+#ifndef WIN32
 static pthread_key_t sqlca_key;
 static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
 #else
+static DWORD sqlca_key;
+#endif
+#else
 static struct sqlca_t sqlca =
 {
{
@@ -90,8 +98,13 @@
 #endif
 
 #ifdef ENABLE_THREAD_SAFETY
+#ifndef WIN32
 static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+#else
+static HANDLE debug_mutex = INVALID_HANDLE_VALUE;
+static HANDLE debug_init_mutex = INVALID_HANDLE_VALUE;
+#endif /* WIN32 */
 #endif
 static int simple_debug = 0;
 static FILE *debugstream = NULL;
@@ -138,8 +151,13 @@
 {
 #ifdef ENABLE_THREAD_SAFETY
struct sqlca_t *sqlca;
-
+#ifdef WIN32
+   static long has_run = 0;
+   if (InterlockedCompareExchange(has_run, 1, 0) == 0)
+   ecpg_sqlca_key_init();
+#else
pthread_once(sqlca_key_once, ecpg_sqlca_key_init);
+#endif
 
sqlca = pthread_getspecific(sqlca_key);
if (sqlca == NULL)

/* $PostgreSQL$ */
/*
 * pthread mapping macros for win32 native thread implementation
 */
#ifndef _ECPG_PTHREAD_WIN32_H
#define _ECPG_PTHREAD_WIN32_H
#define pthread_mutex_lock(x) do { \
	if (*x == INVALID_HANDLE_VALUE) \
	   *x = CreateMutex(NULL, FALSE, NULL); \
WaitForSingleObject(*x, INFINITE); \
} while (0);
#define pthread_mutex_unlock(x) ReleaseMutex(*x)
#define pthread_getspecific(x) TlsGetValue(x)
#define pthread_setspecific(x,y) TlsSetValue(x,y)
#define pthread_key_create(x,y) *x = TlsAlloc();
#endif

---(end of broadcast)---
TIP 9: In versions below 8.0, the planner will ignore your desire to
   choose an index scan if your joining column's datatypes do not
   match


Re: [PATCHES] Code-Cleanup: char* - const char*

2007-03-17 Thread Neil Conway

Stefan Huehner wrote:

attached patches marks several char* variables as const where they are
initialized with constant strings.
  


I really wonder how much value there is in using the const modifier 
very widely. const for function parameters is valuable (because it 
adds information about the function's behavior to its interface). It 
also makes sense to use const on global variables, when it reduces the 
size of the binary's data segment. Beyond that, you reach the point of 
diminishing returns fairly quickly, IMHO. (In C, anyway; it makes more 
sense to use it widely in C++, of course.)


I also don't see the value in modifying the regexp code, as that is just 
an import of Henry Spencer's regexp package. I'm not sure whether we're 
planning on merging any upstream changes any time soon, but making 
cosmetic changes to the RE code will only make that more difficult.


Anyway, I'll apply this tomorrow without the RE changes, barring any 
objections.


BTW, the preferred format for patches is context diffs, not unified diffs.

-Neil


---(end of broadcast)---
TIP 4: Have you searched our list archives?

  http://archives.postgresql.org


Re: [PATCHES] Code-Cleanup: function declarations (void, and kr style)

2007-03-17 Thread Neil Conway

Stefan Huehner wrote:

attached patch fixes some function declarations:

- () - (void)
- kr style - ansi C
  


Applied, thanks for the patch.

-Neil


---(end of broadcast)---
TIP 6: explain analyze is your friend


Re: [PATCHES] patch adding new regexp functions

2007-03-17 Thread Neil Conway

Jeremy Drake wrote:

The patch has been sitting in the unapplied patches queue for a while

Barring any objections, I'll apply this tomorrow.

-Neil


---(end of broadcast)---
TIP 1: if posting/reading through Usenet, please send an appropriate
  subscribe-nomail command to [EMAIL PROTECTED] so that your
  message can get through to the mailing list cleanly