/** * \fn msiPrintGenQueryOutToBuffer(msParam_t *queryOut, msParam_t *format, msParam_t *buffer, ruleExecInfo_t *rei) * * \brief Writes the contents of a GenQueryOut_MS_T into a BUF_LEN_MS_T. * * \module core * * \author Antoine de Torcy * \date 2009-12-16 * * \note This microservice writes the contents of a GenQueryOut_MS_T into a BUF_LEN_MS_T. * The results can be formatted with an optional C-style format string the same way it is done in iquest. * * \usage See clients/icommands/test/rules3.0/ * * \param[in] queryOut - Required - A GenQueryOut_MS_T. * \param[in] format - Optional - A STR_MS_T with a C-style format string, like in iquest. * \param[out] buffer - A BUF_LEN_MS_T * \param[in,out] rei - The RuleExecInfo structure that is automatically * handled by the rule engine. The user does not include rei as a * parameter in the rule invocation. * * \DolVarDependence none * \DolVarModified none * \iCatAttrDependence none * \iCatAttrModified none * \sideeffect none * * \return integer * \retval 0 on success * \pre none * \post none * \sa none **/ int msiPrintGenQueryOutToBuffer( msParam_t *queryOut, msParam_t *format, msParam_t *buffer, ruleExecInfo_t *rei ) { genQueryOut_t *genQueryOut; char *format_str; bytesBuf_t *bytesBuf; FILE *stream; char readbuffer[MAX_NAME_LEN]; /************************************* INIT **********************************/ /* For testing mode when used with irule --test */ RE_TEST_MACRO( " Calling msiPrintGenQueryOutToBuffer" ) /* Sanity checks */ if ( rei == NULL || rei->rsComm == NULL ) { rodsLog( LOG_ERROR, "msiPrintGenQueryOutToBuffer: input rei or rsComm is NULL." ); return ( SYS_INTERNAL_NULL_INPUT_ERR ); } /********************************** PARAM PARSING *********************************/ /* Check for proper param type */ if ( !queryOut || !queryOut->inOutStruct || !queryOut->type || strcmp( queryOut->type, GenQueryOut_MS_T ) ) { rodsLog( LOG_ERROR, "msiPrintGenQueryOutToBuffer: Invalid input for queryOut." ); return( USER_PARAM_TYPE_ERR ); } genQueryOut = ( genQueryOut_t * )queryOut->inOutStruct; /* Parse format */ format_str = parseMspForStr( format ); /********************************** EXTRACT SQL RESULTS *********************************/ /* Let's use printGenQueryOut() here for the sake of consistency over efficiency (somewhat). It needs a stream. */ stream = tmpfile(); if ( !stream ) { /* Since it won't be caught by printGenQueryOut */ rodsLog( LOG_ERROR, "msiPrintGenQueryOutToBuffer: tmpfile() failed." ); return( FILE_OPEN_ERR ); /* accurate enough */ } /* Write results to temp file */ rei->status = printGenQueryOut( stream, format_str, NULL, genQueryOut ); if ( rei->status < 0 ) { rodsLog( LOG_ERROR, "msiPrintGenQueryOutToBuffer: printGenQueryOut() failed, status = %d", rei->status ); return( rei->status ); } /* bytesBuf init */ bytesBuf = ( bytesBuf_t * )malloc( sizeof( bytesBuf_t ) ); memset( bytesBuf, 0, sizeof( bytesBuf_t ) ); /* Read from temp file and write to bytesBuf */ rewind( stream ); while ( fgets( readbuffer, MAX_NAME_LEN, stream ) != NULL ) { appendToByteBuf( bytesBuf, readbuffer ); } /********************************* RETURN AND DONE **********************************/ /* Free memory previously allocated for previous result batches (when used in loop). */ if ( buffer && buffer->inpOutBuf ) { freeBBuf( buffer->inpOutBuf ); } resetMsParam( buffer ); /* Fill bytesBuf in our buffer output */ fillBufLenInMsParam( buffer, bytesBuf->len, bytesBuf ); return 0; }
/** * \fn msiGetMoreRows(msParam_t *genQueryInp_msp, msParam_t *genQueryOut_msp, msParam_t *continueInx, ruleExecInfo_t *rei) * * \brief This microservice continues an unfinished query. * * \module core * * \since pre-2.1 * * \author Antoine de Torcy * \date 2008-09-18 * * \note This microservice gets the next batch of rows for an open iCAT query. Likely to follow #msiMakeGenQuery and #msiExecGenQuery. * * \usage None * * \param[in] genQueryInp_msp - Required - a GenQueryInp_MS_T containing the query parameters and conditions. * \param[in] genQueryOut_msp - Required - a GenQueryOut_MS_T to write results to. If its continuation index is 0 the query will be closed. * \param[out] continueInx - a INT_MS_T containing the new continuation index (after the query). * \param[in,out] rei - The RuleExecInfo structure that is automatically * handled by the rule engine. The user does not include rei as a * parameter in the rule invocation. * * \DolVarDependence none * \DolVarModified none * \iCatAttrDependence none * \iCatAttrModified none * \sideeffect none * * \return integer * \retval 0 on success * \pre none * \post none * \sa none **/ int msiGetMoreRows( msParam_t *genQueryInp_msp, msParam_t *genQueryOut_msp, msParam_t *continueInx, ruleExecInfo_t *rei ) { genQueryInp_t *genQueryInp; genQueryOut_t *genQueryOut; RE_TEST_MACRO( " Calling msiGetMoreRows" ) if ( rei == NULL || rei->rsComm == NULL ) { rodsLog( LOG_ERROR, "msiGetMoreRows: input rei or rsComm is NULL." ); return ( SYS_INTERNAL_NULL_INPUT_ERR ); } /* check for non null parameters */ if ( !genQueryInp_msp || !genQueryOut_msp ) { rodsLog( LOG_ERROR, "msiGetMoreRows: Missing parameter(s)" ); return ( USER__NULL_INPUT_ERR ); } /* check for proper input types */ if ( strcmp( genQueryOut_msp->type, GenQueryOut_MS_T ) ) { rodsLog( LOG_ERROR, "msiGetMoreRows: genQueryOut_msp type is %s, should be GenQueryOut_MS_T", genQueryOut_msp->type ); return ( USER_PARAM_TYPE_ERR ); } if ( strcmp( genQueryInp_msp->type, GenQueryInp_MS_T ) ) { rodsLog( LOG_ERROR, "msiGetMoreRows: query_msp type is %s, should be GenQueryInp_MS_T", genQueryInp_msp->type ); return ( USER_PARAM_TYPE_ERR ); } /* retrieve genQueryXXX data structures */ genQueryOut = ( genQueryOut_t* )genQueryOut_msp->inOutStruct; genQueryInp = ( genQueryInp_t* )genQueryInp_msp->inOutStruct; /* match continuation indexes */ genQueryInp->continueInx = genQueryOut->continueInx; if ( genQueryInp->continueInx > 0 ) { /* get the next batch */ genQueryInp->maxRows = MAX_SQL_ROWS; } else { /* close query */ genQueryInp->maxRows = -1; } /* free memory allocated for previous results */ freeGenQueryOut( &genQueryOut ); /* query */ rei->status = rsGenQuery( rei->rsComm, genQueryInp, &genQueryOut ); if ( rei->status == 0 ) { /* return query results */ genQueryOut_msp->inOutStruct = genQueryOut; /* return continuation index separately in case it is needed in conditional expressions */ resetMsParam( continueInx ); fillIntInMsParam( continueInx, genQueryOut->continueInx ); } return ( rei->status ); }
/** * \fn msiXmlDocSchemaValidate(msParam_t *xmlObj, msParam_t *xsdObj, msParam_t *status, ruleExecInfo_t *rei) * * \brief This microservice validates an XML file against an XSD schema, both iRODS objects. * * \module xml * * \since pre-2.1 * * \author Antoine de Torcy * \date 2008/05/29 * * \usage See clients/icommands/test/rules3.0/ * * \param[in] xmlObj - a msParam of type DataObjInp_MS_T or STR_MS_T which is irods path of the XML object. * \param[in] xsdObj - a msParam of type DataObjInp_MS_T or STR_MS_T which is irods path of the XSD object. * \param[out] status - a msParam of type INT_MS_T which is a validation result. * \param[in,out] rei - The RuleExecInfo structure that is automatically * handled by the rule engine. The user does not include rei as a * parameter in the rule invocation. * * \DolVarDependence None * \DolVarModified None * \iCatAttrDependence None * \iCatAttrModified None * \sideeffect None * * \return integer * \retval 0 on success * \pre None * \post None * \sa None **/ int msiXmlDocSchemaValidate(msParam_t *xmlObj, msParam_t *xsdObj, msParam_t *status, ruleExecInfo_t *rei) { /* for parsing msParams and to open iRODS objects */ dataObjInp_t xmlObjInp, *myXmlObjInp; dataObjInp_t xsdObjInp, *myXsdObjInp; int xmlObjID, xsdObjID; /* for getting size of objects to read from */ rodsObjStat_t *rodsObjStatOut = NULL; /* for reading from iRODS objects */ openedDataObjInp_t openedDataObjInp; bytesBuf_t *xmlBuf = NULL; char *tail; /* for xml parsing and validating */ xmlDocPtr doc, xsd_doc; xmlSchemaParserCtxtPtr parser_ctxt; xmlSchemaPtr schema; xmlSchemaValidCtxtPtr valid_ctxt; bytesBuf_t *errBuf; /* misc. to avoid repeating rei->rsComm */ rsComm_t *rsComm; /************************************* USUAL INIT PROCEDURE **********************************/ /* For testing mode when used with irule --test */ RE_TEST_MACRO (" Calling msiXmlDocSchemaValidate") /* Sanity checks */ if (rei == NULL || rei->rsComm == NULL) { rodsLog (LOG_ERROR, "msiXmlDocSchemaValidate: input rei or rsComm is NULL."); return (SYS_INTERNAL_NULL_INPUT_ERR); } rsComm = rei->rsComm; /************************************ ADDITIONAL INIT SETTINGS *********************************/ /* XML constants */ xmlSubstituteEntitiesDefault(1); xmlLoadExtDtdDefaultValue = 1; /* allocate memory for output error buffer */ errBuf = (bytesBuf_t *)malloc(sizeof(bytesBuf_t)); errBuf->buf = strdup(""); errBuf->len = strlen((char*)errBuf->buf); /* Default status is failure, overwrite if success */ fillBufLenInMsParam (status, -1, NULL); /********************************** RETRIEVE INPUT PARAMS **************************************/ /* Get path of XML document */ rei->status = parseMspForDataObjInp (xmlObj, &xmlObjInp, &myXmlObjInp, 0); if (rei->status < 0) { rodsLog (LOG_ERROR, "msiXmlDocSchemaValidate: input xmlObj error. status = %d", rei->status); free(errBuf); return (rei->status); } /* Get path of schema */ rei->status = parseMspForDataObjInp (xsdObj, &xsdObjInp, &myXsdObjInp, 0); if (rei->status < 0) { rodsLog (LOG_ERROR, "msiXmlDocSchemaValidate: input xsdObj error. status = %d", rei->status); free(errBuf); return (rei->status); } /******************************** OPEN AND READ FROM XML OBJECT ********************************/ /* Open XML file */ if ((xmlObjID = rsDataObjOpen(rsComm, &xmlObjInp)) < 0) { rodsLog (LOG_ERROR, "msiXmlDocSchemaValidate: Cannot open XML data object. status = %d", xmlObjID); free(errBuf); return (xmlObjID); } /* Get size of XML file */ rei->status = rsObjStat (rsComm, &xmlObjInp, &rodsObjStatOut); if (rei->status < 0 || !rodsObjStatOut) { rodsLog (LOG_ERROR, "msiXmlDocSchemaValidate: Cannot stat XML data object. status = %d", rei->status); free(errBuf); return (rei->status); } /* xmlBuf init */ /* memory for xmlBuf->buf is allocated in rsFileRead() */ xmlBuf = (bytesBuf_t *) malloc (sizeof (bytesBuf_t)); memset (xmlBuf, 0, sizeof (bytesBuf_t)); /* Read content of XML file */ memset (&openedDataObjInp, 0, sizeof (openedDataObjInp_t)); openedDataObjInp.l1descInx = xmlObjID; openedDataObjInp.len = (int)rodsObjStatOut->objSize + 1; /* extra byte to add a null char */ rei->status = rsDataObjRead (rsComm, &openedDataObjInp, xmlBuf); /* add terminating null character */ tail = (char*)xmlBuf->buf; tail[openedDataObjInp.len - 1] = '\0'; /* Close XML file */ rei->status = rsDataObjClose (rsComm, &openedDataObjInp); /* cleanup */ freeRodsObjStat (rodsObjStatOut); /*************************************** PARSE XML DOCUMENT **************************************/ /* Parse xmlBuf.buf into an xmlDocPtr */ doc = xmlParseDoc((xmlChar*)xmlBuf->buf); clearBBuf(xmlBuf); if (doc == NULL) { rodsLog (LOG_ERROR, "msiXmlDocSchemaValidate: XML document cannot be loaded or is not well-formed."); free(errBuf); xmlCleanupParser(); return (USER_INPUT_FORMAT_ERR); } /******************************** OPEN AND READ FROM XSD OBJECT ********************************/ /* Open schema file */ if ((xsdObjID = rsDataObjOpen(rsComm, &xsdObjInp)) < 0) { rodsLog (LOG_ERROR, "msiXmlDocSchemaValidate: Cannot open XSD data object. status = %d", xsdObjID); free(errBuf); xmlFreeDoc(doc); xmlCleanupParser(); return (xsdObjID); } /* Get size of schema file */ rei->status = rsObjStat (rsComm, &xsdObjInp, &rodsObjStatOut); /* Read entire schema file */ memset (&openedDataObjInp, 0, sizeof (openedDataObjInp_t)); openedDataObjInp.l1descInx = xsdObjID; openedDataObjInp.len = (int)rodsObjStatOut->objSize + 1; /* to add null char */ rei->status = rsDataObjRead (rsComm, &openedDataObjInp, xmlBuf); /* add terminating null character */ tail = (char*)xmlBuf->buf; tail[openedDataObjInp.len - 1] = '\0'; /* Close schema file */ rei->status = rsDataObjClose (rsComm, &openedDataObjInp); /* cleanup */ freeRodsObjStat (rodsObjStatOut); /*************************************** PARSE XSD DOCUMENT **************************************/ /* Parse xmlBuf.buf into an xmlDocPtr */ xsd_doc = xmlParseDoc((xmlChar*)xmlBuf->buf); clearBBuf(xmlBuf); if (xsd_doc == NULL) { rodsLog (LOG_ERROR, "msiXmlDocSchemaValidate: XML Schema cannot be loaded or is not well-formed."); free(errBuf); xmlFreeDoc(doc); xmlCleanupParser(); return (USER_INPUT_FORMAT_ERR); } /**************************************** VALIDATE DOCUMENT **************************************/ /* Create a parser context */ parser_ctxt = xmlSchemaNewDocParserCtxt(xsd_doc); if (parser_ctxt == NULL) { rodsLog (LOG_ERROR, "msiXmlDocSchemaValidate: Unable to create a parser context for the schema."); free(errBuf); xmlFreeDoc(xsd_doc); xmlFreeDoc(doc); xmlCleanupParser(); return (USER_INPUT_FORMAT_ERR); } /* Parse the XML schema */ schema = xmlSchemaParse(parser_ctxt); if (schema == NULL) { rodsLog (LOG_ERROR, "msiXmlDocSchemaValidate: Invalid schema."); free(errBuf); xmlSchemaFreeParserCtxt(parser_ctxt); xmlFreeDoc(doc); xmlFreeDoc(xsd_doc); xmlCleanupParser(); return (USER_INPUT_FORMAT_ERR); } /* Create a validation context */ valid_ctxt = xmlSchemaNewValidCtxt(schema); if (valid_ctxt == NULL) { rodsLog (LOG_ERROR, "msiXmlDocSchemaValidate: Unable to create a validation context for the schema."); free(errBuf); xmlSchemaFree(schema); xmlSchemaFreeParserCtxt(parser_ctxt); xmlFreeDoc(xsd_doc); xmlFreeDoc(doc); xmlCleanupParser(); return (USER_INPUT_FORMAT_ERR); } /* Set myErrorCallback() as the default handler for error messages and warnings */ xmlSchemaSetValidErrors(valid_ctxt, (xmlSchemaValidityErrorFunc)myErrorCallback, (xmlSchemaValidityWarningFunc)myErrorCallback, errBuf); /* Validate XML doc */ rei->status = xmlSchemaValidateDoc(valid_ctxt, doc); /******************************************* WE'RE DONE ******************************************/ /* return both error code and messages through status */ resetMsParam (status); fillBufLenInMsParam (status, rei->status, errBuf); /* cleanup of all xml parsing stuff */ xmlSchemaFreeValidCtxt(valid_ctxt); xmlSchemaFree(schema); xmlSchemaFreeParserCtxt(parser_ctxt); xmlFreeDoc(doc); xmlFreeDoc(xsd_doc); xmlCleanupParser(); return (rei->status); }