From d3b267ab028106f890e14adac6ddfa0b9e3f42cb Mon Sep 17 00:00:00 2001 From: FredericoFalcao Date: Sat, 7 Jun 2025 15:05:11 +0300 Subject: [PATCH] Add sql_read_and_hydrate utility --- install/SYS_PRD_BND.PyPi.sql | 8 ++++ plt/generatePythonTriggerCode.inc.php | 51 ++++++++++++++++++++ plt/runSandboxedPython.inc.php | 49 +++++++++++++++++++ sys.php | 68 +++++++++++++++++++++++++++ 4 files changed, 176 insertions(+) create mode 100644 install/SYS_PRD_BND.PyPi.sql create mode 100644 plt/generatePythonTriggerCode.inc.php create mode 100644 plt/runSandboxedPython.inc.php diff --git a/install/SYS_PRD_BND.PyPi.sql b/install/SYS_PRD_BND.PyPi.sql new file mode 100644 index 0000000..625dac9 --- /dev/null +++ b/install/SYS_PRD_BND.PyPi.sql @@ -0,0 +1,8 @@ +USE SYS_PRD_BND; +CREATE TABLE `PyPi` ( + `LibName` varchar(255) NOT NULL, + `AliasName` varchar(255) DEFAULT NULL, + `LastUpdated` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), + PRIMARY KEY (`LibName`) +); + diff --git a/plt/generatePythonTriggerCode.inc.php b/plt/generatePythonTriggerCode.inc.php new file mode 100644 index 0000000..f185cde --- /dev/null +++ b/plt/generatePythonTriggerCode.inc.php @@ -0,0 +1,51 @@ + ' ' . $line, explode("\n", $pyCode))); + + // Assemble complete Python script + $pythonCode = << ['pipe', 'w'], // stdout + 2 => ['pipe', 'w'], // stderr + ]; + + // Execute the Python code using proc_open + $process = proc_open($command, $descriptorspec, $pipes); + + if (!is_resource($process)) { + unlink($tempFile); + throw new Exception('Failed to execute sandboxed Python code.'); + } + + // Capture stdout and stderr + $stdout = stream_get_contents($pipes[1]); + fclose($pipes[1]); + + $stderr = stream_get_contents($pipes[2]); + fclose($pipes[2]); + + // Get the exit code + $exitCode = proc_close($process); + + // Cleanup temporary file + unlink($tempFile); + + return $exitCode; +} diff --git a/sys.php b/sys.php index a8ed32e..30f3cf6 100755 --- a/sys.php +++ b/sys.php @@ -66,3 +66,71 @@ function getTblPrimaryKeyColName($tblName) { return $cols; } +/** + * Executes a SELECT query and hydrates any foreign key columns with the + * referenced row data. + * + * The query should target a single table (e.g., "SELECT * FROM db.table WHERE …"). + * For each foreign key in that table, an additional key named + * `_ref` is added to each returned row containing the referenced row + * from the foreign table. + * + * @param string $query SQL SELECT statement for a single table. + * @return array Result set with hydrated foreign key data. + */ +function sql_read_and_hydrate($query) { + $rows = sql_read($query); + if (empty($rows)) { + return $rows; + } + + if (!preg_match('/FROM\s+([`\w\.]+)/i', $query, $m)) { + return $rows; // Unable to determine table + } + + $table = str_replace('`', '', $m[1]); + if (strpos($table, '.') !== false) { + list($dbName, $tblName) = explode('.', $table, 2); + } else { + $dbName = DB_NAME; + $tblName = $table; + } + + $fks = sql_read( + "SELECT COLUMN_NAME, REFERENCED_TABLE_SCHEMA, REFERENCED_TABLE_NAME, " . + "REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE " . + "WHERE TABLE_SCHEMA = '$dbName' AND TABLE_NAME = '$tblName' " . + "AND REFERENCED_TABLE_NAME IS NOT NULL" + ); + + if (empty($fks)) { + return $rows; // no foreign keys + } + + foreach ($rows as &$row) { + foreach ($fks as $fk) { + $col = $fk['COLUMN_NAME']; + if (!isset($row[$col])) { + continue; + } + + $val = $row[$col]; + if ($val === null) { + $row[$col . '_ref'] = null; + continue; + } + + $refTable = $fk['REFERENCED_TABLE_SCHEMA'] . '.' . $fk['REFERENCED_TABLE_NAME']; + $refCol = $fk['REFERENCED_COLUMN_NAME']; + $condition = is_numeric($val) + ? "$refCol = $val" + : "$refCol = '" . str_replace("'", "''", $val) . "'"; + $refRow = sql_read("SELECT * FROM $refTable WHERE $condition LIMIT 1"); + $row[$col . '_ref'] = $refRow[0] ?? null; + } + } + unset($row); + + return $rows; +} +