Index: include/db.h
===================================================================
--- include/db.h	(revision 90998)
+++ include/db.h	(working copy)
@@ -183,23 +183,37 @@
 #define ZBX_SQL_ITEM_SELECT	ZBX_SQL_ITEM_FIELDS " from " ZBX_SQL_ITEM_TABLES
 
 #ifdef HAVE_ORACLE
-#define	DBbegin_multiple_update(sql, sql_alloc, sql_offset)	zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "begin\n")
-#define	DBend_multiple_update(sql, sql_alloc, sql_offset)	zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "end;")
+#	define ZBX_PLSQL_BEGIN	"begin\n"
+#	define ZBX_PLSQL_END	"end;"
+#	define	DBbegin_multiple_update(sql, sql_alloc, sql_offset)			\
+			zbx_strcpy_alloc(sql, sql_alloc, sql_offset, ZBX_PLSQL_BEGIN)
+#	define	DBend_multiple_update(sql, sql_alloc, sql_offset)			\
+			zbx_strcpy_alloc(sql, sql_alloc, sql_offset, ZBX_PLSQL_END)
+#	if 0 == ZBX_MAX_OVERFLOW_SQL_SIZE
+#		define	ZBX_SQL_EXEC_FROM	ZBX_CONST_STRLEN(ZBX_PLSQL_BEGIN)
+#	else
+#		define	ZBX_SQL_EXEC_FROM	0
+#	endif
 
-#define	ZBX_SQL_STRCMP		"%s%s%s"
-#define	ZBX_SQL_STRVAL_EQ(str)	'\0' != *str ? "='"  : "",		\
-				'\0' != *str ? str   : " is null",	\
-				'\0' != *str ? "'"   : ""
-#define	ZBX_SQL_STRVAL_NE(str)	'\0' != *str ? "<>'" : "",		\
-				'\0' != *str ? str   : " is not null",	\
-				'\0' != *str ? "'"   : ""
+#	define	ZBX_SQL_STRCMP		"%s%s%s"
+#	define	ZBX_SQL_STRVAL_EQ(str)				\
+			'\0' != *str ? "='"  : "",		\
+			'\0' != *str ? str   : " is null",	\
+			'\0' != *str ? "'"   : ""
+#	define	ZBX_SQL_STRVAL_NE(str)				\
+			'\0' != *str ? "<>'" : "",		\
+			'\0' != *str ? str   : " is not null",	\
+			'\0' != *str ? "'"   : ""
+
 #else
-#define	DBbegin_multiple_update(sql, sql_alloc, sql_offset)
-#define	DBend_multiple_update(sql, sql_alloc, sql_offset)
+#	define	DBbegin_multiple_update(sql, sql_alloc, sql_offset)	do {} while (0)
+#	define	DBend_multiple_update(sql, sql_alloc, sql_offset)	do {} while (0)
 
-#define	ZBX_SQL_STRCMP		"%s'%s'"
-#define	ZBX_SQL_STRVAL_EQ(str)	"=", str
-#define	ZBX_SQL_STRVAL_NE(str)	"<>", str
+#	define	ZBX_SQL_EXEC_FROM	0
+
+#	define	ZBX_SQL_STRCMP		"%s'%s'"
+#	define	ZBX_SQL_STRVAL_EQ(str)	"=", str
+#	define	ZBX_SQL_STRVAL_NE(str)	"<>", str
 #endif
 
 #define ZBX_SQL_NULLCMP(f1, f2)	"((" f1 " is null and " f2 " is null) or " f1 "=" f2 ")"
Index: include/zbxdb.h
===================================================================
--- include/zbxdb.h	(revision 90998)
+++ include/zbxdb.h	(working copy)
@@ -29,6 +29,19 @@
 #define ZBX_DB_WAIT_DOWN	10
 
 #define ZBX_MAX_SQL_SIZE	262144	/* 256KB */
+#ifndef ZBX_MAX_OVERFLOW_SQL_SIZE
+#	ifdef HAVE_ORACLE
+		/* Do not use "overflowing" (multi-statement) queries for Oracle. */
+		/* Zabbix benefits from cursor_sharing=force Oracle parameter */
+		/* which doesn't apply to PL/SQL blocks. */
+#		define ZBX_MAX_OVERFLOW_SQL_SIZE	0
+#	else
+#		define ZBX_MAX_OVERFLOW_SQL_SIZE	ZBX_MAX_SQL_SIZE
+#	endif
+#elif 0 != ZBX_MAX_OVERFLOW_SQL_SIZE && \
+		(1024 > ZBX_MAX_OVERFLOW_SQL_SIZE || ZBX_MAX_OVERFLOW_SQL_SIZE > ZBX_MAX_SQL_SIZE)
+#error ZBX_MAX_OVERFLOW_SQL_SIZE is out of range
+#endif
 
 typedef char	**DB_ROW;
 typedef struct zbx_db_result	*DB_RESULT;
Index: src/libs/zbxdbhigh/db.c
===================================================================
--- src/libs/zbxdbhigh/db.c	(revision 90998)
+++ src/libs/zbxdbhigh/db.c	(working copy)
@@ -1541,7 +1541,7 @@
 {
 	int	ret = SUCCEED;
 
-	if (ZBX_MAX_SQL_SIZE < *sql_offset)
+	if (ZBX_MAX_OVERFLOW_SQL_SIZE < *sql_offset)
 	{
 #ifdef HAVE_MULTIROW_INSERT
 		if (',' == (*sql)[*sql_offset - 1])
@@ -1550,10 +1550,25 @@
 			zbx_strcpy_alloc(sql, sql_alloc, sql_offset, ";\n");
 		}
 #endif
+#if defined(HAVE_ORACLE) && 0 == ZBX_MAX_OVERFLOW_SQL_SIZE
+		/* make sure we are not called twice without */
+		/* putting a new sql into the buffer first */
+		if (*sql_offset <= ZBX_SQL_EXEC_FROM)
+		{
+			THIS_SHOULD_NEVER_HAPPEN;
+			return ret;
+		}
+
+		/* Oracle fails with ORA-00911 if it encounters ';' w/o PL/SQL block */
+		zbx_rtrim(*sql, ZBX_WHITESPACE ";");
+#else
 		DBend_multiple_update(sql, sql_alloc, sql_offset);
+#endif
+		/* For Oracle with max_overflow_sql_size == 0, jump over "begin\n" */
+		/* before execution. ZBX_SQL_EXEC_FROM is 0 for all other cases. */
+		if (ZBX_DB_OK > DBexecute("%s", *sql + ZBX_SQL_EXEC_FROM))
+			ret = FAIL;
 
-		if (ZBX_DB_OK > DBexecute("%s", *sql))
-			ret = FAIL;
 		*sql_offset = 0;
 
 		DBbegin_multiple_update(sql, sql_alloc, sql_offset);
Index: src/libs/zbxdbhigh/lld_item.c
===================================================================
--- src/libs/zbxdbhigh/lld_item.c	(revision 90998)
+++ src/libs/zbxdbhigh/lld_item.c	(working copy)
@@ -1603,8 +1603,7 @@
  *                                                                            *
  * Purpose: prepare sql to update LLD item                                    *
  *                                                                            *
- * Parameters: hostid               - [IN] parent host id                     *
- *             item_prototypes      - [IN] item prototypes                    *
+ * Parameters: item_prototype       - [IN] item prototype                     *
  *             item                 - [IN] item to be updated                 *
  *             sql                  - [IN/OUT] sql buffer pointer used for    *
  *                                             update operations              *
@@ -1614,26 +1613,12 @@
  *                                             buffer                         *
  *                                                                            *
  ******************************************************************************/
-static void	lld_item_prepare_update(const zbx_vector_ptr_t *item_prototypes, const zbx_lld_item_t *item, char **sql,
-		size_t *sql_alloc, size_t *sql_offset)
+static void	lld_item_prepare_update(const zbx_lld_item_prototype_t *item_prototype, const zbx_lld_item_t *item,
+		char **sql, size_t *sql_alloc, size_t *sql_offset)
 {
-	const zbx_lld_item_prototype_t	*item_prototype;
 	char				*value_esc;
 	const char			*d = "";
-	int				index;
 
-	if (0 == (item->flags & ZBX_FLAG_LLD_ITEM_DISCOVERED) || 0 == (item->flags & ZBX_FLAG_LLD_ITEM_UPDATE))
-		return;
-
-	if (FAIL == (index = zbx_vector_ptr_bsearch(item_prototypes, &item->parent_itemid,
-			ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
-	{
-		THIS_SHOULD_NEVER_HAPPEN;
-		return;
-	}
-
-	item_prototype = item_prototypes->values[index];
-
 	zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "update items set ");
 	if (0 != (item->flags & ZBX_FLAG_LLD_ITEM_UPDATE_NAME))
 	{
@@ -1857,6 +1842,30 @@
 
 	zbx_snprintf_alloc(sql, sql_alloc, sql_offset, " where itemid=" ZBX_FS_UI64 ";\n", item->itemid);
 
+	DBexecute_overflowed_sql(sql, sql_alloc, sql_offset);
+}
+
+/******************************************************************************
+ *                                                                            *
+ * Function: lld_item_discovery_prepare_update                                *
+ *                                                                            *
+ * Purpose: prepare sql to update key in LLD item discovery                   *
+ *                                                                            *
+ * Parameters: item_prototype       - [IN] item prototype                     *
+ *             item                 - [IN] item to be updated                 *
+ *             sql                  - [IN/OUT] sql buffer pointer used for    *
+ *                                             update operations              *
+ *             sql_alloc            - [IN/OUT] sql buffer already allocated   *
+ *                                             memory                         *
+ *             sql_offset           - [IN/OUT] offset for writing within sql  *
+ *                                             buffer                         *
+ *                                                                            *
+ ******************************************************************************/
+static void lld_item_discovery_prepare_update(const zbx_lld_item_prototype_t *item_prototype,
+		const zbx_lld_item_t *item, char **sql, size_t *sql_alloc, size_t *sql_offset)
+{
+	char	*value_esc;
+
 	if (0 != (item->flags & ZBX_FLAG_LLD_ITEM_UPDATE_KEY))
 	{
 		value_esc = DBdyn_escape_string(item_prototype->key);
@@ -1866,9 +1875,12 @@
 				" where itemid=" ZBX_FS_UI64 ";\n",
 				value_esc, item->itemid);
 		zbx_free(value_esc);
+
+		DBexecute_overflowed_sql(sql, sql_alloc, sql_offset);
 	}
 }
 
+
 /******************************************************************************
  *                                                                            *
  * Function: lld_items_save                                                   *
@@ -1969,8 +1981,10 @@
 
 	if (0 != upd_items)
 	{
-		char	*sql = NULL;
-		size_t	sql_alloc = 8 * ZBX_KIBIBYTE, sql_offset = 0;
+		char				*sql = NULL;
+		size_t				sql_alloc = 8 * ZBX_KIBIBYTE, sql_offset = 0;
+		zbx_lld_item_prototype_t	*item_prototype;
+		int				index;
 
 		sql = zbx_malloc(NULL, sql_alloc);
 		DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
@@ -1979,8 +1993,23 @@
 		{
 			item = (zbx_lld_item_t *)items->values[i];
 
-			lld_item_prepare_update(item_prototypes, item, &sql, &sql_alloc, &sql_offset);
-			DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset);
+			if (0 == (item->flags & ZBX_FLAG_LLD_ITEM_DISCOVERED) ||
+					0 == (item->flags & ZBX_FLAG_LLD_ITEM_UPDATE))
+			{
+				continue;
+			}
+
+			if (FAIL == (index = zbx_vector_ptr_bsearch(item_prototypes, &item->parent_itemid,
+					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
+			{
+				THIS_SHOULD_NEVER_HAPPEN;
+				continue;
+			}
+
+			item_prototype = item_prototypes->values[index];
+
+			lld_item_prepare_update(item_prototype, item, &sql, &sql_alloc, &sql_offset);
+			lld_item_discovery_prepare_update(item_prototype, item, &sql, &sql_alloc, &sql_offset);
 		}
 
 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
@@ -2241,9 +2270,6 @@
 
 	for (i = 0; i < applications->values_num; i++)
 	{
-		DBexecute_overflowed_sql(&sql_a, &sql_a_alloc, &sql_a_offset);
-		DBexecute_overflowed_sql(&sql_ad, &sql_ad_alloc, &sql_ad_offset);
-
 		application = (zbx_lld_application_t *)applications->values[i];
 
 		if (0 != (application->flags & ZBX_FLAG_LLD_APPLICATION_REMOVE_DISCOVERY))
@@ -2273,6 +2299,11 @@
 
 		if (0 != (application->flags & ZBX_FLAG_LLD_APPLICATION_UPDATE_NAME))
 		{
+			if (NULL == sql_a)
+				DBbegin_multiple_update(&sql_a, &sql_a_alloc, &sql_a_offset);
+			if (NULL == sql_ad)
+				DBbegin_multiple_update(&sql_ad, &sql_ad_alloc, &sql_ad_offset);
+
 			name = DBdyn_escape_string(application->name);
 			zbx_snprintf_alloc(&sql_a, &sql_a_alloc, &sql_a_offset,
 					"update applications set name='%s'"
@@ -2286,6 +2317,10 @@
 					" where application_discoveryid=" ZBX_FS_UI64 ";\n",
 					name, application->application_discoveryid);
 			zbx_free(name);
+
+			DBexecute_overflowed_sql(&sql_a, &sql_a_alloc, &sql_a_offset);
+			DBexecute_overflowed_sql(&sql_ad, &sql_ad_alloc, &sql_ad_offset);
+
 			continue;
 		}
 
@@ -2298,34 +2333,49 @@
 				application_prototype->name);
 	}
 
+	if (NULL != sql_a)
+	{
+		DBend_multiple_update(&sql_a, &sql_a_alloc, &sql_a_offset);
+
+		if (16 < sql_a_offset)	/* in ORACLE always present begin..end; */
+			DBexecute("%s", sql_a);
+	}
+
+	if (NULL != sql_ad)
+	{
+		DBend_multiple_update(&sql_ad, &sql_ad_alloc, &sql_ad_offset);
+
+		if (16 < sql_ad_offset)
+			DBexecute("%s", sql_ad);
+	}
+
 	if (0 != del_applicationids.values_num)
 	{
+		sql_a_offset = 0;
+
 		zbx_strcpy_alloc(&sql_a, &sql_a_alloc, &sql_a_offset, "delete from applications where");
 		DBadd_condition_alloc(&sql_a, &sql_a_alloc, &sql_a_offset, "applicationid", del_applicationids.values,
 				del_applicationids.values_num);
 		zbx_strcpy_alloc(&sql_a, &sql_a_alloc, &sql_a_offset, ";\n");
+
+		DBexecute("%s", sql_a);
 	}
 
 	if (0 != del_discoveryids.values_num)
 	{
+		sql_ad_offset = 0;
+
 		zbx_strcpy_alloc(&sql_a, &sql_a_alloc, &sql_a_offset, "delete from application_discovery where");
 		DBadd_condition_alloc(&sql_a, &sql_a_alloc, &sql_a_offset, "application_discoveryid",
 				del_discoveryids.values, del_discoveryids.values_num);
 		zbx_strcpy_alloc(&sql_a, &sql_a_alloc, &sql_a_offset, ";\n");
-	}
 
-	if (NULL != sql_a)
-	{
-		DBexecute("%s", sql_a);
-		zbx_free(sql_a);
-	}
-
-	if (NULL != sql_ad)
-	{
 		DBexecute("%s", sql_ad);
-		zbx_free(sql_ad);
 	}
 
+	zbx_free(sql_a);
+	zbx_free(sql_ad);
+
 	if (0 != new_applications)
 	{
 		zbx_db_insert_execute(&db_insert);
@@ -2601,6 +2651,8 @@
 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "itemid",
 				ts_itemids.values, ts_itemids.values_num);
 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
+
+		DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset);
 	}
 
 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
@@ -2791,6 +2843,8 @@
 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "applicationid", del_applicationids.values,
 				del_applicationids.values_num);
 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
+
+		DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset);
 	}
 
 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
@@ -3077,11 +3131,14 @@
 static void	lld_application_make(const zbx_lld_application_prototype_t *application_prototype,
 		const zbx_lld_row_t *lld_row, zbx_vector_ptr_t *applications, zbx_hashset_t *applications_index)
 {
+	const char			*__function_name = "lld_application_make";
 	zbx_lld_application_t		*application;
 	zbx_lld_application_index_t	*application_index, application_index_local;
 	struct zbx_json_parse		*jp_row = (struct zbx_json_parse *)&lld_row->jp_row;
 	char				*buffer = NULL;
 
+	zabbix_log(LOG_LEVEL_DEBUG, "In %s(), proto %s", __function_name, application_prototype->name);
+
 	application_index_local.application_prototypeid = application_prototype->application_prototypeid;
 	application_index_local.lld_row = lld_row;
 
@@ -3105,6 +3162,9 @@
 
 		application_index_local.application = application;
 		zbx_hashset_insert(applications_index, &application_index_local, sizeof(zbx_lld_application_index_t));
+
+		zabbix_log(LOG_LEVEL_TRACE, "%s(): created new application, proto %s, name %s", __function_name,
+				application_prototype->name, application->name);
 	}
 	else
 	{
@@ -3121,6 +3181,8 @@
 				application->name_orig = application->name;
 				application->name = buffer;
 				application->flags |= ZBX_FLAG_LLD_APPLICATION_UPDATE_NAME;
+				zabbix_log(LOG_LEVEL_TRACE, "%s(): updated application name to %s", __function_name,
+						application->name);
 			}
 			else
 				zbx_free(buffer);
@@ -3128,6 +3190,8 @@
 	}
 
 	application->flags |= ZBX_FLAG_LLD_APPLICATION_DISCOVERED;
+
+	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
 }
 
 /******************************************************************************
Index: src/libs/zbxdbhigh/proxy.c
===================================================================
--- src/libs/zbxdbhigh/proxy.c	(revision 90998)
+++ src/libs/zbxdbhigh/proxy.c	(working copy)
@@ -1464,6 +1464,9 @@
 			{
 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where %s=" ZBX_FS_UI64 ";\n",
 						table->recid, recid);
+
+				if (SUCCEED != DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset))
+					goto clean;
 			}
 			else
 			{
@@ -1470,13 +1473,10 @@
 				sql_offset = tmp_offset;	/* discard this update, all fields are the same */
 				*(sql + sql_offset) = '\0';
 			}
-
-			if (SUCCEED != DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset))
-				goto clean;
 		}
 	}
 
-	if (sql_offset > 16)	/* in ORACLE always present begin..end; */
+	if (16 < sql_offset)	/* in ORACLE always present begin..end; */
 	{
 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
 
Index: src/zabbix_server/alerter/alert_manager.c
===================================================================
--- src/zabbix_server/alerter/alert_manager.c	(revision 90998)
+++ src/zabbix_server/alerter/alert_manager.c	(working copy)
@@ -1401,13 +1401,23 @@
 	if (ZBX_DB_DOWN == zbx_db_begin())
 		goto cleanup;
 
-	for (i = 0; i < updates.values_num; i += 100)
+#if defined(HAVE_ORACLE) && 0 == ZBX_MAX_OVERFLOW_SQL_SIZE
+#	define ZBX_SQL_UPDATE_BATCH_SIZE	1
+#	define ZBX_SQL_DELIMITER
+#else
+#	define ZBX_SQL_UPDATE_BATCH_SIZE	100
+#	define ZBX_SQL_DELIMITER		";\n"
+#endif
+
+	for (i = 0; i < updates.values_num; i += ZBX_SQL_UPDATE_BATCH_SIZE)
 	{
 		sql_offset = 0;
 
-		limit = MIN(i + 100, updates.values_num);
+		limit = MIN(i + ZBX_SQL_UPDATE_BATCH_SIZE, updates.values_num);
 
+#if !defined(HAVE_ORACLE) || 0 != ZBX_MAX_OVERFLOW_SQL_SIZE
 		DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
+#endif
 
 		for (j = i; j < limit; j++)
 		{
@@ -1420,15 +1430,17 @@
 					" set status=%d,"
 						"retries=%d,"
 						"error='%s'"
-					" where alertid=" ZBX_FS_UI64 ";\n",
+					" where alertid=" ZBX_FS_UI64 ZBX_SQL_DELIMITER,
 					update->status, update->retries, error_esc, update->alertid);
 
 			zbx_free(error_esc);
 		}
 
+#if !defined(HAVE_ORACLE) || 0 != ZBX_MAX_OVERFLOW_SQL_SIZE
 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
+#endif
 
-		if (ZBX_DB_DOWN == DBexecute_once("%s", sql))
+		if (16 < sql_offset && ZBX_DB_DOWN == DBexecute_once("%s", sql))
 			goto cleanup;
 	}
 
Index: .
===================================================================
--- .	(revision 90998)
+++ .	(working copy)

Property changes on: .
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,2 ##
   Merged /branches/4.0:r90992
   Merged /branches/dev/ZBX-15798:r90866-90983
