'$LastUpdated'"); foreach ($rowsToProcess as $unprocessedRow) { processTableRow($activeTable, $unprocessedRow); } } /** * Ensures the 'LastUpdated' column exists, adding it if missing. */ function ensureLastUpdatedColumnExists($_tableName) { echo "Ensuring LastUpdated column is created if not exists..\n"; list($dbName,$tableName) = (strpos($_tableName,".") ? explode(".",$_tableName) : ["",$_tableName]); sql((empty($dbName)?"":"USE $dbName; ")."ALTER TABLE `$tableName` ADD COLUMN IF NOT EXISTS LastUpdated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"); } /** * Processes an individual row for triggers. */ function processTableRow($activeTable, $unprocessedRow) { $functionName = "handleNew" . str_replace(".", "__", $activeTable["Name"]) . "Row"; if (function_exists($functionName)) { runSystemLevelTrigger($functionName, $activeTable, $unprocessedRow); } if (!empty($activeTable['onUpdate_phpCode'])) { runPHPCodeTrigger($functionName, $activeTable, $unprocessedRow); } if (!empty($activeTable['onUpdate_pyCode'])) { runPythonCodeTrigger($functionName, $activeTable, $unprocessedRow); } } /** * Executes system-level PHP trigger function. */ function runSystemLevelTrigger($functionName, $activeTable, &$row) { echo "Calling system-level function " . greenText($functionName) . "\n"; $error = ''; if ($functionName($row, $error) === false) { updateTriggerError($activeTable['Name'], $error); } else { clearTriggerError($activeTable['Name']); } } /** * Executes database-level dynamic PHP trigger code. */ function runPHPCodeTrigger($functionName, $activeTable, $row) { echo "Running PHP Code trigger...\n"; $phpCode = generatePHPTriggerCode($functionName, $activeTable['onUpdate_phpCode'], $row); $result = runSandboxedPHP($phpCode,$stdout,$stderr); handleTriggerExecutionResult($result, $stdout,$stderr,$row, $activeTable); } /** * Executes database-level dynamic Python trigger code. */ function runPythonCodeTrigger($functionName, $activeTable, $row) { echo "Running Python Code trigger...\n"; $pyCode = generatePythonTriggerCode($functionName, $activeTable['onUpdate_pyCode'], $row); $result = runSandboxedPython($pyCode,$stdout,$stderr); handleTriggerExecutionResult($result, $stdout, $stderr, $row, $activeTable); } /** * Helper functions implementations. */ function updateDatabaseRow($tableName, $originalRow, $newRowValue) { if (empty($originalRow) || empty($newRowValue)) return; $pkColsName = getTblPrimaryKeyColName($tableName); $pkColsValues = array_map(fn($cName) => $originalRow[$cName], $pkColsName); $setStatements = []; foreach ($newRowValue as $k => $v) { $value = is_numeric($v) ? $v : "'" . str_replace("'", "''", is_string($v)?$v:json_encode($v)) . "'"; $setStatements[] = "$k = $value"; } $whereStatements = []; foreach ($pkColsName as $k) { $val = is_numeric($originalRow[$k]) ? $originalRow[$k] : "'" . $originalRow[$k] . "'"; $whereStatements[] = "$k = $val"; } $sql_instruction = "UPDATE $tableName SET " . implode(", ", $setStatements) . " WHERE " . implode(" AND ", $whereStatements); sql($sql_instruction); } function updateTriggerError($tableName, $error) { sql("UPDATE SYS_PRD_BND.Tables SET LastError = '" . str_replace("'", '"', $error) . "', LastUpdated = NOW() WHERE Name = '$tableName'"); sendTelegramMessage("*ERROR* on trigger function for table $tableName : " . $error, "DatabaseGroup"); } function clearTriggerError($tableName) { sql("UPDATE SYS_PRD_BND.Tables SET LastError = '', LastUpdated = NOW() WHERE Name = '$tableName'"); } function getConstantsDefinition() { $constants = ""; foreach (sql("SELECT Name, Type, Value FROM SYS_PRD_BND.Constants") as $const) { $value = $const["Type"] != "String" ? $const["Value"] : '"' . $const["Value"] . '"'; $constants .= "define(\"{$const['Name']}\", $value);\n"; } return $constants; } function getSupportFunctionsDefinition() { $supportFunctions = ""; foreach (sql("SELECT Name, InputArgs_json, PhpCode FROM SYS_PRD_BND.SupportFunctions WHERE PhpCode IS NOT NULL") as $f) { $args = implode(", ", array_map(fn($s) => "\$$s", array_keys(json_decode($f["InputArgs_json"], true)))); $supportFunctions .= "function {$f['Name']}($args) {\n{$f['PhpCode']}\n}\n"; } return $supportFunctions; } function getPythonImports() { $imports = ""; foreach (sql("SELECT LibName, AliasName FROM SYS_PRD_BND.PyPi") as $module) { $alias = !empty($module["AliasName"]) ? " as {$module['AliasName']}" : ""; $imports .= "import {$module['LibName']}{$alias}\n"; } return $imports; } function greenText($string) { $green = "\033[0;32m"; $reset = "\033[0m"; return $green . $string . $reset ; } function blueText($string) { $green = "\033[0;34m"; $reset = "\033[0m"; return $green . $string . $reset ; } function redText($string) { $green = "\033[0;31m"; $reset = "\033[0m"; return $green . $string . $reset ; } function sendTelegramMessage($message, $dstUsers) { global $BOT_TOKEN, $CHAT_IDS; if (is_string($dstUsers)) $dstUsers = [$dstUsers]; foreach($dstUsers as $dstUser) { if (!isset($CHAT_IDS[$dstUser])) continue; else $CHAT_ID = $CHAT_IDS[$dstUser]; $JSON_RAW_DATA = json_encode([ 'chat_id' => $CHAT_ID, 'text' => $message, 'parse_mode' => 'markdown' ]); $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, "https://api.telegram.org/bot$BOT_TOKEN/sendMessage"); curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json')); curl_setopt($curl, CURLOPT_POST, 1); curl_setopt($curl, CURLOPT_POSTFIELDS, $JSON_RAW_DATA); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($curl); //print_r($response); curl_close($curl); } }