diff -uNr postgis-1.5.0/postgis/lwgeom_geos.c postgis-1.5.0-patched/postgis/lwgeom_geos.c
--- postgis-1.5.0/postgis/lwgeom_geos.c	2010-02-10 00:04:02.777410133 +0100
+++ postgis-1.5.0-patched/postgis/lwgeom_geos.c	2010-02-10 00:25:16.324659889 +0100
@@ -43,6 +43,7 @@
 Datum isvalid(PG_FUNCTION_ARGS);
 Datum isvalidreason(PG_FUNCTION_ARGS);
 Datum buffer(PG_FUNCTION_ARGS);
+Datum singlesidedbuffer(PG_FUNCTION_ARGS);
 Datum intersection(PG_FUNCTION_ARGS);
 Datum convexhull(PG_FUNCTION_ARGS);
 Datum topologypreservesimplify(PG_FUNCTION_ARGS);
@@ -1040,6 +1041,172 @@
 	PG_RETURN_POINTER(result);
 }
 
+PG_FUNCTION_INFO_V1(singlesidedbuffer);
+Datum singlesidedbuffer(PG_FUNCTION_ARGS)
+{
+	PG_LWGEOM	*geom1;
+	double	size;
+	GEOSGeometry *g1, *g3;
+	PG_LWGEOM *result;
+	int quadsegs = 8; /* the default */
+	int nargs;
+
+	enum
+	{
+		JOIN_ROUND = 1,
+		JOIN_MITRE = 2,
+		JOIN_BEVEL = 3
+	};
+	static const double DEFAULT_MITRE_LIMIT = 5.0;
+	static const int DEFAULT_JOIN_STYLE = JOIN_ROUND;
+
+	double mitreLimit = DEFAULT_MITRE_LIMIT;
+	int joinStyle  = DEFAULT_JOIN_STYLE;
+	int leftSide = 0;
+	char *param;
+	char *params = NULL;
+
+
+	PROFSTART(PROF_QRUN);
+
+	geom1 = (PG_LWGEOM *)  PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+	size = PG_GETARG_FLOAT8(1);
+
+	nargs = PG_NARGS();
+
+	initGEOS(lwnotice, lwnotice);
+
+	PROFSTART(PROF_P2G1);
+	g1 = (GEOSGeometry *)POSTGIS2GEOS(geom1);
+	PROFSTOP(PROF_P2G1);
+
+	if (nargs > 2)
+	{
+		/* We strdup `cause we're going to modify it */
+		params = pstrdup(PG_GETARG_CSTRING(2));
+
+		POSTGIS_DEBUGF(3, "Params: %s", params);
+
+		for (param=params; ; param=NULL)
+		{
+			char *key, *val;
+			param = strtok(param, " ");
+			if ( param == NULL ) break;
+			POSTGIS_DEBUGF(3, "Param: %s", param);
+
+			key = param;
+			val = strchr(key, '=');
+			if ( val == NULL || *(val+1) == '\0' )
+			{
+				lwerror("Missing value for buffer "
+				        "parameter %s", key);
+				break;
+			}
+			*val = '\0';
+			++val;
+
+			POSTGIS_DEBUGF(3, "Param: %s : %s", key, val);
+
+			if ( !strcmp(key, "join") )
+			{
+				if ( !strcmp(val, "round") )
+				{
+					joinStyle = JOIN_ROUND;
+				}
+				else if ( !strcmp(val, "mitre") ||
+				          !strcmp(val, "miter")    )
+				{
+					joinStyle = JOIN_MITRE;
+				}
+				else if ( !strcmp(val, "bevel") )
+				{
+					joinStyle = JOIN_BEVEL;
+				}
+				else
+				{
+					lwerror("Invalid buffer end cap "
+					        "style: %s (accept: "
+					        "'round', 'mitre', 'miter' "
+					        " or 'bevel'"
+					        ")", val);
+					break;
+				}
+			}
+			else if ( !strcmp(key, "mitre_limit") ||
+			          !strcmp(key, "miter_limit")    )
+			{
+				/* mitreLimit is a float */
+				mitreLimit = atof(val);
+			}
+			else if ( !strcmp(key, "quad_segs") )
+			{
+				/* quadrant segments is an int */
+				quadsegs = atoi(val);
+			}
+			else
+			{
+				lwerror("Invalid buffer parameter: %s (accept: "
+				        "'join', 'mitre_limit', "
+				        "'miter_limit and "
+				        "'quad_segs')", key);
+				break;
+			}
+		}
+
+		pfree(params); /* was pstrduped */
+
+		POSTGIS_DEBUGF(3, "joinStyle:%d mitreLimit:%g",
+		               joinStyle, mitreLimit);
+
+	}
+	if (nargs > 3)
+	{
+		leftSide = PG_GETARG_INT16(3);
+		// TODO debug !?
+	}
+
+	PROFSTART(PROF_GRUN);
+	g3 = GEOSSingleSidedBuffer(g1, size, quadsegs,
+	                         joinStyle, mitreLimit, leftSide);
+	PROFSTOP(PROF_GRUN);
+
+	if (g3 == NULL)
+	{
+		elog(ERROR,"GEOS singlesidedbuffer() threw an error!");
+		GEOSGeom_destroy(g1);
+		PG_RETURN_NULL(); /* never get here */
+	}
+
+	POSTGIS_DEBUGF(3, "result: %s", GEOSGeomToWKT(g3));
+
+	GEOSSetSRID(g3, pglwgeom_getSRID(geom1));
+
+	PROFSTART(PROF_G2P);
+	result = GEOS2POSTGIS(g3, TYPE_HASZ(geom1->type));
+	PROFSTOP(PROF_G2P);
+
+	if (result == NULL)
+	{
+		GEOSGeom_destroy(g1);
+		GEOSGeom_destroy(g3);
+		elog(ERROR,"GEOS singlesidedbuffer() threw an error (result postgis geometry formation)!");
+		PG_RETURN_NULL(); /* never get here */
+	}
+	GEOSGeom_destroy(g1);
+	GEOSGeom_destroy(g3);
+
+
+	/* compressType(result); */
+
+	PROFSTOP(PROF_QRUN);
+	PROFREPORT("geos",geom1, NULL, result);
+
+	PG_FREE_IF_COPY(geom1, 0);
+
+	PG_RETURN_POINTER(result);
+}
+
+
 PG_FUNCTION_INFO_V1(intersection);
 Datum intersection(PG_FUNCTION_ARGS)
 {
diff -uNr postgis-1.5.0/postgis/postgis.sql.in.c postgis-1.5.0-patched/postgis/postgis.sql.in.c
--- postgis-1.5.0/postgis/postgis.sql.in.c	2010-02-10 00:04:02.781410135 +0100
+++ postgis-1.5.0-patched/postgis/postgis.sql.in.c	2010-02-10 00:25:43.868660026 +0100
@@ -3871,6 +3871,24 @@
 	AS 'SELECT ST_Buffer($1, $2, $3)'
 	LANGUAGE 'SQL' IMMUTABLE STRICT;
 
+-- Availability: 1.5.0 - requires GEOS-3.2 or higher
+CREATE OR REPLACE FUNCTION _ST_Single_Sided_Buffer(geometry,float8,cstring,integer)
+	RETURNS geometry
+	AS 'MODULE_PATHNAME','singlesidedbuffer'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
+-- Availability: 1.5.0 - requires GEOS-3.2 or higher
+CREATE OR REPLACE FUNCTION ST_Single_Sided_Buffer(geometry,float8,text,integer)
+	RETURNS geometry
+	AS $$ SELECT _ST_Single_Sided_Buffer($1, $2,
+		CAST( regexp_replace($3, '^[0123456789]+$',
+			'quad_segs='||$3) AS cstring),
+		$4
+		)
+	   $$
+	LANGUAGE 'SQL' IMMUTABLE STRICT;
+
 -- Deprecation in 1.2.3
 CREATE OR REPLACE FUNCTION convexhull(geometry)
 	RETURNS geometry

