See nmudiff...

On Tue, Aug 19, 2025 at 1:25 AM Leandro Cunha
<[email protected]> wrote:
>
> Control: tags 1110464 + patch
> Control: tags 1110464 + pending
>
> Dear maintainer,
>
> I've prepared an NMU for libphp-adodb (versioned as 5.22.10-0.1) and
> uploaded it to DELAYED/2. Please feel free to tell me if I
> should cancel it.
>
> Regards.
diffstat for libphp-adodb-5.22.9 libphp-adodb-5.22.10

 adodb.inc.php                 |    2 
 debian/changelog              |    7 +
 docs/changelog.md             |   18 +++
 drivers/adodb-sqlite3.inc.php |  209 +++++++++++++++---------------------------
 4 files changed, 105 insertions(+), 131 deletions(-)

diff -Nru libphp-adodb-5.22.9/adodb.inc.php libphp-adodb-5.22.10/adodb.inc.php
--- libphp-adodb-5.22.9/adodb.inc.php	2025-05-01 08:49:24.000000000 -0300
+++ libphp-adodb-5.22.10/adodb.inc.php	2025-08-03 13:20:39.000000000 -0300
@@ -198,7 +198,7 @@
 		/**
 		 * ADODB version as a string.
 		 */
-		$ADODB_vers = 'v5.22.9  2025-05-01';
+		$ADODB_vers = 'v5.22.10  2025-08-03';
 
 		/**
 		 * Determines whether recordset->RecordCount() is used.
diff -Nru libphp-adodb-5.22.9/debian/changelog libphp-adodb-5.22.10/debian/changelog
--- libphp-adodb-5.22.9/debian/changelog	2025-05-02 10:48:03.000000000 -0300
+++ libphp-adodb-5.22.10/debian/changelog	2025-08-18 23:30:17.000000000 -0300
@@ -1,3 +1,10 @@
+libphp-adodb (5.22.10-0.1) unstable; urgency=high
+
+  * Non-maintainer upload.
+  * New upstream version 5.22.10 (Closes: #1110464, CVE-2025-54119)
+
+ -- Leandro Cunha <[email protected]>  Mon, 18 Aug 2025 23:30:17 -0300
+
 libphp-adodb (5.22.9-0.1) unstable; urgency=high
 
   * Non-maintainer upload.
diff -Nru libphp-adodb-5.22.9/docs/changelog.md libphp-adodb-5.22.10/docs/changelog.md
--- libphp-adodb-5.22.9/docs/changelog.md	2025-05-01 08:49:24.000000000 -0300
+++ libphp-adodb-5.22.10/docs/changelog.md	2025-08-03 13:20:39.000000000 -0300
@@ -14,6 +14,23 @@
 
 --------------------------------------------------------------------------------
 
+## [5.22.10] - 2025-08-03
+
+### Security
+
+- pgsql: SQL injection in pg_insert_id() method (CVE-2025-54119)
+  [#1083](https://github.com/ADOdb/ADOdb/issues/1083)
+
+### Fixed
+
+- sqlite: metaForeignKeys() returns nothing when FOREIGN keyword is in lower case
+  [#1078](https://github.com/ADOdb/ADOdb/issues/1078)
+- sqlite: metaForeignKeys() does not support column-levels constraints
+  [#1079](https://github.com/ADOdb/ADOdb/issues/1079)
+- sqlite: metaForeignKeys() composite foreign keys are not supported
+  [#1080](https://github.com/ADOdb/ADOdb/issues/1080)
+
+
 ## [5.22.9] - 2025-05-01
 
 ### Security
@@ -1490,6 +1507,7 @@
 - Adodb5 version,more error checking code now will use exceptions if available.
 
 
+[5.22.10]: https://github.com/adodb/adodb/compare/v5.22.9...v5.22.10
 [5.22.9]: https://github.com/adodb/adodb/compare/v5.22.8...v5.22.9
 [5.22.8]: https://github.com/adodb/adodb/compare/v5.22.7...v5.22.8
 [5.22.7]: https://github.com/adodb/adodb/compare/v5.22.6...v5.22.7
diff -Nru libphp-adodb-5.22.9/drivers/adodb-sqlite3.inc.php libphp-adodb-5.22.10/drivers/adodb-sqlite3.inc.php
--- libphp-adodb-5.22.9/drivers/adodb-sqlite3.inc.php	2025-05-01 08:49:24.000000000 -0300
+++ libphp-adodb-5.22.10/drivers/adodb-sqlite3.inc.php	2025-08-03 13:20:39.000000000 -0300
@@ -19,6 +19,9 @@
  *
  * @copyright 2000-2013 John Lim
  * @copyright 2014 Damien Regad, Mark Newnham and the ADOdb community
+ *
+ * @TODO Duplicate code is due to the legacy sqlite driver - delete this when removing the old driver
+ * @noinspection DuplicatedCode
  */
 
 // security - hide paths
@@ -95,7 +98,6 @@
 		{
 			$fieldobj = $t;
 			$t = $fieldobj->type;
-			$len = $fieldobj->max_length;
 		}
 
 		$t = strtoupper($t);
@@ -162,28 +164,30 @@
 	function MetaColumns($table, $normalize=true)
 	{
 		global $ADODB_FETCH_MODE;
-		$false = false;
 		$save = $ADODB_FETCH_MODE;
 		$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
 		if ($this->fetchMode !== false) {
 			$savem = $this->SetFetchMode(false);
 		}
-		$rs = $this->Execute("PRAGMA table_info('$table')");
+
+		$rs = $this->execute("PRAGMA table_info(?)", array($table));
+
 		if (isset($savem)) {
 			$this->SetFetchMode($savem);
 		}
+
 		if (!$rs) {
 			$ADODB_FETCH_MODE = $save;
-			return $false;
+			return false;
 		}
+
 		$arr = array();
 		while ($r = $rs->FetchRow()) {
-			$type = explode('(',$r['type']);
+			$type = explode('(', $r['type']);
 			$size = '';
-			if (sizeof($type)==2) {
-				$size = trim($type[1],')');
+			if (sizeof($type) == 2) {
+				$size = trim($type[1], ')');
 			}
-			$fn = strtoupper($r['name']);
 			$fld = new ADOFieldObject;
 			$fld->name = $r['name'];
 			$fld->type = $type[0];
@@ -192,7 +196,7 @@
 			$fld->default_value = $r['dflt_value'];
 			$fld->scale = 0;
 			if (isset($r['pk']) && $r['pk']) {
-				$fld->primary_key=1;
+				$fld->primary_key = 1;
 			}
 			if ($save == ADODB_FETCH_NUM) {
 				$arr[] = $fld;
@@ -207,58 +211,44 @@
 
 	public function metaForeignKeys($table, $owner = '', $upper =  false, $associative =  false)
 	{
-	    global $ADODB_FETCH_MODE;
-		if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC
-		|| $this->fetchMode == ADODB_FETCH_ASSOC)
-		$associative = true;
+		global $ADODB_FETCH_MODE;
+		if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) {
+			$associative = true;
+		}
 
-	    /*
-		* Read sqlite master to find foreign keys
-		*/
+		// Read sqlite master to find foreign keys
 		$sql = "SELECT sql
-				 FROM (
-				SELECT sql sql, type type, tbl_name tbl_name, name name
-				  FROM sqlite_master
-			          )
-				WHERE type != 'meta'
-				  AND sql NOTNULL
-				  AND LOWER(name) ='" . strtolower($table) . "'";
-
-		$tableSql = $this->getOne($sql);
+				FROM sqlite_master
+				WHERE sql NOTNULL
+				  AND LOWER(name) = ?";
+		$tableSql = $this->getOne($sql, [strtolower($table)]);
+
+		// Regex will identify foreign keys in both column and table constraints
+		// Reference: https://sqlite.org/syntax/foreign-key-clause.html
+		// Subpatterns: 1/2 = source columns; 3 = parent table; 4 = parent columns.
+		preg_match_all(
+			'/[(,]\s*(?:FOREIGN\s+KEY\s*\(([^)]+)\)|(\w+).*?)\s*REFERENCES\s+(\w+|"[^"]+")\(([^)]+)\)/i',
+			$tableSql,
+			$fkeyMatches,
+			PREG_SET_ORDER
+		);
 
 		$fkeyList = array();
-		$ylist = preg_split("/,+/",$tableSql);
-		foreach ($ylist as $y)
-		{
-			if (!preg_match('/FOREIGN/',$y))
-				continue;
+		foreach ($fkeyMatches as $fkey) {
+			$src_col = $fkey[1] ?: $fkey[2];
+			$ref_table = $upper ? strtoupper($fkey[3]) : $fkey[3];
+			$ref_col = $fkey[4];
 
-			$matches = false;
-			preg_match_all('/\((.+?)\)/i',$y,$matches);
-			$tmatches = false;
-			preg_match_all('/REFERENCES (.+?)\(/i',$y,$tmatches);
-
-			if ($associative)
-			{
-				if (!isset($fkeyList[$tmatches[1][0]]))
-					$fkeyList[$tmatches[1][0]]	= array();
-				$fkeyList[$tmatches[1][0]][$matches[1][0]] = $matches[1][1];
+			if ($associative) {
+				$fkeyList[$ref_table][$src_col] = $ref_col;
+			} else {
+				$fkeyList[$ref_table][] = $src_col . '=' . $ref_col;
 			}
-			else
-				$fkeyList[$tmatches[1][0]][] = $matches[1][0] . '=' . $matches[1][1];
 		}
 
-		if ($associative)
-		{
-			if ($upper)
-				$fkeyList = array_change_key_case($fkeyList,CASE_UPPER);
-			else
-				$fkeyList = array_change_key_case($fkeyList,CASE_LOWER);
-		}
 		return $fkeyList;
 	}
 
-
 	function _init($parentDriver)
 	{
 		$parentDriver->hasTransactions = false;
@@ -371,24 +361,24 @@
 	*/
 	var $_genSeqSQL = "create table %s (id integer)";
 
-	function GenID($seq='adodbseq',$start=1)
+	function GenID($seqname='adodbseq', $startID=1)
 	{
 		// if you have to modify the parameter below, your database is overloaded,
 		// or you need to implement generation of id's yourself!
 		$MAXLOOPS = 100;
 		//$this->debug=1;
 		while (--$MAXLOOPS>=0) {
-			@($num = $this->GetOne("select id from $seq"));
+			@($num = $this->GetOne("select id from $seqname"));
 			if ($num === false) {
-				$this->Execute(sprintf($this->_genSeqSQL ,$seq));
-				$start -= 1;
+				$this->Execute(sprintf($this->_genSeqSQL ,$seqname));
+				$startID -= 1;
 				$num = '0';
-				$ok = $this->Execute("insert into $seq values($start)");
+				$ok = $this->Execute("insert into $seqname values($startID)");
 				if (!$ok) {
 					return false;
 				}
 			}
-			$this->Execute("update $seq set id=id+1 where id=$num");
+			$this->Execute("update $seqname set id=id+1 where id=$num");
 
 			if ($this->affected_rows() > 0) {
 				$num += 1;
@@ -397,7 +387,7 @@
 			}
 		}
 		if ($fn = $this->raiseErrorFn) {
-			$fn($this->databaseType,'GENID',-32000,"Unable to generate unique id after $MAXLOOPS attempts",$seq,$num);
+			$fn($this->databaseType, 'GENID', -32000, "Unable to generate unique id after $MAXLOOPS attempts", $seqname, $num);
 		}
 		return false;
 	}
@@ -430,111 +420,70 @@
 		return $this->_connectionID->close();
 	}
 
-	function metaIndexes($table, $primary = FALSE, $owner = false)
+	function metaIndexes($table, $primary = false, $owner = false)
 	{
-		$false = false;
 		// save old fetch mode
 		global $ADODB_FETCH_MODE;
 		$save = $ADODB_FETCH_MODE;
 		$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
-		if ($this->fetchMode !== FALSE) {
-			$savem = $this->SetFetchMode(FALSE);
-		}
-
-		$pragmaData = array();
-
-		/*
-		* If we want the primary key, we must extract
-		* it from the table statement, and the pragma
-		*/
-		if ($primary)
-		{
-			$sql = sprintf('PRAGMA table_info([%s]);',
-						   strtolower($table)
-						   );
-			$pragmaData = $this->getAll($sql);
+		if ($this->fetchMode !== false) {
+			$savem = $this->SetFetchMode(false);
 		}
 
-		/*
-		* Exclude the empty entry for the primary index
-		*/
-		$sqlite = "SELECT name,sql
-					 FROM sqlite_master
-					WHERE type='index'
-					  AND sql IS NOT NULL
-					  AND LOWER(tbl_name)='%s'";
-
-		$SQL = sprintf($sqlite,
-				     strtolower($table)
-					 );
+		$table = strtolower($table);
 
-		$rs = $this->execute($SQL);
+		// Exclude the empty entry for the primary index
+		$sql = "SELECT name,sql
+				FROM sqlite_master
+				WHERE type='index'
+				  AND sql IS NOT NULL
+				  AND LOWER(tbl_name)=?";
+		$rs = $this->execute($sql, [$table]);
 
 		if (!is_object($rs)) {
 			if (isset($savem)) {
 				$this->SetFetchMode($savem);
 			}
 			$ADODB_FETCH_MODE = $save;
-			return $false;
+			return false;
 		}
 
-		$indexes = array ();
-
-		while ($row = $rs->FetchRow())
-		{
+		$indexes = array();
 
+		while ($row = $rs->FetchRow()) {
 			if (!isset($indexes[$row[0]])) {
 				$indexes[$row[0]] = array(
-					'unique' => preg_match("/unique/i",$row[1]),
-					'columns' => array()
+					'unique' => preg_match("/unique/i", $row[1]),
 				);
 			}
-			/**
-			 * The index elements appear in the SQL statement
-			 * in cols[1] between parentheses
-			 * e.g CREATE UNIQUE INDEX ware_0 ON warehouse (org,warehouse)
-			 */
-			preg_match_all('/\((.*)\)/',$row[1],$indexExpression);
-			$indexes[$row[0]]['columns'] = array_map('trim',explode(',',$indexExpression[1][0]));
+			// Index elements appear in the SQL statement in cols[1] between parentheses
+			// e.g CREATE UNIQUE INDEX ware_0 ON warehouse (org,warehouse)
+			preg_match_all('/\((.*)\)/', $row[1], $indexExpression);
+			$indexes[$row[0]]['columns'] = array_map('trim', explode(',', $indexExpression[1][0]));
 		}
 
-		if (isset($savem)) {
-			$this->SetFetchMode($savem);
-			$ADODB_FETCH_MODE = $save;
-		}
-
-		/*
-		* If we want primary, add it here
-		*/
+		// If we want the primary key, we must extract it from the pragma
 		if ($primary){
-
-			/*
-			* Check the previously retrieved pragma to search
-			* with a closure
-			*/
-
+			$pragmaData = $this->getAll('PRAGMA table_info(?);', [$table]);
 			$pkIndexData = array('unique'=>1,'columns'=>array());
 
 			$pkCallBack = function ($value, $key) use (&$pkIndexData) {
-
-				/*
-				* As we iterate the elements check for pk index and sort
-				*/
-				if ($value[5] > 0)
-				{
+				// As we iterate the elements check for pk index
+				if ($value[5] > 0) {
 					$pkIndexData['columns'][$value[5]] = strtolower($value[1]);
-					ksort($pkIndexData['columns']);
 				}
 			};
+			array_walk($pragmaData, $pkCallBack);
 
-			array_walk($pragmaData,$pkCallBack);
-
-			/*
-			* If we found no columns, there is no
-			* primary index
-			*/
-			if (count($pkIndexData['columns']) > 0)
+			// If we found no columns, there is no primary index
+			if (count($pkIndexData['columns']) > 0) {
 				$indexes['PRIMARY'] = $pkIndexData;
+			}
+		}
+
+		if (isset($savem)) {
+			$this->SetFetchMode($savem);
+			$ADODB_FETCH_MODE = $save;
 		}
 
 		return $indexes;

Reply via email to