diff --git a/interface/code_systems/dataloads_ajax.php b/interface/code_systems/dataloads_ajax.php index ed2404e071a..5e90a91c6c6 100644 --- a/interface/code_systems/dataloads_ajax.php +++ b/interface/code_systems/dataloads_ajax.php @@ -131,7 +131,7 @@ // // placemaker for when support DSMIV //$db_list = array("DSMIV", "ICD9", "ICD10", "RXNORM", "SNOMED"); - $db_list = array("ICD9", "ICD10", "RXNORM", "SNOMED","CQM_VALUESET"); + $db_list = array("ICD10", "RXNORM", "SNOMED","CQM_VALUESET"); foreach ($db_list as $db) { ?>
diff --git a/library/smarty_legacy/smarty/Smarty_Compiler_Legacy.class.php b/library/smarty_legacy/smarty/Smarty_Compiler_Legacy.class.php index ad9198a59d1..02ca1556ba7 100644 --- a/library/smarty_legacy/smarty/Smarty_Compiler_Legacy.class.php +++ b/library/smarty_legacy/smarty/Smarty_Compiler_Legacy.class.php @@ -1526,78 +1526,80 @@ function _parse_is_expr($is_arg, $tokens) */ function _parse_attrs($tag_args) { - - /* Tokenize tag attributes. */ - preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) - )+ | - [=] - ~x', $tag_args, $match); - $tokens = $match[0]; - $attrs = array(); - /* Parse state: - 0 - expecting attribute name - 1 - expecting '=' - 2 - expecting attribute value (not '=') */ - $state = 0; - - foreach ($tokens as $token) { - switch ($state) { - case 0: - /* If the token is a valid identifier, we set attribute name - and go to state 1. */ - if (preg_match('~^\w+$~', $token)) { - $attr_name = $token; - $state = 1; - } else - $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); - break; - case 1: - /* If the token is '=', then we go to state 2. */ - if ($token == '=') { - $state = 2; - } else - $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); - break; + if (!empty($tag_args)) { + /* Tokenize tag attributes. */ + preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) + )+ | + [=] + ~x', $tag_args, $match); + $tokens = $match[0]; + + /* Parse state: + 0 - expecting attribute name + 1 - expecting '=' + 2 - expecting attribute value (not '=') */ + $state = 0; + + foreach ($tokens as $token) { + switch ($state) { + case 0: + /* If the token is a valid identifier, we set attribute name + and go to state 1. */ + if (preg_match('~^\w+$~', $token)) { + $attr_name = $token; + $state = 1; + } else + $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); + break; - case 2: - /* If token is not '=', we set the attribute value and go to - state 0. */ - if ($token != '=') { - /* We booleanize the token if it's a non-quoted possible - boolean value. */ - if (preg_match('~^(on|yes|true)$~', $token)) { - $token = 'true'; - } else if (preg_match('~^(off|no|false)$~', $token)) { - $token = 'false'; - } else if ($token == 'null') { - $token = 'null'; - } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) { - /* treat integer literally */ - } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) { - /* treat as a string, double-quote it escaping quotes */ - $token = '"'.addslashes($token).'"'; - } + case 1: + /* If the token is '=', then we go to state 2. */ + if ($token == '=') { + $state = 2; + } else + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + break; - $attrs[$attr_name] = $token; - $state = 0; - } else - $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); - break; + case 2: + /* If token is not '=', we set the attribute value and go to + state 0. */ + if ($token != '=') { + /* We booleanize the token if it's a non-quoted possible + boolean value. */ + if (preg_match('~^(on|yes|true)$~', $token)) { + $token = 'true'; + } else if (preg_match('~^(off|no|false)$~', $token)) { + $token = 'false'; + } else if ($token == 'null') { + $token = 'null'; + } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) { + /* treat integer literally */ + } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) { + /* treat as a string, double-quote it escaping quotes */ + $token = '"'.addslashes($token).'"'; + } + + $attrs[$attr_name] = $token; + $state = 0; + } else + $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); + break; + } + $last_token = $token; } - $last_token = $token; - } - if($state != 0) { - if($state == 1) { - $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); - } else { - $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); + if($state != 0) { + if($state == 1) { + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + } else { + $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); + } } - } - $this->_parse_vars_props($attrs); + $this->_parse_vars_props($attrs); + } return $attrs; } diff --git a/library/standard_tables_capture.inc.php b/library/standard_tables_capture.inc.php index c748c70d309..633d8eda55b 100644 --- a/library/standard_tables_capture.inc.php +++ b/library/standard_tables_capture.inc.php @@ -12,8 +12,8 @@ * @author Roberto Vasquez * @author Stephen Waite * @copyright Copyright (c) 2011 Phyaura, LLC - * @copyright Copyright (c) 2019 Brady Miller - * @copyright Copyright (c) 2019 Stephen Waite + * @copyright Copyright (c) 2019-2022 Brady Miller + * @copyright Copyright (c) 2019-2022 Stephen Waite * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3 */ @@ -220,7 +220,7 @@ function snomed_import($us_extension = false) $dir = $dir_snomed; $dir = str_replace('\\', '/', $dir); - // executing the create statement for tables, these are defined in snomed_capture.inc file + // executing the create statement for tables, these are defined in snomed_capture.inc.php file // this is skipped if the US extension is being added if (!$us_extension) { foreach ($table_array_for_snomed as $val) { @@ -502,124 +502,79 @@ function icd_import($type) // followed by the field name, position and length of each fixed length text record in the incoming // flat files. There are separate definitions for ICD 9 and 10 based on the type passed in $incoming = array(); - if ($type == 'ICD9') { - $incoming['SHORT_DX'] = array('#TABLENAME#' => "icd9_dx_code", - '#FLD1#' => "dx_code", '#POS1#' => 1, '#LEN1#' => 5, - '#FLD2#' => "short_desc", '#POS2#' => 7, '#LEN2#' => 60); - $incoming['SHORT_SG'] = array('#TABLENAME#' => "icd9_sg_code", - '#FLD1#' => "sg_code", '#POS1#' => 1, '#LEN1#' => 4, - '#FLD2#' => "short_desc", '#POS2#' => 6, '#LEN2#' => 60); - $incoming['LONG_SG'] = array('#TABLENAME#' => "icd9_sg_long_code", - '#FLD1#' => "sg_code", '#POS1#' => 1, '#LEN1#' => 4, - '#FLD2#' => "long_desc", '#POS2#' => 6, '#LEN2#' => 300); - $incoming['LONG_DX'] = array('#TABLENAME#' => "icd9_dx_long_code", - '#FLD1#' => "dx_code", '#POS1#' => 1, '#LEN1#' => 5, - '#FLD2#' => "long_desc", '#POS2#' => 7, '#LEN2#' => 300); - } else { - $incoming['icd10pcs_order_'] = array('#TABLENAME#' => "icd10_pcs_order_code", - '#FLD1#' => "pcs_code", '#POS1#' => 7, '#LEN1#' => 7, - '#FLD2#' => "valid_for_coding", '#POS2#' => 15, '#LEN2#' => 1, - '#FLD3#' => "short_desc", '#POS3#' => 17, '#LEN3#' => 60, - '#FLD4#' => "long_desc", '#POS4#' => 78, '#LEN4#' => 300); - $incoming['icd10cm_order_'] = array('#TABLENAME#' => "icd10_dx_order_code", - '#FLD1#' => "dx_code", '#POS1#' => 7, '#LEN1#' => 7, - '#FLD2#' => "valid_for_coding", '#POS2#' => 15, '#LEN2#' => 1, - '#FLD3#' => "short_desc", '#POS3#' => 17, '#LEN3#' => 60, - '#FLD4#' => "long_desc", '#POS4#' => 78, '#LEN4#' => 300); - $incoming['reimb_map_pr_'] = array('#TABLENAME#' => "icd10_reimbr_pcs_9_10", - '#FLD1#' => "code", '#POS1#' => 1, '#LEN1#' => 7, - '#FLD2#' => "code_cnt", '#POS2#' => 9, '#LEN2#' => 1, - '#FLD3#' => "ICD9_01", '#POS3#' => 11, '#LEN3#' => 5, - '#FLD4#' => "ICD9_02", '#POS4#' => 17, '#LEN4#' => 5, - '#FLD5#' => "ICD9_03", '#POS5#' => 23, '#LEN5#' => 5, - '#FLD6#' => "ICD9_04", '#POS6#' => 29, '#LEN6#' => 5, - '#FLD7#' => "ICD9_05", '#POS7#' => 35, '#LEN7#' => 5, - '#FLD8#' => "ICD9_06", '#POS8#' => 41, '#LEN8#' => 5); - $incoming['reimb_map_dx_'] = array('#TABLENAME#' => "icd10_reimbr_dx_9_10", - '#FLD1#' => "code", '#POS1#' => 1, '#LEN1#' => 7, - '#FLD2#' => "code_cnt", '#POS2#' => 9, '#LEN2#' => 1, - '#FLD3#' => "ICD9_01", '#POS3#' => 11, '#LEN3#' => 5, - '#FLD4#' => "ICD9_02", '#POS4#' => 17, '#LEN4#' => 5, - '#FLD5#' => "ICD9_03", '#POS5#' => 23, '#LEN5#' => 5, - '#FLD6#' => "ICD9_04", '#POS6#' => 29, '#LEN6#' => 5, - '#FLD7#' => "ICD9_05", '#POS7#' => 35, '#LEN7#' => 5, - '#FLD8#' => "ICD9_06", '#POS8#' => 41, '#LEN8#' => 5); - $incoming['I10gem'] = array('#TABLENAME#' => "icd10_gem_dx_10_9", - '#FLD1#' => "dx_icd10_source", '#POS1#' => 1, '#LEN1#' => 7, - '#FLD2#' => "dx_icd9_target", '#POS2#' => 9, '#LEN2#' => 5, - '#FLD3#' => "flags", '#POS3#' => 15, '#LEN3#' => 5); - $incoming['I9gem'] = array('#TABLENAME#' => "icd10_gem_dx_9_10", - '#FLD1#' => "dx_icd9_source", '#POS1#' => 1, '#LEN1#' => 5, - '#FLD2#' => "dx_icd10_target", '#POS2#' => 7, '#LEN2#' => 7, - '#FLD3#' => "flags", '#POS3#' => 15, '#LEN3#' => 5); - $incoming['gem_pcsi9'] = array('#TABLENAME#' => "icd10_gem_pcs_10_9", - '#FLD1#' => "pcs_icd10_source", '#POS1#' => 1, '#LEN1#' => 7, - '#FLD2#' => "pcs_icd9_target", '#POS2#' => 9, '#LEN2#' => 5, - '#FLD3#' => "flags", '#POS3#' => 15, '#LEN3#' => 5); - $incoming['gem_i9pcs'] = array('#TABLENAME#' => "icd10_gem_pcs_9_10", - '#FLD1#' => "pcs_icd9_source", '#POS1#' => 1, '#LEN1#' => 5, - '#FLD2#' => "pcs_icd10_target", '#POS2#' => 7, '#LEN2#' => 7, - '#FLD3#' => "flags", '#POS3#' => 15, '#LEN3#' => 5); - } - - // set up the start of the load script to be appended from the incoming array defined above where incoming - // file matches - $db_load = "LOAD DATA LOCAL INFILE '#INFILE#' INTO TABLE #TABLENAME# FIELDS TERMINATED BY '\0' (@var) SET revision = 0, "; - $col_template = "#FLD# = trim(Substring(@var, #POS#, #LEN#))"; - - // load all data and set active revision + + // find active revision + $res = sqlQueryNoLog("SELECT max(revision) rev FROM icd10_pcs_order_code"); + $next_rev = ($res['rev'] ?? 0) + 1; + $incoming['icd10pcs_codes_'] = array( + 'TABLENAME' => "icd10_pcs_order_code", + 'FLD1' => "pcs_code", 'POS1' => 0, 'LEN1' => 7, + 'FLD2' => "long_desc", 'POS2' => 8, 'LEN2' => 300, + 'REV' => $next_rev + ); + + $res = sqlQueryNoLog("SELECT max(revision) rev FROM icd10_dx_order_code"); + $next_rev = ($res['rev'] ?? 0) + 1; + $incoming['icd10cm_order_'] = array( + 'TABLENAME' => "icd10_dx_order_code", + 'FLD1' => "dx_code", 'POS1' => 6, 'LEN1' => 7, + 'FLD2' => "valid_for_coding", 'POS2' => 14, 'LEN2' => 1, + 'FLD3' => "short_desc", 'POS3' => 16, 'LEN3' => 60, + 'FLD4' => "long_desc", 'POS4' => 77, 'LEN4' => 300, + 'REV' => $next_rev + ); + + // Settings to drastically speed up import with InnoDB + sqlStatementNoLog("SET autocommit=0"); + sqlStatementNoLog("START TRANSACTION"); + + // first inactivate older set(s) + sqlStatementNoLog("UPDATE icd10_pcs_order_code SET active = 0"); + sqlStatementNoLog("UPDATE icd10_dx_order_code SET active = 0"); + if (is_dir($dir) && $handle = opendir($dir)) { while (false !== ($filename = readdir($handle))) { - // bypass unwanted entries - if (!stripos($filename, ".txt") || stripos($filename, "diff") || stripos($filename, "addenda")) { + // bypass unwanted entries + if (!stripos($filename, ".txt") || stripos($filename, "addenda")) { continue; } - // reset the sql load command and susbtitute the filename - $run_sql = $db_load; - $run_sql = str_replace("#INFILE#", $dir . $filename, $run_sql); $keys = array_keys($incoming); while ($this_key = array_pop($keys)) { if (stripos($filename, $this_key) !== false) { - // now substitute the tablename - $run_sql = str_replace("#TABLENAME#", $incoming[$this_key]['#TABLENAME#'], $run_sql); - - // the range defines the maximum number of fields contained - // in any of the incoming files - foreach (range(1, 8) as $field) { - $fld = "#FLD" . $field . "#"; - $nxtfld = "#FLD" . ($field + 1) . "#"; - $pos = "#POS" . $field . "#"; - $len = "#LEN" . $field . "#"; - - // concat this fields template in the sql string - $run_sql .= $col_template; - $run_sql = str_replace("#FLD#", $incoming[$this_key][$fld], $run_sql); - $run_sql = str_replace("#POS#", $incoming[$this_key][$pos], $run_sql); - $run_sql = str_replace("#LEN#", $incoming[$this_key][$len], $run_sql); - // at the end of this table's field list - if (!array_key_exists($nxtfld, $incoming[$this_key])) { - break; + $generator = getFileData($dir . $filename); + foreach ($generator as $value) { + $run_sql = "INSERT INTO `" . $incoming[$this_key]['TABLENAME'] . "` ("; + $sql_place = "("; + $sql_values = []; + foreach (range(1, 4) as $field) { + $fld = "FLD" . $field; + $nxtfld = "FLD" . ($field + 1); + $pos = "POS" . $field; + $len = "LEN" . $field; + $run_sql .= $incoming[$this_key][$fld] . ", "; + $sql_place .= "?, "; + // concat this fields template in the sql string + array_push($sql_values, substr($value, $incoming[$this_key][$pos], $incoming[$this_key][$len])); + if (!array_key_exists($nxtfld, $incoming[$this_key])) { + $run_sql .= "active, revision) VALUES "; + $sql_place .= "?, ?)"; + array_push($sql_values, 1); + array_push($sql_values, $incoming[$this_key]['REV']); + sqlStatementNoLog($run_sql . $sql_place, $sql_values); + break; + } else { + $run_sql .= " "; + $sql_place .= " "; + } } - - $run_sql .= ","; } - - sqlStatement($run_sql); - - // now update the revision for this load - $res = sqlStatement("SELECT max(revision) rev FROM " . escape_table_name($incoming[$this_key]['#TABLENAME#'])); - $row = sqlFetchArray($res); - $next_rev = $row['rev'] + 1; - $run_sql = "UPDATE " . $incoming[$this_key]['#TABLENAME#'] . " SET active = 0"; - sqlQuery($run_sql); - $run_sql = "UPDATE " . $incoming[$this_key]['#TABLENAME#'] . " SET active = 1, revision = ? WHERE revision = 0"; - sqlQuery($run_sql, array($next_rev)); - break; } } } - + // Settings to drastically speed up import with InnoDB + sqlStatementNoLog("COMMIT"); + sqlStatementNoLog("SET autocommit=1"); closedir($handle); } else { echo htmlspecialchars(xl('ERROR: No ICD import directory.'), ENT_NOQUOTES) . "
"; @@ -627,17 +582,8 @@ function icd_import($type) } // now update the tables where necessary - if ($type == 'ICD9') { - sqlStatement("update `icd9_dx_code` SET formatted_dx_code = dx_code"); - sqlStatement("update `icd9_dx_code` SET formatted_dx_code = concat(concat(left(dx_code, 3), '.'), substr(dx_code, 4)) WHERE dx_code RLIKE '^[V0-9]{1}.*' AND LENGTH(dx_code) > 3"); - sqlStatement("update `icd9_dx_code` SET formatted_dx_code = concat(concat(left(dx_code, 4), '.'), substr(dx_code, 5)) WHERE dx_code RLIKE '^[E]{1}.*' AND LENGTH(dx_code) > 4"); - sqlStatement("update `icd9_sg_code` SET formatted_sg_code = concat(concat(left(sg_code, 2), '.'), substr(sg_code, 3))"); - sqlStatement("update `icd9_dx_code` A, `icd9_dx_long_code` B set A.long_desc = B.long_desc where A.dx_code = B.dx_code and A.active = 1 and A.long_desc is NULL"); - sqlStatement("update `icd9_sg_code` A, `icd9_sg_long_code` B set A.long_desc = B.long_desc where A.sg_code = B.sg_code and A.active = 1 and A.long_desc is NULL"); - } else { // ICD 10 - sqlStatement("update `icd10_dx_order_code` SET formatted_dx_code = dx_code"); - sqlStatement("update `icd10_dx_order_code` SET formatted_dx_code = concat(concat(left(dx_code, 3), '.'), substr(dx_code, 4)) WHERE LENGTH(dx_code) > 3"); - } + sqlStatement("update `icd10_dx_order_code` SET formatted_dx_code = dx_code"); + sqlStatement("update `icd10_dx_order_code` SET formatted_dx_code = concat(concat(left(dx_code, 3), '.'), substr(dx_code, 4)) WHERE LENGTH(dx_code) > 3"); // let's fire off an event so people can listen if needed and handle any module upgrading, version checks, // or any manual processing that needs to occur. @@ -659,7 +605,7 @@ function valueset_import($type) } $dir_valueset = $GLOBALS['temporary_files_dir'] . "/" . $type . "/"; - $dir = str_replace('\\', '/', $dir_valueset); + $dir = str_replace('\\', '/', $dir_valueset); // Settings to drastically speed up import with InnoDB sqlStatementNoLog("SET autocommit=0"); @@ -711,9 +657,9 @@ function valueset_import($type) } } - sqlStatementNoLog("UPDATE valueset set code_type='SNOMED CT' where code_type='SNOMEDCT'"); - sqlStatementNoLog("UPDATE valueset set code_type='ICD9' where code_type='ICD9CM'"); - sqlStatementNoLog("UPDATE valueset set code_type='ICD10' where code_type='ICD10CM'"); + sqlStatementNoLog("UPDATE valueset set code_type='SNOMED CT' where code_type='SNOMEDCT'"); + sqlStatementNoLog("UPDATE valueset set code_type='ICD9' where code_type='ICD9CM'"); + sqlStatementNoLog("UPDATE valueset set code_type='ICD10' where code_type='ICD10CM'"); } } } @@ -800,3 +746,21 @@ function handle_zip_file($mode, $file) exit; } } + +/** + * @return Generator + */ +function getFileData($fn) +{ + $file = fopen($fn, 'r'); + + if (!$file) { + return; + } + + while (($line = fgets($file)) !== false) { + yield $line; + } + + fclose($file); +}